2#include <Media/Libav.hpp>
17#include <libavcodec/avcodec.h>
18#include <libavformat/avformat.h>
19#include <libavutil/pixdesc.h>
20#include <libavutil/version.h>
21#if __has_include(<libavutil/hwcontext.h>)
22#include <libavutil/hwcontext.h>
30inline bool hardwareDecoderIsAvailable(AVPixelFormat p)
noexcept
35 case AV_PIX_FMT_DRM_PRIME: {
36 static const bool ok = avcodec_find_decoder_by_name(
"h264_v4l2m2m");
39 case AV_PIX_FMT_VAAPI: {
43 static const bool ok = avcodec_find_decoder_by_name(
"mjpeg_vaapi")
44 || av_hwdevice_find_type_by_name(
"vaapi") != AV_HWDEVICE_TYPE_NONE;
47 case AV_PIX_FMT_VDPAU: {
48 static const bool ok = avcodec_find_decoder_by_name(
"h264_vdpau");
53 case AV_PIX_FMT_DXVA2_VLD:
55 case AV_PIX_FMT_D3D11:
57#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
58 case AV_PIX_FMT_D3D12:
63 case AV_PIX_FMT_VIDEOTOOLBOX:
67 case AV_PIX_FMT_CUDA: {
68 static const bool ok = avcodec_find_decoder_by_name(
"mjpeg_cuvid")
69 || avcodec_find_decoder_by_name(
"h264_cuvid");
72 case AV_PIX_FMT_QSV: {
73 static const bool ok = avcodec_find_decoder_by_name(
"mjpeg_qsv")
74 || avcodec_find_decoder_by_name(
"h264_qsv");
77 case AV_PIX_FMT_VULKAN: {
79 = av_hwdevice_find_type_by_name(
"vulkan") != AV_HWDEVICE_TYPE_NONE;
87inline constexpr bool formatIsHardwareDecoded(AVPixelFormat fmt)
noexcept
89#if LIBAVUTIL_VERSION_MAJOR < 57
94 case AV_PIX_FMT_VAAPI:
95 case AV_PIX_FMT_VDPAU:
96 case AV_PIX_FMT_DXVA2_VLD:
97 case AV_PIX_FMT_D3D11:
98#if defined(_WIN32) && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
99 case AV_PIX_FMT_D3D12:
101 case AV_PIX_FMT_CUDA:
103 case AV_PIX_FMT_VIDEOTOOLBOX:
104 case AV_PIX_FMT_DRM_PRIME:
105 case AV_PIX_FMT_VULKAN:
113inline constexpr bool formatNeedsDecoding(AVPixelFormat fmt)
noexcept
116 if(formatIsHardwareDecoded(fmt))
121 case AV_PIX_FMT_YUV420P:
122 case AV_PIX_FMT_RGB24:
123 case AV_PIX_FMT_BGR24:
124 case AV_PIX_FMT_RGB48LE:
125 case AV_PIX_FMT_BGR48LE:
126 case AV_PIX_FMT_NV12:
127 case AV_PIX_FMT_NV21:
128 case AV_PIX_FMT_NV16:
129 case AV_PIX_FMT_P010LE:
130 case AV_PIX_FMT_P016LE:
131 case AV_PIX_FMT_YUVJ420P:
132 case AV_PIX_FMT_YUVJ422P:
133 case AV_PIX_FMT_YUVJ440P:
134 case AV_PIX_FMT_YUV422P:
135 case AV_PIX_FMT_YUV440P:
136 case AV_PIX_FMT_YUV444P:
137 case AV_PIX_FMT_YUVJ444P:
138 case AV_PIX_FMT_YUVA420P:
139 case AV_PIX_FMT_YUVA444P:
140 case AV_PIX_FMT_UYVY422:
141 case AV_PIX_FMT_YUYV422:
142 case AV_PIX_FMT_RGB0:
143 case AV_PIX_FMT_RGBA:
144 case AV_PIX_FMT_BGR0:
145 case AV_PIX_FMT_BGRA:
146 case AV_PIX_FMT_ARGB:
147 case AV_PIX_FMT_ABGR:
148 case AV_PIX_FMT_RGBA64LE:
149 case AV_PIX_FMT_BGRA64LE:
150 case AV_PIX_FMT_X2RGB10LE:
151 case AV_PIX_FMT_GBRP:
152 case AV_PIX_FMT_GBRAP:
154 case AV_PIX_FMT_YA16LE:
156#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(56, 19, 100)
157 case AV_PIX_FMT_YUV420P10LE:
158 case AV_PIX_FMT_YUV420P12LE:
159 case AV_PIX_FMT_YUV422P10LE:
160 case AV_PIX_FMT_YUV422P12LE:
161 case AV_PIX_FMT_YUV444P10LE:
162 case AV_PIX_FMT_YUV444P12LE:
163 case AV_PIX_FMT_YUVA444P10LE:
164 case AV_PIX_FMT_YUVA444P12LE:
165 case AV_PIX_FMT_GBRP10LE:
166 case AV_PIX_FMT_GBRP12LE:
167 case AV_PIX_FMT_GBRP16LE:
168 case AV_PIX_FMT_GBRAP10LE:
169 case AV_PIX_FMT_GBRAP12LE:
170 case AV_PIX_FMT_GBRAP16LE:
171 case AV_PIX_FMT_GBRPF32LE:
172 case AV_PIX_FMT_GBRAPF32LE:
173 case AV_PIX_FMT_GRAYF32:
174 case AV_PIX_FMT_NV24:
175 case AV_PIX_FMT_NV42:
176 case AV_PIX_FMT_Y210LE:
179#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 17, 100)
180 case AV_PIX_FMT_X2BGR10LE:
181 case AV_PIX_FMT_P210LE:
182 case AV_PIX_FMT_P410LE:
188#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
189 case AV_PIX_FMT_RGBAF32LE:
190 case AV_PIX_FMT_VUYA:
191 case AV_PIX_FMT_VUYX:
192 case AV_PIX_FMT_P012LE:
193 case AV_PIX_FMT_RGBAF16LE:
194#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
195 case AV_PIX_FMT_XV30LE:
199#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(60, 8, 100)
200 case AV_PIX_FMT_GRAYF16:
203 case AV_PIX_FMT_GRAY8:
204 case AV_PIX_FMT_GRAY16:
213#if LIBAVUTIL_VERSION_MAJOR >= 57
217 AVPixelFormat format{AV_PIX_FMT_NONE};
218 AVHWDeviceType device{AV_HWDEVICE_TYPE_NONE};
221inline constexpr HWAccelFormats ffmpegHardwareDecodingFormats(AVPixelFormat p)
noexcept
225#if defined(__linux__)
226 case AV_PIX_FMT_DRM_PRIME:
227 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_DRM_PRIME))
229 return {AV_PIX_FMT_DRM_PRIME, AV_HWDEVICE_TYPE_DRM};
230 case AV_PIX_FMT_VAAPI:
231 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_VAAPI))
233 return {AV_PIX_FMT_VAAPI, AV_HWDEVICE_TYPE_VAAPI};
234 case AV_PIX_FMT_VDPAU:
235 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_VDPAU))
237 return {AV_PIX_FMT_VDPAU, AV_HWDEVICE_TYPE_VDPAU};
240 case AV_PIX_FMT_DXVA2_VLD:
241 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_DXVA2_VLD))
243 return {AV_PIX_FMT_DXVA2_VLD, AV_HWDEVICE_TYPE_DXVA2};
244 case AV_PIX_FMT_D3D11:
245 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_D3D11))
247 return {AV_PIX_FMT_D3D11, AV_HWDEVICE_TYPE_D3D11VA};
248#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
249 case AV_PIX_FMT_D3D12:
250 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_D3D12))
252 return {AV_PIX_FMT_D3D12, AV_HWDEVICE_TYPE_D3D12VA};
255#if defined(__APPLE__)
256 case AV_PIX_FMT_VIDEOTOOLBOX:
257 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_VIDEOTOOLBOX))
259 return {AV_PIX_FMT_VIDEOTOOLBOX, AV_HWDEVICE_TYPE_VIDEOTOOLBOX};
262 case AV_PIX_FMT_CUDA:
263 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_CUDA))
265 return {AV_PIX_FMT_CUDA, AV_HWDEVICE_TYPE_CUDA};
267 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_QSV))
269 return {AV_PIX_FMT_QSV, AV_HWDEVICE_TYPE_QSV};
270 case AV_PIX_FMT_VULKAN:
271 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_VULKAN))
273 return {AV_PIX_FMT_VULKAN, AV_HWDEVICE_TYPE_VULKAN};
281inline constexpr bool ffmpegCanDoHardwareDecoding(AVCodecID
id)
noexcept
285 case AV_CODEC_ID_AV1:
286 case AV_CODEC_ID_H264:
287 case AV_CODEC_ID_HEVC:
288 case AV_CODEC_ID_MJPEG:
289 case AV_CODEC_ID_MPEG1VIDEO:
290 case AV_CODEC_ID_MPEG2VIDEO:
291 case AV_CODEC_ID_MPEG4:
292 case AV_CODEC_ID_VC1:
293 case AV_CODEC_ID_VP8:
294 case AV_CODEC_ID_VP9:
295 case AV_CODEC_ID_WMV1:
296 case AV_CODEC_ID_WMV2:
297 case AV_CODEC_ID_WMV3:
298 case AV_CODEC_ID_PRORES:
305inline std::string
hwCodecName(
const char* codec_name, AVHWDeviceType device)
307 std::string name{codec_name};
310 case AV_HWDEVICE_TYPE_CUDA:
311 return name +
"_cuvid";
312 case AV_HWDEVICE_TYPE_QSV:
313 return name +
"_qsv";
314 case AV_HWDEVICE_TYPE_VDPAU:
315 return name +
"_vdpau";
316 case AV_HWDEVICE_TYPE_VAAPI:
318 case AV_HWDEVICE_TYPE_DRM:
319 return name +
"_v4l2m2m";
320 case AV_HWDEVICE_TYPE_DXVA2:
321 case AV_HWDEVICE_TYPE_D3D11VA:
322#if defined(_WIN32) && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
323 case AV_HWDEVICE_TYPE_D3D12VA:
325 case AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
326 case AV_HWDEVICE_TYPE_VULKAN:
335inline bool isVulkanComputeCodec(AVCodecID
id)
339 case AV_CODEC_ID_PRORES:
340 case AV_CODEC_ID_FFV1:
349 AVCodecID codec_id, AVPixelFormat pix_fmt, uint32_t gpuVendorId = 0)
358 if(pix_fmt == AV_PIX_FMT_VULKAN && isVulkanComputeCodec(codec_id))
361 auto hwInfo = ffmpegHardwareDecodingFormats(pix_fmt);
362 if(hwInfo.device == AV_HWDEVICE_TYPE_NONE)
365 const AVCodec* codec = avcodec_find_decoder(codec_id);
369 auto dedicated =
hwCodecName(codec->name, hwInfo.device);
370 if(!dedicated.empty() && dedicated != codec->name)
372 if(avcodec_find_decoder_by_name(dedicated.c_str()))
379 const AVCodecHWConfig* config = avcodec_get_hw_config(codec, i);
382 if(config->pix_fmt == pix_fmt
383 && (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
392inline constexpr uint32_t NVIDIA = 0x10DE;
393inline constexpr uint32_t
Intel = 0x8086;
394inline constexpr uint32_t AMD = 0x1002;
395inline constexpr uint32_t
Apple = 0x106B;
396inline constexpr uint32_t Broadcom = 0x14E4;
397inline constexpr uint32_t ARM = 0x13B5;
398inline constexpr uint32_t Qualcomm = 0x5143;
399inline constexpr uint32_t Samsung = 0x144D;
406inline std::vector<AVPixelFormat> selectHardwareAccelerations(
407 int graphicsApi, AVCodecID codec_id, uint32_t gpuVendorId = 0)
409 struct Candidate { AVPixelFormat fmt; };
410 std::vector<Candidate> candidates;
416 candidates = {{AV_PIX_FMT_D3D11}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
419#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
420 candidates = {{AV_PIX_FMT_D3D12}, {AV_PIX_FMT_D3D11}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
422 candidates = {{AV_PIX_FMT_D3D11}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
426#if defined(__APPLE__)
428 candidates = {{AV_PIX_FMT_VIDEOTOOLBOX}};
433#if defined(__linux__)
434 if(gpuVendorId == GpuVendor::NVIDIA)
436 candidates = {{AV_PIX_FMT_VULKAN}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_VAAPI}, {AV_PIX_FMT_QSV}};
438 else if(gpuVendorId == GpuVendor::Intel)
440 candidates = {{AV_PIX_FMT_VAAPI}, {AV_PIX_FMT_VULKAN}, {AV_PIX_FMT_QSV}};
442 else if(gpuVendorId == GpuVendor::AMD)
444 candidates = {{AV_PIX_FMT_VAAPI}, {AV_PIX_FMT_VULKAN}};
446 else if(gpuVendorId == GpuVendor::Broadcom
447 || gpuVendorId == GpuVendor::ARM
448 || gpuVendorId == GpuVendor::Qualcomm)
450 candidates = {{AV_PIX_FMT_DRM_PRIME}, {AV_PIX_FMT_VULKAN}};
454 candidates = {{AV_PIX_FMT_VAAPI}, {AV_PIX_FMT_VULKAN}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
458 {AV_PIX_FMT_VULKAN}, {AV_PIX_FMT_D3D11},
459#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
462 {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
463#elif defined(__APPLE__)
464 candidates = {{AV_PIX_FMT_VIDEOTOOLBOX}};
466 candidates = {{AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
472#if defined(__linux__)
473 if(gpuVendorId == GpuVendor::Broadcom
474 || gpuVendorId == GpuVendor::ARM
475 || gpuVendorId == GpuVendor::Qualcomm)
477 candidates = {{AV_PIX_FMT_DRM_PRIME}};
481 candidates = {{AV_PIX_FMT_VAAPI}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
484 candidates = {{AV_PIX_FMT_D3D11}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
485#elif defined(__APPLE__)
486 candidates = {{AV_PIX_FMT_VIDEOTOOLBOX}};
492#if defined(__linux__)
493#if defined(__arm__) || defined(__aarch64__)
494 candidates = {{AV_PIX_FMT_DRM_PRIME}, {AV_PIX_FMT_VAAPI}};
496 candidates = {{AV_PIX_FMT_VAAPI}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
499 candidates = {{AV_PIX_FMT_D3D11}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
500#elif defined(__APPLE__)
501 candidates = {{AV_PIX_FMT_VIDEOTOOLBOX}};
507 std::vector<AVPixelFormat> result;
508 for(
auto& c : candidates)
510 if(hardwareDecoderIsAvailable(c.fmt)
512 result.push_back(c.fmt);
519 int graphicsApi, AVCodecID codec_id, uint32_t gpuVendorId = 0)
521 auto fmts = selectHardwareAccelerations(graphicsApi, codec_id, gpuVendorId);
522 return fmts.empty() ? AV_PIX_FMT_NONE : fmts.front();
525#if defined(__linux__)
532inline std::string preferredVAAPIRenderNode() noexcept
534 for(
int i = 128; i < 128 + 16; i++)
536 char link[64], drv[256];
537 snprintf(link,
sizeof link,
"/sys/class/drm/renderD%d/device/driver", i);
538 ssize_t n = readlink(link, drv,
sizeof(drv) - 1);
542 std::string_view driver{drv};
543 if(
auto slash = driver.rfind(
'/'); slash != std::string_view::npos)
544 driver.remove_prefix(slash + 1);
545 if(driver !=
"nvidia")
548 snprintf(dev,
sizeof dev,
"/dev/dri/renderD%d", i);
562inline std::string hardwareDecodingDeviceName(AVHWDeviceType device)
noexcept
564 if(
const char* env = getenv(
"SCORE_VIDEO_HW_DEVICE"); env && *env)
566#if defined(__linux__)
567 if(device == AV_HWDEVICE_TYPE_VAAPI)
568 return preferredVAAPIRenderNode();
574inline int createHardwareDevice(AVBufferRef** ctx, AVHWDeviceType device)
noexcept
576 const std::string name = hardwareDecodingDeviceName(device);
577 return av_hwdevice_ctx_create(
578 ctx, device, name.empty() ?
nullptr : name.c_str(), nullptr, 0);
GpuVendor
Definition GpuCapabilities.hpp:50
AVPixelFormat selectHardwareAcceleration(score::gfx::GraphicsApi api, AVCodecID codec_id, QRhi *rhi)
Picks the best HW accel for the given API/codec, using QRhi for vendor detection.
Definition HWAccelSetup.cpp:36
std::string hwCodecName(const char *codec_name, AVHWDeviceType device)
Delegates to Video::hwCodecName (score-plugin-gfx wrapper)
Definition HWAccelSetup.cpp:18
bool codecSupportsHWPixelFormat(AVCodecID codec_id, AVPixelFormat pix_fmt)
Delegates to Video::codecSupportsHWPixelFormat (score-plugin-gfx wrapper)
Definition HWAccelSetup.cpp:27