ohmu
·
2026-10-15
1extern "C" {
2#include "codec.h"
3#include "common/debug.h"
4#include "common/library.h"
5#include "common/windows/com.h"
6#include "common/windows/unicode.h"
7#include "common/windows/nt.h"
8}
9
10#include <d3d11.h>
11#include <d3d12.h>
12#include <dxgi.h>
13#include <initguid.h>
14#include <dxva.h>
15#include <d3d12video.h>
16#include <mfapi.h>
17
18typedef struct D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC {
19 UINT NodeIndex;
20 D3D12_VIDEO_ENCODER_CODEC Codec;
21 BOOL IsSupported;
22} D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC;
23
24HRESULT MFTEnum2(
25 _In_ GUID guidCategory,
26 _In_ UINT32 Flags,
27 _In_ const MFT_REGISTER_TYPE_INFO* pInputType,
28 _In_ const MFT_REGISTER_TYPE_INFO* pOutputType,
29 _In_opt_ IMFAttributes* pAttributes,
30 _Out_ IMFActivate*** pppMFTActivate,
31 _Out_ UINT32* pnumMFTActivate);
32
33// clang-format off
34#ifndef MFT_ENUM_ADAPTER_LUID
35// {1D39518C-E220-4DA8-A07F-BA172552D6B1}
36DEFINE_GUID(MFT_ENUM_ADAPTER_LUID,
37 0x1d39518c, 0xe220, 0x4da8, 0xa0, 0x7f, 0xba, 0x17, 0x25, 0x52, 0xd6, 0xb1);
38#endif
39// clang-format on
40
41static const DXGI_FORMAT FF_NATIVE_CODEC_FORMATS[] = {
42 DXGI_FORMAT_420_OPAQUE,
43 DXGI_FORMAT_NV12,
44 DXGI_FORMAT_P010,
45 DXGI_FORMAT_P016,
46 DXGI_FORMAT_YUY2,
47 DXGI_FORMAT_Y210,
48 DXGI_FORMAT_Y216,
49 DXGI_FORMAT_AYUV,
50 DXGI_FORMAT_Y410,
51 DXGI_FORMAT_Y416,
52};
53
54static FFCodecType ffCodecProfileToTypeDx11(const GUID& profile) {
55 // clang-format off
56 if (IsEqualGUID(profile, DXVA_ModeH261_A) ||
57 IsEqualGUID(profile, DXVA_ModeH261_B)) {
58 return FF_CODEC_TYPE_H261;
59 }
60
61 if (IsEqualGUID(profile, DXVA_ModeH263_A) ||
62 IsEqualGUID(profile, DXVA_ModeH263_B) ||
63 IsEqualGUID(profile, DXVA_ModeH263_C) ||
64 IsEqualGUID(profile, DXVA_ModeH263_D) ||
65 IsEqualGUID(profile, DXVA_ModeH263_E) ||
66 IsEqualGUID(profile, DXVA_ModeH263_F)) {
67 return FF_CODEC_TYPE_H263;
68 }
69
70 if (IsEqualGUID(profile, DXVA_ModeMJPEG_VLD_420) ||
71 IsEqualGUID(profile, DXVA_ModeMJPEG_VLD_422) ||
72 IsEqualGUID(profile, DXVA_ModeMJPEG_VLD_444) ||
73 IsEqualGUID(profile, DXVA_ModeMJPEG_VLD_4444) ||
74 IsEqualGUID(profile, DXVA_ModeJPEG_VLD_420) ||
75 IsEqualGUID(profile, DXVA_ModeJPEG_VLD_422) ||
76 IsEqualGUID(profile, DXVA_ModeJPEG_VLD_444)) {
77 return FF_CODEC_TYPE_MJPEG;
78 }
79
80 if (IsEqualGUID(profile, DXVA_ModeMPEG1_A) ||
81 IsEqualGUID(profile, DXVA_ModeMPEG1_VLD)) {
82 return FF_CODEC_TYPE_MPEG1;
83 }
84
85 if (IsEqualGUID(profile, DXVA_ModeMPEG2_A) ||
86 IsEqualGUID(profile, DXVA_ModeMPEG2_B) ||
87 IsEqualGUID(profile, DXVA_ModeMPEG2_C) ||
88 IsEqualGUID(profile, DXVA_ModeMPEG2_D) ||
89 IsEqualGUID(profile, DXVA_ModeMPEG2and1_VLD)) {
90 return FF_CODEC_TYPE_MPEG2;
91 }
92
93 if (IsEqualGUID(profile, DXVA_ModeMPEG4pt2_VLD_Simple) ||
94 IsEqualGUID(profile, DXVA_ModeMPEG4pt2_VLD_AdvSimple_NoGMC) ||
95 IsEqualGUID(profile, DXVA_ModeMPEG4pt2_VLD_AdvSimple_GMC)) {
96 return FF_CODEC_TYPE_DIVX_XVID;
97 }
98
99 if (IsEqualGUID(profile, DXVA_ModeH264_E) ||
100 IsEqualGUID(profile, DXVA_ModeH264_F) ||
101 IsEqualGUID(profile, DXVA_ModeH264_VLD_WithFMOASO_NoFGT) ||
102 IsEqualGUID(profile, DXVA_ModeH264_VLD_Stereo_Progressive_NoFGT) ||
103 IsEqualGUID(profile, DXVA_ModeH264_VLD_Stereo_NoFGT) ||
104 IsEqualGUID(profile, DXVA_ModeH264_VLD_Multiview_NoFGT)) {
105 return FF_CODEC_TYPE_H264;
106 }
107
108 if (IsEqualGUID(profile, DXVA_ModeWMV8_A) ||
109 IsEqualGUID(profile, DXVA_ModeWMV8_B)) {
110 return FF_CODEC_TYPE_WMV8;
111 }
112
113 if (IsEqualGUID(profile, DXVA_ModeWMV9_A) ||
114 IsEqualGUID(profile, DXVA_ModeWMV9_B) ||
115 IsEqualGUID(profile, DXVA_ModeWMV9_C)) {
116 return FF_CODEC_TYPE_WMV9;
117 }
118
119 if (IsEqualGUID(profile, DXVA_ModeVC1_A) ||
120 IsEqualGUID(profile, DXVA_ModeVC1_B) ||
121 IsEqualGUID(profile, DXVA_ModeVC1_C) ||
122 IsEqualGUID(profile, DXVA_ModeVC1_D) ||
123 IsEqualGUID(profile, DXVA_ModeVC1_D2010)) {
124 return FF_CODEC_TYPE_VC1;
125 }
126
127 if (IsEqualGUID(profile, DXVA_ModeVP8_VLD)) {
128 return FF_CODEC_TYPE_VP8;
129 }
130
131 if (IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main) ||
132 IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main10) ||
133 IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main12) ||
134 IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main10_422) ||
135 IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main12_422) ||
136 IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main_444) ||
137 IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main10_Ext) ||
138 IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main10_444) ||
139 IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main12_444) ||
140 IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main16)) {
141 return FF_CODEC_TYPE_HEVC;
142 }
143
144 if (IsEqualGUID(profile, DXVA_ModeVP9_VLD_Profile0) ||
145 IsEqualGUID(profile, DXVA_ModeVP9_VLD_10bit_Profile2)) {
146 return FF_CODEC_TYPE_VP9;
147 }
148
149 if (IsEqualGUID(profile, DXVA_ModeAV1_VLD_Profile0) ||
150 IsEqualGUID(profile, DXVA_ModeAV1_VLD_Profile1) ||
151 IsEqualGUID(profile, DXVA_ModeAV1_VLD_Profile2) ||
152 IsEqualGUID(profile, DXVA_ModeAV1_VLD_12bit_Profile2) ||
153 IsEqualGUID(profile, DXVA_ModeAV1_VLD_12bit_Profile2_420)) {
154 return FF_CODEC_TYPE_AV1;
155 }
156 // clang-format on
157
158 return FF_CODEC_TYPE_UNKNOWN;
159}
160
161static FFCodecType ffCodecProfileToTypeDx12(const GUID& profile) {
162 // clang-format off
163 if (IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_MPEG1_AND_MPEG2)) {
164 return FFCodecType(FF_CODEC_TYPE_MPEG1 | FF_CODEC_TYPE_MPEG2);
165 }
166
167 if (IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_MPEG2)) {
168 return FF_CODEC_TYPE_MPEG2;
169 }
170
171 if (IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_MPEG4PT2_SIMPLE) ||
172 IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_MPEG4PT2_ADVSIMPLE_NOGMC)) {
173 return FF_CODEC_TYPE_DIVX_XVID;
174 }
175
176 if (IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_H264) ||
177 IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_H264_STEREO_PROGRESSIVE) ||
178 IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_H264_STEREO) ||
179 IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_H264_MULTIVIEW)) {
180 return FF_CODEC_TYPE_H264;
181 }
182
183 if (IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_VC1) ||
184 IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_VC1_D2010)) {
185 return FF_CODEC_TYPE_VC1;
186 }
187
188 if (IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_VP8)) {
189 return FF_CODEC_TYPE_VP8;
190 }
191
192 if (IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN) ||
193 IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN10)) {
194 return FF_CODEC_TYPE_HEVC;
195 }
196
197 if (IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_VP9) ||
198 IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_VP9_10BIT_PROFILE2)) {
199 return FF_CODEC_TYPE_VP9;
200 }
201
202 if (IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE0) ||
203 IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE1) ||
204 IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE2) ||
205 IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_AV1_12BIT_PROFILE2) ||
206 IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_AV1_12BIT_PROFILE2_420)) {
207 return FF_CODEC_TYPE_AV1;
208 }
209 // clang-format on
210
211 return FF_CODEC_TYPE_UNKNOWN;
212}
213
214static bool ffCodecProfileHasNativeOutput(ID3D11VideoDevice* videoDevice, const GUID& profile) {
215 for (uint32_t i = 0; i < ARRAY_SIZE(FF_NATIVE_CODEC_FORMATS); ++i) {
216 BOOL supported = FALSE;
217 if (SUCCEEDED(videoDevice->CheckVideoDecoderFormat(&profile, FF_NATIVE_CODEC_FORMATS[i], &supported)) && supported) {
218 return true;
219 }
220 }
221
222 return false;
223}
224
225static bool ffCodecProfileHasNativeOutput(ID3D12VideoDevice* videoDevice, const GUID& profile, UINT nodeIndex) {
226 for (uint32_t i = 0; i < ARRAY_SIZE(FF_NATIVE_CODEC_FORMATS); ++i) {
227 D3D12_FEATURE_DATA_VIDEO_DECODE_SUPPORT support = {
228 .NodeIndex = nodeIndex,
229 .Configuration = {
230 .DecodeProfile = profile,
231 .BitstreamEncryption = D3D12_BITSTREAM_ENCRYPTION_TYPE_NONE,
232 .InterlaceType = D3D12_VIDEO_FRAME_CODED_INTERLACE_TYPE_NONE,
233 },
234 .Width = 1920,
235 .Height = 1080,
236 .DecodeFormat = FF_NATIVE_CODEC_FORMATS[i],
237 .FrameRate = {
238 .Numerator = 30,
239 .Denominator = 1,
240 },
241 .BitRate = 10000000,
242 .SupportFlags = D3D12_VIDEO_DECODE_SUPPORT_FLAG_NONE,
243 .ConfigurationFlags = D3D12_VIDEO_DECODE_CONFIGURATION_FLAG_NONE,
244 .DecodeTier = D3D12_VIDEO_DECODE_TIER_NOT_SUPPORTED,
245 };
246
247 if (SUCCEEDED(videoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_DECODE_SUPPORT, &support, sizeof(support))) &&
248 (support.SupportFlags & D3D12_VIDEO_DECODE_SUPPORT_FLAG_SUPPORTED)) {
249 return true;
250 }
251 }
252
253 return false;
254}
255
256static bool ffCodecEncoderSupportedD3d12(ID3D12VideoDevice* videoDevice, D3D12_VIDEO_ENCODER_CODEC codec, UINT nodeIndex) {
257 D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC encoderCodec = {
258 .NodeIndex = nodeIndex,
259 .Codec = codec,
260 .IsSupported = FALSE,
261 };
262
263 return SUCCEEDED(videoDevice->CheckFeatureSupport(
264 D3D12_FEATURE_VIDEO_ENCODER_CODEC,
265 &encoderCodec,
266 sizeof(encoderCodec))) &&
267 encoderCodec.IsSupported;
268}
269
270typedef struct FFCodecMftEncoderSubtype {
271 const GUID* subtype;
272 FFCodecType codecType;
273} FFCodecMftEncoderSubtype;
274
275static const FFCodecMftEncoderSubtype FF_D3D11VA_MFT_ENCODER_SUBTYPES[] = {
276 { &MFVideoFormat_H264, FF_CODEC_TYPE_H264 },
277 { &MFVideoFormat_HEVC, FF_CODEC_TYPE_HEVC },
278 { &MFVideoFormat_AV1, FF_CODEC_TYPE_AV1 },
279};
280
281static FFCodecType ffDetectD3d11vaDecoders(IDXGIAdapter1* adapter, typeof(&D3D11CreateDevice) ffD3D11CreateDevice) {
282 FF_AUTO_RELEASE_COM_OBJECT ID3D11Device* d3dDevice = nullptr;
283 D3D_FEATURE_LEVEL featureLevel;
284 if (FAILED(ffD3D11CreateDevice(
285 adapter,
286 D3D_DRIVER_TYPE_UNKNOWN,
287 nullptr,
288 D3D11_CREATE_DEVICE_VIDEO_SUPPORT,
289 nullptr,
290 0,
291 D3D11_SDK_VERSION,
292 &d3dDevice,
293 &featureLevel,
294 nullptr)) ||
295 !d3dDevice) {
296 return FF_CODEC_TYPE_NONE;
297 }
298
299 FF_AUTO_RELEASE_COM_OBJECT ID3D11VideoDevice* videoDevice = nullptr;
300 if (FAILED(d3dDevice->QueryInterface(__uuidof(ID3D11VideoDevice), (void**) &videoDevice)) || !videoDevice) {
301 return FF_CODEC_TYPE_NONE;
302 }
303
304 FFCodecType decoders = FF_CODEC_TYPE_NONE;
305 UINT profileCount = videoDevice->GetVideoDecoderProfileCount();
306 for (UINT profileIndex = 0; profileIndex < profileCount; ++profileIndex) {
307 GUID profile;
308 if (FAILED(videoDevice->GetVideoDecoderProfile(profileIndex, &profile))) {
309 continue;
310 }
311
312 FFCodecType type = ffCodecProfileToTypeDx11(profile);
313
314 if ((decoders & type) || !ffCodecProfileHasNativeOutput(videoDevice, profile)) {
315 continue;
316 }
317
318 decoders = (FFCodecType) (((uint32_t) decoders) | ((uint32_t) type));
319 }
320 return decoders;
321}
322
323static FFCodecType ffDetectD3d11MftEncoders(const LUID& adapterLuid, typeof(&MFCreateAttributes) ffMFCreateAttributes, typeof(&MFTEnum2) ffMFTEnum2) {
324 FF_AUTO_RELEASE_COM_OBJECT IMFAttributes* attributes = nullptr;
325 if (FAILED(ffMFCreateAttributes(&attributes, 1)) || !attributes) {
326 return FF_CODEC_TYPE_NONE;
327 }
328
329 if (FAILED(attributes->SetBlob(MFT_ENUM_ADAPTER_LUID, (const UINT8*) &adapterLuid, sizeof(adapterLuid)))) {
330 return FF_CODEC_TYPE_NONE;
331 }
332
333 FFCodecType encoders = FF_CODEC_TYPE_NONE;
334
335 for (uint32_t subtypeIndex = 0; subtypeIndex < ARRAY_SIZE(FF_D3D11VA_MFT_ENCODER_SUBTYPES); ++subtypeIndex) {
336 const FFCodecMftEncoderSubtype& subtype = FF_D3D11VA_MFT_ENCODER_SUBTYPES[subtypeIndex];
337 if (encoders & subtype.codecType) {
338 continue;
339 }
340
341 MFT_REGISTER_TYPE_INFO outputType = {
342 .guidMajorType = MFMediaType_Video,
343 .guidSubtype = *subtype.subtype,
344 };
345
346 IMFActivate** activateList = nullptr;
347 UINT32 activateCount = 0;
348
349 if (SUCCEEDED(ffMFTEnum2(
350 MFT_CATEGORY_VIDEO_ENCODER,
351 MFT_ENUM_FLAG_HARDWARE | MFT_ENUM_FLAG_SORTANDFILTER,
352 nullptr,
353 &outputType,
354 attributes,
355 &activateList,
356 &activateCount)) &&
357 activateCount > 0) {
358 encoders = (FFCodecType) (((uint32_t) encoders) | ((uint32_t) subtype.codecType));
359 }
360
361 for (uint32_t i = 0; i < activateCount; ++i) {
362 activateList[i]->Release();
363 }
364 CoTaskMemFree(activateList);
365 }
366
367 return encoders;
368}
369
370static FFCodecType ffCodecEncoderToType(D3D12_VIDEO_ENCODER_CODEC codec) {
371 switch (codec) {
372 case D3D12_VIDEO_ENCODER_CODEC_H264:
373 return FF_CODEC_TYPE_H264;
374 case D3D12_VIDEO_ENCODER_CODEC_HEVC:
375 return FF_CODEC_TYPE_HEVC;
376 case D3D12_VIDEO_ENCODER_CODEC_AV1:
377 return FF_CODEC_TYPE_AV1;
378 default:
379 return FF_CODEC_TYPE_UNKNOWN;
380 }
381}
382
383template <typename Func>
384static void ffEnumHardwareAdapters(IDXGIFactory1* factory, Func&& onAdapter) {
385 for (UINT adapterIndex = 0;; ++adapterIndex) {
386 FF_AUTO_RELEASE_COM_OBJECT IDXGIAdapter1* adapter = nullptr;
387 HRESULT adapterStatus = factory->EnumAdapters1(adapterIndex, &adapter);
388 if (adapterStatus == DXGI_ERROR_NOT_FOUND) {
389 break;
390 }
391 if (FAILED(adapterStatus) || !adapter) {
392 continue;
393 }
394
395 DXGI_ADAPTER_DESC1 desc;
396 if (FAILED(adapter->GetDesc1(&desc))) {
397 continue;
398 }
399 if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
400 continue;
401 }
402
403 onAdapter(adapter, desc);
404 }
405}
406
407const char* detectD3d11va(FFCodecOptions* options, FFlist* result /*list of FFCodecResult*/, IDXGIFactory1* factory) {
408 FF_LIBRARY_LOAD_MESSAGE(d3d11, "d3d11" FF_LIBRARY_EXTENSION, 1)
409 FF_LIBRARY_LOAD_SYMBOL_MESSAGE(d3d11, D3D11CreateDevice)
410 FF_LIBRARY_LOAD_MESSAGE(mfplat, "mfplat" FF_LIBRARY_EXTENSION, 1)
411 FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mfplat, MFCreateAttributes)
412 FF_LIBRARY_LOAD_SYMBOL_LAZY(mfplat, MFTEnum2) // Not available on Windows 8.1
413
414 ffEnumHardwareAdapters(factory, [&](IDXGIAdapter1* adapter, const DXGI_ADAPTER_DESC1& desc) {
415 FFCodecType decoders = (options->showType & FF_CODEC_SHOW_TYPE_DECODER)
416 ? ffDetectD3d11vaDecoders(adapter, ffD3D11CreateDevice)
417 : FF_CODEC_TYPE_NONE;
418 FFCodecType encoders = ffMFTEnum2 && (options->showType & FF_CODEC_SHOW_TYPE_ENCODER)
419 ? ffDetectD3d11MftEncoders(desc.AdapterLuid, ffMFCreateAttributes, ffMFTEnum2)
420 : FF_CODEC_TYPE_NONE;
421
422 if (decoders == FF_CODEC_TYPE_NONE && encoders == FF_CODEC_TYPE_NONE) {
423 return;
424 }
425
426 FFCodecResult* gpuResult = FF_LIST_ADD(FFCodecResult, *result);
427 ffStrbufInitWS(&gpuResult->gpu, desc.Description);
428 gpuResult->decoders = decoders;
429 gpuResult->encoders = encoders;
430 gpuResult->platformApi = ffMFTEnum2 ? "D3D11VA+MFT" : "D3D11VA";
431 });
432
433 return nullptr;
434}
435
436const char* detectD3d12va(FFCodecOptions* options, FFlist* result /*list of FFCodecResult*/, IDXGIFactory1* factory) {
437 FF_LIBRARY_LOAD_MESSAGE(d3d12, "d3d12" FF_LIBRARY_EXTENSION, 1)
438 FF_LIBRARY_LOAD_SYMBOL_MESSAGE(d3d12, D3D12CreateDevice)
439
440 static const GUID FF_D3D12_DECODE_PROFILES[] = {
441 D3D12_VIDEO_DECODE_PROFILE_MPEG2,
442 D3D12_VIDEO_DECODE_PROFILE_MPEG1_AND_MPEG2,
443 D3D12_VIDEO_DECODE_PROFILE_H264,
444 D3D12_VIDEO_DECODE_PROFILE_H264_STEREO_PROGRESSIVE,
445 D3D12_VIDEO_DECODE_PROFILE_H264_STEREO,
446 D3D12_VIDEO_DECODE_PROFILE_H264_MULTIVIEW,
447 D3D12_VIDEO_DECODE_PROFILE_VC1,
448 D3D12_VIDEO_DECODE_PROFILE_VC1_D2010,
449 D3D12_VIDEO_DECODE_PROFILE_MPEG4PT2_SIMPLE,
450 D3D12_VIDEO_DECODE_PROFILE_MPEG4PT2_ADVSIMPLE_NOGMC,
451 D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN,
452 D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN10,
453 D3D12_VIDEO_DECODE_PROFILE_VP9,
454 D3D12_VIDEO_DECODE_PROFILE_VP9_10BIT_PROFILE2,
455 D3D12_VIDEO_DECODE_PROFILE_VP8,
456 D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE0,
457 D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE1,
458 D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE2,
459 D3D12_VIDEO_DECODE_PROFILE_AV1_12BIT_PROFILE2,
460 D3D12_VIDEO_DECODE_PROFILE_AV1_12BIT_PROFILE2_420,
461 };
462
463 static const D3D12_VIDEO_ENCODER_CODEC FF_D3D12_ENCODER_CODECS[] = {
464 D3D12_VIDEO_ENCODER_CODEC_H264,
465 D3D12_VIDEO_ENCODER_CODEC_HEVC,
466 D3D12_VIDEO_ENCODER_CODEC_AV1,
467 };
468
469 const uint32_t resultLengthBefore = result->length;
470
471 ffEnumHardwareAdapters(factory, [&](IDXGIAdapter1* adapter, const DXGI_ADAPTER_DESC1& desc) {
472 FF_AUTO_RELEASE_COM_OBJECT ID3D12Device* d3dDevice = nullptr;
473 if (FAILED(ffD3D12CreateDevice(
474 adapter,
475 D3D_FEATURE_LEVEL_11_0,
476 __uuidof(ID3D12Device),
477 (void**) &d3dDevice)) ||
478 !d3dDevice) {
479 return;
480 }
481
482 FF_AUTO_RELEASE_COM_OBJECT ID3D12VideoDevice* videoDevice = nullptr;
483 if (FAILED(d3dDevice->QueryInterface(__uuidof(ID3D12VideoDevice), (void**) &videoDevice)) || !videoDevice) {
484 return;
485 }
486
487 FFCodecType decoders = FF_CODEC_TYPE_NONE;
488 if (options->showType & FF_CODEC_SHOW_TYPE_DECODER) {
489 for (uint32_t profileIndex = 0; profileIndex < ARRAY_SIZE(FF_D3D12_DECODE_PROFILES); ++profileIndex) {
490 const GUID& profile = FF_D3D12_DECODE_PROFILES[profileIndex];
491 FFCodecType codecType = ffCodecProfileToTypeDx12(profile);
492
493 if ((decoders & codecType) || !ffCodecProfileHasNativeOutput(videoDevice, profile, 0)) {
494 continue;
495 }
496
497 decoders = (FFCodecType) (((uint32_t) decoders) | ((uint32_t) codecType));
498 }
499 }
500
501 FFCodecType encoders = FF_CODEC_TYPE_NONE;
502 if (options->showType & FF_CODEC_SHOW_TYPE_ENCODER) {
503 for (uint32_t codecIndex = 0; codecIndex < ARRAY_SIZE(FF_D3D12_ENCODER_CODECS); ++codecIndex) {
504 D3D12_VIDEO_ENCODER_CODEC codec = FF_D3D12_ENCODER_CODECS[codecIndex];
505 FFCodecType codecType = ffCodecEncoderToType(codec);
506
507 if ((encoders & codecType) || !ffCodecEncoderSupportedD3d12(videoDevice, codec, 0)) {
508 continue;
509 }
510
511 encoders = (FFCodecType) (((uint32_t) encoders) | ((uint32_t) codecType));
512 }
513 }
514
515 if (decoders == FF_CODEC_TYPE_NONE && encoders == FF_CODEC_TYPE_NONE) {
516 return;
517 }
518
519 FFCodecResult* gpuResult = FF_LIST_ADD(FFCodecResult, *result);
520 ffStrbufInitWS(&gpuResult->gpu, desc.Description);
521 gpuResult->decoders = decoders;
522 gpuResult->encoders = encoders;
523 gpuResult->platformApi = "D3D12VA";
524 });
525
526 if (result->length == resultLengthBefore) {
527 FF_DEBUG("No D3D12 video acceleration support");
528 return "No D3D12 video acceleration support";
529 }
530
531 return nullptr;
532}
533
534const char* ffDetectCodecNative(FFCodecOptions* options, FFlist* result /*list of FFCodecResult*/) {
535 FF_LIBRARY_LOAD_MESSAGE(dxgi, "dxgi" FF_LIBRARY_EXTENSION, 1)
536 FF_LIBRARY_LOAD_SYMBOL_MESSAGE(dxgi, CreateDXGIFactory1)
537
538 const char* error = ffInitCom();
539 if (error) {
540 return error;
541 }
542
543 FF_AUTO_RELEASE_COM_OBJECT IDXGIFactory1* factory = nullptr;
544 HRESULT hr = ffCreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**) &factory);
545 if (FAILED(hr) || !factory) {
546 FF_DEBUG("CreateDXGIFactory1() failed: %s", ffDebugHResult(hr));
547 return "CreateDXGIFactory1() failed";
548 }
549
550 if (ffIsWindows11OrGreater()) {
551 // D3D12 video encoding is supported only on Windows 11
552 if (detectD3d12va(options, result, factory) == nullptr) {
553 return nullptr;
554 }
555 }
556 return detectD3d11va(options, result, factory);
557}