Loading...
Searching...
No Matches
GpuFormats.hpp
1#pragma once
2#include <Media/Libav.hpp>
3
4#include <string>
5#include <vector>
6
7#if SCORE_HAS_LIBAV
8extern "C" {
9#include <libavcodec/avcodec.h>
10#include <libavformat/avformat.h>
11#include <libavutil/pixdesc.h>
12#include <libavutil/version.h>
13#if __has_include(<libavutil/hwcontext.h>)
14#include <libavutil/hwcontext.h>
15#endif
16struct AVCodecContext;
17}
18
19namespace Video
20{
21
22inline bool hardwareDecoderIsAvailable(AVPixelFormat p) noexcept
23{
24 switch(p)
25 {
26#if defined(__linux__)
27 case AV_PIX_FMT_DRM_PRIME: {
28 static const bool ok = avcodec_find_decoder_by_name("h264_v4l2m2m");
29 return ok;
30 }
31 case AV_PIX_FMT_VAAPI: {
32 // FFmpeg 7+ removed dedicated VAAPI decoders (mjpeg_vaapi, etc.).
33 // VAAPI now uses the generic decoder with hw_device_ctx.
34 // Check if the VAAPI device type is supported instead.
35 static const bool ok = avcodec_find_decoder_by_name("mjpeg_vaapi")
36 || av_hwdevice_find_type_by_name("vaapi") != AV_HWDEVICE_TYPE_NONE;
37 return ok;
38 }
39 case AV_PIX_FMT_VDPAU: {
40 static const bool ok = avcodec_find_decoder_by_name("h264_vdpau");
41 return ok;
42 }
43#endif
44#if defined(_WIN32)
45 case AV_PIX_FMT_DXVA2_VLD:
46 return true;
47 case AV_PIX_FMT_D3D11:
48 return true;
49#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
50 case AV_PIX_FMT_D3D12:
51 return true;
52#endif
53#endif
54#if defined(__APPLE__)
55 case AV_PIX_FMT_VIDEOTOOLBOX:
56 return true;
57#endif
58 // Cross-platform pix formats
59 case AV_PIX_FMT_CUDA: {
60 static const bool ok = avcodec_find_decoder_by_name("mjpeg_cuvid")
61 || avcodec_find_decoder_by_name("h264_cuvid");
62 return ok;
63 }
64 case AV_PIX_FMT_QSV: {
65 static const bool ok = avcodec_find_decoder_by_name("mjpeg_qsv")
66 || avcodec_find_decoder_by_name("h264_qsv");
67 return ok;
68 }
69 case AV_PIX_FMT_VULKAN: {
70 static const bool ok
71 = av_hwdevice_find_type_by_name("vulkan") != AV_HWDEVICE_TYPE_NONE;
72 return ok;
73 }
74 default:
75 return false;
76 }
77}
78
79inline constexpr bool formatIsHardwareDecoded(AVPixelFormat fmt) noexcept
80{
81#if LIBAVUTIL_VERSION_MAJOR < 57
82 return false;
83#else
84 switch(fmt)
85 {
86 case AV_PIX_FMT_VAAPI:
87 case AV_PIX_FMT_VDPAU:
88 case AV_PIX_FMT_DXVA2_VLD:
89 case AV_PIX_FMT_D3D11:
90#if defined(_WIN32) && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
91 case AV_PIX_FMT_D3D12:
92#endif
93 case AV_PIX_FMT_CUDA:
94 case AV_PIX_FMT_QSV:
95 case AV_PIX_FMT_VIDEOTOOLBOX:
96 case AV_PIX_FMT_DRM_PRIME:
97 case AV_PIX_FMT_VULKAN:
98 return true;
99 default:
100 return false;
101 }
102#endif
103}
104
105inline constexpr bool formatNeedsDecoding(AVPixelFormat fmt) noexcept
106{
107 // They all get translated to some NV12 or something like that
108 if(formatIsHardwareDecoded(fmt))
109 return false;
110
111 switch(fmt)
112 {
113 case AV_PIX_FMT_YUV420P:
114 case AV_PIX_FMT_RGB24:
115 case AV_PIX_FMT_BGR24:
116 case AV_PIX_FMT_RGB48LE:
117 case AV_PIX_FMT_BGR48LE:
118 case AV_PIX_FMT_NV12:
119 case AV_PIX_FMT_NV21:
120 case AV_PIX_FMT_NV16:
121 case AV_PIX_FMT_P010LE:
122 case AV_PIX_FMT_P016LE:
123 case AV_PIX_FMT_YUVJ420P:
124 case AV_PIX_FMT_YUVJ422P:
125 case AV_PIX_FMT_YUVJ440P:
126 case AV_PIX_FMT_YUV422P:
127 case AV_PIX_FMT_YUV440P:
128 case AV_PIX_FMT_YUV444P:
129 case AV_PIX_FMT_YUVJ444P:
130 case AV_PIX_FMT_YUVA420P:
131 case AV_PIX_FMT_YUVA444P:
132 case AV_PIX_FMT_UYVY422:
133 case AV_PIX_FMT_YUYV422:
134 case AV_PIX_FMT_RGB0:
135 case AV_PIX_FMT_RGBA:
136 case AV_PIX_FMT_BGR0:
137 case AV_PIX_FMT_BGRA:
138 case AV_PIX_FMT_ARGB:
139 case AV_PIX_FMT_ABGR:
140 case AV_PIX_FMT_RGBA64LE:
141 case AV_PIX_FMT_BGRA64LE:
142 case AV_PIX_FMT_X2RGB10LE:
143 case AV_PIX_FMT_GBRP:
144 case AV_PIX_FMT_GBRAP:
145 case AV_PIX_FMT_YA8:
146 case AV_PIX_FMT_YA16LE:
147
148#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(56, 19, 100)
149 case AV_PIX_FMT_YUV420P10LE:
150 case AV_PIX_FMT_YUV420P12LE:
151 case AV_PIX_FMT_YUV422P10LE:
152 case AV_PIX_FMT_YUV422P12LE:
153 case AV_PIX_FMT_YUV444P10LE:
154 case AV_PIX_FMT_YUV444P12LE:
155 case AV_PIX_FMT_YUVA444P10LE:
156 case AV_PIX_FMT_YUVA444P12LE:
157 case AV_PIX_FMT_GBRP10LE:
158 case AV_PIX_FMT_GBRP12LE:
159 case AV_PIX_FMT_GBRP16LE:
160 case AV_PIX_FMT_GBRAP10LE:
161 case AV_PIX_FMT_GBRAP12LE:
162 case AV_PIX_FMT_GBRAP16LE:
163 case AV_PIX_FMT_GBRPF32LE:
164 case AV_PIX_FMT_GBRAPF32LE:
165 case AV_PIX_FMT_GRAYF32LE:
166 case AV_PIX_FMT_GRAYF32BE:
167 case AV_PIX_FMT_NV24:
168 case AV_PIX_FMT_NV42:
169 case AV_PIX_FMT_Y210LE:
170#endif
171
172#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 17, 100)
173 case AV_PIX_FMT_X2BGR10LE:
174 case AV_PIX_FMT_P210LE:
175 case AV_PIX_FMT_P410LE:
176#endif
177
178#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(60, 8, 100)
179 case AV_PIX_FMT_RGBAF32LE:
180 case AV_PIX_FMT_VUYA:
181 case AV_PIX_FMT_VUYX:
182 case AV_PIX_FMT_GRAYF16LE:
183 case AV_PIX_FMT_GRAYF16BE:
184#endif
185
186 case AV_PIX_FMT_GRAY8:
187 case AV_PIX_FMT_GRAY16:
188 return false;
189
190 // Other formats get rgb'd
191 default:
192 return true;
193 }
194}
195
196#if LIBAVUTIL_VERSION_MAJOR >= 57
197// Get hardware pix format
198struct HWAccelFormats
199{
200 AVPixelFormat format{AV_PIX_FMT_NONE};
201 AVHWDeviceType device{AV_HWDEVICE_TYPE_NONE};
202};
203
204inline constexpr HWAccelFormats ffmpegHardwareDecodingFormats(AVPixelFormat p) noexcept
205{
206 switch(p)
207 {
208#if defined(__linux__)
209 case AV_PIX_FMT_DRM_PRIME:
210 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_DRM_PRIME))
211 return {};
212 return {AV_PIX_FMT_DRM_PRIME, AV_HWDEVICE_TYPE_DRM};
213 case AV_PIX_FMT_VAAPI:
214 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_VAAPI))
215 return {};
216 return {AV_PIX_FMT_VAAPI, AV_HWDEVICE_TYPE_VAAPI};
217 case AV_PIX_FMT_VDPAU:
218 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_VDPAU))
219 return {};
220 return {AV_PIX_FMT_VDPAU, AV_HWDEVICE_TYPE_VDPAU};
221#endif
222#if defined(_WIN32)
223 case AV_PIX_FMT_DXVA2_VLD:
224 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_DXVA2_VLD))
225 return {};
226 return {AV_PIX_FMT_DXVA2_VLD, AV_HWDEVICE_TYPE_DXVA2};
227 case AV_PIX_FMT_D3D11:
228 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_D3D11))
229 return {};
230 return {AV_PIX_FMT_D3D11, AV_HWDEVICE_TYPE_D3D11VA};
231#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
232 case AV_PIX_FMT_D3D12:
233 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_D3D12))
234 return {};
235 return {AV_PIX_FMT_D3D12, AV_HWDEVICE_TYPE_D3D12VA};
236#endif
237#endif
238#if defined(__APPLE__)
239 case AV_PIX_FMT_VIDEOTOOLBOX:
240 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_VIDEOTOOLBOX))
241 return {};
242 return {AV_PIX_FMT_VIDEOTOOLBOX, AV_HWDEVICE_TYPE_VIDEOTOOLBOX};
243#endif
244 // Cross-platform pix formats
245 case AV_PIX_FMT_CUDA:
246 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_CUDA))
247 return {};
248 return {AV_PIX_FMT_CUDA, AV_HWDEVICE_TYPE_CUDA};
249 case AV_PIX_FMT_QSV:
250 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_QSV))
251 return {};
252 return {AV_PIX_FMT_QSV, AV_HWDEVICE_TYPE_QSV};
253 case AV_PIX_FMT_VULKAN:
254 if(!hardwareDecoderIsAvailable(AV_PIX_FMT_VULKAN))
255 return {};
256 return {AV_PIX_FMT_VULKAN, AV_HWDEVICE_TYPE_VULKAN};
257 // case AV_PIX_FMT_OPENCL:
258 // return {AV_PIX_FMT_OPENCL, AV_HWDEVICE_TYPE_OPENCL};
259 default:
260 return {};
261 }
262}
263
264inline constexpr bool ffmpegCanDoHardwareDecoding(AVCodecID id) noexcept
265{
266 switch(id)
267 {
268 case AV_CODEC_ID_AV1:
269 case AV_CODEC_ID_H264:
270 case AV_CODEC_ID_HEVC:
271 case AV_CODEC_ID_MJPEG:
272 case AV_CODEC_ID_MPEG1VIDEO:
273 case AV_CODEC_ID_MPEG2VIDEO:
274 case AV_CODEC_ID_MPEG4:
275 case AV_CODEC_ID_VC1:
276 case AV_CODEC_ID_VP8:
277 case AV_CODEC_ID_VP9:
278 case AV_CODEC_ID_WMV1:
279 case AV_CODEC_ID_WMV2:
280 case AV_CODEC_ID_WMV3:
281 case AV_CODEC_ID_PRORES:
282 return true;
283 default:
284 return false;
285 }
286}
288inline std::string hwCodecName(const char* codec_name, AVHWDeviceType device)
289{
290 std::string name{codec_name};
291 switch(device)
292 {
293 case AV_HWDEVICE_TYPE_CUDA:
294 return name + "_cuvid";
295 case AV_HWDEVICE_TYPE_QSV:
296 return name + "_qsv";
297 case AV_HWDEVICE_TYPE_VDPAU:
298 return name + "_vdpau";
299 case AV_HWDEVICE_TYPE_VAAPI:
300 return name;
301 case AV_HWDEVICE_TYPE_DRM:
302 return name + "_v4l2m2m";
303 case AV_HWDEVICE_TYPE_DXVA2:
304 case AV_HWDEVICE_TYPE_D3D11VA:
305#if defined(_WIN32) && LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
306 case AV_HWDEVICE_TYPE_D3D12VA:
307#endif
308 case AV_HWDEVICE_TYPE_VIDEOTOOLBOX:
309 case AV_HWDEVICE_TYPE_VULKAN:
310 return name;
311 default:
312 return {};
313 }
314}
315
318inline bool isVulkanComputeCodec(AVCodecID id)
319{
320 switch(id)
321 {
322 case AV_CODEC_ID_PRORES:
323 case AV_CODEC_ID_FFV1:
324 return true;
325 default:
326 return false;
327 }
328}
329
332 AVCodecID codec_id, AVPixelFormat pix_fmt, uint32_t gpuVendorId = 0)
333{
334 (void)gpuVendorId;
335
336 auto hwInfo = ffmpegHardwareDecodingFormats(pix_fmt);
337 if(hwInfo.device == AV_HWDEVICE_TYPE_NONE)
338 return false;
339
340 const AVCodec* codec = avcodec_find_decoder(codec_id);
341 if(!codec)
342 return false;
343
344 auto dedicated = hwCodecName(codec->name, hwInfo.device);
345 if(!dedicated.empty() && dedicated != codec->name)
346 {
347 if(avcodec_find_decoder_by_name(dedicated.c_str()))
348 return true;
349 return false;
350 }
351
352 for(int i = 0;; i++)
353 {
354 const AVCodecHWConfig* config = avcodec_get_hw_config(codec, i);
355 if(!config)
356 break;
357 if(config->pix_fmt == pix_fmt
358 && (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
359 return true;
360 }
361 return false;
362}
363
365namespace GpuVendor
366{
367inline constexpr uint32_t NVIDIA = 0x10DE;
368inline constexpr uint32_t Intel = 0x8086;
369inline constexpr uint32_t AMD = 0x1002;
370inline constexpr uint32_t Apple = 0x106B;
371inline constexpr uint32_t Broadcom = 0x14E4; // RPi VideoCore
372inline constexpr uint32_t ARM = 0x13B5; // Mali
373inline constexpr uint32_t Qualcomm = 0x5143;
374inline constexpr uint32_t Samsung = 0x144D;
375}
376
381inline std::vector<AVPixelFormat> selectHardwareAccelerations(
382 int graphicsApi, AVCodecID codec_id, uint32_t gpuVendorId = 0)
383{
384 struct Candidate { AVPixelFormat fmt; };
385 std::vector<Candidate> candidates;
386
387 switch(graphicsApi)
388 {
389#if defined(_WIN32)
390 case 3: // D3D11
391 candidates = {{AV_PIX_FMT_D3D11}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
392 break;
393 case 5: // D3D12
394#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
395 candidates = {{AV_PIX_FMT_D3D12}, {AV_PIX_FMT_D3D11}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
396#else
397 candidates = {{AV_PIX_FMT_D3D11}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
398#endif
399 break;
400#endif
401#if defined(__APPLE__)
402 case 4: // Metal
403 candidates = {{AV_PIX_FMT_VIDEOTOOLBOX}};
404 break;
405#endif
406 case 2: // Vulkan
407 {
408#if defined(__linux__)
409 if(gpuVendorId == GpuVendor::NVIDIA)
410 {
411 candidates = {{AV_PIX_FMT_VULKAN}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_VAAPI}, {AV_PIX_FMT_QSV}};
412 }
413 else if(gpuVendorId == GpuVendor::Intel)
414 {
415 candidates = {{AV_PIX_FMT_VAAPI}, {AV_PIX_FMT_VULKAN}, {AV_PIX_FMT_QSV}};
416 }
417 else if(gpuVendorId == GpuVendor::AMD)
418 {
419 candidates = {{AV_PIX_FMT_VAAPI}, {AV_PIX_FMT_VULKAN}};
420 }
421 else if(gpuVendorId == GpuVendor::Broadcom
422 || gpuVendorId == GpuVendor::ARM
423 || gpuVendorId == GpuVendor::Qualcomm)
424 {
425 candidates = {{AV_PIX_FMT_DRM_PRIME}, {AV_PIX_FMT_VULKAN}};
426 }
427 else
428 {
429 candidates = {{AV_PIX_FMT_VAAPI}, {AV_PIX_FMT_VULKAN}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
430 }
431#elif defined(_WIN32)
432 candidates = {
433 {AV_PIX_FMT_VULKAN}, {AV_PIX_FMT_D3D11},
434#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
435 {AV_PIX_FMT_D3D12},
436#endif
437 {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
438#elif defined(__APPLE__)
439 candidates = {{AV_PIX_FMT_VIDEOTOOLBOX}};
440#else
441 candidates = {{AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
442#endif
443 break;
444 }
445 case 1: // OpenGL
446 {
447#if defined(__linux__)
448 if(gpuVendorId == GpuVendor::Broadcom
449 || gpuVendorId == GpuVendor::ARM
450 || gpuVendorId == GpuVendor::Qualcomm)
451 {
452 candidates = {{AV_PIX_FMT_DRM_PRIME}};
453 }
454 else
455 {
456 candidates = {{AV_PIX_FMT_VAAPI}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
457 }
458#elif defined(_WIN32)
459 candidates = {{AV_PIX_FMT_D3D11}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
460#elif defined(__APPLE__)
461 candidates = {{AV_PIX_FMT_VIDEOTOOLBOX}};
462#endif
463 break;
464 }
465 default:
466 {
467#if defined(__linux__)
468#if defined(__arm__) || defined(__aarch64__)
469 candidates = {{AV_PIX_FMT_DRM_PRIME}, {AV_PIX_FMT_VAAPI}};
470#else
471 candidates = {{AV_PIX_FMT_VAAPI}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
472#endif
473#elif defined(_WIN32)
474 candidates = {{AV_PIX_FMT_D3D11}, {AV_PIX_FMT_CUDA}, {AV_PIX_FMT_QSV}};
475#elif defined(__APPLE__)
476 candidates = {{AV_PIX_FMT_VIDEOTOOLBOX}};
477#endif
478 break;
479 }
480 }
481
482 std::vector<AVPixelFormat> result;
483 for(auto& c : candidates)
484 {
485 if(hardwareDecoderIsAvailable(c.fmt)
486 && codecSupportsHWPixelFormat(codec_id, c.fmt, gpuVendorId))
487 result.push_back(c.fmt);
488 }
489 return result;
490}
491
493inline AVPixelFormat selectHardwareAcceleration(
494 int graphicsApi, AVCodecID codec_id, uint32_t gpuVendorId = 0)
495{
496 auto fmts = selectHardwareAccelerations(graphicsApi, codec_id, gpuVendorId);
497 return fmts.empty() ? AV_PIX_FMT_NONE : fmts.front();
498}
499
500#endif
501}
502
503#endif
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