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_XYZ12LE:
127 case AV_PIX_FMT_NV12:
128 case AV_PIX_FMT_NV21:
129 case AV_PIX_FMT_NV16:
130 case AV_PIX_FMT_P010LE:
131 case AV_PIX_FMT_P016LE:
132 case AV_PIX_FMT_YUVJ420P:
133 case AV_PIX_FMT_YUVJ422P:
134 case AV_PIX_FMT_YUVJ440P:
135 case AV_PIX_FMT_YUV422P:
136 case AV_PIX_FMT_YUV440P:
137 case AV_PIX_FMT_YUV444P:
138 case AV_PIX_FMT_YUVJ444P:
139 case AV_PIX_FMT_YUVA420P:
140 case AV_PIX_FMT_YUVA444P:
141 case AV_PIX_FMT_UYVY422:
142 case AV_PIX_FMT_YUYV422:
143 case AV_PIX_FMT_RGB0:
144 case AV_PIX_FMT_RGBA:
145 case AV_PIX_FMT_BGR0:
146 case AV_PIX_FMT_BGRA:
147 case AV_PIX_FMT_ARGB:
148 case AV_PIX_FMT_ABGR:
149 case AV_PIX_FMT_RGBA64LE:
150 case AV_PIX_FMT_BGRA64LE:
151 case AV_PIX_FMT_X2RGB10LE:
152 case AV_PIX_FMT_GBRP:
153 case AV_PIX_FMT_GBRAP:
155 case AV_PIX_FMT_YA16LE:
157#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(56, 19, 100)
158 case AV_PIX_FMT_YUV420P10LE:
159 case AV_PIX_FMT_YUV420P12LE:
160 case AV_PIX_FMT_YUV422P10LE:
161 case AV_PIX_FMT_YUV422P12LE:
162 case AV_PIX_FMT_YUV444P10LE:
163 case AV_PIX_FMT_YUV444P12LE:
164 case AV_PIX_FMT_YUVA444P10LE:
165 case AV_PIX_FMT_YUVA444P12LE:
166 case AV_PIX_FMT_GBRP10LE:
167 case AV_PIX_FMT_GBRP12LE:
168 case AV_PIX_FMT_GBRP16LE:
169 case AV_PIX_FMT_GBRAP10LE:
170 case AV_PIX_FMT_GBRAP12LE:
171 case AV_PIX_FMT_GBRAP16LE:
172 case AV_PIX_FMT_GBRPF32LE:
173 case AV_PIX_FMT_GBRAPF32LE:
174 case AV_PIX_FMT_GRAYF32:
175 case AV_PIX_FMT_NV24:
176 case AV_PIX_FMT_NV42:
177 case AV_PIX_FMT_Y210LE:
180#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 17, 100)
181 case AV_PIX_FMT_X2BGR10LE:
182 case AV_PIX_FMT_P210LE:
183 case AV_PIX_FMT_P216LE:
184 case AV_PIX_FMT_P410LE:
190#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
191 case AV_PIX_FMT_RGBAF32LE:
192 case AV_PIX_FMT_VUYA:
193 case AV_PIX_FMT_VUYX:
194 case AV_PIX_FMT_P012LE:
195 case AV_PIX_FMT_RGBAF16LE:
196#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
197 case AV_PIX_FMT_XV30LE:
201#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(59, 55, 100)
202 case AV_PIX_FMT_GBRPF16LE:
203 case AV_PIX_FMT_GBRAPF16LE:
206#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(60, 8, 100)
207 case AV_PIX_FMT_GRAYF16:
210 case AV_PIX_FMT_GRAY8:
211 case AV_PIX_FMT_GRAY16:
213 case AV_PIX_FMT_YUV410P:
214 case AV_PIX_FMT_YUV411P:
215 case AV_PIX_FMT_YUVA422P:
216 case AV_PIX_FMT_YUV420P16LE:
217 case AV_PIX_FMT_YUV422P16LE:
218 case AV_PIX_FMT_YUVA422P16LE:
219 case AV_PIX_FMT_PAL8:
220 case AV_PIX_FMT_RGB555LE:
221 case AV_PIX_FMT_RGB555BE:
222 case AV_PIX_FMT_BGR555LE:
223 case AV_PIX_FMT_RGB565LE:
224 case AV_PIX_FMT_RGB565BE:
225 case AV_PIX_FMT_BGR8:
226 case AV_PIX_FMT_0RGB:
227 case AV_PIX_FMT_BAYER_RGGB8:
228 case AV_PIX_FMT_BAYER_BGGR8:
229 case AV_PIX_FMT_BAYER_GRBG8:
230 case AV_PIX_FMT_BAYER_GBRG8:
231 case AV_PIX_FMT_BAYER_RGGB16LE:
232 case AV_PIX_FMT_BAYER_BGGR16LE:
233 case AV_PIX_FMT_BAYER_GRBG16LE:
234 case AV_PIX_FMT_BAYER_GBRG16LE:
243#if LIBAVUTIL_VERSION_MAJOR >= 57
247 AVPixelFormat format{AV_PIX_FMT_NONE};
248 AVHWDeviceType device{AV_HWDEVICE_TYPE_NONE};
251inline constexpr HWAccelFormats ffmpegHardwareDecodingFormats(AVPixelFormat p)
noexcept
255#if defined(__linux__)
256 case AV_PIX_FMT_DRM_PRIME:
257 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_DRM_PRIME))
259 return {AV_PIX_FMT_DRM_PRIME, AV_HWDEVICE_TYPE_DRM};
260 case AV_PIX_FMT_VAAPI:
261 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_VAAPI))
263 return {AV_PIX_FMT_VAAPI, AV_HWDEVICE_TYPE_VAAPI};
264 case AV_PIX_FMT_VDPAU:
265 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_VDPAU))
267 return {AV_PIX_FMT_VDPAU, AV_HWDEVICE_TYPE_VDPAU};
270 case AV_PIX_FMT_DXVA2_VLD:
271 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_DXVA2_VLD))
273 return {AV_PIX_FMT_DXVA2_VLD, AV_HWDEVICE_TYPE_DXVA2};
274 case AV_PIX_FMT_D3D11:
275 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_D3D11))
277 return {AV_PIX_FMT_D3D11, AV_HWDEVICE_TYPE_D3D11VA};
278#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
279 case AV_PIX_FMT_D3D12:
280 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_D3D12))
282 return {AV_PIX_FMT_D3D12, AV_HWDEVICE_TYPE_D3D12VA};
285#if defined(__APPLE__)
286 case AV_PIX_FMT_VIDEOTOOLBOX:
287 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_VIDEOTOOLBOX))
289 return {AV_PIX_FMT_VIDEOTOOLBOX, AV_HWDEVICE_TYPE_VIDEOTOOLBOX};
292 case AV_PIX_FMT_CUDA:
293 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_CUDA))
295 return {AV_PIX_FMT_CUDA, AV_HWDEVICE_TYPE_CUDA};
297 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_QSV))
299 return {AV_PIX_FMT_QSV, AV_HWDEVICE_TYPE_QSV};
300 case AV_PIX_FMT_VULKAN:
301 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_VULKAN))
303 return {AV_PIX_FMT_VULKAN, AV_HWDEVICE_TYPE_VULKAN};
311inline constexpr bool ffmpegCanDoHardwareDecoding(AVCodecID
id)
noexcept
315 case AV_CODEC_ID_AV1:
316 case AV_CODEC_ID_H264:
317 case AV_CODEC_ID_HEVC:
318 case AV_CODEC_ID_MJPEG:
319 case AV_CODEC_ID_MPEG1VIDEO:
320 case AV_CODEC_ID_MPEG2VIDEO:
321 case AV_CODEC_ID_MPEG4:
322 case AV_CODEC_ID_VC1:
323 case AV_CODEC_ID_VP8:
324 case AV_CODEC_ID_VP9:
325 case AV_CODEC_ID_WMV1:
326 case AV_CODEC_ID_WMV2:
327 case AV_CODEC_ID_WMV3:
328 case AV_CODEC_ID_PRORES:
335inline std::string
hwCodecName(
const char* codec_name, AVHWDeviceType device)
337 std::string name{codec_name};
340 case AV_HWDEVICE_TYPE_CUDA:
341 return name +
"_cuvid";
342 case AV_HWDEVICE_TYPE_QSV:
343 return name +
"_qsv";
344 case AV_HWDEVICE_TYPE_VDPAU:
345 return name +
"_vdpau";
346 case AV_HWDEVICE_TYPE_VAAPI:
348 case AV_HWDEVICE_TYPE_DRM:
349 return name +
"_v4l2m2m";
350 case AV_HWDEVICE_TYPE_DXVA2:
351 case AV_HWDEVICE_TYPE_D3D11VA:
352#if defined(_WIN32) && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
353 case AV_HWDEVICE_TYPE_D3D12VA:
355 case AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
356 case AV_HWDEVICE_TYPE_VULKAN:
364inline bool isVulkanComputeCodec(AVCodecID
id)
368 case AV_CODEC_ID_PRORES:
369 case AV_CODEC_ID_FFV1:
384inline bool vulkanComputeDecodersAreReliable() noexcept
386 return avcodec_version() >= AV_VERSION_INT(63, 2, 0);
391 AVCodecID codec_id, AVPixelFormat pix_fmt, uint32_t gpuVendorId = 0)
399 if(pix_fmt == AV_PIX_FMT_VULKAN && isVulkanComputeCodec(codec_id)
400 && !vulkanComputeDecodersAreReliable())
403 auto hwInfo = ffmpegHardwareDecodingFormats(pix_fmt);
404 if(hwInfo.device == AV_HWDEVICE_TYPE_NONE)
407 const AVCodec* codec = avcodec_find_decoder(codec_id);
411 auto dedicated =
hwCodecName(codec->name, hwInfo.device);
412 if(!dedicated.empty() && dedicated != codec->name)
414 if(avcodec_find_decoder_by_name(dedicated.c_str()))
421 const AVCodecHWConfig* config = avcodec_get_hw_config(codec, i);
424 if(config->pix_fmt == pix_fmt
425 && (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
434inline constexpr uint32_t NVIDIA = 0x10DE;
435inline constexpr uint32_t
Intel = 0x8086;
436inline constexpr uint32_t AMD = 0x1002;
437inline constexpr uint32_t
Apple = 0x106B;
438inline constexpr uint32_t Broadcom = 0x14E4;
439inline constexpr uint32_t ARM = 0x13B5;
440inline constexpr uint32_t Qualcomm = 0x5143;
441inline constexpr uint32_t Samsung = 0x144D;
448inline std::vector<AVPixelFormat> selectHardwareAccelerations(
449 int graphicsApi, AVCodecID codec_id, uint32_t gpuVendorId = 0)
451 struct Candidate { AVPixelFormat fmt; };
452 std::vector<Candidate> candidates;
458 candidates = {{AV_PIX_FMT_D3D11}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
461#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
462 candidates = {{AV_PIX_FMT_D3D12}, {AV_PIX_FMT_D3D11}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
464 candidates = {{AV_PIX_FMT_D3D11}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
468#if defined(__APPLE__)
470 candidates = {{AV_PIX_FMT_VIDEOTOOLBOX}};
475#if defined(__linux__)
476 if(gpuVendorId == GpuVendor::NVIDIA)
478 candidates = {{AV_PIX_FMT_VULKAN}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_VAAPI}, {AV_PIX_FMT_QSV}};
480 else if(gpuVendorId == GpuVendor::Intel)
482 candidates = {{AV_PIX_FMT_VAAPI}, {AV_PIX_FMT_VULKAN}, {AV_PIX_FMT_QSV}};
484 else if(gpuVendorId == GpuVendor::AMD)
486 candidates = {{AV_PIX_FMT_VAAPI}, {AV_PIX_FMT_VULKAN}};
488 else if(gpuVendorId == GpuVendor::Broadcom
489 || gpuVendorId == GpuVendor::ARM
490 || gpuVendorId == GpuVendor::Qualcomm)
492 candidates = {{AV_PIX_FMT_DRM_PRIME}, {AV_PIX_FMT_VULKAN}};
496 candidates = {{AV_PIX_FMT_VAAPI}, {AV_PIX_FMT_VULKAN}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
500 {AV_PIX_FMT_VULKAN}, {AV_PIX_FMT_D3D11},
501#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
504 {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
505#elif defined(__APPLE__)
506 candidates = {{AV_PIX_FMT_VIDEOTOOLBOX}};
508 candidates = {{AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
514#if defined(__linux__)
515 if(gpuVendorId == GpuVendor::Broadcom
516 || gpuVendorId == GpuVendor::ARM
517 || gpuVendorId == GpuVendor::Qualcomm)
519 candidates = {{AV_PIX_FMT_DRM_PRIME}};
523 candidates = {{AV_PIX_FMT_VAAPI}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
526 candidates = {{AV_PIX_FMT_D3D11}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
527#elif defined(__APPLE__)
528 candidates = {{AV_PIX_FMT_VIDEOTOOLBOX}};
534#if defined(__linux__)
535#if defined(__arm__) || defined(__aarch64__)
536 candidates = {{AV_PIX_FMT_DRM_PRIME}, {AV_PIX_FMT_VAAPI}};
538 candidates = {{AV_PIX_FMT_VAAPI}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
541 candidates = {{AV_PIX_FMT_D3D11}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
542#elif defined(__APPLE__)
543 candidates = {{AV_PIX_FMT_VIDEOTOOLBOX}};
549 std::vector<AVPixelFormat> result;
550 for(
auto& c : candidates)
552 if(hardwareDecoderIsAvailable(c.fmt)
554 result.push_back(c.fmt);
561 int graphicsApi, AVCodecID codec_id, uint32_t gpuVendorId = 0)
563 auto fmts = selectHardwareAccelerations(graphicsApi, codec_id, gpuVendorId);
564 return fmts.empty() ? AV_PIX_FMT_NONE : fmts.front();
567#if defined(__linux__)
574inline std::string preferredVAAPIRenderNode() noexcept
576 for(
int i = 128; i < 128 + 16; i++)
578 char link[64], drv[256];
579 snprintf(link,
sizeof link,
"/sys/class/drm/renderD%d/device/driver", i);
580 ssize_t n = readlink(link, drv,
sizeof(drv) - 1);
584 std::string_view driver{drv};
585 if(
auto slash = driver.rfind(
'/'); slash != std::string_view::npos)
586 driver.remove_prefix(slash + 1);
587 if(driver !=
"nvidia")
590 snprintf(dev,
sizeof dev,
"/dev/dri/renderD%d", i);
604inline std::string hardwareDecodingDeviceName(AVHWDeviceType device)
noexcept
606 if(
const char* env = getenv(
"SCORE_VIDEO_HW_DEVICE"); env && *env)
608#if defined(__linux__)
609 if(device == AV_HWDEVICE_TYPE_VAAPI)
610 return preferredVAAPIRenderNode();
616inline int createHardwareDevice(AVBufferRef** ctx, AVHWDeviceType device)
noexcept
618 const std::string name = hardwareDecodingDeviceName(device);
619 return av_hwdevice_ctx_create(
620 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