1 /* qsv_common.c
2  *
3  * Copyright (c) 2003-2021 HandBrake Team
4  * This file is part of the HandBrake source code.
5  * Homepage: <http://handbrake.fr/>.
6  * It may be used under the terms of the GNU General Public License v2.
7  * For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
8  */
9 
10 #include "handbrake/handbrake.h"
11 #include "handbrake/project.h"
12 
13 #if HB_PROJECT_FEATURE_QSV
14 
15 #include <stdio.h>
16 #include <string.h>
17 
18 #include "handbrake/handbrake.h"
19 #include "handbrake/ports.h"
20 #include "handbrake/common.h"
21 #include "handbrake/hb_dict.h"
22 #include "handbrake/qsv_common.h"
23 #include "handbrake/h264_common.h"
24 #include "handbrake/h265_common.h"
25 #include "handbrake/hbffmpeg.h"
26 #include "libavfilter/avfilter.h"
27 #include "libavfilter/buffersrc.h"
28 #include "libavfilter/buffersink.h"
29 #include "libavutil/hwcontext_qsv.h"
30 #include "libavutil/hwcontext.h"
31 #include "mfx/mfxadapter.h"
32 
33 typedef struct hb_qsv_adapter_details
34 {
35     // DirectX index
36     int index;
37     // QSV info for each codec
38     hb_qsv_info_t *hb_qsv_info_avc;
39     hb_qsv_info_t *hb_qsv_info_hevc;
40     // API versions
41     mfxVersion qsv_software_version;
42     mfxVersion qsv_hardware_version;
43     // AVC implementations
44     hb_qsv_info_t qsv_software_info_avc;
45     hb_qsv_info_t qsv_hardware_info_avc;
46     // HEVC implementations
47     hb_qsv_info_t qsv_software_info_hevc;
48     hb_qsv_info_t qsv_hardware_info_hevc;
49 } hb_qsv_adapter_details_t;
50 
51 // QSV info about adapters
52 #if defined(_WIN32) || defined(__MINGW32__)
53 static mfxAdaptersInfo g_qsv_adapters_info;
54 static const char* hb_qsv_get_adapter_type(const mfxAdapterInfo* info);
55 #endif
56 int hb_qsv_get_platform(int adapter_index);
57 static hb_list_t *g_qsv_adapters_list         = NULL;
58 static hb_list_t *g_qsv_adapters_details_list = NULL;
59 static int g_adapter_index = 0;
60 static int g_default_adapter_index = 0;
61 
init_adapter_details(hb_qsv_adapter_details_t * adapter_details)62 static void init_adapter_details(hb_qsv_adapter_details_t *adapter_details)
63 {
64     adapter_details->index                                 = 0;
65     // QSV info for each codec
66     adapter_details->hb_qsv_info_avc                       = NULL;
67     adapter_details->hb_qsv_info_hevc                      = NULL;
68     // API versions
69     adapter_details->qsv_software_version.Version          = 0;
70     adapter_details->qsv_hardware_version.Version          = 0;
71     // AVC implementations
72     adapter_details->qsv_software_info_avc.available       = 0;
73     adapter_details->qsv_software_info_avc.codec_id        = MFX_CODEC_AVC;
74     adapter_details->qsv_software_info_avc.implementation  = MFX_IMPL_SOFTWARE;
75 
76     adapter_details->qsv_hardware_info_avc.available       = 0;
77     adapter_details->qsv_hardware_info_avc.codec_id        = MFX_CODEC_AVC;
78     adapter_details->qsv_hardware_info_avc.implementation  = MFX_IMPL_HARDWARE_ANY|MFX_IMPL_VIA_ANY;
79     // HEVC implementations
80     adapter_details->qsv_software_info_hevc.available      = 0;
81     adapter_details->qsv_software_info_hevc.codec_id       = MFX_CODEC_HEVC;
82     adapter_details->qsv_software_info_hevc.implementation = MFX_IMPL_SOFTWARE;
83 
84     adapter_details->qsv_hardware_info_hevc.available      = 0;
85     adapter_details->qsv_hardware_info_hevc.codec_id       = MFX_CODEC_HEVC;
86     adapter_details->qsv_hardware_info_hevc.implementation = MFX_IMPL_HARDWARE_ANY|MFX_IMPL_VIA_ANY;
87 }
88 
89 // QSV-supported profile and level lists (not all exposed to the user)
90 static hb_triplet_t hb_qsv_h264_profiles[] =
91 {
92     { "Baseline",             "baseline",       MFX_PROFILE_AVC_BASELINE,             },
93     { "Main",                 "main",           MFX_PROFILE_AVC_MAIN,                 },
94     { "Extended",             "extended",       MFX_PROFILE_AVC_EXTENDED,             },
95     { "High",                 "high",           MFX_PROFILE_AVC_HIGH,                 },
96     { "High 4:2:2",           "high422",        MFX_PROFILE_AVC_HIGH_422,             },
97     { "Constrained Baseline", "baseline|set1",  MFX_PROFILE_AVC_CONSTRAINED_BASELINE, },
98     { "Constrained High",     "high|set4|set5", MFX_PROFILE_AVC_CONSTRAINED_HIGH,     },
99     { "Progressive High",     "high|set4",      MFX_PROFILE_AVC_PROGRESSIVE_HIGH,     },
100     { NULL,                                                                           },
101 };
102 static hb_triplet_t hb_qsv_h265_profiles[] =
103 {
104     { "Main",               "main",             MFX_PROFILE_HEVC_MAIN,   },
105     { "Main 10",            "main10",           MFX_PROFILE_HEVC_MAIN10, },
106     { "Main Still Picture", "mainstillpicture", MFX_PROFILE_HEVC_MAINSP, },
107     { NULL,                                                              },
108 };
109 static hb_triplet_t hb_qsv_vpp_scale_modes[] =
110 {
111     { "lowpower",          "low_power",         MFX_SCALING_MODE_LOWPOWER, },
112     { "hq",                "hq",                MFX_SCALING_MODE_QUALITY,  },
113     { NULL,                                                                },
114 };
115 static hb_triplet_t hb_qsv_vpp_interpolation_methods[] =
116 {
117     { "nearest",            "nearest",          MFX_INTERPOLATION_NEAREST_NEIGHBOR, },
118     { "bilinear",           "bilinear",         MFX_INTERPOLATION_BILINEAR,         },
119     { "advanced",           "advanced",         MFX_INTERPOLATION_ADVANCED,         },
120     { NULL,                                                                         },
121 };
122 static hb_triplet_t hb_qsv_h264_levels[] =
123 {
124     { "1.0", "1.0", MFX_LEVEL_AVC_1,  },
125     { "1b",  "1b",  MFX_LEVEL_AVC_1b, },
126     { "1.1", "1.1", MFX_LEVEL_AVC_11, },
127     { "1.2", "1.2", MFX_LEVEL_AVC_12, },
128     { "1.3", "1.3", MFX_LEVEL_AVC_13, },
129     { "2.0", "2.0", MFX_LEVEL_AVC_2,  },
130     { "2.1", "2.1", MFX_LEVEL_AVC_21, },
131     { "2.2", "2.2", MFX_LEVEL_AVC_22, },
132     { "3.0", "3.0", MFX_LEVEL_AVC_3,  },
133     { "3.1", "3.1", MFX_LEVEL_AVC_31, },
134     { "3.2", "3.2", MFX_LEVEL_AVC_32, },
135     { "4.0", "4.0", MFX_LEVEL_AVC_4,  },
136     { "4.1", "4.1", MFX_LEVEL_AVC_41, },
137     { "4.2", "4.2", MFX_LEVEL_AVC_42, },
138     { "5.0", "5.0", MFX_LEVEL_AVC_5,  },
139     { "5.1", "5.1", MFX_LEVEL_AVC_51, },
140     { "5.2", "5.2", MFX_LEVEL_AVC_52, },
141     { NULL,                           },
142 };
143 static hb_triplet_t hb_qsv_h265_levels[] =
144 {
145     { "1.0", "1.0", MFX_LEVEL_HEVC_1,  },
146     { "2.0", "2.0", MFX_LEVEL_HEVC_2,  },
147     { "2.1", "2.1", MFX_LEVEL_HEVC_21, },
148     { "3.0", "3.0", MFX_LEVEL_HEVC_3,  },
149     { "3.1", "3.1", MFX_LEVEL_HEVC_31, },
150     { "4.0", "4.0", MFX_LEVEL_HEVC_4,  },
151     { "4.1", "4.1", MFX_LEVEL_HEVC_41, },
152     { "5.0", "5.0", MFX_LEVEL_HEVC_5,  },
153     { "5.1", "5.1", MFX_LEVEL_HEVC_51, },
154     { "5.2", "5.2", MFX_LEVEL_HEVC_52, },
155     { "6.0", "6.0", MFX_LEVEL_HEVC_6,  },
156     { "6.1", "6.1", MFX_LEVEL_HEVC_61, },
157     { "6.2", "6.2", MFX_LEVEL_HEVC_62, },
158     { NULL,                            },
159 };
160 
161 #if defined(_WIN32) || defined(__MINGW32__)
162 static const enum AVPixelFormat hb_qsv_pix_fmts[] =
163 {
164     AV_PIX_FMT_NV12, AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE
165 };
166 
167 static const enum AVPixelFormat hb_qsv_10bit_pix_fmts[] =
168 {
169     AV_PIX_FMT_P010LE, AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE
170 };
171 #else
172 static const enum AVPixelFormat hb_qsv_pix_fmts[] =
173 {
174     AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE
175 };
176 
177 static const enum AVPixelFormat hb_qsv_10bit_pix_fmts[] =
178 {
179     AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE
180 };
181 #endif
182 
183 #define MFX_IMPL_VIA_MASK(impl) (0x0f00 & (impl))
184 
185 // check available Intel Media SDK version against a minimum
186 #define HB_CHECK_MFX_VERSION(MFX_VERSION, MAJOR, MINOR) \
187     ((MFX_VERSION.Major * 1000 + MFX_VERSION.Minor) >= (MAJOR * 1000 + MINOR))
188 
hb_qsv_get_adapter_index()189 int hb_qsv_get_adapter_index()
190 {
191     return g_adapter_index;
192 }
193 
hb_qsv_set_default_adapter_index(int adapter_index)194 static int hb_qsv_set_default_adapter_index(int adapter_index)
195 {
196     g_default_adapter_index = adapter_index;
197     return 0;
198 }
199 
hb_qsv_get_default_adapter_index()200 static int hb_qsv_get_default_adapter_index()
201 {
202     return g_default_adapter_index;
203 }
204 
hb_qsv_adapters_list()205 hb_list_t* hb_qsv_adapters_list()
206 {
207     return g_qsv_adapters_list;
208 }
209 
hb_qsv_get_adapters_details_by_index(int adapter_index)210 static hb_qsv_adapter_details_t* hb_qsv_get_adapters_details_by_index(int adapter_index)
211 {
212     for (int i = 0; i < hb_list_count(g_qsv_adapters_details_list); i++)
213     {
214         hb_qsv_adapter_details_t *details = hb_list_item(g_qsv_adapters_details_list, i);
215         if (details->index == adapter_index || adapter_index == -1)
216         {
217             return details;
218         }
219     }
220     return NULL;
221 }
222 
qsv_impl_set_preferred(hb_qsv_adapter_details_t * details,const char * name)223 static int qsv_impl_set_preferred(hb_qsv_adapter_details_t *details, const char *name)
224 {
225     if (name == NULL || details == NULL)
226     {
227         return -1;
228     }
229     if (!strcasecmp(name, "software"))
230     {
231         if (details->qsv_software_info_avc.available)
232         {
233             details->hb_qsv_info_avc = &details->qsv_software_info_avc;
234         }
235         if (details->qsv_software_info_hevc.available)
236         {
237             details->hb_qsv_info_hevc = &details->qsv_software_info_hevc;
238         }
239         return 0;
240     }
241     if (!strcasecmp(name, "hardware"))
242     {
243         if (details->qsv_hardware_info_avc.available)
244         {
245             details->hb_qsv_info_avc = &details->qsv_hardware_info_avc;
246         }
247         if (details->qsv_hardware_info_hevc.available)
248         {
249             details->hb_qsv_info_hevc = &details->qsv_hardware_info_hevc;
250         }
251         return 0;
252     }
253     return -1;
254 }
255 
hb_qsv_impl_set_preferred(const char * name)256 int hb_qsv_impl_set_preferred(const char *name)
257 {
258     hb_qsv_adapter_details_t* details = hb_qsv_get_adapters_details_by_index(hb_qsv_get_adapter_index());
259     return qsv_impl_set_preferred(details, name);
260 }
261 
hb_qsv_hardware_generation(int cpu_platform)262 int hb_qsv_hardware_generation(int cpu_platform)
263 {
264     switch (cpu_platform)
265     {
266         case HB_CPU_PLATFORM_INTEL_BNL:
267             return QSV_G0;
268         case HB_CPU_PLATFORM_INTEL_SNB:
269             return QSV_G1;
270         case HB_CPU_PLATFORM_INTEL_IVB:
271         case HB_CPU_PLATFORM_INTEL_SLM:
272         case HB_CPU_PLATFORM_INTEL_CHT:
273             return QSV_G2;
274         case HB_CPU_PLATFORM_INTEL_HSW:
275             return QSV_G3;
276         case HB_CPU_PLATFORM_INTEL_BDW:
277             return QSV_G4;
278         case HB_CPU_PLATFORM_INTEL_SKL:
279             return QSV_G5;
280         case HB_CPU_PLATFORM_INTEL_KBL:
281         case HB_CPU_PLATFORM_INTEL_CML:
282             return QSV_G6;
283         case HB_CPU_PLATFORM_INTEL_ICL:
284             return QSV_G7;
285         case HB_CPU_PLATFORM_INTEL_TGL:
286             return QSV_G8;
287         default:
288             return QSV_FU;
289     }
290 }
291 
292 /*
293  * Determine whether a given mfxIMPL is hardware-accelerated.
294  */
hb_qsv_implementation_is_hardware(mfxIMPL implementation)295 int hb_qsv_implementation_is_hardware(mfxIMPL implementation)
296 {
297     return MFX_IMPL_BASETYPE(implementation) != MFX_IMPL_SOFTWARE;
298 }
299 
hb_qsv_available()300 int hb_qsv_available()
301 {
302     if (is_hardware_disabled())
303     {
304         return 0;
305     }
306 
307     static int init_done = 0;
308     if (init_done == 0)
309     {
310         int result = hb_qsv_info_init();
311         if (result != 0)
312         {
313             init_done = -1;
314             hb_log("hb_qsv_available: hb_qsv_info_init failed");
315             return -1;
316         }
317         init_done = 1;
318     }
319     else if (init_done == -1)
320     {
321         hb_log("hb_qsv_available: hb_qsv_info_init failed");
322         return -1;
323     }
324 
325     return ((hb_qsv_video_encoder_is_enabled(hb_qsv_get_adapter_index(), HB_VCODEC_QSV_H264) ? HB_VCODEC_QSV_H264 : 0) |
326             (hb_qsv_video_encoder_is_enabled(hb_qsv_get_adapter_index(), HB_VCODEC_QSV_H265) ? HB_VCODEC_QSV_H265 : 0) |
327             (hb_qsv_video_encoder_is_enabled(hb_qsv_get_adapter_index(), HB_VCODEC_QSV_H265_10BIT) ? HB_VCODEC_QSV_H265_10BIT : 0));
328 }
329 
hb_qsv_video_encoder_is_enabled(int adapter_index,int encoder)330 int hb_qsv_video_encoder_is_enabled(int adapter_index, int encoder)
331 {
332     hb_qsv_adapter_details_t* details = hb_qsv_get_adapters_details_by_index(adapter_index);
333 
334     if (details)
335     {
336         switch (encoder)
337         {
338             case HB_VCODEC_QSV_H264:
339                 return details->hb_qsv_info_avc != NULL && details->hb_qsv_info_avc->available;
340             case HB_VCODEC_QSV_H265_10BIT:
341                 if (hb_qsv_hardware_generation(hb_qsv_get_platform(adapter_index)) < QSV_G6)
342                     return 0;
343             case HB_VCODEC_QSV_H265:
344                 return details->hb_qsv_info_hevc != NULL && details->hb_qsv_info_hevc->available;
345             default:
346                 return 0;
347         }
348     }
349     else
350     {
351         return 0;
352     }
353 }
354 
hb_qsv_audio_encoder_is_enabled(int encoder)355 int hb_qsv_audio_encoder_is_enabled(int encoder)
356 {
357     switch (encoder)
358     {
359         default:
360             return 0;
361     }
362 }
363 
init_video_param(mfxVideoParam * videoParam)364 static void init_video_param(mfxVideoParam *videoParam)
365 {
366     if (videoParam == NULL)
367     {
368         return;
369     }
370 
371     memset(videoParam, 0, sizeof(mfxVideoParam));
372     videoParam->mfx.CodecId                 = MFX_CODEC_AVC;
373     videoParam->mfx.CodecLevel              = MFX_LEVEL_UNKNOWN;
374     videoParam->mfx.CodecProfile            = MFX_PROFILE_UNKNOWN;
375     videoParam->mfx.RateControlMethod       = MFX_RATECONTROL_VBR;
376     videoParam->mfx.TargetUsage             = MFX_TARGETUSAGE_BALANCED;
377     videoParam->mfx.TargetKbps              = 5000;
378     videoParam->mfx.GopOptFlag              = MFX_GOP_CLOSED;
379     videoParam->mfx.FrameInfo.FourCC        = MFX_FOURCC_NV12;
380     videoParam->mfx.FrameInfo.ChromaFormat  = MFX_CHROMAFORMAT_YUV420;
381     videoParam->mfx.FrameInfo.PicStruct     = MFX_PICSTRUCT_PROGRESSIVE;
382     videoParam->mfx.FrameInfo.FrameRateExtN = 25;
383     videoParam->mfx.FrameInfo.FrameRateExtD = 1;
384     videoParam->mfx.FrameInfo.Width         = 1920;
385     videoParam->mfx.FrameInfo.CropW         = 1920;
386     videoParam->mfx.FrameInfo.AspectRatioW  = 1;
387     videoParam->mfx.FrameInfo.Height        = 1088;
388     videoParam->mfx.FrameInfo.CropH         = 1080;
389     videoParam->mfx.FrameInfo.AspectRatioH  = 1;
390     videoParam->AsyncDepth                  = HB_QSV_ASYNC_DEPTH_DEFAULT;
391     videoParam->IOPattern                   = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
392 }
393 
init_ext_video_signal_info(mfxExtVideoSignalInfo * extVideoSignalInfo)394 static void init_ext_video_signal_info(mfxExtVideoSignalInfo *extVideoSignalInfo)
395 {
396     if (extVideoSignalInfo == NULL)
397     {
398         return;
399     }
400 
401     memset(extVideoSignalInfo, 0, sizeof(mfxExtVideoSignalInfo));
402     extVideoSignalInfo->Header.BufferId          = MFX_EXTBUFF_VIDEO_SIGNAL_INFO;
403     extVideoSignalInfo->Header.BufferSz          = sizeof(mfxExtVideoSignalInfo);
404     extVideoSignalInfo->VideoFormat              = 5; // undefined
405     extVideoSignalInfo->VideoFullRange           = 0; // TV range
406     extVideoSignalInfo->ColourDescriptionPresent = 0; // don't write to bitstream
407     extVideoSignalInfo->ColourPrimaries          = 2; // undefined
408     extVideoSignalInfo->TransferCharacteristics  = 2; // undefined
409     extVideoSignalInfo->MatrixCoefficients       = 2; // undefined
410 }
411 
init_ext_coding_option(mfxExtCodingOption * extCodingOption)412 static void init_ext_coding_option(mfxExtCodingOption *extCodingOption)
413 {
414     if (extCodingOption == NULL)
415     {
416         return;
417     }
418 
419     memset(extCodingOption, 0, sizeof(mfxExtCodingOption));
420     extCodingOption->Header.BufferId = MFX_EXTBUFF_CODING_OPTION;
421     extCodingOption->Header.BufferSz = sizeof(mfxExtCodingOption);
422     extCodingOption->AUDelimiter     = MFX_CODINGOPTION_OFF;
423     extCodingOption->PicTimingSEI    = MFX_CODINGOPTION_OFF;
424     extCodingOption->CAVLC           = MFX_CODINGOPTION_OFF;
425 }
426 
init_ext_coding_option2(mfxExtCodingOption2 * extCodingOption2)427 static void init_ext_coding_option2(mfxExtCodingOption2 *extCodingOption2)
428 {
429     if (extCodingOption2 == NULL)
430     {
431         return;
432     }
433 
434     memset(extCodingOption2, 0, sizeof(mfxExtCodingOption2));
435     extCodingOption2->Header.BufferId = MFX_EXTBUFF_CODING_OPTION2;
436     extCodingOption2->Header.BufferSz = sizeof(mfxExtCodingOption2);
437     extCodingOption2->MBBRC           = MFX_CODINGOPTION_ON;
438     extCodingOption2->ExtBRC          = MFX_CODINGOPTION_ON;
439     extCodingOption2->Trellis         = MFX_TRELLIS_I|MFX_TRELLIS_P|MFX_TRELLIS_B;
440     extCodingOption2->RepeatPPS       = MFX_CODINGOPTION_ON;
441     extCodingOption2->BRefType        = MFX_B_REF_PYRAMID;
442     extCodingOption2->AdaptiveI       = MFX_CODINGOPTION_ON;
443     extCodingOption2->AdaptiveB       = MFX_CODINGOPTION_ON;
444     extCodingOption2->LookAheadDS     = MFX_LOOKAHEAD_DS_4x;
445     extCodingOption2->NumMbPerSlice   = 2040; // 1920x1088/4
446 }
447 
query_capabilities(mfxSession session,int index,mfxVersion version,hb_qsv_info_t * info)448 static int query_capabilities(mfxSession session, int index, mfxVersion version, hb_qsv_info_t *info)
449 {
450     /*
451      * MFXVideoENCODE_Query(mfxSession, mfxVideoParam *in, mfxVideoParam *out);
452      *
453      * Mode 1:
454      * - in is NULL
455      * - out has the parameters we want to query set to 1
456      * - out->mfx.CodecId field has to be set (mandatory)
457      * - MFXVideoENCODE_Query should zero out all unsupported parameters
458      *
459      * Mode 2:
460      * - the parameters we want to query are set for in
461      * - in ->mfx.CodecId field has to be set (mandatory)
462      * - out->mfx.CodecId field has to be set (mandatory)
463      * - MFXVideoENCODE_Query should sanitize all unsupported parameters
464      */
465     mfxStatus     status;
466     hb_list_t    *mfxPluginList;
467     mfxExtBuffer *videoExtParam[1];
468     mfxVideoParam videoParam, inputParam;
469     mfxExtCodingOption    extCodingOption;
470     mfxExtCodingOption2   extCodingOption2;
471     mfxExtVideoSignalInfo extVideoSignalInfo;
472 
473     /* Reset capabilities before querying */
474     info->capabilities = 0;
475 
476     /* Load required MFX plug-ins */
477     if ((mfxPluginList = hb_qsv_load_plugins(index, info, session, version)) == NULL)
478     {
479         return 0; // the required plugin(s) couldn't be loaded
480     }
481 
482     /*
483      * First of all, check availability of an encoder for
484      * this combination of a codec ID and implementation.
485      *
486      * Note: can error out rather than sanitizing
487      * unsupported codec IDs, so don't log errors.
488      */
489     if (HB_CHECK_MFX_VERSION(version, HB_QSV_MINVERSION_MAJOR, HB_QSV_MINVERSION_MINOR))
490     {
491         if (info->implementation & MFX_IMPL_AUDIO)
492         {
493             /* Not yet supported */
494             return 0;
495         }
496         else
497         {
498             mfxStatus mfxRes;
499             init_video_param(&inputParam);
500             inputParam.mfx.CodecId = info->codec_id;
501 
502             memset(&videoParam, 0, sizeof(mfxVideoParam));
503             videoParam.mfx.CodecId = inputParam.mfx.CodecId;
504 
505             mfxRes = MFXVideoENCODE_Query(session, &inputParam, &videoParam);
506             if (mfxRes >= MFX_ERR_NONE &&
507                 videoParam.mfx.CodecId == info->codec_id)
508             {
509                 /*
510                  * MFXVideoENCODE_Query might tell you that an HEVC encoder is
511                  * available on Haswell hardware, but it'll fail to initialize.
512                  * So check encoder availability with MFXVideoENCODE_Init too.
513                  */
514                 if ((status = MFXVideoENCODE_Init(session, &videoParam)) >= MFX_ERR_NONE)
515                 {
516                     info->available = 1;
517                 }
518                 else if (info->codec_id == MFX_CODEC_AVC)
519                 {
520                     /*
521                      * This should not fail for AVC encoders, so we want to know
522                      * about it - however, it may fail for other encoders (ignore)
523                      */
524                     fprintf(stderr,
525                             "query_capabilities: MFXVideoENCODE_Init failed"
526                             " (0x%"PRIX32", 0x%"PRIX32", %d)\n",
527                             info->codec_id, info->implementation, status);
528                 }
529                 MFXVideoENCODE_Close(session);
530             }
531         }
532     }
533     if (!info->available)
534     {
535         /* Don't check capabilities for unavailable encoders */
536         return 0;
537     }
538 
539     if (info->implementation & MFX_IMPL_AUDIO)
540     {
541         /* We don't have any audio capability checks yet */
542         return 0;
543     }
544     else
545     {
546         /* Implementation-specific features that can't be queried */
547         if (info->codec_id == MFX_CODEC_AVC || info->codec_id == MFX_CODEC_HEVC)
548         {
549             if (hb_qsv_implementation_is_hardware(info->implementation))
550             {
551                 if (hb_qsv_hardware_generation(hb_qsv_get_platform(index)) >= QSV_G3)
552                 {
553                     info->capabilities |= HB_QSV_CAP_B_REF_PYRAMID;
554                 }
555                 if (info->codec_id == MFX_CODEC_HEVC &&
556                     (hb_qsv_hardware_generation(hb_qsv_get_platform(index)) >= QSV_G7))
557                 {
558                     info->capabilities |= HB_QSV_CAP_LOWPOWER_ENCODE;
559                 }
560             }
561             else
562             {
563                 if (HB_CHECK_MFX_VERSION(version, 1, 6))
564                 {
565                     info->capabilities |= HB_QSV_CAP_B_REF_PYRAMID;
566                 }
567             }
568         }
569 
570         /* API-specific features that can't be queried */
571         if (HB_CHECK_MFX_VERSION(version, 1, 6))
572         {
573             // API >= 1.6 (mfxBitstream::DecodeTimeStamp, mfxExtCodingOption2)
574             info->capabilities |= HB_QSV_CAP_MSDK_API_1_6;
575         }
576 
577         /*
578          * Check availability of optional rate control methods.
579          *
580          * Mode 2 tends to error out, but mode 1 gives false negatives, which
581          * is worse. So use mode 2 and assume an error means it's unsupported.
582          *
583          * Also assume that LA and ICQ combined imply LA_ICQ is
584          * supported, so we don't need to check the latter too.
585          */
586         if (HB_CHECK_MFX_VERSION(version, 1, 7))
587         {
588             init_video_param(&inputParam);
589             inputParam.mfx.CodecId           = info->codec_id;
590             inputParam.mfx.RateControlMethod = MFX_RATECONTROL_LA;
591             inputParam.mfx.TargetKbps        = 5000;
592 
593             memset(&videoParam, 0, sizeof(mfxVideoParam));
594             videoParam.mfx.CodecId = inputParam.mfx.CodecId;
595 
596             if (MFXVideoENCODE_Query(session, &inputParam, &videoParam) >= MFX_ERR_NONE &&
597                 videoParam.mfx.RateControlMethod == MFX_RATECONTROL_LA)
598             {
599                 info->capabilities |= HB_QSV_CAP_RATECONTROL_LA;
600 
601                 // also check for LA + interlaced support
602                 init_video_param(&inputParam);
603                 inputParam.mfx.CodecId             = info->codec_id;
604                 inputParam.mfx.RateControlMethod   = MFX_RATECONTROL_LA;
605                 inputParam.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_FIELD_TFF;
606                 inputParam.mfx.TargetKbps          = 5000;
607 
608                 memset(&videoParam, 0, sizeof(mfxVideoParam));
609                 videoParam.mfx.CodecId = inputParam.mfx.CodecId;
610 
611                 if (MFXVideoENCODE_Query(session, &inputParam, &videoParam) >= MFX_ERR_NONE &&
612                     videoParam.mfx.FrameInfo.PicStruct == MFX_PICSTRUCT_FIELD_TFF           &&
613                     videoParam.mfx.RateControlMethod   == MFX_RATECONTROL_LA)
614                 {
615                     info->capabilities |= HB_QSV_CAP_RATECONTROL_LAi;
616                 }
617             }
618         }
619         if (HB_CHECK_MFX_VERSION(version, 1, 8))
620         {
621             init_video_param(&inputParam);
622             inputParam.mfx.CodecId           = info->codec_id;
623             inputParam.mfx.RateControlMethod = MFX_RATECONTROL_ICQ;
624             inputParam.mfx.ICQQuality        = 20;
625 
626             memset(&videoParam, 0, sizeof(mfxVideoParam));
627             videoParam.mfx.CodecId = inputParam.mfx.CodecId;
628 
629             if (MFXVideoENCODE_Query(session, &inputParam, &videoParam) >= MFX_ERR_NONE &&
630                 videoParam.mfx.RateControlMethod == MFX_RATECONTROL_ICQ)
631             {
632                 info->capabilities |= HB_QSV_CAP_RATECONTROL_ICQ;
633             }
634         }
635 
636         /*
637          * Determine whether mfxExtVideoSignalInfo is supported.
638          */
639         if (HB_CHECK_MFX_VERSION(version, 1, 3))
640         {
641             init_video_param(&videoParam);
642             videoParam.mfx.CodecId = info->codec_id;
643 
644             init_ext_video_signal_info(&extVideoSignalInfo);
645             videoParam.ExtParam    = videoExtParam;
646             videoParam.ExtParam[0] = (mfxExtBuffer*)&extVideoSignalInfo;
647             videoParam.NumExtParam = 1;
648 
649             status = MFXVideoENCODE_Query(session, NULL, &videoParam);
650             if (status >= MFX_ERR_NONE)
651             {
652                 /* Encoder can be configured via mfxExtVideoSignalInfo */
653                 info->capabilities |= HB_QSV_CAP_VUI_VSINFO;
654             }
655             else if (info->codec_id == MFX_CODEC_AVC)
656             {
657                 /*
658                  * This should not fail for AVC encoders, so we want to know
659                  * about it - however, it may fail for other encoders (ignore)
660                  */
661                 fprintf(stderr,
662                         "query_capabilities: mfxExtVideoSignalInfo check"
663                         " failed (0x%"PRIX32", 0x%"PRIX32", %d)\n",
664                         info->codec_id, info->implementation, status);
665             }
666         }
667 
668         /*
669          * Determine whether mfxExtCodingOption is supported.
670          */
671         if (HB_CHECK_MFX_VERSION(version, 1, 0))
672         {
673             init_video_param(&videoParam);
674             videoParam.mfx.CodecId = info->codec_id;
675 
676             init_ext_coding_option(&extCodingOption);
677             videoParam.ExtParam    = videoExtParam;
678             videoParam.ExtParam[0] = (mfxExtBuffer*)&extCodingOption;
679             videoParam.NumExtParam = 1;
680 
681             status = MFXVideoENCODE_Query(session, NULL, &videoParam);
682             if (status >= MFX_ERR_NONE)
683             {
684                 /* Encoder can be configured via mfxExtCodingOption */
685                 info->capabilities |= HB_QSV_CAP_OPTION1;
686             }
687             else if (info->codec_id == MFX_CODEC_AVC)
688             {
689                 /*
690                  * This should not fail for AVC encoders, so we want to know
691                  * about it - however, it may fail for other encoders (ignore)
692                  */
693                 fprintf(stderr,
694                         "query_capabilities: mfxExtCodingOption check"
695                         " failed (0x%"PRIX32", 0x%"PRIX32", %d)\n",
696                         info->codec_id, info->implementation, status);
697             }
698         }
699 
700         /*
701          * Determine whether mfxExtCodingOption2 and its fields are supported.
702          *
703          * Mode 2 suffers from false negatives with some drivers, whereas mode 1
704          * suffers from false positives instead. The latter is probably easier
705          * and/or safer to sanitize for us, so use mode 1.
706          */
707         if (HB_CHECK_MFX_VERSION(version, 1, 6) && info->codec_id == MFX_CODEC_AVC)
708         {
709             init_video_param(&videoParam);
710             videoParam.mfx.CodecId = info->codec_id;
711 
712             init_ext_coding_option2(&extCodingOption2);
713             videoParam.ExtParam    = videoExtParam;
714             videoParam.ExtParam[0] = (mfxExtBuffer*)&extCodingOption2;
715             videoParam.NumExtParam = 1;
716 
717             status = MFXVideoENCODE_Query(session, NULL, &videoParam);
718             if (status >= MFX_ERR_NONE)
719             {
720 #if 0
721                 // testing code that could come in handy
722                 fprintf(stderr, "-------------------\n");
723                 fprintf(stderr, "MBBRC:         0x%02X\n",     extCodingOption2.MBBRC);
724                 fprintf(stderr, "ExtBRC:        0x%02X\n",     extCodingOption2.ExtBRC);
725                 fprintf(stderr, "Trellis:       0x%02X\n",     extCodingOption2.Trellis);
726                 fprintf(stderr, "RepeatPPS:     0x%02X\n",     extCodingOption2.RepeatPPS);
727                 fprintf(stderr, "BRefType:      %4"PRIu16"\n", extCodingOption2.BRefType);
728                 fprintf(stderr, "AdaptiveI:     0x%02X\n",     extCodingOption2.AdaptiveI);
729                 fprintf(stderr, "AdaptiveB:     0x%02X\n",     extCodingOption2.AdaptiveB);
730                 fprintf(stderr, "LookAheadDS:   %4"PRIu16"\n", extCodingOption2.LookAheadDS);
731                 fprintf(stderr, "-------------------\n");
732 #endif
733 
734                 /* Encoder can be configured via mfxExtCodingOption2 */
735                 info->capabilities |= HB_QSV_CAP_OPTION2;
736 
737                 /*
738                  * Sanitize API 1.6 fields:
739                  *
740                  * - MBBRC  requires G3 hardware (Haswell or equivalent)
741                  * - ExtBRC requires G2 hardware (Ivy Bridge or equivalent)
742                  */
743                 if (hb_qsv_implementation_is_hardware(info->implementation) &&
744                     hb_qsv_hardware_generation(hb_qsv_get_platform(index)) >= QSV_G3)
745                 {
746                     if (extCodingOption2.MBBRC)
747                     {
748                         info->capabilities |= HB_QSV_CAP_OPTION2_MBBRC;
749                     }
750                 }
751                 if (hb_qsv_implementation_is_hardware(info->implementation) &&
752                     hb_qsv_hardware_generation(hb_qsv_get_platform(index)) >= QSV_G2)
753                 {
754                     if (extCodingOption2.ExtBRC)
755                     {
756                         info->capabilities |= HB_QSV_CAP_OPTION2_EXTBRC;
757                     }
758                 }
759 
760                 /*
761                  * Sanitize API 1.7 fields:
762                  *
763                  * - Trellis requires G3 hardware (Haswell or equivalent)
764                  */
765                 if (HB_CHECK_MFX_VERSION(version, 1, 7))
766                 {
767                     if (hb_qsv_implementation_is_hardware(info->implementation) &&
768                         hb_qsv_hardware_generation(hb_qsv_get_platform(index)) >= QSV_G3)
769                     {
770                         if (extCodingOption2.Trellis)
771                         {
772                             info->capabilities |= HB_QSV_CAP_OPTION2_TRELLIS;
773                         }
774                     }
775                 }
776 
777                 /*
778                  * Sanitize API 1.8 fields:
779                  *
780                  * - BRefType    requires B-pyramid support
781                  * - LookAheadDS requires lookahead support
782                  * - AdaptiveI, AdaptiveB, NumMbPerSlice unknown (trust Query)
783                  */
784                 if (HB_CHECK_MFX_VERSION(version, 1, 8))
785                 {
786                     if (info->capabilities & HB_QSV_CAP_B_REF_PYRAMID)
787                     {
788                         if (extCodingOption2.BRefType)
789                         {
790                             info->capabilities |= HB_QSV_CAP_OPTION2_BREFTYPE;
791                         }
792                     }
793                     if (info->capabilities & HB_QSV_CAP_RATECONTROL_LA)
794                     {
795                         if (extCodingOption2.LookAheadDS)
796                         {
797                             info->capabilities |= HB_QSV_CAP_OPTION2_LA_DOWNS;
798                         }
799                     }
800                     if (extCodingOption2.AdaptiveI && extCodingOption2.AdaptiveB)
801                     {
802                         info->capabilities |= HB_QSV_CAP_OPTION2_IB_ADAPT;
803                     }
804                     if (extCodingOption2.NumMbPerSlice)
805                     {
806                         info->capabilities |= HB_QSV_CAP_OPTION2_NMPSLICE;
807                     }
808                 }
809             }
810             else
811             {
812                 fprintf(stderr,
813                         "query_capabilities: mfxExtCodingOption2 check failed (0x%"PRIX32", 0x%"PRIX32", %d)\n",
814                         info->codec_id, info->implementation, status);
815             }
816         }
817         if (HB_CHECK_MFX_VERSION(version, 1, 19))
818         {
819             if (hb_qsv_hardware_generation(hb_qsv_get_platform(index)) >= QSV_G7)
820             {
821                 info->capabilities |= HB_QSV_CAP_VPP_SCALING;
822             }
823         }
824         if (HB_CHECK_MFX_VERSION(version, 1, 33))
825         {
826             if (hb_qsv_hardware_generation(hb_qsv_get_platform(index)) >= QSV_G7)
827             {
828                 info->capabilities |= HB_QSV_CAP_VPP_INTERPOLATION;
829             }
830         }
831     }
832 
833     /* Unload MFX plug-ins */
834     hb_qsv_unload_plugins(&mfxPluginList, session, version);
835 
836     return 0;
837 }
838 
839 const char * DRM_INTEL_DRIVER_NAME = "i915";
840 const char * VA_INTEL_DRIVER_NAMES[] = { "iHD", "i965", NULL};
841 
hb_qsv_display_init(void)842 hb_display_t * hb_qsv_display_init(void)
843 {
844     return hb_display_init(DRM_INTEL_DRIVER_NAME, VA_INTEL_DRIVER_NAMES);
845 }
846 
847 #if defined(_WIN32) || defined(__MINGW32__)
848 static int hb_qsv_query_adapters(mfxAdaptersInfo* adapters_info);
849 static int hb_qsv_make_adapters_list(const mfxAdaptersInfo* adapters_info, hb_list_t **qsv_adapters_list);
850 static int hb_qsv_make_adapters_details_list(const mfxAdaptersInfo* adapters_info, hb_list_t **hb_qsv_adapter_details_list);
851 
hb_qsv_dx_index_to_impl(int dx_index)852 mfxIMPL hb_qsv_dx_index_to_impl(int dx_index)
853 {
854     mfxIMPL impl;
855 
856     switch (dx_index)
857     {
858         {
859         case 0:
860             impl = MFX_IMPL_HARDWARE;
861             break;
862         case 1:
863             impl = MFX_IMPL_HARDWARE2;
864             break;
865         case 2:
866             impl = MFX_IMPL_HARDWARE3;
867             break;
868         case 3:
869             impl = MFX_IMPL_HARDWARE4;
870             break;
871 
872         default:
873             // try searching on all display adapters
874             impl = MFX_IMPL_HARDWARE_ANY;
875             break;
876         }
877     }
878     return impl;
879 }
880 #endif
881 
hb_qsv_collect_adapters_details(hb_list_t * qsv_adapters_list,hb_list_t * hb_qsv_adapter_details_list)882 static int hb_qsv_collect_adapters_details(hb_list_t *qsv_adapters_list, hb_list_t *hb_qsv_adapter_details_list)
883 {
884     for (int i = 0; i < hb_list_count(hb_qsv_adapter_details_list); i++)
885     {
886         int *dx_index = (int *)hb_list_item(qsv_adapters_list, i);
887         hb_qsv_adapter_details_t *details = hb_list_item(hb_qsv_adapter_details_list, i);
888         details->index = *dx_index;
889         /*
890         * First, check for any MSDK version to determine whether one or
891         * more implementations are present; then check if we can use them.
892         *
893         * I've had issues using a NULL version with some combinations of
894         * hardware and driver, so use a low version number (1.0) instead.
895         */
896         mfxSession session;
897         mfxVersion version = { .Major = 1, .Minor = 0, };
898 #if defined(_WIN32) || defined(__MINGW32__)
899         mfxIMPL hw_preference = MFX_IMPL_VIA_D3D11;
900 #else
901         mfxIMPL hw_preference = MFX_IMPL_VIA_ANY;
902 #endif
903         // check for software fallback
904         if (MFXInit(MFX_IMPL_SOFTWARE, &version, &session) == MFX_ERR_NONE)
905         {
906             // Media SDK software found, but check that our minimum is supported
907             MFXQueryVersion(session, &details->qsv_software_version);
908             if (HB_CHECK_MFX_VERSION(details->qsv_software_version,
909                                     HB_QSV_MINVERSION_MAJOR,
910                                     HB_QSV_MINVERSION_MINOR))
911             {
912                 query_capabilities(session, details->index, details->qsv_software_version, &details->qsv_software_info_avc);
913                 query_capabilities(session, details->index, details->qsv_software_version, &details->qsv_software_info_hevc);
914                 // now that we know which hardware encoders are
915                 // available, we can set the preferred implementation
916                 qsv_impl_set_preferred(details, "software");
917             }
918             MFXClose(session);
919         }
920         // check for actual hardware support
921         do{
922 #if defined(_WIN32) || defined(__MINGW32__)
923             mfxIMPL hw_impl = hb_qsv_dx_index_to_impl(details->index);
924 #else
925             mfxIMPL hw_impl = MFX_IMPL_HARDWARE_ANY;
926 #endif
927             if (MFXInit(hw_impl | hw_preference, &version, &session) == MFX_ERR_NONE)
928             {
929                 // On linux, the handle to the VA display must be set.
930                 // This code is essentially a NOP other platforms.
931                 hb_display_t * display = hb_qsv_display_init();
932 
933                 if (display != NULL)
934                 {
935                     MFXVideoCORE_SetHandle(session, display->mfxType,
936                                         (mfxHDL)display->handle);
937                 }
938                 // Media SDK hardware found, but check that our minimum is supported
939                 //
940                 // Note: this-party hardware (QSV_G0) is unsupported for the time being
941                 MFXQueryVersion(session, &details->qsv_hardware_version);
942                 if (hb_qsv_hardware_generation(hb_qsv_get_platform(*dx_index)) >= QSV_G1 &&
943                     HB_CHECK_MFX_VERSION(details->qsv_hardware_version,
944                                         HB_QSV_MINVERSION_MAJOR,
945                                         HB_QSV_MINVERSION_MINOR))
946                 {
947                     query_capabilities(session, details->index, details->qsv_hardware_version, &details->qsv_hardware_info_avc);
948                     details->qsv_hardware_info_avc.implementation = hw_impl | hw_preference;
949                     query_capabilities(session, details->index, details->qsv_hardware_version, &details->qsv_hardware_info_hevc);
950                     details->qsv_hardware_info_hevc.implementation = hw_impl | hw_preference;
951                     // now that we know which hardware encoders are
952                     // available, we can set the preferred implementation
953                     qsv_impl_set_preferred(details, "hardware");
954                 }
955                 hb_display_close(&display);
956                 MFXClose(session);
957                 hw_preference = 0;
958             }
959             else
960             {
961 #if defined(_WIN32) || defined(__MINGW32__)
962                 // Windows only: After D3D11 we will try D3D9
963                 if (hw_preference == MFX_IMPL_VIA_D3D11)
964                     hw_preference = MFX_IMPL_VIA_D3D9;
965                 else
966 #endif
967                     hw_preference = 0;
968             }
969         }
970         while(hw_preference != 0);
971     }
972     return 0;
973 }
974 
log_decoder_capabilities(const int log_level,const hb_qsv_adapter_details_t * adapter_details,const char * prefix)975 static void log_decoder_capabilities(const int log_level, const hb_qsv_adapter_details_t *adapter_details, const char *prefix)
976 {
977     char buffer[128] = "";
978 
979     if (hb_qsv_decode_h264_is_supported(adapter_details->index))
980     {
981         strcat(buffer, " h264");
982     }
983 
984     if (hb_qsv_decode_h265_10_bit_is_supported(adapter_details->index))
985     {
986         strcat(buffer, " hevc (8bit: yes, 10bit: yes)");
987     }
988     else if (hb_qsv_decode_h265_is_supported(adapter_details->index))
989     {
990         strcat(buffer, " hevc (8bit: yes, 10bit: no)");
991     }
992 
993     if (hb_qsv_decode_av1_is_supported(adapter_details->index))
994     {
995         strcat(buffer, " av1 (8bit: yes, 10bit: yes)");
996     }
997 
998     hb_deep_log(log_level, "%s%s", prefix,
999                 strnlen(buffer, 1) ? buffer : " no decode support");
1000 }
1001 
log_encoder_capabilities(const int log_level,const uint64_t caps,const char * prefix)1002 static void log_encoder_capabilities(const int log_level, const uint64_t caps, const char *prefix)
1003 {
1004     /*
1005      * Note: keep the string short, as it may be logged by default.
1006      */
1007     char buffer[128] = "";
1008 
1009     if (caps & HB_QSV_CAP_LOWPOWER_ENCODE)
1010     {
1011         strcat(buffer, " lowpower");
1012     }
1013     /* B-Pyramid, with or without direct control (BRefType) */
1014     if (caps & HB_QSV_CAP_B_REF_PYRAMID)
1015     {
1016         if (caps & HB_QSV_CAP_OPTION2_BREFTYPE)
1017         {
1018             strcat(buffer, " breftype");
1019         }
1020         else
1021         {
1022             strcat(buffer, " bpyramid");
1023         }
1024     }
1025     /* Rate control: ICQ, lookahead (options: interlaced, downsampling) */
1026     if (caps & HB_QSV_CAP_RATECONTROL_LA)
1027     {
1028         if (caps & HB_QSV_CAP_RATECONTROL_ICQ)
1029         {
1030             strcat(buffer, " icq+la");
1031         }
1032         else
1033         {
1034             strcat(buffer, " la");
1035         }
1036         if (caps & HB_QSV_CAP_RATECONTROL_LAi)
1037         {
1038             strcat(buffer, "+i");
1039         }
1040         if (caps & HB_QSV_CAP_OPTION2_LA_DOWNS)
1041         {
1042             strcat(buffer, "+downs");
1043         }
1044     }
1045     else if (caps & HB_QSV_CAP_RATECONTROL_ICQ)
1046     {
1047         strcat(buffer, " icq");
1048     }
1049     if (caps & HB_QSV_CAP_VUI_VSINFO)
1050     {
1051         strcat(buffer, " vsinfo");
1052     }
1053     if (caps & HB_QSV_CAP_OPTION1)
1054     {
1055         strcat(buffer, " opt1");
1056     }
1057     if (caps & HB_QSV_CAP_OPTION2)
1058     {
1059         {
1060             strcat(buffer, " opt2");
1061         }
1062         if (caps & HB_QSV_CAP_OPTION2_MBBRC)
1063         {
1064             strcat(buffer, "+mbbrc");
1065         }
1066         if (caps & HB_QSV_CAP_OPTION2_EXTBRC)
1067         {
1068             strcat(buffer, "+extbrc");
1069         }
1070         if (caps & HB_QSV_CAP_OPTION2_TRELLIS)
1071         {
1072             strcat(buffer, "+trellis");
1073         }
1074         if (caps & HB_QSV_CAP_OPTION2_IB_ADAPT)
1075         {
1076             strcat(buffer, "+ib_adapt");
1077         }
1078         if (caps & HB_QSV_CAP_OPTION2_NMPSLICE)
1079         {
1080             strcat(buffer, "+nmpslice");
1081         }
1082     }
1083 
1084     hb_deep_log(log_level, "%s%s", prefix,
1085                 strnlen(buffer, 1) ? buffer : " standard feature set");
1086 }
1087 
hb_qsv_adapter_info_print(const hb_qsv_adapter_details_t * adapter_details)1088 static void hb_qsv_adapter_info_print(const hb_qsv_adapter_details_t *adapter_details)
1089 {
1090     if (adapter_details->qsv_hardware_version.Version)
1091     {
1092         hb_log(" - Intel Media SDK hardware: API %"PRIu16".%"PRIu16" (minimum: %"PRIu16".%"PRIu16")",
1093                 adapter_details->qsv_hardware_version.Major, adapter_details->qsv_hardware_version.Minor,
1094                 HB_QSV_MINVERSION_MAJOR, HB_QSV_MINVERSION_MINOR);
1095     }
1096 
1097     if (adapter_details->qsv_software_version.Version)
1098     {
1099         hb_deep_log(3, " - Intel Media SDK software: API %"PRIu16".%"PRIu16" (minimum: %"PRIu16".%"PRIu16")",
1100                 adapter_details->qsv_software_version.Major, adapter_details->qsv_software_version.Minor,
1101                 HB_QSV_MINVERSION_MAJOR, HB_QSV_MINVERSION_MINOR);
1102     }
1103 
1104     log_decoder_capabilities(1, adapter_details, " - Decode support: ");
1105 
1106     if (adapter_details->hb_qsv_info_avc != NULL && adapter_details->hb_qsv_info_avc->available)
1107     {
1108         hb_log(" - H.264 encoder: yes");
1109         hb_log("    - preferred implementation: %s %s",
1110                 hb_qsv_impl_get_name(adapter_details->hb_qsv_info_avc->implementation),
1111                 hb_qsv_impl_get_via_name(adapter_details->hb_qsv_info_avc->implementation));
1112         if (adapter_details->qsv_hardware_info_avc.available)
1113         {
1114             log_encoder_capabilities(1, adapter_details->qsv_hardware_info_avc.capabilities,
1115                                 "    - capabilities (hardware): ");
1116         }
1117         if (adapter_details->qsv_software_info_avc.available)
1118         {
1119             log_encoder_capabilities(3, adapter_details->qsv_software_info_avc.capabilities,
1120                                 "    - capabilities (software): ");
1121         }
1122     }
1123     else
1124     {
1125         hb_log(" - H.264 encoder: no");
1126     }
1127     if (adapter_details->hb_qsv_info_hevc != NULL && adapter_details->hb_qsv_info_hevc->available)
1128     {
1129         hb_log(" - H.265 encoder: yes (8bit: yes, 10bit: %s)", (hb_qsv_hardware_generation(hb_qsv_get_platform(adapter_details->index)) < QSV_G6) ? "no" : "yes" );
1130         hb_log("    - preferred implementation: %s %s",
1131                 hb_qsv_impl_get_name(adapter_details->hb_qsv_info_hevc->implementation),
1132                 hb_qsv_impl_get_via_name(adapter_details->hb_qsv_info_hevc->implementation));
1133         if (adapter_details->qsv_hardware_info_hevc.available)
1134         {
1135             log_encoder_capabilities(1, adapter_details->qsv_hardware_info_hevc.capabilities,
1136                                 "    - capabilities (hardware): ");
1137         }
1138         if (adapter_details->qsv_software_info_hevc.available)
1139         {
1140             log_encoder_capabilities(3, adapter_details->qsv_software_info_hevc.capabilities,
1141                                 "    - capabilities (software): ");
1142         }
1143     }
1144     else
1145     {
1146         hb_log(" - H.265 encoder: no");
1147     }
1148 }
1149 
hb_qsv_info_print()1150 void hb_qsv_info_print()
1151 {
1152     // is QSV available and usable?
1153     if (hb_qsv_available())
1154     {
1155 #if defined(_WIN32) || defined(__MINGW32__)
1156         if (g_qsv_adapters_list && hb_list_count(g_qsv_adapters_list))
1157         {
1158             char gpu_list_str[256] = "";
1159             for (int i = 0; i < hb_list_count(g_qsv_adapters_list); i++)
1160             {
1161                 char value_str[256];
1162                 int *value = hb_list_item(g_qsv_adapters_list, i);
1163                 sprintf(value_str, "%d", *value);
1164                 if (i > 0)
1165                     strcat(gpu_list_str, ", ");
1166                 strcat(gpu_list_str, value_str);
1167             }
1168             hb_log("Intel Quick Sync Video support: yes, gpu list: %s", gpu_list_str);
1169         }
1170         else
1171 #endif
1172         {
1173             hb_log("Intel Quick Sync Video support: yes");
1174         }
1175         // also print the details about all QSV adapters
1176         for (int i = 0; i < hb_list_count(g_qsv_adapters_details_list); i++)
1177         {
1178             const hb_qsv_adapter_details_t *details = hb_list_item(g_qsv_adapters_details_list, i);
1179 #if defined(_WIN32) || defined(__MINGW32__)
1180             mfxAdapterInfo* info = &g_qsv_adapters_info.Adapters[i];
1181             hb_log("Intel Quick Sync Video %s adapter with index %d", hb_qsv_get_adapter_type(info), details->index);
1182 #endif
1183             hb_qsv_adapter_info_print(details);
1184         }
1185     }
1186     else
1187     {
1188         hb_log("Intel Quick Sync Video support: no");
1189     }
1190 }
1191 
hb_qsv_encoder_info_get(int adapter_index,int encoder)1192 hb_qsv_info_t* hb_qsv_encoder_info_get(int adapter_index, int encoder)
1193 {
1194     hb_qsv_adapter_details_t* details = hb_qsv_get_adapters_details_by_index(adapter_index);
1195 
1196     if (details)
1197     {
1198         switch (encoder)
1199         {
1200             case HB_VCODEC_QSV_H264:
1201                 return details->hb_qsv_info_avc;
1202             case HB_VCODEC_QSV_H265_10BIT:
1203             case HB_VCODEC_QSV_H265:
1204                 return details->hb_qsv_info_hevc;
1205             default:
1206                 return NULL;
1207         }
1208     }
1209     return NULL;
1210 }
1211 
hb_qsv_load_plugins(int index,hb_qsv_info_t * info,mfxSession session,mfxVersion version)1212 hb_list_t* hb_qsv_load_plugins(int index, hb_qsv_info_t *info, mfxSession session, mfxVersion version)
1213 {
1214     hb_list_t *mfxPluginList = hb_list_init();
1215     if (mfxPluginList == NULL)
1216     {
1217         hb_log("hb_qsv_load_plugins: hb_list_init() failed");
1218         goto fail;
1219     }
1220 
1221     if (HB_CHECK_MFX_VERSION(version, 1, 8))
1222     {
1223         if (info->codec_id == MFX_CODEC_HEVC && !(hb_qsv_hardware_generation(hb_qsv_get_platform(index)) < QSV_G5))
1224         {
1225             if (HB_CHECK_MFX_VERSION(version, 1, 15) &&
1226                 hb_qsv_implementation_is_hardware(info->implementation))
1227             {
1228                 if (MFXVideoUSER_Load(session, &MFX_PLUGINID_HEVCE_HW, 0) == MFX_ERR_NONE)
1229                 {
1230                     hb_list_add(mfxPluginList, (void*)&MFX_PLUGINID_HEVCE_HW);
1231                 }
1232             }
1233             else if (HB_CHECK_MFX_VERSION(version, 1, 15))
1234             {
1235                 if (MFXVideoUSER_Load(session, &MFX_PLUGINID_HEVCE_SW, 0) == MFX_ERR_NONE)
1236                 {
1237                     hb_list_add(mfxPluginList, (void*)&MFX_PLUGINID_HEVCE_SW);
1238                 }
1239             }
1240         }
1241     }
1242 
1243     return mfxPluginList;
1244 
1245 fail:
1246     hb_list_close(&mfxPluginList);
1247     return NULL;
1248 }
1249 
hb_qsv_unload_plugins(hb_list_t ** _l,mfxSession session,mfxVersion version)1250 void hb_qsv_unload_plugins(hb_list_t **_l, mfxSession session, mfxVersion version)
1251 {
1252     mfxPluginUID *pluginUID;
1253     hb_list_t *mfxPluginList = *_l;
1254 
1255     if (mfxPluginList != NULL && HB_CHECK_MFX_VERSION(version, 1, 8))
1256     {
1257         for (int i = 0; i < hb_list_count(mfxPluginList); i++)
1258         {
1259             if ((pluginUID = hb_list_item(mfxPluginList, i)) != NULL)
1260             {
1261                 MFXVideoUSER_UnLoad(session, pluginUID);
1262             }
1263         }
1264     }
1265     hb_list_close(_l);
1266 }
1267 
hb_qsv_decode_get_codec_name(enum AVCodecID codec_id)1268 const char* hb_qsv_decode_get_codec_name(enum AVCodecID codec_id)
1269 {
1270     switch (codec_id)
1271     {
1272         case AV_CODEC_ID_H264:
1273             return "h264_qsv";
1274 
1275         case AV_CODEC_ID_HEVC:
1276             return "hevc_qsv";
1277 
1278         case AV_CODEC_ID_MPEG2VIDEO:
1279             return "mpeg2_qsv";
1280 
1281         case AV_CODEC_ID_AV1:
1282             return "av1_qsv";
1283 
1284         default:
1285             return NULL;
1286     }
1287 }
1288 
hb_qsv_decode_h264_is_supported(int adapter_index)1289 int hb_qsv_decode_h264_is_supported(int adapter_index)
1290 {
1291     return hb_qsv_hardware_generation(hb_qsv_get_platform(adapter_index)) >= QSV_G1;
1292 }
1293 
hb_qsv_decode_h265_is_supported(int adapter_index)1294 int hb_qsv_decode_h265_is_supported(int adapter_index)
1295 {
1296     return hb_qsv_hardware_generation(hb_qsv_get_platform(adapter_index)) >= QSV_G5;
1297 }
1298 
hb_qsv_decode_h265_10_bit_is_supported(int adapter_index)1299 int hb_qsv_decode_h265_10_bit_is_supported(int adapter_index)
1300 {
1301     return hb_qsv_hardware_generation(hb_qsv_get_platform(adapter_index)) >= QSV_G6;
1302 }
1303 
hb_qsv_decode_av1_is_supported(int adapter_index)1304 int hb_qsv_decode_av1_is_supported(int adapter_index)
1305 {
1306     return hb_qsv_hardware_generation(hb_qsv_get_platform(adapter_index)) >= QSV_G8;
1307 }
1308 
hb_qsv_decode_codec_supported_codec(int adapter_index,int video_codec_param,int pix_fmt)1309 int hb_qsv_decode_codec_supported_codec(int adapter_index, int video_codec_param, int pix_fmt)
1310 {
1311     switch (video_codec_param)
1312     {
1313         case AV_CODEC_ID_H264:
1314             if (pix_fmt == AV_PIX_FMT_NV12     ||
1315                 pix_fmt == AV_PIX_FMT_YUV420P  ||
1316                 pix_fmt == AV_PIX_FMT_YUVJ420P)
1317             {
1318                 return hb_qsv_decode_h264_is_supported(adapter_index);
1319             }
1320             break;
1321         case AV_CODEC_ID_HEVC:
1322             if (pix_fmt == AV_PIX_FMT_NV12     ||
1323                 pix_fmt == AV_PIX_FMT_YUV420P  ||
1324                 pix_fmt == AV_PIX_FMT_YUVJ420P)
1325             {
1326                 return hb_qsv_decode_h265_is_supported(adapter_index);
1327             }
1328             else if (pix_fmt == AV_PIX_FMT_P010LE ||
1329                 pix_fmt == AV_PIX_FMT_YUV420P10)
1330             {
1331                 return hb_qsv_decode_h265_10_bit_is_supported(adapter_index);
1332             }
1333             break;
1334         case AV_CODEC_ID_AV1:
1335             if (pix_fmt == AV_PIX_FMT_NV12     ||
1336                 pix_fmt == AV_PIX_FMT_P010LE   ||
1337                 pix_fmt == AV_PIX_FMT_YUV420P  ||
1338                 pix_fmt == AV_PIX_FMT_YUVJ420P ||
1339                 pix_fmt == AV_PIX_FMT_YUV420P10)
1340             {
1341                 return hb_qsv_decode_av1_is_supported(adapter_index);
1342             }
1343             break;
1344         default:
1345             return 0;
1346     }
1347     return 0;
1348 }
1349 
hb_qsv_setup_job(hb_job_t * job)1350 int hb_qsv_setup_job(hb_job_t *job)
1351 {
1352 #if defined(_WIN32) || defined(__MINGW32__)
1353     if (job->qsv.ctx && job->qsv.ctx->dx_index >= 0)
1354     {
1355         hb_qsv_param_parse_dx_index(job, job->qsv.ctx->dx_index);
1356     }
1357     hb_qsv_parse_adapter_index(job);
1358 #endif
1359     int async_depth_default = hb_qsv_param_default_async_depth();
1360     if (job->qsv.async_depth <= 0 || job->qsv.async_depth > async_depth_default)
1361     {
1362         job->qsv.async_depth = async_depth_default;
1363     }
1364     // Make sure QSV Decode is only True if the selected QSV adapter supports decode.
1365     job->qsv.decode = job->qsv.decode && hb_qsv_available();
1366     return 0;
1367 }
1368 
hb_qsv_decode_is_enabled(hb_job_t * job)1369 int hb_qsv_decode_is_enabled(hb_job_t *job)
1370 {
1371     return ((job != NULL && job->qsv.decode) &&
1372             (job->title->video_decode_support & HB_DECODE_SUPPORT_QSV)) &&
1373             hb_qsv_decode_codec_supported_codec(hb_qsv_get_adapter_index(),
1374             job->title->video_codec_param, job->input_pix_fmt);
1375 }
1376 
1377 static int hb_dxva2_device_check();
1378 static int hb_d3d11va_device_check();
1379 
hb_qsv_hw_filters_are_enabled(hb_job_t * job)1380 int hb_qsv_hw_filters_are_enabled(hb_job_t *job)
1381 {
1382     return job && job->qsv.ctx && job->qsv.ctx->qsv_filters_are_enabled;
1383 }
1384 
hb_qsv_is_enabled(hb_job_t * job)1385 int hb_qsv_is_enabled(hb_job_t *job)
1386 {
1387     return hb_qsv_decode_is_enabled(job) || hb_qsv_encoder_info_get(hb_qsv_get_adapter_index(), job->vcodec);
1388 }
1389 
hb_qsv_get_bit_depth_by_codec(int codec_id)1390 static int hb_qsv_get_bit_depth_by_codec(int codec_id)
1391 {
1392     int pix_fmt_bit_depth = 0;
1393 
1394     switch (codec_id)
1395     {
1396         case HB_VCODEC_QSV_H264:
1397         case HB_VCODEC_QSV_H265_8BIT:
1398             pix_fmt_bit_depth = 8;
1399             break;
1400         case HB_VCODEC_QSV_H265_10BIT:
1401             pix_fmt_bit_depth = 10;
1402             break;
1403         default:
1404             break;
1405     }
1406     return pix_fmt_bit_depth;
1407 }
1408 
hb_qsv_full_path_is_enabled(hb_job_t * job)1409 int hb_qsv_full_path_is_enabled(hb_job_t *job)
1410 {
1411     static int device_check_completed = 0;
1412     static int device_check_succeeded = 0;
1413     int qsv_full_path_is_enabled = 0;
1414     hb_qsv_info_t *info = hb_qsv_encoder_info_get(hb_qsv_get_adapter_index(), job->vcodec);
1415 
1416     if(!device_check_completed)
1417     {
1418        device_check_succeeded = (hb_d3d11va_device_check() >= 0) ? 1 : 0;
1419        device_check_completed = 1;
1420     }
1421 
1422     int title_bit_depth = hb_get_bit_depth(job->title->pix_fmt);
1423     int pix_fmt_bit_depth = hb_qsv_get_bit_depth_by_codec(job->vcodec);
1424 
1425     if (pix_fmt_bit_depth != title_bit_depth)
1426     {
1427         return 0;
1428     }
1429 
1430     qsv_full_path_is_enabled = (hb_qsv_decode_is_enabled(job) &&
1431         info && hb_qsv_implementation_is_hardware(info->implementation) &&
1432         device_check_succeeded && job->qsv.ctx && !job->qsv.ctx->num_cpu_filters);
1433     return qsv_full_path_is_enabled;
1434 }
1435 
hb_qsv_copyframe_is_slow(int encoder)1436 int hb_qsv_copyframe_is_slow(int encoder)
1437 {
1438     hb_qsv_info_t *info = hb_qsv_encoder_info_get(hb_qsv_get_adapter_index(), encoder);
1439     if (info != NULL && hb_qsv_implementation_is_hardware(info->implementation))
1440     {
1441         hb_qsv_adapter_details_t* details = hb_qsv_get_adapters_details_by_index(hb_qsv_get_adapter_index());
1442         if (details)
1443         {
1444             // we should really check the driver version, but since it's not
1445             // available, checking the API version is the best we can do :-(
1446             return !HB_CHECK_MFX_VERSION(details->qsv_hardware_version, 1, 7);
1447         }
1448         return 0;
1449     }
1450     return 0;
1451 }
1452 
hb_qsv_codingoption_xlat(int val)1453 int hb_qsv_codingoption_xlat(int val)
1454 {
1455     switch (HB_QSV_CLIP3(-1, 2, val))
1456     {
1457         case 0:
1458             return MFX_CODINGOPTION_OFF;
1459         case 1:
1460         case 2: // MFX_CODINGOPTION_ADAPTIVE, reserved
1461             return MFX_CODINGOPTION_ON;
1462         case -1:
1463         default:
1464             return MFX_CODINGOPTION_UNKNOWN;
1465     }
1466 }
1467 
hb_qsv_trellisvalue_xlat(int val)1468 int hb_qsv_trellisvalue_xlat(int val)
1469 {
1470     switch (HB_QSV_CLIP3(0, 3, val))
1471     {
1472         case 0:
1473             return MFX_TRELLIS_OFF;
1474         case 1: // I-frames only
1475             return MFX_TRELLIS_I;
1476         case 2: // I- and P-frames
1477             return MFX_TRELLIS_I|MFX_TRELLIS_P;
1478         case 3: // all frames
1479             return MFX_TRELLIS_I|MFX_TRELLIS_P|MFX_TRELLIS_B;
1480         default:
1481             return MFX_TRELLIS_UNKNOWN;
1482     }
1483 }
1484 
hb_qsv_codingoption_get_name(int val)1485 const char* hb_qsv_codingoption_get_name(int val)
1486 {
1487     switch (val)
1488     {
1489         case MFX_CODINGOPTION_ON:
1490             return "on";
1491         case MFX_CODINGOPTION_OFF:
1492             return "off";
1493         case MFX_CODINGOPTION_ADAPTIVE:
1494             return "adaptive";
1495         case MFX_CODINGOPTION_UNKNOWN:
1496             return "unknown (auto)";
1497         default:
1498             return NULL;
1499     }
1500 }
1501 
hb_qsv_atoindex(const char * const * arr,const char * str,int * err)1502 int hb_qsv_atoindex(const char* const *arr, const char *str, int *err)
1503 {
1504     int i;
1505     for (i = 0; arr[i] != NULL; i++)
1506     {
1507         if (!strcasecmp(arr[i], str))
1508         {
1509             break;
1510         }
1511     }
1512     *err = (arr[i] == NULL);
1513     return i;
1514 }
1515 
1516 // adapted from libx264
hb_qsv_atobool(const char * str,int * err)1517 int hb_qsv_atobool(const char *str, int *err)
1518 {
1519     if (!strcasecmp(str,    "1") ||
1520         !strcasecmp(str,  "yes") ||
1521         !strcasecmp(str, "true"))
1522     {
1523         return 1;
1524     }
1525     if (!strcasecmp(str,     "0") ||
1526         !strcasecmp(str,    "no") ||
1527         !strcasecmp(str, "false"))
1528     {
1529         return 0;
1530     }
1531     *err = 1;
1532     return 0;
1533 }
1534 
1535 // adapted from libx264
hb_qsv_atoi(const char * str,int * err)1536 int hb_qsv_atoi(const char *str, int *err)
1537 {
1538     char *end;
1539     int v = strtol(str, &end, 0);
1540     if (end == str || end[0] != '\0')
1541     {
1542         *err = 1;
1543     }
1544     return v;
1545 }
1546 
1547 // adapted from libx264
hb_qsv_atof(const char * str,int * err)1548 float hb_qsv_atof(const char *str, int *err)
1549 {
1550     char *end;
1551     float v = strtod(str, &end);
1552     if (end == str || end[0] != '\0')
1553     {
1554         *err = 1;
1555     }
1556     return v;
1557 }
1558 
hb_qsv_param_parse(hb_qsv_param_t * param,hb_qsv_info_t * info,hb_job_t * job,const char * key,const char * value)1559 int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job,
1560                        const char *key, const char *value)
1561 {
1562     float fvalue;
1563     int ivalue, error = 0;
1564     if (param == NULL || info == NULL)
1565     {
1566         return HB_QSV_PARAM_ERROR;
1567     }
1568     if (value == NULL || value[0] == '\0')
1569     {
1570         value = "true";
1571     }
1572     else if (value[0] == '=')
1573     {
1574         value++;
1575     }
1576     if (key == NULL || key[0] == '\0')
1577     {
1578         return HB_QSV_PARAM_BAD_NAME;
1579     }
1580     else if (!strncasecmp(key, "no-", 3))
1581     {
1582         key  += 3;
1583         value = hb_qsv_atobool(value, &error) ? "false" : "true";
1584         if (error)
1585         {
1586             return HB_QSV_PARAM_BAD_VALUE;
1587         }
1588     }
1589     if (!strcasecmp(key, "target-usage") ||
1590         !strcasecmp(key, "tu"))
1591     {
1592         ivalue = hb_qsv_atoi(value, &error);
1593         if (!error)
1594         {
1595             param->videoParam->mfx.TargetUsage = HB_QSV_CLIP3(MFX_TARGETUSAGE_1,
1596                                                               MFX_TARGETUSAGE_7,
1597                                                               ivalue);
1598         }
1599     }
1600     else if (!strcasecmp(key, "num-ref-frame") ||
1601              !strcasecmp(key, "ref"))
1602     {
1603         ivalue = hb_qsv_atoi(value, &error);
1604         if (!error)
1605         {
1606             param->videoParam->mfx.NumRefFrame = HB_QSV_CLIP3(0, 16, ivalue);
1607         }
1608     }
1609     else if (!strcasecmp(key, "gop-ref-dist"))
1610     {
1611         ivalue = hb_qsv_atoi(value, &error);
1612         if (!error)
1613         {
1614             param->gop.gop_ref_dist = HB_QSV_CLIP3(-1, 32, ivalue);
1615         }
1616     }
1617     else if (!strcasecmp(key, "gop-pic-size") ||
1618              !strcasecmp(key, "keyint"))
1619     {
1620         ivalue = hb_qsv_atoi(value, &error);
1621         if (!error)
1622         {
1623             param->gop.gop_pic_size = HB_QSV_CLIP3(-1, UINT16_MAX, ivalue);
1624         }
1625     }
1626     else if (!strcasecmp(key, "b-pyramid"))
1627     {
1628         if (info->capabilities & HB_QSV_CAP_B_REF_PYRAMID)
1629         {
1630             ivalue = hb_qsv_atoi(value, &error);
1631             if (!error)
1632             {
1633                 param->gop.b_pyramid = HB_QSV_CLIP3(-1, 1, ivalue);
1634             }
1635         }
1636         else
1637         {
1638             return HB_QSV_PARAM_UNSUPPORTED;
1639         }
1640     }
1641     else if (!strcasecmp(key, "scenecut"))
1642     {
1643         ivalue = hb_qsv_atobool(value, &error);
1644         if (!error)
1645         {
1646             if (!ivalue)
1647             {
1648                 param->videoParam->mfx.GopOptFlag |= MFX_GOP_STRICT;
1649             }
1650             else
1651             {
1652                 param->videoParam->mfx.GopOptFlag &= ~MFX_GOP_STRICT;
1653             }
1654         }
1655     }
1656     else if (!strcasecmp(key, "adaptive-i") ||
1657              !strcasecmp(key, "i-adapt"))
1658     {
1659         if (info->capabilities & HB_QSV_CAP_OPTION2_IB_ADAPT)
1660         {
1661             ivalue = hb_qsv_atobool(value, &error);
1662             if (!error)
1663             {
1664                 param->codingOption2.AdaptiveI = hb_qsv_codingoption_xlat(ivalue);
1665             }
1666         }
1667         else
1668         {
1669             return HB_QSV_PARAM_UNSUPPORTED;
1670         }
1671     }
1672     else if (!strcasecmp(key, "adaptive-b") ||
1673              !strcasecmp(key, "b-adapt"))
1674     {
1675         if (info->capabilities & HB_QSV_CAP_OPTION2_IB_ADAPT)
1676         {
1677             ivalue = hb_qsv_atobool(value, &error);
1678             if (!error)
1679             {
1680                 param->codingOption2.AdaptiveB = hb_qsv_codingoption_xlat(ivalue);
1681             }
1682         }
1683         else
1684         {
1685             return HB_QSV_PARAM_UNSUPPORTED;
1686         }
1687     }
1688     else if (!strcasecmp(key, "force-cqp"))
1689     {
1690         ivalue = hb_qsv_atobool(value, &error);
1691         if (!error)
1692         {
1693             param->rc.icq = !ivalue;
1694         }
1695     }
1696     else if (!strcasecmp(key, "cqp-offset-i"))
1697     {
1698         ivalue = hb_qsv_atoi(value, &error);
1699         if (!error)
1700         {
1701             param->rc.cqp_offsets[0] = HB_QSV_CLIP3(INT16_MIN, INT16_MAX, ivalue);
1702         }
1703     }
1704     else if (!strcasecmp(key, "cqp-offset-p"))
1705     {
1706         ivalue = hb_qsv_atoi(value, &error);
1707         if (!error)
1708         {
1709             param->rc.cqp_offsets[1] = HB_QSV_CLIP3(INT16_MIN, INT16_MAX, ivalue);
1710         }
1711     }
1712     else if (!strcasecmp(key, "cqp-offset-b"))
1713     {
1714         ivalue = hb_qsv_atoi(value, &error);
1715         if (!error)
1716         {
1717             param->rc.cqp_offsets[2] = HB_QSV_CLIP3(INT16_MIN, INT16_MAX, ivalue);
1718         }
1719     }
1720     else if (!strcasecmp(key, "vbv-init"))
1721     {
1722         fvalue = hb_qsv_atof(value, &error);
1723         if (!error)
1724         {
1725             param->rc.vbv_buffer_init = HB_QSV_CLIP3(0, UINT16_MAX, fvalue);
1726         }
1727     }
1728     else if (!strcasecmp(key, "vbv-bufsize"))
1729     {
1730         ivalue = hb_qsv_atoi(value, &error);
1731         if (!error)
1732         {
1733             param->rc.vbv_buffer_size = HB_QSV_CLIP3(0, UINT16_MAX, ivalue);
1734         }
1735     }
1736     else if (!strcasecmp(key, "vbv-maxrate"))
1737     {
1738         ivalue = hb_qsv_atoi(value, &error);
1739         if (!error)
1740         {
1741             param->rc.vbv_max_bitrate = HB_QSV_CLIP3(0, UINT16_MAX, ivalue);
1742         }
1743     }
1744     else if (!strcasecmp(key, "cavlc") || !strcasecmp(key, "cabac"))
1745     {
1746         if (info->capabilities & HB_QSV_CAP_OPTION1)
1747         {
1748             switch (info->codec_id)
1749             {
1750                 case MFX_CODEC_AVC:
1751                     ivalue = hb_qsv_atobool(value, &error);
1752                     break;
1753                 default:
1754                     return HB_QSV_PARAM_UNSUPPORTED;
1755             }
1756         }
1757         else
1758         {
1759             return HB_QSV_PARAM_UNSUPPORTED;
1760         }
1761         if (!error)
1762         {
1763             if (!strcasecmp(key, "cabac"))
1764             {
1765                 ivalue = !ivalue;
1766             }
1767             param->codingOption.CAVLC = hb_qsv_codingoption_xlat(ivalue);
1768         }
1769     }
1770     else if (!strcasecmp(key, "videoformat"))
1771     {
1772         if (info->capabilities & HB_QSV_CAP_VUI_VSINFO)
1773         {
1774             switch (info->codec_id)
1775             {
1776                 case MFX_CODEC_AVC:
1777                     ivalue = hb_qsv_atoindex(hb_h264_vidformat_names, value, &error);
1778                     break;
1779                 case MFX_CODEC_HEVC:
1780                     ivalue = hb_qsv_atoindex(hb_h265_vidformat_names, value, &error);
1781                     break;
1782                 default:
1783                     return HB_QSV_PARAM_UNSUPPORTED;
1784             }
1785         }
1786         else
1787         {
1788             return HB_QSV_PARAM_UNSUPPORTED;
1789         }
1790         if (!error)
1791         {
1792             param->videoSignalInfo.VideoFormat = ivalue;
1793         }
1794     }
1795     else if (!strcasecmp(key, "fullrange"))
1796     {
1797         if (info->capabilities & HB_QSV_CAP_VUI_VSINFO)
1798         {
1799             switch (info->codec_id)
1800             {
1801                 case MFX_CODEC_AVC:
1802                     ivalue = hb_qsv_atoindex(hb_h264_fullrange_names, value, &error);
1803                     break;
1804                 case MFX_CODEC_HEVC:
1805                     ivalue = hb_qsv_atoindex(hb_h265_fullrange_names, value, &error);
1806                     break;
1807                 default:
1808                     return HB_QSV_PARAM_UNSUPPORTED;
1809             }
1810         }
1811         else
1812         {
1813             return HB_QSV_PARAM_UNSUPPORTED;
1814         }
1815         if (!error)
1816         {
1817             param->videoSignalInfo.VideoFullRange = ivalue;
1818         }
1819     }
1820     else if (!strcasecmp(key, "colorprim"))
1821     {
1822         if (info->capabilities & HB_QSV_CAP_VUI_VSINFO)
1823         {
1824             switch (info->codec_id)
1825             {
1826                 case MFX_CODEC_AVC:
1827                     ivalue = hb_qsv_atoindex(hb_h264_colorprim_names, value, &error);
1828                     break;
1829                 case MFX_CODEC_HEVC:
1830                     ivalue = hb_qsv_atoindex(hb_h265_colorprim_names, value, &error);
1831                     break;
1832                 default:
1833                     return HB_QSV_PARAM_UNSUPPORTED;
1834             }
1835         }
1836         else
1837         {
1838             return HB_QSV_PARAM_UNSUPPORTED;
1839         }
1840         if (!error)
1841         {
1842             param->videoSignalInfo.ColourDescriptionPresent = 1;
1843             param->videoSignalInfo.ColourPrimaries = ivalue;
1844         }
1845     }
1846     else if (!strcasecmp(key, "transfer"))
1847     {
1848         if (info->capabilities & HB_QSV_CAP_VUI_VSINFO)
1849         {
1850             switch (info->codec_id)
1851             {
1852                 case MFX_CODEC_AVC:
1853                     ivalue = hb_qsv_atoindex(hb_h264_transfer_names, value, &error);
1854                     break;
1855                 case MFX_CODEC_HEVC:
1856                     ivalue = hb_qsv_atoindex(hb_h265_transfer_names, value, &error);
1857                     break;
1858                 default:
1859                     return HB_QSV_PARAM_UNSUPPORTED;
1860             }
1861         }
1862         else
1863         {
1864             return HB_QSV_PARAM_UNSUPPORTED;
1865         }
1866         if (!error)
1867         {
1868             param->videoSignalInfo.ColourDescriptionPresent = 1;
1869             param->videoSignalInfo.TransferCharacteristics = ivalue;
1870         }
1871     }
1872     else if (!strcasecmp(key, "colormatrix"))
1873     {
1874         if (info->capabilities & HB_QSV_CAP_VUI_VSINFO)
1875         {
1876             switch (info->codec_id)
1877             {
1878                 case MFX_CODEC_AVC:
1879                     ivalue = hb_qsv_atoindex(hb_h264_colmatrix_names, value, &error);
1880                     break;
1881                 case MFX_CODEC_HEVC:
1882                     ivalue = hb_qsv_atoindex(hb_h265_colmatrix_names, value, &error);
1883                     break;
1884                 default:
1885                     return HB_QSV_PARAM_UNSUPPORTED;
1886             }
1887         }
1888         else
1889         {
1890             return HB_QSV_PARAM_UNSUPPORTED;
1891         }
1892         if (!error)
1893         {
1894             param->videoSignalInfo.ColourDescriptionPresent = 1;
1895             param->videoSignalInfo.MatrixCoefficients = ivalue;
1896         }
1897     }
1898     else if (!strcasecmp(key, "tff") ||
1899              !strcasecmp(key, "interlaced"))
1900     {
1901         switch (info->codec_id)
1902         {
1903             case MFX_CODEC_AVC:
1904                 ivalue = hb_qsv_atobool(value, &error);
1905                 break;
1906             default:
1907                 return HB_QSV_PARAM_UNSUPPORTED;
1908         }
1909         if (!error)
1910         {
1911             param->videoParam->mfx.FrameInfo.PicStruct = (ivalue                  ?
1912                                                           MFX_PICSTRUCT_FIELD_TFF :
1913                                                           MFX_PICSTRUCT_PROGRESSIVE);
1914         }
1915     }
1916     else if (!strcasecmp(key, "bff"))
1917     {
1918         switch (info->codec_id)
1919         {
1920             case MFX_CODEC_AVC:
1921                 ivalue = hb_qsv_atobool(value, &error);
1922                 break;
1923             default:
1924                 return HB_QSV_PARAM_UNSUPPORTED;
1925         }
1926         if (!error)
1927         {
1928             param->videoParam->mfx.FrameInfo.PicStruct = (ivalue                  ?
1929                                                           MFX_PICSTRUCT_FIELD_BFF :
1930                                                           MFX_PICSTRUCT_PROGRESSIVE);
1931         }
1932     }
1933     else if (!strcasecmp(key, "mbbrc"))
1934     {
1935         if (info->capabilities & HB_QSV_CAP_OPTION2_MBBRC)
1936         {
1937             ivalue = hb_qsv_atobool(value, &error);
1938             if (!error)
1939             {
1940                 param->codingOption2.MBBRC = hb_qsv_codingoption_xlat(ivalue);
1941             }
1942         }
1943         else
1944         {
1945             return HB_QSV_PARAM_UNSUPPORTED;
1946         }
1947     }
1948     else if (!strcasecmp(key, "extbrc"))
1949     {
1950         if (info->capabilities & HB_QSV_CAP_OPTION2_EXTBRC)
1951         {
1952             ivalue = hb_qsv_atobool(value, &error);
1953             if (!error)
1954             {
1955                 param->codingOption2.ExtBRC = hb_qsv_codingoption_xlat(ivalue);
1956             }
1957         }
1958         else
1959         {
1960             return HB_QSV_PARAM_UNSUPPORTED;
1961         }
1962     }
1963     else if (!strcasecmp(key, "lookahead") ||
1964              !strcasecmp(key, "la"))
1965     {
1966         if (info->capabilities & HB_QSV_CAP_RATECONTROL_LA)
1967         {
1968             ivalue = hb_qsv_atobool(value, &error);
1969             if (!error)
1970             {
1971                 param->rc.lookahead = ivalue;
1972             }
1973         }
1974         else
1975         {
1976             return HB_QSV_PARAM_UNSUPPORTED;
1977         }
1978     }
1979     else if (!strcasecmp(key, "lookahead-depth") ||
1980              !strcasecmp(key, "la-depth"))
1981     {
1982         if (info->capabilities & HB_QSV_CAP_RATECONTROL_LA)
1983         {
1984             ivalue = hb_qsv_atoi(value, &error);
1985             if (!error)
1986             {
1987                 param->codingOption2.LookAheadDepth = HB_QSV_CLIP3(10, 100,
1988                                                                    ivalue);
1989             }
1990         }
1991         else
1992         {
1993             return HB_QSV_PARAM_UNSUPPORTED;
1994         }
1995     }
1996     else if (!strcasecmp(key, "lookahead-ds") ||
1997              !strcasecmp(key, "la-ds"))
1998     {
1999         if (info->capabilities & HB_QSV_CAP_OPTION2_LA_DOWNS)
2000         {
2001             ivalue = hb_qsv_atoi(value, &error);
2002             if (!error)
2003             {
2004                 param->codingOption2.LookAheadDS = HB_QSV_CLIP3(MFX_LOOKAHEAD_DS_UNKNOWN,
2005                                                                 MFX_LOOKAHEAD_DS_4x,
2006                                                                 ivalue);
2007             }
2008         }
2009         else
2010         {
2011             return HB_QSV_PARAM_UNSUPPORTED;
2012         }
2013     }
2014     else if (!strcasecmp(key, "trellis"))
2015     {
2016         if (info->capabilities & HB_QSV_CAP_OPTION2_TRELLIS)
2017         {
2018             ivalue = hb_qsv_atoi(value, &error);
2019             if (!error)
2020             {
2021                 param->codingOption2.Trellis = hb_qsv_trellisvalue_xlat(ivalue);
2022             }
2023         }
2024         else
2025         {
2026             return HB_QSV_PARAM_UNSUPPORTED;
2027         }
2028     }
2029     else if (!strcasecmp(key, "lowpower"))
2030     {
2031         if (info->capabilities & HB_QSV_CAP_LOWPOWER_ENCODE)
2032         {
2033             ivalue = hb_qsv_atobool(value, &error);
2034             if (!error)
2035             {
2036                 param->videoParam->mfx.LowPower = ivalue ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF;
2037             }
2038         }
2039         else
2040         {
2041             return HB_QSV_PARAM_UNSUPPORTED;
2042         }
2043     }
2044 #if defined(_WIN32) || defined(__MINGW32__)
2045     else if (!strcasecmp(key, "gpu"))
2046     {
2047         // Check if was parsed already in decoder initialization
2048         if (job->qsv.ctx && !job->qsv.ctx->qsv_device)
2049         {
2050             int gpu_index = hb_qsv_atoi(value, &error);
2051             if (!error)
2052             {
2053                 hb_qsv_param_parse_dx_index(job, gpu_index);
2054             }
2055         }
2056     }
2057 #endif
2058     else if (!strcasecmp(key, "scalingmode") ||
2059              !strcasecmp(key, "vpp-sm"))
2060     {
2061         // Already parsed it in decoder but need to check support
2062         if (info->capabilities & HB_QSV_CAP_VPP_SCALING)
2063         {
2064             hb_triplet_t *mode = NULL;
2065             mode = hb_triplet4key(hb_qsv_vpp_scale_modes, value);
2066             if (!mode)
2067             {
2068                 error = HB_QSV_PARAM_BAD_VALUE;
2069             }
2070         }
2071         else
2072         {
2073             return HB_QSV_PARAM_UNSUPPORTED;
2074         }
2075     }
2076     else if (!strcasecmp(key, "interpolationmethod") ||
2077              !strcasecmp(key, "vpp-im"))
2078     {
2079         // Already parsed it in decoder but need to check support
2080         if (info->capabilities & HB_QSV_CAP_VPP_INTERPOLATION)
2081         {
2082             hb_triplet_t *method = NULL;
2083             method = hb_triplet4key(hb_qsv_vpp_interpolation_methods, value);
2084             if (!method)
2085             {
2086                 error = HB_QSV_PARAM_BAD_VALUE;
2087             }
2088         }
2089         else
2090         {
2091             return HB_QSV_PARAM_UNSUPPORTED;
2092         }
2093     }
2094     else
2095     {
2096         /*
2097          * TODO:
2098          * - slice count (num-slice/slices, num-mb-per-slice/slice-max-mbs)
2099          * - open-gop
2100          * - fake-interlaced (mfxExtCodingOption.FramePicture???)
2101          * - intra-refresh
2102          */
2103         return HB_QSV_PARAM_BAD_NAME;
2104     }
2105     return error ? HB_QSV_PARAM_BAD_VALUE : HB_QSV_PARAM_OK;
2106 }
2107 
hb_qsv_profile_parse(hb_qsv_param_t * param,hb_qsv_info_t * info,const char * profile_key,const int codec)2108 int hb_qsv_profile_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, const char *profile_key, const int codec)
2109 {
2110     hb_triplet_t *profile = NULL;
2111     if (profile_key != NULL && *profile_key && strcasecmp(profile_key, "auto"))
2112     {
2113         switch (param->videoParam->mfx.CodecId)
2114         {
2115             case MFX_CODEC_AVC:
2116                 profile = hb_triplet4key(hb_qsv_h264_profiles, profile_key);
2117                 break;
2118 
2119             case MFX_CODEC_HEVC:
2120                 profile = hb_triplet4key(hb_qsv_h265_profiles, profile_key);
2121 
2122                 /* HEVC10 supported starting from KBL/G6 */
2123                 if (profile->value == MFX_PROFILE_HEVC_MAIN10 &&
2124                     hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) < QSV_G6)
2125                 {
2126                     hb_log("qsv: HEVC Main10 is not supported on this platform");
2127                     profile = NULL;
2128                 }
2129 
2130                 break;
2131 
2132             default:
2133                 break;
2134         }
2135         if (profile == NULL)
2136         {
2137             return -1;
2138         }
2139         param->videoParam->mfx.CodecProfile = profile->value;
2140     }
2141     /* HEVC 10 bits defaults to Main 10 */
2142     else if (((profile_key != NULL && !strcasecmp(profile_key, "auto")) || profile_key == NULL) &&
2143               codec == HB_VCODEC_QSV_H265_10BIT &&
2144               param->videoParam->mfx.CodecId == MFX_CODEC_HEVC &&
2145               hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) >= QSV_G6)
2146     {
2147          profile = &hb_qsv_h265_profiles[1];
2148          param->videoParam->mfx.CodecProfile = profile->value;
2149     }
2150     return 0;
2151 }
2152 
hb_qsv_level_parse(hb_qsv_param_t * param,hb_qsv_info_t * info,const char * level_key)2153 int hb_qsv_level_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, const char *level_key)
2154 {
2155     hb_triplet_t *level = NULL;
2156     if (level_key != NULL && *level_key && strcasecmp(level_key, "auto"))
2157     {
2158         switch (param->videoParam->mfx.CodecId)
2159         {
2160             case MFX_CODEC_AVC:
2161                 level = hb_triplet4key(hb_qsv_h264_levels, level_key);
2162                 break;
2163 
2164             case MFX_CODEC_HEVC:
2165                 level = hb_triplet4key(hb_qsv_h265_levels, level_key);
2166                 break;
2167 
2168             default:
2169                 break;
2170         }
2171         if (level == NULL)
2172         {
2173             return -1;
2174         }
2175         if (param->videoParam->mfx.CodecId == MFX_CODEC_AVC)
2176         {
2177             if (info->capabilities & HB_QSV_CAP_MSDK_API_1_6)
2178             {
2179                 param->videoParam->mfx.CodecLevel = FFMIN(MFX_LEVEL_AVC_52, level->value);
2180             }
2181             else
2182             {
2183                 // Media SDK API < 1.6, MFX_LEVEL_AVC_52 unsupported
2184                 param->videoParam->mfx.CodecLevel = FFMIN(MFX_LEVEL_AVC_51, level->value);
2185             }
2186         }
2187         else
2188         {
2189             param->videoParam->mfx.CodecLevel = level->value;
2190         }
2191     }
2192     return 0;
2193 }
2194 
hb_qsv_preset_get_names()2195 const char* const* hb_qsv_preset_get_names()
2196 {
2197     if (hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) >= QSV_G3)
2198     {
2199         return hb_qsv_preset_names2;
2200     }
2201     else
2202     {
2203         return hb_qsv_preset_names1;
2204     }
2205 }
2206 
hb_qsv_profile_get_names(int encoder)2207 const char* const* hb_qsv_profile_get_names(int encoder)
2208 {
2209     switch (encoder)
2210     {
2211         case HB_VCODEC_QSV_H264:
2212             return hb_h264_profile_names_8bit;
2213         case HB_VCODEC_QSV_H265_8BIT:
2214             return hb_h265_profile_names_8bit;
2215         case HB_VCODEC_QSV_H265_10BIT:
2216             return hb_h265_qsv_profile_names_10bit;
2217         default:
2218             return NULL;
2219     }
2220 }
2221 
hb_qsv_level_get_names(int encoder)2222 const char* const* hb_qsv_level_get_names(int encoder)
2223 {
2224     switch (encoder)
2225     {
2226         case HB_VCODEC_QSV_H264:
2227             return hb_h264_level_names;
2228         case HB_VCODEC_QSV_H265_10BIT:
2229         case HB_VCODEC_QSV_H265:
2230             return hb_h265_level_names;
2231         default:
2232             return NULL;
2233     }
2234 }
2235 
hb_qsv_get_pix_fmts(int encoder)2236 const int* hb_qsv_get_pix_fmts(int encoder)
2237 {
2238     switch (encoder)
2239     {
2240         case HB_VCODEC_QSV_H264:
2241         case HB_VCODEC_QSV_H265:
2242             return hb_qsv_pix_fmts;
2243         case HB_VCODEC_QSV_H265_10BIT:
2244             return hb_qsv_10bit_pix_fmts;
2245 
2246          default:
2247              return hb_qsv_pix_fmts;
2248      }
2249 }
2250 
hb_qsv_video_quality_get_name(uint32_t codec)2251 const char* hb_qsv_video_quality_get_name(uint32_t codec)
2252 {
2253     uint64_t caps = 0;
2254     hb_qsv_adapter_details_t* details = hb_qsv_get_adapters_details_by_index(hb_qsv_get_adapter_index());
2255     if (details)
2256     {
2257         switch (codec)
2258         {
2259             case HB_VCODEC_QSV_H264:
2260                 if (details->hb_qsv_info_avc != NULL) caps = details->hb_qsv_info_avc->capabilities;
2261                 break;
2262 
2263             case HB_VCODEC_QSV_H265_10BIT:
2264             case HB_VCODEC_QSV_H265:
2265                 if (details->hb_qsv_info_hevc != NULL) caps = details->hb_qsv_info_hevc->capabilities;
2266                 break;
2267 
2268             default:
2269                 break;
2270         }
2271     }
2272     return (caps & HB_QSV_CAP_RATECONTROL_ICQ) ? "ICQ" : "QP";
2273 }
2274 
hb_qsv_video_quality_get_limits(uint32_t codec,float * low,float * high,float * granularity,int * direction)2275 void hb_qsv_video_quality_get_limits(uint32_t codec, float *low, float *high,
2276                                      float *granularity, int *direction)
2277 {
2278     uint64_t caps = 0;
2279     hb_qsv_adapter_details_t* details = hb_qsv_get_adapters_details_by_index(hb_qsv_get_adapter_index());
2280     if (details)
2281     {
2282         switch (codec)
2283         {
2284             case HB_VCODEC_QSV_H265_10BIT:
2285             case HB_VCODEC_QSV_H265:
2286                 if (details->hb_qsv_info_hevc != NULL) caps = details->hb_qsv_info_hevc->capabilities;
2287                 *direction   = 1;
2288                 *granularity = 1.;
2289                 *low         = (caps & HB_QSV_CAP_RATECONTROL_ICQ) ? 1. : 0.;
2290                 *high        = 51.;
2291                 break;
2292 
2293             case HB_VCODEC_QSV_H264:
2294             default:
2295                 if (details->hb_qsv_info_avc != NULL) caps = details->hb_qsv_info_avc->capabilities;
2296                 *direction   = 1;
2297                 *granularity = 1.;
2298                 *low         = (caps & HB_QSV_CAP_RATECONTROL_ICQ) ? 1. : 0.;
2299                 *high        = 51.;
2300                 break;
2301         }
2302     }
2303 }
2304 
hb_qsv_param_default_preset(hb_qsv_param_t * param,mfxVideoParam * videoParam,hb_qsv_info_t * info,const char * preset)2305 int hb_qsv_param_default_preset(hb_qsv_param_t *param,
2306                                 mfxVideoParam *videoParam,
2307                                 hb_qsv_info_t *info, const char *preset)
2308 {
2309     if (param != NULL && videoParam != NULL && info != NULL)
2310     {
2311         int ret = hb_qsv_param_default(param, videoParam, info);
2312         if (ret)
2313         {
2314             return ret;
2315         }
2316     }
2317     else
2318     {
2319         hb_error("hb_qsv_param_default_preset: invalid pointer(s) param=%p videoParam=%p info=%p preset=%p", param, videoParam, info, preset);
2320         return -1;
2321     }
2322     if (preset != NULL && preset[0] != '\0')
2323     {
2324         if (!strcasecmp(preset, "quality"))
2325         {
2326             /*
2327              * HSW TargetUsage:     2
2328              *     NumRefFrame:     0
2329              *     GopRefDist:      4 (CQP), 3 (VBR)        -> -1 (set by encoder)
2330              *     GopPicSize:     32 (CQP), 1 second (VBR) -> -1 (set by encoder)
2331              *     BPyramid:        1 (CQP), 0 (VBR)        -> -1 (set by encoder)
2332              *     LookAhead:       1 (on)
2333              *     LookAheadDepth: 40
2334              *
2335              *
2336              * SNB
2337              * IVB Preset Not Available
2338              *
2339              * Note: this preset is the libhb default (like x264's "medium").
2340              */
2341         }
2342         else if (!strcasecmp(preset, "balanced"))
2343         {
2344             /*
2345              * HSW TargetUsage:     4
2346              *     NumRefFrame:     1
2347              *     GopRefDist:      4 (CQP), 3 (VBR)        -> -1 (set by encoder)
2348              *     GopPicSize:     32 (CQP), 1 second (VBR) -> -1 (set by encoder)
2349              *     BPyramid:        1 (CQP), 0 (VBR)        -> -1 (set by encoder)
2350              *     LookAhead:       0 (off)
2351              *     LookAheadDepth: Not Applicable
2352              */
2353             if (hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) >= QSV_G3)
2354             {
2355                 param->rc.lookahead                = 0;
2356                 param->videoParam->mfx.NumRefFrame = 1;
2357                 param->videoParam->mfx.TargetUsage = MFX_TARGETUSAGE_4;
2358             }
2359             else
2360             {
2361                 /*
2362                  * SNB
2363                  * IVB TargetUsage:     2
2364                  *     NumRefFrame:     0
2365                  *     GopRefDist:      4 (CQP), 3 (VBR)        -> -1 (set by encoder)
2366                  *     GopPicSize:     32 (CQP), 1 second (VBR) -> -1 (set by encoder)
2367                  *     BPyramid:       Not Applicable
2368                  *     LookAhead:      Not Applicable
2369                  *     LookAheadDepth: Not Applicable
2370                  *
2371                  * Note: this preset is not the libhb default,
2372                  * but the settings are the same so do nothing.
2373                  */
2374             }
2375         }
2376         else if (!strcasecmp(preset, "speed"))
2377         {
2378             if (hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) >= QSV_G7)
2379             {
2380                 // Since IceLake only
2381                 param->rc.lookahead                = 0;
2382                 param->videoParam->mfx.NumRefFrame = 1;
2383                 param->videoParam->mfx.TargetUsage = MFX_TARGETUSAGE_7;
2384             }
2385             else if (hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) >= QSV_G3)
2386             {
2387                 /*
2388                  * HSW TargetUsage:     6
2389                  *     NumRefFrame:     0 (CQP), 1 (VBR)        -> see note
2390                  *     GopRefDist:      4 (CQP), 3 (VBR)        -> -1 (set by encoder)
2391                  *     GopPicSize:     32 (CQP), 1 second (VBR) -> -1 (set by encoder)
2392                  *     BPyramid:        1 (CQP), 0 (VBR)        -> -1 (set by encoder)
2393                  *     LookAhead:       0 (off)
2394                  *     LookAheadDepth: Not Applicable
2395                  *
2396                  * Note: NumRefFrame depends on the RC method, which we don't
2397                  *       know here. Rather than have an additional variable and
2398                  *       having the encoder set it, we set it to 1 and let the
2399                  *       B-pyramid code sanitize it. Since BPyramid is 1 w/CQP,
2400                  *       the result (3) is the same as what MSDK would pick for
2401                  *       NumRefFrame 0 GopRefDist 4 GopPicSize 32.
2402                  */
2403                 param->rc.lookahead                = 0;
2404                 param->videoParam->mfx.NumRefFrame = 1;
2405                 param->videoParam->mfx.TargetUsage = MFX_TARGETUSAGE_6;
2406             }
2407             else
2408             {
2409                 /*
2410                  * SNB
2411                  * IVB TargetUsage:     4
2412                  *     NumRefFrame:     0
2413                  *     GopRefDist:      4 (CQP), 3 (VBR)        -> -1 (set by encoder)
2414                  *     GopPicSize:     32 (CQP), 1 second (VBR) -> -1 (set by encoder)
2415                  *     BPyramid:       Not Applicable
2416                  *     LookAhead:      Not Applicable
2417                  *     LookAheadDepth: Not Applicable
2418                  */
2419                 param->videoParam->mfx.TargetUsage = MFX_TARGETUSAGE_4;
2420             }
2421         }
2422         else
2423         {
2424             hb_error("hb_qsv_param_default_preset: invalid preset '%s'", preset);
2425             return -1;
2426         }
2427     }
2428     return 0;
2429 }
2430 
hb_qsv_param_default_async_depth()2431 int hb_qsv_param_default_async_depth()
2432 {
2433     return hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) >= QSV_G7 ? 6 : HB_QSV_ASYNC_DEPTH_DEFAULT;
2434 }
2435 
hb_qsv_param_default(hb_qsv_param_t * param,mfxVideoParam * videoParam,hb_qsv_info_t * info)2436 int hb_qsv_param_default(hb_qsv_param_t *param, mfxVideoParam *videoParam,
2437                          hb_qsv_info_t  *info)
2438 {
2439     if (param != NULL && videoParam != NULL && info != NULL)
2440     {
2441         // introduced in API 1.0
2442         memset(&param->codingOption, 0, sizeof(mfxExtCodingOption));
2443         param->codingOption.Header.BufferId      = MFX_EXTBUFF_CODING_OPTION;
2444         param->codingOption.Header.BufferSz      = sizeof(mfxExtCodingOption);
2445         param->codingOption.MECostType           = 0; // reserved, must be 0
2446         param->codingOption.MESearchType         = 0; // reserved, must be 0
2447         param->codingOption.MVSearchWindow.x     = 0; // reserved, must be 0
2448         param->codingOption.MVSearchWindow.y     = 0; // reserved, must be 0
2449         param->codingOption.RefPicListReordering = 0; // reserved, must be 0
2450         param->codingOption.IntraPredBlockSize   = 0; // reserved, must be 0
2451         param->codingOption.InterPredBlockSize   = 0; // reserved, must be 0
2452         param->codingOption.MVPrecision          = 0; // reserved, must be 0
2453         param->codingOption.EndOfSequence        = MFX_CODINGOPTION_UNKNOWN;
2454         param->codingOption.RateDistortionOpt    = MFX_CODINGOPTION_UNKNOWN;
2455         param->codingOption.ResetRefList         = MFX_CODINGOPTION_UNKNOWN;
2456         param->codingOption.MaxDecFrameBuffering = 0; // unspecified
2457         param->codingOption.AUDelimiter          = MFX_CODINGOPTION_OFF;
2458         param->codingOption.SingleSeiNalUnit     = MFX_CODINGOPTION_UNKNOWN;
2459         param->codingOption.PicTimingSEI         = MFX_CODINGOPTION_OFF;
2460         param->codingOption.VuiNalHrdParameters  = MFX_CODINGOPTION_UNKNOWN;
2461         param->codingOption.FramePicture         = MFX_CODINGOPTION_UNKNOWN;
2462         param->codingOption.CAVLC                = MFX_CODINGOPTION_OFF;
2463         // introduced in API 1.3
2464         param->codingOption.RefPicMarkRep        = MFX_CODINGOPTION_UNKNOWN;
2465         param->codingOption.FieldOutput          = MFX_CODINGOPTION_UNKNOWN;
2466         param->codingOption.NalHrdConformance    = MFX_CODINGOPTION_UNKNOWN;
2467         param->codingOption.SingleSeiNalUnit     = MFX_CODINGOPTION_UNKNOWN;
2468         param->codingOption.VuiVclHrdParameters  = MFX_CODINGOPTION_UNKNOWN;
2469         // introduced in API 1.4
2470         param->codingOption.ViewOutput           = MFX_CODINGOPTION_UNKNOWN;
2471         // introduced in API 1.6
2472         param->codingOption.RecoveryPointSEI     = MFX_CODINGOPTION_UNKNOWN;
2473 
2474         // introduced in API 1.3
2475         memset(&param->videoSignalInfo, 0, sizeof(mfxExtVideoSignalInfo));
2476         param->videoSignalInfo.Header.BufferId          = MFX_EXTBUFF_VIDEO_SIGNAL_INFO;
2477         param->videoSignalInfo.Header.BufferSz          = sizeof(mfxExtVideoSignalInfo);
2478         param->videoSignalInfo.VideoFormat              = 5; // undefined
2479         param->videoSignalInfo.VideoFullRange           = 0; // TV range
2480         param->videoSignalInfo.ColourDescriptionPresent = 0; // don't write to bitstream
2481         param->videoSignalInfo.ColourPrimaries          = 2; // undefined
2482         param->videoSignalInfo.TransferCharacteristics  = 2; // undefined
2483         param->videoSignalInfo.MatrixCoefficients       = 2; // undefined
2484 
2485         // introduced in API 1.6
2486         memset(&param->codingOption2, 0, sizeof(mfxExtCodingOption2));
2487         param->codingOption2.Header.BufferId = MFX_EXTBUFF_CODING_OPTION2;
2488         param->codingOption2.Header.BufferSz = sizeof(mfxExtCodingOption2);
2489         param->codingOption2.IntRefType      = 0;
2490         param->codingOption2.IntRefCycleSize = 2;
2491         param->codingOption2.IntRefQPDelta   = 0;
2492         param->codingOption2.MaxFrameSize    = 0;
2493         param->codingOption2.BitrateLimit    = MFX_CODINGOPTION_ON;
2494         param->codingOption2.MBBRC           = MFX_CODINGOPTION_ON;
2495         param->codingOption2.ExtBRC          = MFX_CODINGOPTION_OFF;
2496         // introduced in API 1.7
2497         param->codingOption2.LookAheadDepth  = 40;
2498         param->codingOption2.Trellis         = MFX_TRELLIS_OFF;
2499         // introduced in API 1.8
2500         param->codingOption2.RepeatPPS       = MFX_CODINGOPTION_ON;
2501         param->codingOption2.BRefType        = MFX_B_REF_UNKNOWN; // controlled via gop.b_pyramid
2502         param->codingOption2.AdaptiveI       = MFX_CODINGOPTION_OFF;
2503         param->codingOption2.AdaptiveB       = MFX_CODINGOPTION_OFF;
2504         param->codingOption2.LookAheadDS     = MFX_LOOKAHEAD_DS_OFF;
2505         param->codingOption2.NumMbPerSlice   = 0;
2506 
2507         // GOP & rate control
2508         param->gop.b_pyramid          = -1; // set automatically
2509         param->gop.gop_pic_size       = -1; // set automatically
2510         param->gop.gop_ref_dist       = -1; // set automatically
2511         param->gop.int_ref_cycle_size = -1; // set automatically
2512         param->rc.icq                 =  1; // enabled by default (if supported)
2513         param->rc.lookahead           =  1; // enabled by default (if supported)
2514         param->rc.cqp_offsets[0]      =  0;
2515         param->rc.cqp_offsets[1]      =  2;
2516         param->rc.cqp_offsets[2]      =  4;
2517         param->rc.vbv_max_bitrate     =  0; // set automatically
2518         param->rc.vbv_buffer_size     =  0; // set automatically
2519         param->rc.vbv_buffer_init     = .0; // set automatically
2520 
2521         // introduced in API 1.0
2522         memset(videoParam, 0, sizeof(mfxVideoParam));
2523         param->videoParam                   = videoParam;
2524         param->videoParam->Protected        = 0; // reserved, must be 0
2525         param->videoParam->NumExtParam      = 0;
2526         param->videoParam->IOPattern        = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
2527         param->videoParam->mfx.TargetUsage  = MFX_TARGETUSAGE_BALANCED;
2528         param->videoParam->mfx.GopOptFlag   = MFX_GOP_CLOSED;
2529         param->videoParam->mfx.NumThread    = 0; // deprecated, must be 0
2530         param->videoParam->mfx.EncodedOrder = 0; // input is in display order
2531         param->videoParam->mfx.IdrInterval  = 0; // all I-frames are IDR
2532         param->videoParam->mfx.NumSlice     = 0; // use Media SDK default
2533         param->videoParam->mfx.NumRefFrame  = 0; // use Media SDK default
2534         param->videoParam->mfx.GopPicSize   = 0; // use Media SDK default
2535         param->videoParam->mfx.GopRefDist   = 0; // use Media SDK default
2536         param->videoParam->mfx.LowPower     = MFX_CODINGOPTION_OFF; // use Media SDK default
2537         // introduced in API 1.1
2538         param->videoParam->AsyncDepth       = hb_qsv_param_default_async_depth();
2539         // introduced in API 1.3
2540         param->videoParam->mfx.BRCParamMultiplier = 0; // no multiplier
2541 
2542         // FrameInfo: set by video encoder, except PicStruct
2543         param->videoParam->mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
2544 
2545         // attach supported mfxExtBuffer structures to the mfxVideoParam
2546         param->videoParam->NumExtParam                                = 0;
2547         param->videoParam->ExtParam                                   = param->ExtParamArray;
2548         if (info->capabilities & HB_QSV_CAP_VUI_VSINFO)
2549         {
2550             param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)&param->videoSignalInfo;
2551         }
2552         if (info->capabilities & HB_QSV_CAP_OPTION1)
2553         {
2554             param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)&param->codingOption;
2555         }
2556         if (info->capabilities & HB_QSV_CAP_OPTION2)
2557         {
2558             param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)&param->codingOption2;
2559         }
2560         if (info->capabilities & HB_QSV_CAP_LOWPOWER_ENCODE)
2561         {
2562             param->videoParam->mfx.LowPower = MFX_CODINGOPTION_ON;
2563         }
2564     }
2565     else
2566     {
2567         hb_error("hb_qsv_param_default: invalid pointer(s)");
2568         return -1;
2569     }
2570     return 0;
2571 }
2572 
hb_triplet4value(hb_triplet_t * triplets,const int value)2573 hb_triplet_t* hb_triplet4value(hb_triplet_t *triplets, const int value)
2574 {
2575     for (int i = 0; triplets[i].name != NULL; i++)
2576     {
2577         if (triplets[i].value == value)
2578         {
2579             return &triplets[i];
2580         }
2581     }
2582     return NULL;
2583 }
2584 
hb_triplet4name(hb_triplet_t * triplets,const char * name)2585 hb_triplet_t* hb_triplet4name(hb_triplet_t *triplets, const char *name)
2586 {
2587     for (int i = 0; triplets[i].name != NULL; i++)
2588     {
2589         if (!strcasecmp(triplets[i].name, name))
2590         {
2591             return &triplets[i];
2592         }
2593     }
2594     return NULL;
2595 }
2596 
hb_triplet4key(hb_triplet_t * triplets,const char * key)2597 hb_triplet_t* hb_triplet4key(hb_triplet_t *triplets, const char *key)
2598 {
2599     for (int i = 0; triplets[i].name != NULL; i++)
2600     {
2601         if (!strcasecmp(triplets[i].key, key))
2602         {
2603             return &triplets[i];
2604         }
2605     }
2606     return NULL;
2607 }
2608 
hb_qsv_codec_name(uint32_t codec_id)2609 const char* hb_qsv_codec_name(uint32_t codec_id)
2610 {
2611     switch (codec_id)
2612     {
2613         case MFX_CODEC_AVC:
2614             return "H.264/AVC";
2615 
2616         case MFX_CODEC_HEVC:
2617             return "H.265/HEVC";
2618 
2619         default:
2620             return NULL;
2621     }
2622 }
2623 
hb_qsv_profile_name(uint32_t codec_id,uint16_t profile_id)2624 const char* hb_qsv_profile_name(uint32_t codec_id, uint16_t profile_id)
2625 {
2626     hb_triplet_t *profile = NULL;
2627     switch (codec_id)
2628     {
2629         case MFX_CODEC_AVC:
2630             profile = hb_triplet4value(hb_qsv_h264_profiles, profile_id);
2631             break;
2632 
2633         case MFX_CODEC_HEVC:
2634             profile = hb_triplet4value(hb_qsv_h265_profiles, profile_id);
2635             break;
2636 
2637         default:
2638             break;
2639     }
2640     return profile != NULL ? profile->name : NULL;
2641 }
2642 
hb_qsv_level_name(uint32_t codec_id,uint16_t level_id)2643 const char* hb_qsv_level_name(uint32_t codec_id, uint16_t level_id)
2644 {
2645     hb_triplet_t *level = NULL;
2646     switch (codec_id)
2647     {
2648         case MFX_CODEC_AVC:
2649             level = hb_triplet4value(hb_qsv_h264_levels, level_id);
2650             break;
2651 
2652         case MFX_CODEC_HEVC:
2653             level = hb_triplet4value(hb_qsv_h265_levels, level_id);
2654             break;
2655 
2656         default:
2657             break;
2658     }
2659     return level != NULL ? level->name : NULL;
2660 }
2661 
hb_qsv_frametype_name(uint16_t qsv_frametype)2662 const char* hb_qsv_frametype_name(uint16_t qsv_frametype)
2663 {
2664     if      (qsv_frametype & MFX_FRAMETYPE_IDR)
2665     {
2666         return qsv_frametype & MFX_FRAMETYPE_REF ? "IDR (ref)" : "IDR";
2667     }
2668     else if (qsv_frametype & MFX_FRAMETYPE_I)
2669     {
2670         return qsv_frametype & MFX_FRAMETYPE_REF ? "I (ref)"   : "I";
2671     }
2672     else if (qsv_frametype & MFX_FRAMETYPE_P)
2673     {
2674         return qsv_frametype & MFX_FRAMETYPE_REF ? "P (ref)"   : "P";
2675     }
2676     else if (qsv_frametype & MFX_FRAMETYPE_B)
2677     {
2678         return qsv_frametype & MFX_FRAMETYPE_REF ? "B (ref)"   : "B";
2679     }
2680     else
2681     {
2682         return "unknown";
2683     }
2684 }
2685 
hb_qsv_frametype_xlat(uint16_t qsv_frametype,uint16_t * out_flags)2686 uint8_t hb_qsv_frametype_xlat(uint16_t qsv_frametype, uint16_t *out_flags)
2687 {
2688     uint16_t flags     = 0;
2689     uint8_t  frametype = 0;
2690 
2691     if (qsv_frametype & MFX_FRAMETYPE_IDR)
2692     {
2693         flags |= HB_FLAG_FRAMETYPE_KEY;
2694         frametype = HB_FRAME_IDR;
2695     }
2696     else if (qsv_frametype & MFX_FRAMETYPE_I)
2697     {
2698         frametype = HB_FRAME_I;
2699     }
2700     else if (qsv_frametype & MFX_FRAMETYPE_P)
2701     {
2702         frametype = HB_FRAME_P;
2703     }
2704     else if (qsv_frametype & MFX_FRAMETYPE_B)
2705     {
2706         frametype = HB_FRAME_B;
2707     }
2708 
2709     if (qsv_frametype & MFX_FRAMETYPE_REF)
2710     {
2711         flags |= HB_FLAG_FRAMETYPE_REF;
2712     }
2713 
2714     if (out_flags != NULL)
2715     {
2716        *out_flags = flags;
2717     }
2718     return frametype;
2719 }
2720 
hb_qsv_impl_get_name(int impl)2721 const char* hb_qsv_impl_get_name(int impl)
2722 {
2723     switch (MFX_IMPL_BASETYPE(impl))
2724     {
2725         case MFX_IMPL_SOFTWARE:
2726             return "software";
2727 
2728         case MFX_IMPL_HARDWARE:
2729             return "hardware (1)";
2730         case MFX_IMPL_HARDWARE2:
2731             return "hardware (2)";
2732         case MFX_IMPL_HARDWARE3:
2733             return "hardware (3)";
2734         case MFX_IMPL_HARDWARE4:
2735             return "hardware (4)";
2736         case MFX_IMPL_HARDWARE_ANY:
2737             return "hardware (any)";
2738 
2739         case MFX_IMPL_AUTO:
2740             return "automatic";
2741         case MFX_IMPL_AUTO_ANY:
2742             return "automatic (any)";
2743 
2744         default:
2745             return NULL;
2746     }
2747 }
2748 
hb_qsv_impl_get_via_name(int impl)2749 const char* hb_qsv_impl_get_via_name(int impl)
2750 {
2751     if      ((impl & 0xF00) == MFX_IMPL_VIA_VAAPI)
2752         return "via VAAPI";
2753     else if ((impl & 0xF00) == MFX_IMPL_VIA_D3D11)
2754         return "via D3D11";
2755     else if ((impl & 0xF00) == MFX_IMPL_VIA_D3D9)
2756         return "via D3D9";
2757     else if ((impl & 0xF00) == MFX_IMPL_VIA_ANY)
2758         return "via ANY";
2759     else return NULL;
2760 }
2761 
hb_qsv_force_workarounds()2762 void hb_qsv_force_workarounds()
2763 {
2764 #define FORCE_WORKAROUNDS ~(HB_QSV_CAP_OPTION2_BREFTYPE)
2765     hb_qsv_adapter_details_t* details = hb_qsv_get_adapters_details_by_index(hb_qsv_get_adapter_index());
2766     if (details)
2767     {
2768         details->qsv_software_info_avc.capabilities  &= FORCE_WORKAROUNDS;
2769         details->qsv_hardware_info_avc.capabilities  &= FORCE_WORKAROUNDS;
2770         details->qsv_software_info_hevc.capabilities &= FORCE_WORKAROUNDS;
2771         details->qsv_hardware_info_hevc.capabilities &= FORCE_WORKAROUNDS;
2772     }
2773 #undef FORCE_WORKAROUNDS
2774 }
2775 
2776 #if defined(_WIN32) || defined(__MINGW32__)
2777 // Direct X
2778 #define COBJMACROS
2779 #include <d3d11.h>
2780 #include <dxgi1_2.h>
2781 #include <d3d9.h>
2782 #include <dxva2api.h>
2783 
2784 #if HAVE_DXGIDEBUG_H
2785 #include <dxgidebug.h>
2786 #endif
2787 
2788 typedef IDirect3D9* WINAPI pDirect3DCreate9(UINT);
2789 typedef HRESULT WINAPI pDirect3DCreate9Ex(UINT, IDirect3D9Ex **);
2790 typedef HRESULT(WINAPI *HB_PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory);
2791 
hb_qsv_info_init()2792 int hb_qsv_info_init()
2793 {
2794     // Collect the information about qsv adapters
2795     g_qsv_adapters_info.Adapters = NULL;
2796     g_qsv_adapters_info.NumAlloc = 0;
2797     g_qsv_adapters_info.NumActual = 0;
2798     int err = hb_qsv_query_adapters(&g_qsv_adapters_info);
2799     if (err)
2800     {
2801         hb_error("hb_qsv_info_init: failed to query qsv adapters");
2802         return -1;
2803     }
2804     hb_qsv_make_adapters_list(&g_qsv_adapters_info, &g_qsv_adapters_list);
2805     hb_qsv_make_adapters_details_list(&g_qsv_adapters_info, &g_qsv_adapters_details_list);
2806     hb_qsv_collect_adapters_details(g_qsv_adapters_list, g_qsv_adapters_details_list);
2807     return 0;
2808 }
2809 
hb_qsv_set_adapter_index(int adapter_index)2810 int hb_qsv_set_adapter_index(int adapter_index)
2811 {
2812     if (g_adapter_index == adapter_index)
2813         return 0;
2814 
2815     for (int i = 0; i < g_qsv_adapters_info.NumActual; i++)
2816     {
2817         mfxAdapterInfo* info = &g_qsv_adapters_info.Adapters[i];
2818         if (info && (info->Number == adapter_index))
2819         {
2820             g_adapter_index = adapter_index;
2821             return 0;
2822         }
2823     }
2824     hb_error("hb_qsv_set_adapter_index: incorrect qsv device index %d", adapter_index);
2825     return -1;
2826 }
2827 
qsv_map_mfx_platform_codename(int mfx_platform_codename)2828 int qsv_map_mfx_platform_codename(int mfx_platform_codename)
2829 {
2830     int platform = HB_CPU_PLATFORM_UNSPECIFIED;
2831 
2832     switch (mfx_platform_codename)
2833     {
2834     case MFX_PLATFORM_SANDYBRIDGE:
2835         platform = HB_CPU_PLATFORM_INTEL_SNB;
2836         break;
2837     case MFX_PLATFORM_IVYBRIDGE:
2838         platform = HB_CPU_PLATFORM_INTEL_IVB;
2839         break;
2840     case MFX_PLATFORM_HASWELL:
2841         platform = HB_CPU_PLATFORM_INTEL_HSW;
2842         break;
2843     case MFX_PLATFORM_BAYTRAIL:
2844     case MFX_PLATFORM_BROADWELL:
2845         platform = HB_CPU_PLATFORM_INTEL_BDW;
2846         break;
2847     case MFX_PLATFORM_CHERRYTRAIL:
2848         platform = HB_CPU_PLATFORM_INTEL_CHT;
2849         break;
2850     case MFX_PLATFORM_SKYLAKE:
2851         platform = HB_CPU_PLATFORM_INTEL_SKL;
2852         break;
2853     case MFX_PLATFORM_APOLLOLAKE:
2854     case MFX_PLATFORM_KABYLAKE:
2855         platform = HB_CPU_PLATFORM_INTEL_KBL;
2856         break;
2857 #if (MFX_VERSION >= 1025)
2858     case MFX_PLATFORM_GEMINILAKE:
2859     case MFX_PLATFORM_COFFEELAKE:
2860     case MFX_PLATFORM_CANNONLAKE:
2861         platform = HB_CPU_PLATFORM_INTEL_KBL;
2862         break;
2863 #endif
2864 #if (MFX_VERSION >= 1027)
2865     case MFX_PLATFORM_ICELAKE:
2866         platform = HB_CPU_PLATFORM_INTEL_ICL;
2867         break;
2868 #endif
2869 #if (MFX_VERSION >= 1031)
2870     case MFX_PLATFORM_ELKHARTLAKE:
2871     case MFX_PLATFORM_JASPERLAKE:
2872     case MFX_PLATFORM_TIGERLAKE:
2873     case MFX_PLATFORM_ROCKETLAKE:
2874     case MFX_PLATFORM_ALDERLAKE_S:
2875         platform = HB_CPU_PLATFORM_INTEL_TGL;
2876         break;
2877 #endif
2878     default:
2879         platform = HB_CPU_PLATFORM_UNSPECIFIED;
2880     }
2881     return platform;
2882 }
2883 
hb_qsv_free_adapters_details()2884 static void hb_qsv_free_adapters_details()
2885 {
2886     for (int i = 0; i < hb_list_count(g_qsv_adapters_details_list); i++)
2887     {
2888         hb_qsv_adapter_details_t *details = hb_list_item(g_qsv_adapters_details_list, i);
2889         if (details->index)
2890         {
2891             av_free(details);
2892         }
2893     }
2894 }
2895 
hb_qsv_get_adapter_type(const mfxAdapterInfo * info)2896 static const char* hb_qsv_get_adapter_type(const mfxAdapterInfo* info)
2897 {
2898     if (info)
2899     {
2900         return (info->Platform.MediaAdapterType == MFX_MEDIA_INTEGRATED) ? "integrated" :
2901         (info->Platform.MediaAdapterType == MFX_MEDIA_DISCRETE) ? "discrete" : "unknown";
2902     }
2903     return NULL;
2904 }
2905 
hb_qsv_get_platform(int adapter_index)2906 int hb_qsv_get_platform(int adapter_index)
2907 {
2908     for (int i = 0; i < g_qsv_adapters_info.NumActual; i++)
2909     {
2910         mfxAdapterInfo* info = &g_qsv_adapters_info.Adapters[i];
2911         // find DirectX adapter with given index in list of QSV adapters
2912         // if -1 use first adapter with highest priority
2913         if (info && ((info->Number == adapter_index) || (adapter_index == -1)))
2914         {
2915             return qsv_map_mfx_platform_codename(info->Platform.CodeName);
2916         }
2917     }
2918     return HB_CPU_PLATFORM_UNSPECIFIED;
2919 }
2920 
hb_qsv_param_parse_dx_index(hb_job_t * job,const int dx_index)2921 int hb_qsv_param_parse_dx_index(hb_job_t *job, const int dx_index)
2922 {
2923     for (int i = 0; i < g_qsv_adapters_info.NumActual; i++)
2924     {
2925         mfxAdapterInfo* info = &g_qsv_adapters_info.Adapters[i];
2926         // find DirectX adapter with given index in list of QSV adapters
2927         // if -1 use first adapter with highest priority
2928         if (info && ((info->Number == dx_index) || (dx_index == -1)))
2929         {
2930             if (job->qsv.ctx && !job->qsv.ctx->qsv_device)
2931             {
2932                 job->qsv.ctx->qsv_device = av_mallocz_array(32, sizeof(*job->qsv.ctx->qsv_device));
2933                 if (!job->qsv.ctx->qsv_device)
2934                 {
2935                     hb_error("hb_qsv_param_parse_dx_index: failed to allocate memory for qsv device");
2936                     return -1;
2937                 }
2938             }
2939             sprintf(job->qsv.ctx->qsv_device, "%u", info->Number);
2940             job->qsv.ctx->dx_index = info->Number;
2941             hb_log("qsv: %s qsv adapter with index %s has been selected", hb_qsv_get_adapter_type(info), job->qsv.ctx->qsv_device);
2942             hb_qsv_set_adapter_index(info->Number);
2943             return 0;
2944         }
2945     }
2946     hb_error("qsv: hb_qsv_param_parse_dx_index incorrect qsv device index %d", dx_index);
2947     return -1;
2948 }
2949 
hb_dxva2_device_create9(HMODULE d3dlib,UINT adapter,IDirect3D9 ** d3d9_out)2950 static int hb_dxva2_device_create9(HMODULE d3dlib, UINT adapter, IDirect3D9 **d3d9_out)
2951 {
2952     pDirect3DCreate9 *createD3D = (pDirect3DCreate9 *)hb_dlsym(d3dlib, "Direct3DCreate9");
2953     if (!createD3D) {
2954         hb_error("hb_dxva2_device_create9: failed to locate Direct3DCreate9");
2955         return -1;
2956     }
2957 
2958     IDirect3D9 *d3d9 = createD3D(D3D_SDK_VERSION);
2959     if (!d3d9) {
2960         hb_error("hb_dxva2_device_create9: createD3D failed");
2961         return -1;
2962     }
2963     *d3d9_out = d3d9;
2964     return 0;
2965 }
2966 
hb_dxva2_device_create9ex(HMODULE d3dlib,UINT adapter,IDirect3D9 ** d3d9_out)2967 static int hb_dxva2_device_create9ex(HMODULE d3dlib, UINT adapter, IDirect3D9 **d3d9_out)
2968 {
2969     IDirect3D9Ex *d3d9ex = NULL;
2970     HRESULT hr;
2971     pDirect3DCreate9Ex *createD3DEx = (pDirect3DCreate9Ex *)hb_dlsym(d3dlib, "Direct3DCreate9Ex");
2972     if (!createD3DEx)
2973     {
2974         hb_error("hb_dxva2_device_create9ex: failed to locate Direct3DCreate9Ex");
2975         return -1;
2976     }
2977 
2978     hr = createD3DEx(D3D_SDK_VERSION, &d3d9ex);
2979     if (FAILED(hr))
2980     {
2981         hb_error("hb_dxva2_device_create9ex: createD3DEx failed %d", hr);
2982         return -1;
2983     }
2984     *d3d9_out = (IDirect3D9 *)d3d9ex;
2985     return 0;
2986 }
2987 
hb_d3d11va_device_create(int adapter_id,ID3D11Device ** d3d11_out)2988 static int hb_d3d11va_device_create(int adapter_id, ID3D11Device** d3d11_out)
2989 {
2990     HANDLE d3dlib, dxgilib;
2991 
2992     d3dlib  = hb_dlopen("d3d11.dll");
2993     dxgilib = hb_dlopen("dxgi.dll");
2994     if (!d3dlib || !dxgilib)
2995     {
2996         hb_error("hb_d3d11va_device_check: failed to load d3d11.dll and dxgi.dll");
2997         return -1;
2998     }
2999 
3000     PFN_D3D11_CREATE_DEVICE mD3D11CreateDevice;
3001     HB_PFN_CREATE_DXGI_FACTORY mCreateDXGIFactory;
3002     mD3D11CreateDevice = (PFN_D3D11_CREATE_DEVICE)hb_dlsym(d3dlib, "D3D11CreateDevice");
3003     mCreateDXGIFactory = (HB_PFN_CREATE_DXGI_FACTORY)hb_dlsym(dxgilib, "CreateDXGIFactory1");
3004 
3005     if (!mD3D11CreateDevice || !mCreateDXGIFactory) {
3006         hb_error("hb_d3d11va_device_check: failed to locate D3D11CreateDevice and CreateDXGIFactory1 functions");
3007         return -1;
3008     }
3009 
3010     HRESULT hr;
3011     IDXGIAdapter *pAdapter = NULL;
3012     IDXGIFactory2 *pDXGIFactory;
3013     hr = mCreateDXGIFactory(&IID_IDXGIFactory2, (void **)&pDXGIFactory);
3014     if (FAILED(hr)) {
3015         hb_error("hb_d3d11va_create_device: mCreateDXGIFactory returned %d", hr);
3016         return -1;
3017     }
3018 
3019     if (adapter_id == -1)
3020     {
3021         adapter_id = 0;
3022     }
3023 
3024     while (IDXGIFactory2_EnumAdapters(pDXGIFactory, adapter_id++, &pAdapter) != DXGI_ERROR_NOT_FOUND)
3025     {
3026         ID3D11Device* pd3dDevice = NULL;
3027         DXGI_ADAPTER_DESC adapterDesc;
3028 
3029         hr = IDXGIAdapter2_GetDesc(pAdapter, &adapterDesc);
3030         if (SUCCEEDED(hr)) {
3031             if (adapterDesc.VendorId == 0x8086) {
3032                 hr = mD3D11CreateDevice(pAdapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, D3D11_CREATE_DEVICE_VIDEO_SUPPORT, NULL, 0, D3D11_SDK_VERSION, &pd3dDevice, NULL, NULL);
3033                 if (SUCCEEDED(hr)) {
3034                     IDXGIFactory2_Release(pDXGIFactory);
3035                     *d3d11_out = (ID3D11Device *)pd3dDevice;
3036                     return adapter_id - 1;
3037                 } else {
3038                     hb_error("hb_d3d11va_device_check: D3D11CreateDevice returned %d", hr);
3039                 }
3040             }
3041         } else {
3042             hb_error("hb_d3d11va_device_check: IDXGIAdapter2_GetDesc returned %d", hr);
3043         }
3044 
3045         if (pAdapter)
3046             IDXGIAdapter_Release(pAdapter);
3047     }
3048 
3049     IDXGIFactory2_Release(pDXGIFactory);
3050     return -1;
3051 }
3052 
hb_d3d11va_device_check()3053 static int hb_d3d11va_device_check()
3054 {
3055     ID3D11Device* d3d11 = NULL;
3056     return hb_d3d11va_device_create(-1, &d3d11);
3057 }
3058 
hb_dxva2_device_check()3059 static int hb_dxva2_device_check()
3060 {
3061     HRESULT hr;
3062     HMODULE d3dlib = NULL;
3063     IDirect3D9 *d3d9 = NULL;
3064     D3DADAPTER_IDENTIFIER9 identifier;
3065     D3DADAPTER_IDENTIFIER9 *d3dai = &identifier;
3066     UINT adapter = D3DADAPTER_DEFAULT;
3067 
3068     d3dlib = hb_dlopen("d3d9.dll");
3069     if (!d3dlib)
3070     {
3071         hb_error("hb_dxva2_device_check: failed to load d3d9 library");
3072         return -1;
3073     }
3074 
3075     if (hb_dxva2_device_create9ex(d3dlib, adapter, &d3d9) < 0)
3076     {
3077         // Retry with "classic" d3d9
3078         hr = hb_dxva2_device_create9(d3dlib, adapter, &d3d9);
3079         if (hr < 0)
3080         {
3081             hr = -1;
3082             goto clean_up;
3083         }
3084     }
3085 
3086     hr = IDirect3D9_GetAdapterIdentifier(d3d9, D3DADAPTER_DEFAULT, 0, d3dai);
3087     if (FAILED(hr))
3088     {
3089         hb_error("hb_dxva2_device_check: IDirect3D9_GetAdapterIdentifier failed");
3090         hr = -1;
3091         goto clean_up;
3092     }
3093 
3094     unsigned intel_id = 0x8086;
3095     if(d3dai)
3096     {
3097         if(d3dai->VendorId != intel_id)
3098         {
3099             hb_error("hb_dxva2_device_check: adapter that was found does not support QSV. It is required for zero-copy QSV path");
3100             hr = -1;
3101             goto clean_up;
3102         }
3103     }
3104     hr = 0;
3105 
3106 clean_up:
3107     if (d3d9)
3108         IDirect3D9_Release(d3d9);
3109 
3110     if (d3dlib)
3111         hb_dlclose(d3dlib);
3112 
3113     return hr;
3114 }
3115 
lock_device(IDirect3DDeviceManager9 * pDeviceManager,BOOL fBlock,IDirect3DDevice9 ** ppDevice,HANDLE * pHandle)3116 static HRESULT lock_device(
3117     IDirect3DDeviceManager9 *pDeviceManager,
3118     BOOL fBlock,
3119     IDirect3DDevice9 **ppDevice, // Receives a pointer to the device.
3120     HANDLE *pHandle              // Receives a device handle.
3121     )
3122 {
3123     *pHandle = NULL;
3124     *ppDevice = NULL;
3125 
3126     HANDLE hDevice = 0;
3127 
3128     HRESULT hr = pDeviceManager->lpVtbl->OpenDeviceHandle(pDeviceManager, &hDevice);
3129 
3130     if (SUCCEEDED(hr))
3131     {
3132         hr = pDeviceManager->lpVtbl->LockDevice(pDeviceManager, hDevice, ppDevice, fBlock);
3133     }
3134 
3135     if (hr == DXVA2_E_NEW_VIDEO_DEVICE)
3136     {
3137         // Invalid device handle. Try to open a new device handle.
3138         hr = pDeviceManager->lpVtbl->CloseDeviceHandle(pDeviceManager, hDevice);
3139 
3140         if (SUCCEEDED(hr))
3141         {
3142             hr = pDeviceManager->lpVtbl->OpenDeviceHandle(pDeviceManager, &hDevice);
3143         }
3144 
3145         // Try to lock the device again.
3146         if (SUCCEEDED(hr))
3147         {
3148             hr = pDeviceManager->lpVtbl->LockDevice(pDeviceManager, hDevice, ppDevice, TRUE);
3149         }
3150     }
3151 
3152     if (SUCCEEDED(hr))
3153     {
3154         *pHandle = hDevice;
3155     }
3156     return hr;
3157 }
3158 
unlock_device(IDirect3DDeviceManager9 * pDeviceManager,HANDLE handle)3159 static HRESULT unlock_device(
3160     IDirect3DDeviceManager9 *pDeviceManager,
3161     HANDLE handle              // Receives a device handle.
3162     )
3163 {
3164     HRESULT hr = pDeviceManager->lpVtbl->UnlockDevice(pDeviceManager, handle, 0);
3165     if (SUCCEEDED(hr))
3166     {
3167         hr = pDeviceManager->lpVtbl->CloseDeviceHandle(pDeviceManager, handle);
3168     }
3169     return hr;
3170 }
3171 
hb_qsv_find_surface_idx(const QSVMid * mids,const int nb_mids,const QSVMid * mid)3172 static int hb_qsv_find_surface_idx(const QSVMid *mids, const int nb_mids, const QSVMid *mid)
3173 {
3174     if (mids)
3175     {
3176         int i;
3177         for (i = 0; i < nb_mids; i++) {
3178             const QSVMid *m = &mids[i];
3179             if ((m->handle_pair->first == mid->handle_pair->first) &&
3180                 (m->handle_pair->second == mid->handle_pair->second))
3181                 return i;
3182         }
3183     }
3184     return -1;
3185 }
3186 
hb_qsv_replace_surface_mid(HBQSVFramesContext * hb_enc_qsv_frames_ctx,const QSVMid * mid,mfxFrameSurface1 * surface)3187 int hb_qsv_replace_surface_mid(HBQSVFramesContext* hb_enc_qsv_frames_ctx, const QSVMid *mid, mfxFrameSurface1 *surface)
3188 {
3189     if (!hb_enc_qsv_frames_ctx || !surface)
3190         return -1;
3191 
3192     int ret = hb_qsv_find_surface_idx(hb_enc_qsv_frames_ctx->mids, hb_enc_qsv_frames_ctx->nb_mids, mid);
3193     if (ret < 0)
3194     {
3195         hb_error("hb_qsv_replace_surface_mid: Surface with MemId=%p has not been found in the pool", mid);
3196         return -1;
3197     }
3198     else
3199     {
3200         surface->Data.MemId = &hb_enc_qsv_frames_ctx->mids[ret];
3201     }
3202     return 0;
3203 }
3204 
hb_qsv_release_surface_from_pool_by_surface_pointer(HBQSVFramesContext * hb_enc_qsv_frames_ctx,const mfxFrameSurface1 * surface)3205 int hb_qsv_release_surface_from_pool_by_surface_pointer(HBQSVFramesContext* hb_enc_qsv_frames_ctx, const mfxFrameSurface1 *surface)
3206 {
3207     if (!hb_enc_qsv_frames_ctx || !surface)
3208         return -1;
3209 
3210     AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hb_enc_qsv_frames_ctx->hw_frames_ctx->data;
3211     AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
3212 
3213     for(int i = 0; i < hb_enc_qsv_frames_ctx->nb_mids; i++)
3214     {
3215         mfxFrameSurface1 *pool_surface = &frames_hwctx->surfaces[i];
3216         if(surface == pool_surface)
3217         {
3218             ff_qsv_atomic_dec(&hb_enc_qsv_frames_ctx->pool[i]);
3219             return 0;
3220         }
3221     }
3222     return -1;
3223 }
3224 
hb_qsv_get_mid_by_surface_from_pool(HBQSVFramesContext * hb_enc_qsv_frames_ctx,mfxFrameSurface1 * surface,QSVMid ** out_mid)3225 int hb_qsv_get_mid_by_surface_from_pool(HBQSVFramesContext* hb_enc_qsv_frames_ctx, mfxFrameSurface1 *surface, QSVMid **out_mid)
3226 {
3227     if (!hb_enc_qsv_frames_ctx || !surface)
3228         return -1;
3229 
3230     QSVMid *mid = NULL;
3231 
3232     AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hb_enc_qsv_frames_ctx->hw_frames_ctx->data;
3233     AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
3234     // find the first available surface in the pool
3235     int count = 0;
3236     while(1)
3237     {
3238         if(count > 30)
3239         {
3240             hb_error("hb_qsv_get_mid_by_surface_from_pool has not been found or busy", mid);
3241             hb_qsv_sleep(10); // prevent hang when all surfaces all used
3242             count = 0;
3243         }
3244 
3245         for(int i = 0; i < hb_enc_qsv_frames_ctx->nb_mids; i++)
3246         {
3247             mid = &hb_enc_qsv_frames_ctx->mids[i];
3248             mfxFrameSurface1 *pool_surface = &frames_hwctx->surfaces[i];
3249             if( (pool_surface->Data.Locked == 0) && (surface == pool_surface))
3250             {
3251                 *out_mid = mid;
3252                 return 0;
3253             }
3254         }
3255         count++;
3256     }
3257 }
3258 
hb_qsv_get_free_surface_from_pool(HBQSVFramesContext * hb_enc_qsv_frames_ctx,AVFrame * frame,QSVMid ** out_mid)3259 int hb_qsv_get_free_surface_from_pool(HBQSVFramesContext* hb_enc_qsv_frames_ctx, AVFrame* frame, QSVMid** out_mid)
3260 {
3261     if (!hb_enc_qsv_frames_ctx || !frame)
3262         return -1;
3263 
3264     AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hb_enc_qsv_frames_ctx->hw_frames_ctx->data;
3265     AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
3266 
3267     // find the first available surface in the pool
3268     int count = 0;
3269     while(1)
3270     {
3271         if(count > 30)
3272         {
3273             hb_qsv_sleep(10); // prevent hang when all surfaces all used
3274             count = 0;
3275         }
3276 
3277         int ret = av_hwframe_get_buffer(hb_enc_qsv_frames_ctx->hw_frames_ctx, frame, 0);
3278         if (ret)
3279         {
3280             return -1;
3281         }
3282         else
3283         {
3284             mfxFrameSurface1 *output_surface = (mfxFrameSurface1 *)frame->data[3];
3285             for(int i = 0; i < hb_enc_qsv_frames_ctx->nb_mids; i++)
3286             {
3287                 QSVMid* mid = &hb_enc_qsv_frames_ctx->mids[i];
3288                 mfxFrameSurface1* cur_surface = &frames_hwctx->surfaces[i];
3289                 if(cur_surface == output_surface)
3290                 {
3291                     if((hb_enc_qsv_frames_ctx->pool[i] == 0) && (output_surface->Data.Locked == 0))
3292                     {
3293                         *out_mid = mid;
3294                         ff_qsv_atomic_inc(&hb_enc_qsv_frames_ctx->pool[i]);
3295                         return 0;
3296                     }
3297                     else
3298                     {
3299                         // we need to do unref if surface is not taken to be used, otherwise -12.
3300                         av_frame_unref(frame);
3301                         break;
3302                     }
3303                 }
3304             }
3305         }
3306         count++;
3307     }
3308 }
3309 
hb_qsv_allocate_dx11_encoder_pool(HBQSVFramesContext * frames_ctx,ID3D11Device * device,ID3D11Texture2D * input_texture)3310 static int hb_qsv_allocate_dx11_encoder_pool(HBQSVFramesContext* frames_ctx, ID3D11Device *device, ID3D11Texture2D* input_texture)
3311 {
3312     D3D11_TEXTURE2D_DESC desc = { 0 };
3313     ID3D11Texture2D_GetDesc(input_texture, &desc);
3314     desc.ArraySize = 1;
3315     desc.BindFlags = D3D11_BIND_RENDER_TARGET;
3316 
3317     for (size_t i = 0; i < frames_ctx->nb_mids; i++)
3318     {
3319         ID3D11Texture2D* texture;
3320         HRESULT hr = ID3D11Device_CreateTexture2D(device, &desc, NULL, &texture);
3321         if (hr != S_OK)
3322         {
3323             hb_error("hb_qsv_allocate_dx11_encoder_pool: ID3D11Device_CreateTexture2D error");
3324             return -1;
3325         }
3326 
3327         QSVMid *mid = &frames_ctx->mids[i];
3328         mid->handle_pair->first = texture;
3329         mid->handle_pair->second = 0;
3330     }
3331     return 0;
3332 }
3333 
hb_qsv_get_dx_device(hb_job_t * job)3334 static int hb_qsv_get_dx_device(hb_job_t *job)
3335 {
3336     AVHWDeviceContext    *device_ctx = (AVHWDeviceContext*)job->qsv.ctx->hb_hw_device_ctx->data;
3337     AVQSVDeviceContext *device_hwctx = device_ctx->hwctx;
3338     mfxSession        parent_session = device_hwctx->session;
3339 
3340     if (job->qsv.ctx->device_manager_handle == NULL)
3341     {
3342         mfxIMPL device_impl;
3343         int err = MFXQueryIMPL(parent_session, &device_impl);
3344         if (err != MFX_ERR_NONE)
3345         {
3346             hb_error("hb_qsv_get_dx_device: no impl could be retrieved");
3347             return -1;
3348         }
3349 
3350         if (MFX_IMPL_VIA_D3D11 == MFX_IMPL_VIA_MASK(device_impl))
3351         {
3352             job->qsv.ctx->device_manager_handle_type = MFX_HANDLE_D3D11_DEVICE;
3353         }
3354         else if (MFX_IMPL_VIA_D3D9 == MFX_IMPL_VIA_MASK(device_impl))
3355         {
3356             job->qsv.ctx->device_manager_handle_type = MFX_HANDLE_D3D9_DEVICE_MANAGER;
3357         }
3358         else
3359         {
3360             hb_error("hb_qsv_get_dx_device: unsupported impl");
3361             return -1;
3362         }
3363 
3364         err = MFXVideoCORE_GetHandle(parent_session, job->qsv.ctx->device_manager_handle_type, &job->qsv.ctx->device_manager_handle);
3365         if (err != MFX_ERR_NONE)
3366         {
3367             hb_error("hb_qsv_get_dx_device: no supported hw handle could be retrieved "
3368                 "from the session\n");
3369             return -1;
3370         }
3371         if (job->qsv.ctx->device_manager_handle_type == MFX_HANDLE_D3D11_DEVICE)
3372         {
3373             ID3D11Device *device = (ID3D11Device *)job->qsv.ctx->device_manager_handle;
3374             ID3D11Texture2D* input_texture = job->qsv.ctx->hb_dec_qsv_frames_ctx->input_texture;
3375             err = hb_qsv_allocate_dx11_encoder_pool(job->qsv.ctx->hb_dec_qsv_frames_ctx, device, input_texture);
3376             if (err < 0)
3377             {
3378                 hb_error("hb_qsv_get_dx_device: hb_qsv_allocate_dx11_encoder_pool failed");
3379                 return -1;
3380             }
3381             if (job->qsv.ctx->device_context == NULL)
3382             {
3383                 ID3D11Device_GetImmediateContext(device, (ID3D11DeviceContext *)&job->qsv.ctx->device_context);
3384                 if (!job->qsv.ctx->device_context)
3385                     return -1;
3386             }
3387         }
3388     }
3389     return 0;
3390 }
3391 
hb_qsv_make_adapters_list(const mfxAdaptersInfo * adapters_info,hb_list_t ** qsv_adapters_list)3392 static int hb_qsv_make_adapters_list(const mfxAdaptersInfo* adapters_info, hb_list_t **qsv_adapters_list)
3393 {
3394     int max_generation = QSV_G0;
3395     int default_adapter = 0;
3396 
3397     if (!qsv_adapters_list)
3398     {
3399         hb_error("hb_qsv_make_adapters_list: destination pointer is NULL");
3400         return -1;
3401     }
3402     if (*qsv_adapters_list)
3403     {
3404         hb_error("hb_qsv_make_adapters_list: qsv_adapters_list is allocated already");
3405         return -1;
3406     }
3407     hb_list_t *list = hb_list_init();
3408     if (list == NULL)
3409     {
3410         hb_error("hb_qsv_make_adapters_list: hb_list_init() failed");
3411         return -1;
3412     }
3413     for (int i = 0; i < adapters_info->NumActual; i++)
3414     {
3415         mfxAdapterInfo* info = &adapters_info->Adapters[i];
3416         if (info)
3417         {
3418             int generation = hb_qsv_hardware_generation(qsv_map_mfx_platform_codename(info->Platform.CodeName));
3419             // select default QSV adapter
3420             if (generation > max_generation || info->Platform.MediaAdapterType == MFX_MEDIA_DISCRETE)
3421             {
3422                 max_generation = generation;
3423                 default_adapter = info->Number;
3424             }
3425             hb_list_add(list, (void*)&info->Number);
3426         }
3427     }
3428     hb_qsv_set_default_adapter_index(default_adapter);
3429     hb_qsv_set_adapter_index(default_adapter);
3430     *qsv_adapters_list = list;
3431     return 0;
3432 }
3433 
hb_qsv_make_adapters_details_list(const mfxAdaptersInfo * adapters_info,hb_list_t ** hb_qsv_adapters_details_list)3434 static int hb_qsv_make_adapters_details_list(const mfxAdaptersInfo* adapters_info, hb_list_t **hb_qsv_adapters_details_list)
3435 {
3436     if (*hb_qsv_adapters_details_list)
3437     {
3438         hb_error("hb_qsv_make_adapters_details_list: hb_qsv_adapter_details_list is allocated already");
3439         return -1;
3440     }
3441     hb_list_t *list = hb_list_init();
3442     if (list == NULL)
3443     {
3444         hb_error("hb_qsv_make_adapters_details_list: hb_list_init() failed");
3445         return -1;
3446     }
3447     for (int i = 0; i < adapters_info->NumActual; i++)
3448     {
3449         mfxAdapterInfo* info = &adapters_info->Adapters[i];
3450         if (info)
3451         {
3452             hb_qsv_adapter_details_t* adapter_details = av_mallocz(sizeof(hb_qsv_adapter_details_t));
3453             if (!adapter_details)
3454             {
3455                 hb_error("hb_qsv_make_adapters_details_list: adapter_details allocation failed");
3456                 return -1;
3457             }
3458             init_adapter_details(adapter_details);
3459             hb_list_add(list, (void*)adapter_details);
3460         }
3461     }
3462     *hb_qsv_adapters_details_list = list;
3463     return 0;
3464 }
3465 
hb_qsv_query_adapters(mfxAdaptersInfo * adapters_info)3466 static int hb_qsv_query_adapters(mfxAdaptersInfo* adapters_info)
3467 {
3468     // Get number of Intel graphics adapters
3469     mfxU32 num_adapters_available = 0;
3470     mfxStatus sts = MFXQueryAdaptersNumber(&num_adapters_available);
3471     if (sts != MFX_ERR_NONE)
3472     {
3473         hb_error("hb_qsv_query_adapters: failed to get number of Intel graphics adapters %d", sts);
3474         return -1;
3475     }
3476 
3477     if (num_adapters_available > 0)
3478     {
3479         adapters_info->Adapters = av_mallocz_array(num_adapters_available, sizeof(*adapters_info->Adapters));
3480         if (adapters_info->Adapters)
3481         {
3482             adapters_info->NumActual = 0;
3483             adapters_info->NumAlloc = num_adapters_available;
3484             // Collect information about Intel graphics adapters
3485             sts = MFXQueryAdapters(NULL, adapters_info);
3486             if (sts != MFX_ERR_NONE)
3487             {
3488                 hb_error("hb_qsv_query_adapters: failed to collect information about Intel graphics adapters %d", sts);
3489                 return -1;
3490             }
3491         }
3492     }
3493     return 0;
3494 }
3495 
hb_qsv_get_free_surface_from_pool_with_range(HBQSVFramesContext * hb_enc_qsv_frames_ctx,const int start_index,const int end_index,QSVMid ** out_mid,mfxFrameSurface1 ** out_surface)3496 void hb_qsv_get_free_surface_from_pool_with_range(HBQSVFramesContext* hb_enc_qsv_frames_ctx, const int start_index, const int end_index, QSVMid** out_mid, mfxFrameSurface1** out_surface)
3497 {
3498     AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hb_enc_qsv_frames_ctx->hw_frames_ctx->data;
3499     AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
3500 
3501     // find the first available surface in the pool
3502     int count = 0;
3503     while(1)
3504     {
3505         if (count > 30)
3506         {
3507             hb_qsv_sleep(10); // prevent hang when all surfaces all used
3508             count = 0;
3509         }
3510 
3511         for (int i = start_index; i < end_index; i++)
3512         {
3513             if ((hb_enc_qsv_frames_ctx->pool[i] == 0) && (frames_hwctx->surfaces[i].Data.Locked == 0))
3514             {
3515                 *out_mid = &hb_enc_qsv_frames_ctx->mids[i];
3516                 *out_surface = &frames_hwctx->surfaces[i];
3517                 ff_qsv_atomic_inc(&hb_enc_qsv_frames_ctx->pool[i]);
3518                 return;
3519             }
3520         }
3521         count++;
3522     }
3523 }
3524 
hb_qsv_create_dx11_texture_with_bytes(ID3D11Device * device,const byte * bytes,int stride,int width,int height,DXGI_FORMAT texture_format)3525 static ID3D11Texture2D* hb_qsv_create_dx11_texture_with_bytes(ID3D11Device* device, const byte* bytes, int stride, int width, int height, DXGI_FORMAT texture_format)
3526 {
3527     if (device == NULL)
3528     {
3529         hb_error("hb_qsv_create_dx11_texture_with_bytes: device is NULL");
3530         return NULL;
3531     }
3532 
3533     ID3D11Texture2D* tex;
3534     D3D11_TEXTURE2D_DESC tdesc;
3535     D3D11_SUBRESOURCE_DATA tbsd;
3536     HRESULT hr;
3537 
3538     tbsd.pSysMem = (void *)bytes;
3539     tbsd.SysMemPitch = stride;
3540 
3541     tdesc.Width = width;
3542     tdesc.Height = height;
3543     tdesc.MipLevels = 1;
3544     tdesc.ArraySize = 1;
3545     tdesc.SampleDesc.Count = 1;
3546     tdesc.SampleDesc.Quality = 0;
3547     tdesc.Usage = D3D11_USAGE_DEFAULT;
3548     tdesc.Format = texture_format;
3549     tdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
3550     tdesc.CPUAccessFlags = 0;
3551     tdesc.MiscFlags = 0;
3552 
3553     hr = ID3D11Device_CreateTexture2D(device, &tdesc, &tbsd, &tex);
3554     if (FAILED(hr))
3555     {
3556         hb_error("CreateTexture: ID3D11Device_CreateTexture2D failed", hr);
3557         return NULL;
3558     }
3559     return tex;
3560 }
3561 
hb_qsv_copy_surface(hb_qsv_context * ctx,void * output_surface,int output_index,void * input_surface,int input_index)3562 static int hb_qsv_copy_surface(hb_qsv_context *ctx, void* output_surface, int output_index, void* input_surface, int input_index)
3563 {
3564     if(!ctx)
3565     {
3566         hb_error("hb_qsv_copy_surface: qsv context is NULL");
3567         return -1;
3568     }
3569 
3570     if (ctx->device_manager_handle_type == MFX_HANDLE_D3D9_DEVICE_MANAGER)
3571     {
3572         IDirect3DDevice9 *pDevice = NULL;
3573         HANDLE handle;
3574 
3575         HRESULT result = lock_device((IDirect3DDeviceManager9 *)ctx->device_manager_handle, 1, &pDevice, &handle);
3576         if (FAILED(result))
3577         {
3578             hb_error("hb_qsv_copy_surface: lock_device failed %d", result);
3579             return -1;
3580         }
3581         result = IDirect3DDevice9_StretchRect(pDevice, input_surface, 0, output_surface, 0, D3DTEXF_LINEAR);
3582         if (FAILED(result))
3583         {
3584             hb_error("hb_qsv_copy_surface: IDirect3DDevice9_StretchRect failed %d", result);
3585             return -1;
3586         }
3587         result = unlock_device((IDirect3DDeviceManager9 *)ctx->device_manager_handle, handle);
3588         if (FAILED(result))
3589         {
3590             hb_error("hb_qsv_copy_surface: unlock_device failed %d", result);
3591             return -1;
3592         }
3593     }
3594     else if (ctx->device_manager_handle_type == MFX_HANDLE_D3D11_DEVICE)
3595     {
3596         ID3D11DeviceContext_CopySubresourceRegion((ID3D11DeviceContext *)ctx->device_context, output_surface, output_index, 0, 0, 0, input_surface, input_index, NULL);
3597         ID3D11DeviceContext_Flush((ID3D11DeviceContext *)ctx->device_context);
3598     }
3599     else
3600     {
3601         hb_error("hb_qsv_copy_surface: incorrect device type %d", ctx->device_manager_handle_type);
3602         return -1;
3603     }
3604     return 0;
3605 }
3606 
hb_qsv_attach_surface_to_video_buffer(hb_job_t * job,hb_buffer_t * buf,int is_vpp)3607 int hb_qsv_attach_surface_to_video_buffer(hb_job_t *job, hb_buffer_t* buf, int is_vpp)
3608 {
3609     QSVMid *mid = NULL;
3610     mfxFrameSurface1 *surface = NULL;
3611     HBQSVFramesContext *hb_qsv_frames_ctx = NULL;
3612 
3613     if (is_vpp)
3614     {
3615         hb_qsv_frames_ctx = job->qsv.ctx->hb_vpp_qsv_frames_ctx;
3616     }
3617     else
3618     {
3619         hb_qsv_frames_ctx = job->qsv.ctx->hb_dec_qsv_frames_ctx;
3620     }
3621 
3622     if (job->qsv.ctx->device_manager_handle_type == MFX_HANDLE_D3D11_DEVICE)
3623     {
3624         DXGI_FORMAT texture_format;
3625         ID3D11Texture2D* output_surface;
3626         D3D11_TEXTURE2D_DESC desc = { 0 };
3627         if (job->input_pix_fmt == AV_PIX_FMT_NV12)
3628         {
3629             texture_format = DXGI_FORMAT_NV12;
3630         }
3631         else if(job->input_pix_fmt == AV_PIX_FMT_P010)
3632         {
3633             texture_format = DXGI_FORMAT_P010;
3634         }
3635         else
3636         {
3637             hb_error("hb_qsv_attach_surface_to_video_buffer: unsupported texture_format=%d", job->input_pix_fmt);
3638             return -1;
3639         }
3640         hb_qsv_get_free_surface_from_pool_with_range(hb_qsv_frames_ctx, 0, HB_QSV_POOL_SURFACE_SIZE, &mid, &surface);
3641         output_surface = mid->handle_pair->first;
3642         ID3D11Texture2D_GetDesc(output_surface, &desc);
3643         ID3D11Texture2D* blank_surface = hb_qsv_create_dx11_texture_with_bytes(job->qsv.ctx->device_manager_handle, buf->data, buf->plane[0].stride, desc.Width, desc.Height, texture_format);
3644         if (!blank_surface)
3645         {
3646             hb_error("hb_qsv_attach_surface_to_video_buffer: hb_qsv_create_dx11_texture_with_bytes() failed");
3647             return -1;
3648         }
3649         mfxHDLPair* output_pair = (mfxHDLPair*)surface->Data.MemId;
3650         int output_index = (int)(intptr_t)output_pair->second == MFX_INFINITE ? 0 : (int)(intptr_t)output_pair->second;
3651         int ret = hb_qsv_copy_surface(job->qsv.ctx, output_surface, output_index, blank_surface, 0);
3652         if (ret < 0)
3653         {
3654             hb_error("hb_qsv_attach_surface_to_video_buffer: hb_qsv_copy_surface() failed");
3655             return -1;
3656         }
3657         ID3D11Texture2D_Release(blank_surface);
3658     }
3659 
3660     // alloc new frame
3661     buf->qsv_details.frame = av_frame_alloc();
3662     if (!buf->qsv_details.frame) {
3663         hb_error("hb_qsv_attach_surface_to_video_buffer: av_frame_alloc() failed");
3664         return -1;
3665     }
3666 
3667     buf->qsv_details.frame->data[3] = (uint8_t*)surface;
3668     buf->qsv_details.qsv_frames_ctx = hb_qsv_frames_ctx;
3669     buf->qsv_details.qsv_atom       = 0;
3670     buf->qsv_details.ctx            = job->qsv.ctx;
3671     return 0;
3672 }
3673 
hb_qsv_copy_video_buffer_to_video_buffer(hb_job_t * job,hb_buffer_t * in,hb_buffer_t * out,int is_vpp)3674 int hb_qsv_copy_video_buffer_to_video_buffer(hb_job_t *job, hb_buffer_t* in, hb_buffer_t* out, int is_vpp)
3675 {
3676     // alloc new frame
3677     out->qsv_details.frame = av_frame_alloc();
3678     if (!out->qsv_details.frame)
3679     {
3680         hb_error("hb_qsv_copy_video_buffer_to_video_buffer: av_frame_alloc() failed");
3681         return -1;
3682     }
3683 
3684     if (!in->qsv_details.frame)
3685     {
3686         hb_error("hb_qsv_copy_video_buffer_to_video_buffer: in->qsv_details.frame is NULL");
3687         return -1;
3688     }
3689 
3690     mfxFrameSurface1* input_surface = (mfxFrameSurface1*)in->qsv_details.frame->data[3];
3691     mfxHDLPair* input_pair = (mfxHDLPair*)input_surface->Data.MemId;
3692 
3693     out->qsv_details.frame->format         = in->qsv_details.frame->format;
3694     out->qsv_details.frame->width          = in->qsv_details.frame->width;
3695     out->qsv_details.frame->height         = in->qsv_details.frame->height;
3696     out->qsv_details.frame->channels       = in->qsv_details.frame->channels;
3697     out->qsv_details.frame->channel_layout = in->qsv_details.frame->channel_layout;
3698     out->qsv_details.frame->nb_samples     = in->qsv_details.frame->nb_samples;
3699 
3700     int ret = av_frame_copy_props(out->qsv_details.frame, in->qsv_details.frame);
3701     if (ret < 0)
3702     {
3703         hb_error("hb_qsv_copy_video_buffer_to_video_buffer: av_frame_copy_props error %d", ret);
3704         return -1;
3705     }
3706 
3707     QSVMid *mid = NULL;
3708     mfxFrameSurface1 *surface = NULL;
3709     HBQSVFramesContext *hb_qsv_frames_ctx = NULL;
3710 
3711     if (is_vpp)
3712     {
3713         hb_qsv_frames_ctx = job->qsv.ctx->hb_vpp_qsv_frames_ctx;
3714     }
3715     else
3716     {
3717         hb_qsv_frames_ctx = job->qsv.ctx->hb_dec_qsv_frames_ctx;
3718     }
3719 
3720     if (job->qsv.ctx->device_manager_handle_type == MFX_HANDLE_D3D11_DEVICE)
3721     {
3722         hb_qsv_get_free_surface_from_pool_with_range(hb_qsv_frames_ctx, 0, HB_QSV_POOL_SURFACE_SIZE, &mid, &surface);
3723         mfxHDLPair* output_pair = (mfxHDLPair*)surface->Data.MemId;
3724         int input_index = (int)(intptr_t)input_pair->second == MFX_INFINITE ? 0 : (int)(intptr_t)input_pair->second;
3725         int output_index = (int)(intptr_t)output_pair->second == MFX_INFINITE ? 0 : (int)(intptr_t)output_pair->second;
3726         int ret = hb_qsv_copy_surface(job->qsv.ctx, mid->handle_pair->first, output_index, input_pair->first, input_index);
3727         if (ret < 0)
3728         {
3729             hb_error("hb_qsv_copy_video_buffer_to_video_buffer: hb_qsv_copy_surface() failed");
3730             return -1;
3731         }
3732     }
3733     else
3734     {
3735         hb_error("hb_qsv_copy_video_buffer_to_video_buffer: device_manager_handle_type unsupported=%d", job->qsv.ctx->device_manager_handle_type);
3736     }
3737 
3738     out->qsv_details.frame->data[3] = (uint8_t*)surface;
3739     out->qsv_details.qsv_frames_ctx = hb_qsv_frames_ctx;
3740     out->qsv_details.qsv_atom       = 0;
3741     out->qsv_details.ctx            = job->qsv.ctx;
3742     return 0;
3743 }
3744 
hb_qsv_copy_avframe_to_video_buffer(hb_job_t * job,AVFrame * frame,const int is_vpp)3745 hb_buffer_t* hb_qsv_copy_avframe_to_video_buffer(hb_job_t *job, AVFrame *frame, const int is_vpp)
3746 {
3747     hb_buffer_t *out;
3748     out = hb_frame_buffer_init(frame->format, frame->width, frame->height);
3749     hb_avframe_set_video_buffer_flags(out, frame, (AVRational){1,1});
3750 
3751     // alloc new frame
3752     out->qsv_details.frame = av_frame_alloc();
3753     if (!out->qsv_details.frame) {
3754         return out;
3755     }
3756 
3757     out->qsv_details.frame->format         = frame->format;
3758     out->qsv_details.frame->width          = frame->width;
3759     out->qsv_details.frame->height         = frame->height;
3760     out->qsv_details.frame->channels       = frame->channels;
3761     out->qsv_details.frame->channel_layout = frame->channel_layout;
3762     out->qsv_details.frame->nb_samples     = frame->nb_samples;
3763 
3764     int ret = av_frame_copy_props(out->qsv_details.frame, frame);
3765     if (ret < 0)
3766     {
3767         hb_error("hb_qsv_copy_avframe_to_video_buffer: av_frame_copy_props error %d", ret);
3768     }
3769 
3770     QSVMid *mid = NULL;
3771     mfxFrameSurface1* output_surface = NULL;
3772     HBQSVFramesContext* hb_qsv_frames_ctx = NULL;
3773 
3774     if (is_vpp)
3775     {
3776         hb_qsv_frames_ctx = job->qsv.ctx->hb_vpp_qsv_frames_ctx;
3777     }
3778     else
3779     {
3780         hb_qsv_frames_ctx = job->qsv.ctx->hb_dec_qsv_frames_ctx;
3781     }
3782 
3783     if (!is_vpp && hb_qsv_hw_filters_are_enabled(job))
3784     {
3785         ret = hb_qsv_get_free_surface_from_pool(hb_qsv_frames_ctx, out->qsv_details.frame, &mid);
3786         if (ret < 0)
3787             return out;
3788         output_surface = (mfxFrameSurface1*)out->qsv_details.frame->data[3];
3789     }
3790     else
3791     {
3792         hb_qsv_get_free_surface_from_pool_with_range(hb_qsv_frames_ctx, 0, HB_QSV_POOL_SURFACE_SIZE, &mid, &output_surface);
3793     }
3794 
3795     if (job->qsv.ctx->device_manager_handle_type == MFX_HANDLE_D3D9_DEVICE_MANAGER)
3796     {
3797         mfxFrameSurface1* input_surface = (mfxFrameSurface1*)frame->data[3];
3798         mfxHDLPair* input_pair = (mfxHDLPair*)input_surface->Data.MemId;
3799         // copy all surface fields
3800         *output_surface = *input_surface;
3801         output_surface->Info.CropW = frame->width;
3802         output_surface->Info.CropH = frame->height;
3803         if (hb_qsv_hw_filters_are_enabled(job))
3804         {
3805             output_surface->Data.MemId = mid->handle_pair;
3806         }
3807         else
3808         {
3809             // replace the mem id to mem id from the pool
3810             output_surface->Data.MemId = mid;
3811         }
3812         // copy input surface to surface from the pool
3813         ret = hb_qsv_copy_surface(job->qsv.ctx, mid->handle_pair->first, 0, input_pair->first, 0);
3814         if (ret < 0)
3815         {
3816             hb_error("hb_qsv_copy_avframe_to_video_buffer: hb_qsv_copy_surface() failed");
3817             return -1;
3818         }
3819     }
3820     else if (job->qsv.ctx->device_manager_handle_type == MFX_HANDLE_D3D11_DEVICE)
3821     {
3822         mfxFrameSurface1* input_surface = (mfxFrameSurface1*)frame->data[3];
3823         mfxHDLPair* input_pair = (mfxHDLPair*)input_surface->Data.MemId;
3824         // Need to pass 0 instead of MFX_INFINITE to DirectX as index of surface
3825         int input_index = (int)(intptr_t)input_pair->second == MFX_INFINITE ? 0 : (int)(intptr_t)input_pair->second;
3826         int output_index = (int)(intptr_t)mid->handle_pair->second == MFX_INFINITE ? 0 : (int)(intptr_t)mid->handle_pair->second;
3827         // copy all surface fields
3828         *output_surface = *input_surface;
3829         output_surface->Info.CropW = frame->width;
3830         output_surface->Info.CropH = frame->height;
3831         if (hb_qsv_hw_filters_are_enabled(job))
3832         {
3833             // Make sure that we pass handle_pair to scale_qsv
3834             output_surface->Data.MemId = mid->handle_pair;
3835         }
3836         else
3837         {
3838             // Make sure that we pass QSVMid to QSV encoder
3839             output_surface->Data.MemId = mid;
3840         }
3841         // copy input surface to surface from the pool
3842         ret = hb_qsv_copy_surface(job->qsv.ctx, mid->handle_pair->first, output_index, input_pair->first, input_index);
3843         if (ret < 0)
3844         {
3845             hb_error("hb_qsv_copy_avframe_to_video_buffer: hb_qsv_copy_surface() failed");
3846             return -1;
3847         }
3848     }
3849     else
3850     {
3851         hb_error("hb_qsv_copy_avframe_to_video_buffer: incorrect mfx impl");
3852         return out;
3853     }
3854     out->qsv_details.frame->data[3] = (uint8_t*)output_surface;
3855     out->qsv_details.qsv_frames_ctx = hb_qsv_frames_ctx;
3856     out->qsv_details.qsv_atom       = 0;
3857     out->qsv_details.ctx            = job->qsv.ctx;
3858     return out;
3859 }
3860 
qsv_get_buffer(AVCodecContext * s,AVFrame * frame,int flags)3861 static int qsv_get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
3862 {
3863     int ret = -1;
3864     if(s->hw_frames_ctx)
3865     {
3866         ret = av_hwframe_get_buffer(s->hw_frames_ctx, frame, 0);
3867     }
3868     return ret;
3869 }
3870 
hb_qsv_uninit_dec(AVCodecContext * s)3871 void hb_qsv_uninit_dec(AVCodecContext *s)
3872 {
3873     if(s && s->hw_frames_ctx)
3874         av_buffer_unref(&s->hw_frames_ctx);
3875 }
3876 
hb_qsv_uninit_enc(hb_job_t * job)3877 void hb_qsv_uninit_enc(hb_job_t *job)
3878 {
3879     if(job->qsv.ctx && job->qsv.ctx->hb_dec_qsv_frames_ctx)
3880     {
3881         av_buffer_unref(&job->qsv.ctx->hb_dec_qsv_frames_ctx->hw_frames_ctx);
3882         job->qsv.ctx->hb_dec_qsv_frames_ctx->hw_frames_ctx = NULL;
3883         av_free(job->qsv.ctx->hb_dec_qsv_frames_ctx);
3884         job->qsv.ctx->hb_dec_qsv_frames_ctx = NULL;
3885     }
3886     if(job->qsv.ctx && job->qsv.ctx->hb_vpp_qsv_frames_ctx)
3887     {
3888         av_buffer_unref(&job->qsv.ctx->hb_vpp_qsv_frames_ctx->hw_frames_ctx);
3889         job->qsv.ctx->hb_vpp_qsv_frames_ctx->hw_frames_ctx = NULL;
3890         av_free(job->qsv.ctx->hb_vpp_qsv_frames_ctx);
3891         job->qsv.ctx->hb_vpp_qsv_frames_ctx = NULL;
3892     }
3893     if (job->qsv.ctx->device_context)
3894     {
3895         ID3D11DeviceContext_Release((ID3D11DeviceContext *)job->qsv.ctx->device_context);
3896         job->qsv.ctx->device_context = NULL;
3897     }
3898     if (job->qsv.ctx)
3899     {
3900         job->qsv.ctx->hb_hw_device_ctx = NULL;
3901         if (job->qsv.ctx->qsv_device)
3902         {
3903             av_free(job->qsv.ctx->qsv_device);
3904             job->qsv.ctx->qsv_device = NULL;
3905         }
3906     }
3907     job->qsv.ctx->device_manager_handle = NULL;
3908 }
3909 
qsv_device_init(hb_job_t * job)3910 static int qsv_device_init(hb_job_t *job)
3911 {
3912     int err;
3913     AVDictionary *dict = NULL;
3914 
3915     if (job->qsv.ctx && job->qsv.ctx->qsv_device)
3916     {
3917         err = av_dict_set(&dict, "child_device", job->qsv.ctx->qsv_device, 0);
3918         if (err < 0)
3919             return err;
3920     }
3921     else
3922     {
3923         av_dict_set(&dict, "vendor", "0x8086", 0);
3924     }
3925     av_dict_set(&dict, "child_device_type", "d3d11va", 0);
3926 
3927     err = av_hwdevice_ctx_create(&job->qsv.ctx->hb_hw_device_ctx, AV_HWDEVICE_TYPE_QSV,
3928                                  0, dict, 0);
3929     if (err < 0) {
3930         hb_error("qsv_device_init: error creating a QSV device %d", err);
3931         goto err_out;
3932     }
3933 
3934 err_out:
3935     if (dict)
3936         av_dict_free(&dict);
3937 
3938     return err;
3939 }
3940 
hb_qsv_parse_adapter_index(hb_job_t * job)3941 int hb_qsv_parse_adapter_index(hb_job_t *job)
3942 {
3943     int ret = 0;
3944 
3945     if (job->encoder_options != NULL && *job->encoder_options)
3946     {
3947         hb_dict_t *options_list;
3948         options_list = hb_encopts_to_dict(job->encoder_options, job->vcodec);
3949         hb_dict_iter_t iter;
3950         for (iter  = hb_dict_iter_init(options_list);
3951             iter != HB_DICT_ITER_DONE;
3952             iter  = hb_dict_iter_next(options_list, iter))
3953         {
3954             const char *key = hb_dict_iter_key(iter);
3955             if (!strcasecmp(key, "gpu"))
3956             {
3957                 hb_value_t *value = hb_dict_iter_value(iter);
3958                 char *str = hb_value_get_string_xform(value);
3959                 int dx_index = hb_qsv_atoi(str, &ret);
3960                 free(str);
3961                 if (!ret)
3962                 {
3963                     hb_qsv_param_parse_dx_index(job, dx_index);
3964                 }
3965             }
3966         }
3967         hb_dict_free(&options_list);
3968     }
3969     return 0;
3970 }
3971 
hb_create_ffmpeg_pool(hb_job_t * job,int coded_width,int coded_height,enum AVPixelFormat sw_pix_fmt,int pool_size,int extra_hw_frames,AVBufferRef ** out_hw_frames_ctx)3972 int hb_create_ffmpeg_pool(hb_job_t *job, int coded_width, int coded_height, enum AVPixelFormat sw_pix_fmt, int pool_size, int extra_hw_frames, AVBufferRef **out_hw_frames_ctx)
3973 {
3974     AVHWFramesContext *frames_ctx;
3975     AVQSVFramesContext *frames_hwctx;
3976 
3977     AVBufferRef *hw_frames_ctx = *out_hw_frames_ctx;
3978 
3979     int ret = 0;
3980 
3981     if (job->qsv.ctx && !job->qsv.ctx->hb_hw_device_ctx) {
3982         // parse and use user-specified encoder options for decoder, if present
3983         if (job->encoder_options != NULL && *job->encoder_options)
3984         {
3985             hb_dict_t *options_list;
3986             options_list = hb_encopts_to_dict(job->encoder_options, job->vcodec);
3987 
3988             hb_dict_iter_t iter;
3989             for (iter  = hb_dict_iter_init(options_list);
3990                 iter != HB_DICT_ITER_DONE;
3991                 iter  = hb_dict_iter_next(options_list, iter))
3992             {
3993                 const char *key = hb_dict_iter_key(iter);
3994                 if ((!strcasecmp(key, "scalingmode") || !strcasecmp(key, "vpp-sm")) && hb_qsv_hw_filters_are_enabled(job))
3995                 {
3996                     hb_qsv_info_t *info = hb_qsv_encoder_info_get(hb_qsv_get_adapter_index(), job->vcodec);
3997                     if (info && (info->capabilities & HB_QSV_CAP_VPP_SCALING))
3998                     {
3999                         hb_value_t *value = hb_dict_iter_value(iter);
4000                         char *mode_key = hb_value_get_string_xform(value);
4001                         hb_triplet_t *mode = NULL;
4002                         if (mode_key != NULL)
4003                         {
4004                             mode = hb_triplet4key(hb_qsv_vpp_scale_modes, mode_key);
4005                         }
4006                         if (mode != NULL)
4007                         {
4008                             job->qsv.ctx->vpp_scale_mode = mode->key;
4009                         }
4010                     }
4011                 }
4012                 if ((!strcasecmp(key, "interpolationmethod") || !strcasecmp(key, "vpp-im")) && hb_qsv_hw_filters_are_enabled(job))
4013                 {
4014                     hb_qsv_info_t *info = hb_qsv_encoder_info_get(hb_qsv_get_adapter_index(), job->vcodec);
4015                     if (info && (info->capabilities & HB_QSV_CAP_VPP_INTERPOLATION))
4016                     {
4017                         hb_value_t *value = hb_dict_iter_value(iter);
4018                         char *mode_key = hb_value_get_string_xform(value);
4019                         hb_triplet_t *mode = NULL;
4020                         if (mode_key != NULL)
4021                         {
4022                             mode = hb_triplet4key(hb_qsv_vpp_interpolation_methods, mode_key);
4023                         }
4024                         if (mode != NULL)
4025                         {
4026                             job->qsv.ctx->vpp_interpolation_method = mode->key;
4027                         }
4028                     }
4029                 }
4030             }
4031             hb_dict_free(&options_list);
4032         }
4033 
4034         if (!job->qsv.ctx->qsv_device)
4035             hb_qsv_param_parse_dx_index(job, hb_qsv_get_adapter_index());
4036 
4037         ret = qsv_device_init(job);
4038         if (ret < 0)
4039             return ret;
4040     }
4041 
4042     av_buffer_unref(&hw_frames_ctx);
4043     hw_frames_ctx = av_hwframe_ctx_alloc(job->qsv.ctx->hb_hw_device_ctx);
4044     if (!hw_frames_ctx)
4045         return AVERROR(ENOMEM);
4046 
4047     *out_hw_frames_ctx = hw_frames_ctx;
4048 
4049     frames_ctx   = (AVHWFramesContext*)hw_frames_ctx->data;
4050     frames_hwctx = frames_ctx->hwctx;
4051 
4052     frames_ctx->width             = FFALIGN(coded_width,  32);
4053     frames_ctx->height            = FFALIGN(coded_height, 32);
4054     frames_ctx->format            = AV_PIX_FMT_QSV;
4055     frames_ctx->sw_format         = sw_pix_fmt;
4056     frames_ctx->initial_pool_size = pool_size;
4057     if (extra_hw_frames >= 0)
4058         frames_ctx->initial_pool_size += extra_hw_frames;
4059     frames_hwctx->frame_type      = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET;
4060 
4061     ret = av_hwframe_ctx_init(hw_frames_ctx);
4062     if (ret < 0) {
4063         hb_error("hb_create_ffmpeg_pool: av_hwframe_ctx_init failed %d", ret);
4064         return ret;
4065     }
4066     return 0;
4067 }
4068 
hb_qsv_hw_frames_init(AVCodecContext * s)4069 int hb_qsv_hw_frames_init(AVCodecContext *s)
4070 {
4071     AVHWFramesContext *frames_ctx;
4072     AVQSVFramesContext *frames_hwctx;
4073     AVBufferRef *hw_frames_ctx;
4074     int ret;
4075 
4076     hb_job_t *job = s->opaque;
4077     if (!job) {
4078         hb_error("hb_qsv_hw_frames_init: job is NULL");
4079         return -1;
4080     }
4081 
4082     HBQSVFramesContext *hb_dec_qsv_frames_ctx = job->qsv.ctx->hb_dec_qsv_frames_ctx;
4083     int                           coded_width = s->coded_width;
4084     int                          coded_height = s->coded_height;
4085     enum AVPixelFormat             sw_pix_fmt = s->sw_pix_fmt;
4086     int                       extra_hw_frames = s->extra_hw_frames;
4087     AVBufferRef           **out_hw_frames_ctx = &s->hw_frames_ctx;
4088 
4089     ret = hb_create_ffmpeg_pool(job, coded_width, coded_height, sw_pix_fmt, HB_QSV_POOL_FFMPEG_SURFACE_SIZE, extra_hw_frames, out_hw_frames_ctx);
4090     if (ret < 0) {
4091         hb_error("hb_qsv_hw_frames_init: hb_create_ffmpeg_pool decoder failed %d", ret);
4092         return ret;
4093     }
4094 
4095     hw_frames_ctx = *out_hw_frames_ctx;
4096     frames_ctx   = (AVHWFramesContext*)hw_frames_ctx->data;
4097     frames_hwctx = frames_ctx->hwctx;
4098     mfxHDLPair* handle_pair = (mfxHDLPair*)frames_hwctx->surfaces[0].Data.MemId;
4099     hb_dec_qsv_frames_ctx->input_texture = ((size_t)handle_pair->second != MFX_INFINITE) ? handle_pair->first : NULL;
4100 
4101     ret = hb_create_ffmpeg_pool(job, coded_width, coded_height, sw_pix_fmt, HB_QSV_POOL_SURFACE_SIZE, extra_hw_frames, &hb_dec_qsv_frames_ctx->hw_frames_ctx);
4102     if (ret < 0) {
4103         hb_error("hb_qsv_hw_frames_init: hb_create_ffmpeg_pool qsv surface allocation failed %d", ret);
4104         return ret;
4105     }
4106 
4107     /* allocate the memory ids for the external frames */
4108     av_buffer_unref(&hb_dec_qsv_frames_ctx->mids_buf);
4109     hb_dec_qsv_frames_ctx->mids_buf = hb_qsv_create_mids(hb_dec_qsv_frames_ctx->hw_frames_ctx);
4110     if (!hb_dec_qsv_frames_ctx->mids_buf)
4111         return AVERROR(ENOMEM);
4112     hb_dec_qsv_frames_ctx->mids    = (QSVMid*)hb_dec_qsv_frames_ctx->mids_buf->data;
4113     hb_dec_qsv_frames_ctx->nb_mids = frames_hwctx->nb_surfaces;
4114     memset(hb_dec_qsv_frames_ctx->pool, 0, hb_dec_qsv_frames_ctx->nb_mids * sizeof(hb_dec_qsv_frames_ctx->pool[0]));
4115 
4116     ret = hb_qsv_get_dx_device(job);
4117     if (ret < 0) {
4118         hb_error("qsv_init: hb_qsv_get_dx_device failed %d", ret);
4119         return ret;
4120     }
4121     return 0;
4122 }
4123 
hb_qsv_get_buffer(AVCodecContext * s,AVFrame * frame,int flags)4124 int hb_qsv_get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
4125 {
4126     if (frame->format == AV_PIX_FMT_QSV)
4127         return qsv_get_buffer(s, frame, flags);
4128 
4129     return avcodec_default_get_buffer2(s, frame, flags);
4130 }
4131 
hb_qsv_get_format(AVCodecContext * s,const enum AVPixelFormat * pix_fmts)4132 enum AVPixelFormat hb_qsv_get_format(AVCodecContext *s, const enum AVPixelFormat *pix_fmts)
4133 {
4134     while (*pix_fmts != AV_PIX_FMT_NONE) {
4135         if (*pix_fmts == AV_PIX_FMT_QSV) {
4136             int ret = hb_qsv_hw_frames_init(s);
4137             if (ret < 0) {
4138                 hb_error("hb_qsv_get_format: QSV hwaccel initialization failed");
4139                 return AV_PIX_FMT_NONE;
4140             }
4141             if (s->hw_frames_ctx) {
4142                 s->hw_frames_ctx = av_buffer_ref(s->hw_frames_ctx);
4143                 if (!s->hw_frames_ctx)
4144                     return AV_PIX_FMT_NONE;
4145             }
4146             return AV_PIX_FMT_QSV;
4147         }
4148 
4149         pix_fmts++;
4150     }
4151 
4152     hb_error("hb_qsv_get_format: the QSV pixel format not offered in get_format()");
4153     return AV_PIX_FMT_NONE;
4154 }
4155 
hb_qsv_preset_is_zero_copy_enabled(const hb_dict_t * job_dict)4156 int hb_qsv_preset_is_zero_copy_enabled(const hb_dict_t *job_dict)
4157 {
4158     hb_dict_t *video_dict, *qsv, *encoder;
4159     int qsv_encoder_enabled = 0;
4160     int qsv_decoder_enabled = 0;
4161     video_dict = hb_dict_get(job_dict, "Video");
4162     if(video_dict)
4163     {
4164         encoder = hb_dict_get(video_dict, "Encoder");
4165         if(encoder)
4166         {
4167             if (hb_value_type(encoder) == HB_VALUE_TYPE_STRING)
4168             {
4169                 if(!strcasecmp(hb_value_get_string(encoder), "qsv_h264") ||
4170                     !strcasecmp(hb_value_get_string(encoder), "qsv_h265"))
4171                 {
4172                     qsv_encoder_enabled = 1;
4173                 }
4174             }
4175         }
4176         qsv = hb_dict_get(video_dict, "QSV");
4177         if (qsv != NULL)
4178         {
4179             hb_dict_t *decode;
4180             decode = hb_dict_get(qsv, "Decode");
4181             if(decode)
4182             {
4183                 if (hb_value_type(decode) == HB_VALUE_TYPE_BOOL)
4184                 {
4185                     qsv_decoder_enabled = hb_value_get_bool(decode);
4186                 }
4187             }
4188         }
4189     }
4190     return (qsv_encoder_enabled && qsv_decoder_enabled);
4191 }
4192 
hb_qsv_sanitize_filter_list(hb_job_t * job)4193 int hb_qsv_sanitize_filter_list(hb_job_t *job)
4194 {
4195     /*
4196      * When QSV's VPP is used for filtering, not all CPU filters
4197      * are supported, so we need to do a little extra setup here.
4198      */
4199     if (job->vcodec & HB_VCODEC_QSV_MASK)
4200     {
4201         int i = 0;
4202         int num_cpu_filters = 0;
4203         if (job->list_filter != NULL && hb_list_count(job->list_filter) > 0)
4204         {
4205             for (i = 0; i < hb_list_count(job->list_filter); i++)
4206             {
4207                 hb_filter_object_t *filter = hb_list_item(job->list_filter, i);
4208 
4209                 switch (filter->id)
4210                 {
4211                     // cropping and scaling always done via VPP filter
4212                     case HB_FILTER_CROP_SCALE:
4213                         break;
4214 
4215                     case HB_FILTER_DEINTERLACE:
4216                     case HB_FILTER_ROTATE:
4217                     case HB_FILTER_RENDER_SUB:
4218                     case HB_FILTER_AVFILTER:
4219                         num_cpu_filters++;
4220                         break;
4221                     default:
4222                         num_cpu_filters++;
4223                         break;
4224                 }
4225             }
4226         }
4227         job->qsv.ctx->num_cpu_filters = num_cpu_filters;
4228         job->qsv.ctx->qsv_filters_are_enabled = ((hb_list_count(job->list_filter) == 1) && hb_qsv_full_path_is_enabled(job)) ? 1 : 0;
4229         if (job->qsv.ctx->qsv_filters_are_enabled)
4230         {
4231             job->qsv.ctx->hb_vpp_qsv_frames_ctx = av_mallocz(sizeof(HBQSVFramesContext));
4232             if (!job->qsv.ctx->hb_vpp_qsv_frames_ctx)
4233             {
4234                 hb_error( "sanitize_qsv: HBQSVFramesContext vpp alloc failed" );
4235                 return 1;
4236             }
4237         }
4238     }
4239     return 0;
4240 }
4241 
4242 #else // other OS
4243 
hb_qsv_get_platform(int adapter_index)4244 int hb_qsv_get_platform(int adapter_index)
4245 {
4246     return hb_get_cpu_platform();
4247 }
4248 
hb_qsv_info_init()4249 int hb_qsv_info_init()
4250 {
4251     if (g_qsv_adapters_list)
4252     {
4253         hb_error("hb_qsv_info_init: qsv_adapters_list is allocated already");
4254         return -1;
4255     }
4256     g_qsv_adapters_list = hb_list_init();
4257     if (g_qsv_adapters_list == NULL)
4258     {
4259         hb_error("hb_qsv_info_init: g_qsv_adapters_list allocation failed");
4260         return -1;
4261     }
4262     if (g_qsv_adapters_details_list)
4263     {
4264         hb_error("hb_qsv_info_init: g_qsv_adapters_details_list is allocated already");
4265         return -1;
4266     }
4267     g_qsv_adapters_details_list = hb_list_init();
4268     if (g_qsv_adapters_details_list == NULL)
4269     {
4270         hb_error("hb_qsv_info_init: g_qsv_adapters_details_list allocation failed");
4271         return -1;
4272     }
4273     static int adapter_index = 0;
4274     static hb_qsv_adapter_details_t adapter_details;
4275     init_adapter_details(&adapter_details);
4276     hb_list_add(g_qsv_adapters_list, (void*)&adapter_index);
4277     hb_list_add(g_qsv_adapters_details_list, (void*)&adapter_details);
4278     hb_qsv_collect_adapters_details(g_qsv_adapters_list, g_qsv_adapters_details_list);
4279     return 0;
4280 }
4281 
hb_create_ffmpeg_pool(hb_job_t * job,int coded_width,int coded_height,enum AVPixelFormat sw_pix_fmt,int pool_size,int extra_hw_frames,AVBufferRef ** out_hw_frames_ctx)4282 int hb_create_ffmpeg_pool(hb_job_t *job, int coded_width, int coded_height, enum AVPixelFormat sw_pix_fmt, int pool_size, int extra_hw_frames, AVBufferRef **out_hw_frames_ctx)
4283 {
4284     return -1;
4285 }
4286 
hb_qsv_hw_frames_init(AVCodecContext * s)4287 int hb_qsv_hw_frames_init(AVCodecContext *s)
4288 {
4289     return -1;
4290 }
4291 
hb_qsv_attach_surface_to_video_buffer(hb_job_t * job,hb_buffer_t * buf,int is_vpp)4292 int hb_qsv_attach_surface_to_video_buffer(hb_job_t *job, hb_buffer_t* buf, int is_vpp)
4293 {
4294     return -1;
4295 }
4296 
hb_qsv_copy_video_buffer_to_video_buffer(hb_job_t * job,hb_buffer_t * in,hb_buffer_t * out,int is_vpp)4297 int hb_qsv_copy_video_buffer_to_video_buffer(hb_job_t *job, hb_buffer_t* in, hb_buffer_t* out, int is_vpp)
4298 {
4299     return -1;
4300 }
4301 
hb_qsv_copy_avframe_to_video_buffer(hb_job_t * job,AVFrame * frame,int is_vpp)4302 hb_buffer_t* hb_qsv_copy_avframe_to_video_buffer(hb_job_t *job, AVFrame *frame, int is_vpp)
4303 {
4304     return NULL;
4305 }
4306 
hb_qsv_get_free_surface_from_pool(HBQSVFramesContext * hb_enc_qsv_frames_ctx,AVFrame * frame,QSVMid ** out_mid)4307 int hb_qsv_get_free_surface_from_pool(HBQSVFramesContext* hb_enc_qsv_frames_ctx, AVFrame* frame, QSVMid** out_mid)
4308 {
4309     return -1;
4310 }
4311 
hb_qsv_get_free_surface_from_pool_with_range(HBQSVFramesContext * hb_enc_qsv_frames_ctx,const int start_index,const int end_index,QSVMid ** out_mid,mfxFrameSurface1 ** out_surface)4312 void hb_qsv_get_free_surface_from_pool_with_range(HBQSVFramesContext* hb_enc_qsv_frames_ctx, const int start_index, const int end_index, QSVMid** out_mid, mfxFrameSurface1** out_surface)
4313 {
4314     return;
4315 }
4316 
hb_qsv_replace_surface_mid(HBQSVFramesContext * hb_qsv_frames_ctx,const QSVMid * mid,mfxFrameSurface1 * surface)4317 int hb_qsv_replace_surface_mid(HBQSVFramesContext* hb_qsv_frames_ctx, const QSVMid *mid, mfxFrameSurface1 *surface)
4318 {
4319     return -1;
4320 }
4321 
hb_qsv_get_format(AVCodecContext * s,const enum AVPixelFormat * pix_fmts)4322 enum AVPixelFormat hb_qsv_get_format(AVCodecContext *s, const enum AVPixelFormat *pix_fmts)
4323 {
4324     return AV_PIX_FMT_NONE;
4325 }
4326 
hb_qsv_get_buffer(AVCodecContext * s,AVFrame * frame,int flags)4327 int hb_qsv_get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
4328 {
4329     return -1;
4330 }
4331 
hb_qsv_uninit_dec(AVCodecContext * s)4332 void hb_qsv_uninit_dec(AVCodecContext *s)
4333 {
4334 }
4335 
hb_qsv_uninit_enc(hb_job_t * job)4336 void hb_qsv_uninit_enc(hb_job_t *job)
4337 {
4338 }
4339 
hb_qsv_preset_is_zero_copy_enabled(const hb_dict_t * job_dict)4340 int hb_qsv_preset_is_zero_copy_enabled(const hb_dict_t *job_dict)
4341 {
4342     return 0;
4343 }
4344 
hb_dxva2_device_check()4345 static int hb_dxva2_device_check()
4346 {
4347     return -1;
4348 }
4349 
hb_d3d11va_device_check()4350 static int hb_d3d11va_device_check()
4351 {
4352     return -1;
4353 }
4354 
hb_qsv_get_mid_by_surface_from_pool(HBQSVFramesContext * hb_enc_qsv_frames_ctx,mfxFrameSurface1 * surface,QSVMid ** out_mid)4355 int hb_qsv_get_mid_by_surface_from_pool(HBQSVFramesContext* hb_enc_qsv_frames_ctx, mfxFrameSurface1 *surface, QSVMid **out_mid)
4356 {
4357 }
4358 
hb_qsv_release_surface_from_pool_by_surface_pointer(HBQSVFramesContext * hb_enc_qsv_frames_ctx,const mfxFrameSurface1 * surface)4359 int hb_qsv_release_surface_from_pool_by_surface_pointer(HBQSVFramesContext* hb_enc_qsv_frames_ctx, const mfxFrameSurface1 *surface)
4360 {
4361     return -1;
4362 }
4363 
4364 #endif
4365 
hb_qsv_context_init()4366 hb_qsv_context* hb_qsv_context_init()
4367 {
4368     if (!hb_qsv_available()) {
4369         return 0;
4370     }
4371 
4372     hb_qsv_context *ctx;
4373     ctx = av_mallocz(sizeof(hb_qsv_context));
4374     if (!ctx)
4375     {
4376         hb_error( "hb_qsv_context_init: qsv ctx alloc failed" );
4377         return NULL;
4378     }
4379     ctx->dx_index = hb_qsv_get_default_adapter_index();
4380     hb_qsv_add_context_usage(ctx, 0);
4381     return ctx;
4382 }
4383 
hb_qsv_context_uninit(hb_job_t * job)4384 void hb_qsv_context_uninit(hb_job_t *job)
4385 {
4386     hb_qsv_context *ctx = job->qsv.ctx;
4387     if ( ctx == NULL )
4388     {
4389         hb_error( "hb_qsv_context_uninit: ctx is NULL" );
4390         return;
4391     }
4392     /* QSV context cleanup and MFXClose */
4393     hb_qsv_context_clean(ctx, hb_qsv_full_path_is_enabled(job));
4394     av_free(ctx);
4395     job->qsv.ctx = NULL;
4396 
4397     /* Structures below are needed until the end life of the process
4398         It has been collected once in hb_qsv_info_init() and no need to recollect every time.
4399     */
4400 #if 0
4401     if (g_qsv_adapters_details_list)
4402     {
4403 #if defined(_WIN32) || defined(__MINGW32__)
4404         hb_qsv_free_adapters_details(g_qsv_adapters_details_list);
4405 #endif
4406         hb_list_close(&g_qsv_adapters_details_list);
4407         g_qsv_adapters_details_list = NULL;
4408     }
4409     if (g_qsv_adapters_list)
4410     {
4411         hb_list_close(&g_qsv_adapters_list);
4412         g_qsv_adapters_list = NULL;
4413     }
4414 #if defined(_WIN32) || defined(__MINGW32__)
4415     if (g_qsv_adapters_info.Adapters)
4416     {
4417         av_free(g_qsv_adapters_info.Adapters);
4418     }
4419     g_qsv_adapters_info.Adapters = NULL;
4420     g_qsv_adapters_info.NumAlloc = 0;
4421     g_qsv_adapters_info.NumActual = 0;
4422 #endif
4423 #endif
4424     g_adapter_index = hb_qsv_get_default_adapter_index();
4425 }
4426 
4427 #else // HB_PROJECT_FEATURE_QSV
4428 
hb_qsv_available()4429 int hb_qsv_available()
4430 {
4431     return -1;
4432 }
4433 
4434 #endif // HB_PROJECT_FEATURE_QSV
4435