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(¶m->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(¶m->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(¶m->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*)¶m->videoSignalInfo;
2551 }
2552 if (info->capabilities & HB_QSV_CAP_OPTION1)
2553 {
2554 param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)¶m->codingOption;
2555 }
2556 if (info->capabilities & HB_QSV_CAP_OPTION2)
2557 {
2558 param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)¶m->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