summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libhb/common.c3
-rw-r--r--libhb/decavcodec.c31
-rw-r--r--libhb/enc_qsv.c41
-rw-r--r--libhb/handbrake/qsv_common.h21
-rw-r--r--libhb/handbrake/qsv_libav.h1
-rw-r--r--libhb/hb.c5
-rw-r--r--libhb/hb_json.c31
-rw-r--r--libhb/preset.c6
-rw-r--r--libhb/qsv_common.c1200
-rw-r--r--libhb/qsv_libav.c3
-rw-r--r--libhb/sync.c2
-rw-r--r--libhb/work.c6
-rw-r--r--test/test.c77
-rw-r--r--win/CS/HandBrake.Interop/Interop/HandBrakeHardwareEncoderHelper.cs5
-rw-r--r--win/CS/HandBrake.Interop/Interop/HbLib/HbFunctions.cs10
15 files changed, 959 insertions, 483 deletions
diff --git a/libhb/common.c b/libhb/common.c
index 0eb980468..637d14d0b 100644
--- a/libhb/common.c
+++ b/libhb/common.c
@@ -294,7 +294,7 @@ static int hb_video_encoder_is_enabled(int encoder, int disable_hardware)
#if HB_PROJECT_FEATURE_QSV
if (encoder & HB_VCODEC_QSV_MASK)
{
- return hb_qsv_video_encoder_is_enabled(encoder);
+ return hb_qsv_video_encoder_is_enabled(hb_qsv_get_adapter_index(), encoder);
}
#endif
@@ -3897,6 +3897,7 @@ static void job_setup(hb_job_t * job, hb_title_t * title)
job->metadata = hb_metadata_copy( title->metadata );
#if HB_PROJECT_FEATURE_QSV
+ job->qsv.ctx = hb_qsv_context_init();
job->qsv.enc_info.is_init_done = 0;
job->qsv.async_depth = hb_qsv_param_default_async_depth();
job->qsv.decode = !!(title->video_decode_support &
diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c
index 55c38a00b..08c82d5f5 100644
--- a/libhb/decavcodec.c
+++ b/libhb/decavcodec.c
@@ -1423,7 +1423,7 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job )
pv->qsv.config.io_pattern = MFX_IOPATTERN_OUT_SYSTEM_MEMORY;
if(hb_qsv_full_path_is_enabled(job))
{
- hb_qsv_info_t *info = hb_qsv_info_get(job->vcodec);
+ hb_qsv_info_t *info = hb_qsv_encoder_info_get(hb_qsv_get_adapter_index(), job->vcodec);
if (info != NULL)
{
// setup the QSV configuration
@@ -1443,6 +1443,7 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job )
hb_error( "decavcodecvInit: no context" );
return 1;
}
+ pv->job->qsv.ctx->full_path_is_enabled = 1;
if (!pv->job->qsv.ctx->hb_dec_qsv_frames_ctx)
{
pv->job->qsv.ctx->hb_dec_qsv_frames_ctx = av_mallocz(sizeof(HBQSVFramesContext));
@@ -2131,32 +2132,8 @@ static int decavcodecvInfo( hb_work_object_t *w, hb_work_info_t *info )
info->video_decode_support = HB_DECODE_SUPPORT_SW;
#if HB_PROJECT_FEATURE_QSV
- if (avcodec_find_decoder_by_name(hb_qsv_decode_get_codec_name(pv->context->codec_id)))
- {
- switch (pv->context->codec_id)
- {
- case AV_CODEC_ID_HEVC:
- case AV_CODEC_ID_H264:
- if (pv->context->pix_fmt == AV_PIX_FMT_YUV420P ||
- pv->context->pix_fmt == AV_PIX_FMT_YUVJ420P ||
- pv->context->pix_fmt == AV_PIX_FMT_YUV420P10LE)
- {
- info->video_decode_support |= HB_DECODE_SUPPORT_QSV;
- }
- break;
- case AV_CODEC_ID_AV1:
- if ((qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G8) &&
- (pv->context->pix_fmt == AV_PIX_FMT_YUV420P ||
- pv->context->pix_fmt == AV_PIX_FMT_YUVJ420P ||
- pv->context->pix_fmt == AV_PIX_FMT_YUV420P10LE))
- {
- info->video_decode_support |= HB_DECODE_SUPPORT_QSV;
- }
- break;
- default:
- break;
- }
- }
+ if (hb_qsv_decode_codec_supported_codec(hb_qsv_get_adapter_index(), pv->context->codec_id, pv->context->pix_fmt))
+ info->video_decode_support |= HB_DECODE_SUPPORT_QSV;
#endif
return 1;
diff --git a/libhb/enc_qsv.c b/libhb/enc_qsv.c
index 5f3d52fc7..e70ff3eb3 100644
--- a/libhb/enc_qsv.c
+++ b/libhb/enc_qsv.c
@@ -892,7 +892,7 @@ int qsv_enc_init(hb_work_private_t *pv)
*job->die = 1;
return -1;
}
- pv->loaded_plugins = hb_qsv_load_plugins(pv->qsv_info, qsv->mfx_session, version);
+ pv->loaded_plugins = hb_qsv_load_plugins(hb_qsv_get_adapter_index(), pv->qsv_info, qsv->mfx_session, version);
if (pv->loaded_plugins == NULL)
{
hb_error("qsv_enc_init: hb_qsv_load_plugins failed");
@@ -998,35 +998,6 @@ int qsv_enc_init(hb_work_private_t *pv)
return 0;
}
-static mfxIMPL hb_qsv_dx_index_to_impl(int dx_index)
-{
- mfxIMPL impl;
-
- switch (dx_index)
- {
- {
- case 0:
- impl = MFX_IMPL_HARDWARE;
- break;
- case 1:
- impl = MFX_IMPL_HARDWARE2;
- break;
- case 2:
- impl = MFX_IMPL_HARDWARE3;
- break;
- case 3:
- impl = MFX_IMPL_HARDWARE4;
- break;
-
- default:
- // try searching on all display adapters
- impl = MFX_IMPL_HARDWARE_ANY;
- break;
- }
- }
- return impl;
-}
-
/***********************************************************************
* encqsvInit
***********************************************************************
@@ -1039,7 +1010,7 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
pv->is_sys_mem = hb_qsv_full_path_is_enabled(job) ? 0 : 1; // TODO: re-implement QSV VPP filtering support
pv->job = job;
- pv->qsv_info = hb_qsv_info_get(job->vcodec);
+ pv->qsv_info = hb_qsv_encoder_info_get(hb_qsv_get_adapter_index(), job->vcodec);
pv->delayed_processing = hb_list_init();
pv->last_start = INT64_MIN;
hb_buffer_list_clear(&pv->encoded_frames);
@@ -1104,12 +1075,12 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
}
hb_dict_free(&options_list);
}
-#if !defined(SYS_LINUX) && !defined(SYS_FREEBSD)
- if (pv->is_sys_mem)
+#if defined(_WIN32) || defined(__MINGW32__)
+ if (pv->is_sys_mem && hb_qsv_implementation_is_hardware(pv->qsv_info->implementation))
{
// select the right hardware implementation based on dx index
if (!job->qsv.ctx->qsv_device)
- hb_qsv_param_parse_dx_index(pv->job, -1);
+ hb_qsv_param_parse_dx_index(pv->job, hb_qsv_get_adapter_index());
mfxIMPL hw_preference = MFX_IMPL_VIA_D3D11;
pv->qsv_info->implementation = hb_qsv_dx_index_to_impl(job->qsv.ctx->dx_index) | hw_preference;
}
@@ -1465,7 +1436,7 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
}
/* Load required MFX plug-ins */
- pv->loaded_plugins = hb_qsv_load_plugins(pv->qsv_info, session, version);
+ pv->loaded_plugins = hb_qsv_load_plugins(hb_qsv_get_adapter_index(), pv->qsv_info, session, version);
if (pv->loaded_plugins == NULL)
{
hb_error("encqsvInit: hb_qsv_load_plugins failed");
diff --git a/libhb/handbrake/qsv_common.h b/libhb/handbrake/qsv_common.h
index ef27464d9..2d4471bb1 100644
--- a/libhb/handbrake/qsv_common.h
+++ b/libhb/handbrake/qsv_common.h
@@ -44,7 +44,7 @@ void hb_qsv_force_workarounds(); // for developers only
typedef struct hb_qsv_info_s
{
// each info struct only corresponds to one CodecId and implementation combo
- const mfxU32 codec_id;
+ mfxU32 codec_id;
mfxIMPL implementation;
// whether the encoder is available for this implementation
@@ -82,16 +82,19 @@ typedef struct hb_qsv_info_s
/* Intel Quick Sync Video utilities */
hb_display_t * hb_qsv_display_init(void);
-int hb_qsv_video_encoder_is_enabled(int encoder);
+int hb_qsv_video_encoder_is_enabled(int adapter_index, int encoder);
int hb_qsv_audio_encoder_is_enabled(int encoder);
int hb_qsv_info_init();
void hb_qsv_info_print();
hb_list_t* hb_qsv_adapters_list();
-hb_qsv_info_t* hb_qsv_info_get(int encoder);
-int qsv_hardware_generation(int cpu_platform);
+hb_qsv_info_t* hb_qsv_encoder_info_get(int adapter_index, int encoder);
+int hb_qsv_hardware_generation(int cpu_platform);
+int hb_qsv_get_platform(int adapter_index);
+int hb_qsv_get_adapter_index();
+int hb_qsv_implementation_is_hardware(mfxIMPL implementation);
/* Automatically load and unload any required MFX plug-ins */
-hb_list_t* hb_qsv_load_plugins (hb_qsv_info_t *info, mfxSession session, mfxVersion version);
+hb_list_t* hb_qsv_load_plugins (int adapter_index, hb_qsv_info_t *info, mfxSession session, mfxVersion version);
void hb_qsv_unload_plugins(hb_list_t **_l, mfxSession session, mfxVersion version);
/* Intel Quick Sync Video DECODE utilities */
@@ -247,6 +250,14 @@ enum AVPixelFormat hb_qsv_get_format(AVCodecContext *s, const enum AVPixelFormat
int hb_qsv_preset_is_zero_copy_enabled(const hb_dict_t *job_dict);
void hb_qsv_uninit_dec(AVCodecContext *s);
void hb_qsv_uninit_enc(hb_job_t *job);
+mfxIMPL hb_qsv_dx_index_to_impl(int dx_index);
+int hb_qsv_parse_adapter_index(hb_job_t *job);
+int hb_qsv_setup_job(hb_job_t *job);
+int hb_qsv_decode_h264_is_supported(int adapter_index);
+int hb_qsv_decode_h265_is_supported(int adapter_index);
+int hb_qsv_decode_h265_10_bit_is_supported(int adapter_index);
+int hb_qsv_decode_av1_is_supported(int adapter_index);
+int hb_qsv_decode_codec_supported_codec(int adapter_index, int video_codec_param, int pix_fmt);
#endif // __LIBHB__
#endif // HB_PROJECT_FEATURE_QSV
diff --git a/libhb/handbrake/qsv_libav.h b/libhb/handbrake/qsv_libav.h
index 23b4b96c6..f498f3107 100644
--- a/libhb/handbrake/qsv_libav.h
+++ b/libhb/handbrake/qsv_libav.h
@@ -333,6 +333,7 @@ typedef struct hb_qsv_context {
int num_cpu_filters;
int la_is_enabled;
int qsv_filters_are_enabled;
+ int full_path_is_enabled;
char *vpp_scale_mode;
char *vpp_interpolation_method;
char *qsv_device;
diff --git a/libhb/hb.c b/libhb/hb.c
index c85934b5b..ea554207a 100644
--- a/libhb/hb.c
+++ b/libhb/hb.c
@@ -1830,10 +1830,9 @@ int hb_global_init()
#if HB_PROJECT_FEATURE_QSV
if (!disable_hardware)
{
- result = hb_qsv_info_init();
- if (result < 0)
+ if (hb_qsv_available() < 0)
{
- hb_error("hb_qsv_info_init failed!");
+ hb_error("hb_qsv_available failed!");
return -1;
}
hb_param_configure_qsv();
diff --git a/libhb/hb_json.c b/libhb/hb_json.c
index f794c7ab7..1d83f5e3f 100644
--- a/libhb/hb_json.c
+++ b/libhb/hb_json.c
@@ -530,6 +530,13 @@ hb_dict_t* hb_job_to_dict( const hb_job_t * job )
json_error_t error;
int subtitle_search_burn;
int ii;
+ int adapter_index;
+
+#if HB_PROJECT_FEATURE_QSV
+ adapter_index = job->qsv.ctx->dx_index;
+#else
+ adapter_index = 0;
+#endif
if (job == NULL || job->title == NULL)
return NULL;
@@ -538,7 +545,6 @@ hb_dict_t* hb_job_to_dict( const hb_job_t * job )
// necessary PAR value
subtitle_search_burn = job->select_subtitle_config.dest == RENDERSUB;
-
dict = json_pack_ex(&error, 0,
"{"
// SequenceID
@@ -550,8 +556,8 @@ hb_dict_t* hb_job_to_dict( const hb_job_t * job )
"s:{s:o, s:o, s:o,},"
// PAR {Num, Den}
"s:{s:o, s:o},"
- // Video {Encoder, QSV {Decode, AsyncDepth}}
- "s:{s:o, s:{s:o, s:o}},"
+ // Video {Encoder, QSV {Decode, AsyncDepth, AdapterIndex}}
+ "s:{s:o, s:{s:o, s:o, s:o}},"
// Audio {CopyMask, FallbackEncoder, AudioList []}
"s:{s:[], s:o, s:[]},"
// Subtitles {Search {Enable, Forced, Default, Burn}, SubtitleList []}
@@ -580,6 +586,7 @@ hb_dict_t* hb_job_to_dict( const hb_job_t * job )
"QSV",
"Decode", hb_value_bool(job->qsv.decode),
"AsyncDepth", hb_value_int(job->qsv.async_depth),
+ "AdapterIndex", hb_value_int(adapter_index),
"Audio",
"CopyMask",
"FallbackEncoder", hb_value_int(job->acodec_fallback),
@@ -1094,6 +1101,7 @@ hb_job_t* hb_dict_to_job( hb_handle_t * h, hb_dict_t *dict )
json_int_t range_start = -1, range_end = -1, range_seek_points = -1;
int vbitrate = -1;
double vquality = HB_INVALID_VIDEO_QUALITY;
+ int adapter_index = -1;
result = json_unpack_ex(dict, &error, 0,
"{"
@@ -1114,7 +1122,7 @@ hb_job_t* hb_dict_to_job( hb_handle_t * h, hb_dict_t *dict )
// Mastering,
// ContentLightLevel,
// ColorPrimariesOverride, ColorTransferOverride, ColorMatrixOverride,
- // QSV {Decode, AsyncDepth}}
+ // QSV {Decode, AsyncDepth, AdapterIndex}}
"s:{s:o, s?F, s?i, s?s, s?s, s?s, s?s, s?s,"
" s?b, s?b,"
" s?i, s?i,"
@@ -1122,7 +1130,7 @@ hb_job_t* hb_dict_to_job( hb_handle_t * h, hb_dict_t *dict )
" s?o,"
" s?o,"
" s?i, s?i, s?i,"
- " s?{s?b, s?i}},"
+ " s?{s?b, s?i, s?i}},"
// Audio {CopyMask, FallbackEncoder, AudioList}
"s?{s?o, s?o, s?o},"
// Subtitle {Search {Enable, Forced, Default, Burn}, SubtitleList}
@@ -1177,6 +1185,7 @@ hb_job_t* hb_dict_to_job( hb_handle_t * h, hb_dict_t *dict )
"QSV",
"Decode", unpack_b(&job->qsv.decode),
"AsyncDepth", unpack_i(&job->qsv.async_depth),
+ "AdapterIndex", unpack_i(&adapter_index),
"Audio",
"CopyMask", unpack_o(&acodec_copy_mask),
"FallbackEncoder", unpack_o(&acodec_fallback),
@@ -1197,15 +1206,6 @@ hb_job_t* hb_dict_to_job( hb_handle_t * h, hb_dict_t *dict )
hb_error("hb_dict_to_job: failed to parse dict: %s", error.text);
goto fail;
}
- // Make sure QSV Decode is only True if the hardware is available.
- job->qsv.decode = job->qsv.decode && hb_qsv_available();
-#if HB_PROJECT_FEATURE_QSV
- int async_depth_default = hb_qsv_param_default_async_depth();
- if(job->qsv.async_depth <= 0 || job->qsv.async_depth > async_depth_default)
- {
- job->qsv.async_depth = async_depth_default;
- }
-#endif
// Lookup mux id
if (hb_value_type(mux) == HB_VALUE_TYPE_STRING)
{
@@ -1275,6 +1275,9 @@ hb_job_t* hb_dict_to_job( hb_handle_t * h, hb_dict_t *dict )
hb_job_set_encoder_level(job, video_level);
hb_job_set_encoder_options(job, video_options);
+#if HB_PROJECT_FEATURE_QSV
+ job->qsv.ctx->dx_index = adapter_index;
+#endif
// If both vbitrate and vquality were specified, vbitrate is used;
// we need to ensure the unused rate contro mode is always set to an
// invalid value, as if both values are valid, behavior is undefined
diff --git a/libhb/preset.c b/libhb/preset.c
index 21305b2de..e853e183d 100644
--- a/libhb/preset.c
+++ b/libhb/preset.c
@@ -1825,7 +1825,11 @@ int hb_preset_apply_video(const hb_dict_t *preset, hb_dict_t *job_dict)
hb_dict_set(qsv, "AsyncDepth",
hb_value_xform(value, HB_VALUE_TYPE_INT));
}
-
+ if ((value = hb_dict_get(preset, "VideoQSVAdapterIndex")) != NULL)
+ {
+ hb_dict_set(qsv, "AdapterIndex",
+ hb_value_xform(value, HB_VALUE_TYPE_INT));
+ }
return 0;
}
diff --git a/libhb/qsv_common.c b/libhb/qsv_common.c
index 02c960087..52d50302d 100644
--- a/libhb/qsv_common.c
+++ b/libhb/qsv_common.c
@@ -30,21 +30,60 @@
#include "libavutil/hwcontext.h"
#include "mfx/mfxadapter.h"
+typedef struct hb_qsv_adapter_details
+{
+ // DirectX index
+ int index;
+ // QSV info for each codec
+ hb_qsv_info_t *hb_qsv_info_avc;
+ hb_qsv_info_t *hb_qsv_info_hevc;
+ // API versions
+ mfxVersion qsv_software_version;
+ mfxVersion qsv_hardware_version;
+ // AVC implementations
+ hb_qsv_info_t qsv_software_info_avc;
+ hb_qsv_info_t qsv_hardware_info_avc;
+ // HEVC implementations
+ hb_qsv_info_t qsv_software_info_hevc;
+ hb_qsv_info_t qsv_hardware_info_hevc;
+} hb_qsv_adapter_details_t;
+
// QSV info about adapters
-static mfxAdaptersInfo qsv_adapters_info;
-static hb_list_t *qsv_adapters_list = NULL;
-// QSV info for each codec
-static hb_qsv_info_t *hb_qsv_info_avc = NULL;
-static hb_qsv_info_t *hb_qsv_info_hevc = NULL;
-// API versions
-static mfxVersion qsv_software_version = { .Version = 0, };
-static mfxVersion qsv_hardware_version = { .Version = 0, };
-// AVC implementations
-static hb_qsv_info_t qsv_software_info_avc = { .available = 0, .codec_id = MFX_CODEC_AVC, .implementation = MFX_IMPL_SOFTWARE, };
-static hb_qsv_info_t qsv_hardware_info_avc = { .available = 0, .codec_id = MFX_CODEC_AVC, .implementation = MFX_IMPL_HARDWARE_ANY|MFX_IMPL_VIA_ANY, };
-// HEVC implementations
-static hb_qsv_info_t qsv_software_info_hevc = { .available = 0, .codec_id = MFX_CODEC_HEVC, .implementation = MFX_IMPL_SOFTWARE, };
-static hb_qsv_info_t qsv_hardware_info_hevc = { .available = 0, .codec_id = MFX_CODEC_HEVC, .implementation = MFX_IMPL_HARDWARE_ANY|MFX_IMPL_VIA_ANY, };
+#if defined(_WIN32) || defined(__MINGW32__)
+static mfxAdaptersInfo g_qsv_adapters_info;
+static const char* hb_qsv_get_adapter_type(const mfxAdapterInfo* info);
+#endif
+int hb_qsv_get_platform(int adapter_index);
+static hb_list_t *g_qsv_adapters_list = NULL;
+static hb_list_t *g_qsv_adapters_details_list = NULL;
+static int g_adapter_index = -1;
+
+static void init_adapter_details(hb_qsv_adapter_details_t *adapter_details)
+{
+ adapter_details->index = 0;
+ // QSV info for each codec
+ adapter_details->hb_qsv_info_avc = NULL;
+ adapter_details->hb_qsv_info_hevc = NULL;
+ // API versions
+ adapter_details->qsv_software_version.Version = 0;
+ adapter_details->qsv_hardware_version.Version = 0;
+ // AVC implementations
+ adapter_details->qsv_software_info_avc.available = 0;
+ adapter_details->qsv_software_info_avc.codec_id = MFX_CODEC_AVC;
+ adapter_details->qsv_software_info_avc.implementation = MFX_IMPL_SOFTWARE;
+
+ adapter_details->qsv_hardware_info_avc.available = 0;
+ adapter_details->qsv_hardware_info_avc.codec_id = MFX_CODEC_AVC;
+ adapter_details->qsv_hardware_info_avc.implementation = MFX_IMPL_HARDWARE_ANY|MFX_IMPL_VIA_ANY;
+ // HEVC implementations
+ adapter_details->qsv_software_info_hevc.available = 0;
+ adapter_details->qsv_software_info_hevc.codec_id = MFX_CODEC_HEVC;
+ adapter_details->qsv_software_info_hevc.implementation = MFX_IMPL_SOFTWARE;
+
+ adapter_details->qsv_hardware_info_hevc.available = 0;
+ adapter_details->qsv_hardware_info_hevc.codec_id = MFX_CODEC_HEVC;
+ adapter_details->qsv_hardware_info_hevc.implementation = MFX_IMPL_HARDWARE_ANY|MFX_IMPL_VIA_ANY;
+}
// QSV-supported profile and level lists (not all exposed to the user)
static hb_triplet_t hb_qsv_h264_profiles[] =
@@ -124,7 +163,69 @@ static hb_triplet_t hb_qsv_h265_levels[] =
#define HB_CHECK_MFX_VERSION(MFX_VERSION, MAJOR, MINOR) \
(MFX_VERSION.Major == MAJOR && MFX_VERSION.Minor >= MINOR)
-int qsv_hardware_generation(int cpu_platform)
+int hb_qsv_get_adapter_index()
+{
+ return g_adapter_index;
+}
+
+hb_list_t* hb_qsv_adapters_list()
+{
+ return g_qsv_adapters_list;
+}
+
+static hb_qsv_adapter_details_t* hb_qsv_get_adapters_details_by_index(int adapter_index)
+{
+ for (int i = 0; i < hb_list_count(g_qsv_adapters_details_list); i++)
+ {
+ hb_qsv_adapter_details_t *details = hb_list_item(g_qsv_adapters_details_list, i);
+ if (details->index == adapter_index || adapter_index == -1)
+ {
+ return details;
+ }
+ }
+ return NULL;
+}
+
+static int qsv_impl_set_preferred(hb_qsv_adapter_details_t *details, const char *name)
+{
+ if (name == NULL || details == NULL)
+ {
+ return -1;
+ }
+ if (!strcasecmp(name, "software"))
+ {
+ if (details->qsv_software_info_avc.available)
+ {
+ details->hb_qsv_info_avc = &details->qsv_software_info_avc;
+ }
+ if (details->qsv_software_info_hevc.available)
+ {
+ details->hb_qsv_info_hevc = &details->qsv_software_info_hevc;
+ }
+ return 0;
+ }
+ if (!strcasecmp(name, "hardware"))
+ {
+ if (details->qsv_hardware_info_avc.available)
+ {
+ details->hb_qsv_info_avc = &details->qsv_hardware_info_avc;
+ }
+ if (details->qsv_hardware_info_hevc.available)
+ {
+ details->hb_qsv_info_hevc = &details->qsv_hardware_info_hevc;
+ }
+ return 0;
+ }
+ return -1;
+}
+
+int hb_qsv_impl_set_preferred(const char *name)
+{
+ hb_qsv_adapter_details_t* details = hb_qsv_get_adapters_details_by_index(hb_qsv_get_adapter_index());
+ return qsv_impl_set_preferred(details, name);
+}
+
+int hb_qsv_hardware_generation(int cpu_platform)
{
switch (cpu_platform)
{
@@ -157,7 +258,7 @@ int qsv_hardware_generation(int cpu_platform)
/*
* Determine whether a given mfxIMPL is hardware-accelerated.
*/
-static int qsv_implementation_is_hardware(mfxIMPL implementation)
+int hb_qsv_implementation_is_hardware(mfxIMPL implementation)
{
return MFX_IMPL_BASETYPE(implementation) != MFX_IMPL_SOFTWARE;
}
@@ -169,24 +270,51 @@ int hb_qsv_available()
return 0;
}
- return ((hb_qsv_video_encoder_is_enabled(HB_VCODEC_QSV_H264) ? HB_VCODEC_QSV_H264 : 0) |
- (hb_qsv_video_encoder_is_enabled(HB_VCODEC_QSV_H265) ? HB_VCODEC_QSV_H265 : 0) |
- (hb_qsv_video_encoder_is_enabled(HB_VCODEC_QSV_H265_10BIT) ? HB_VCODEC_QSV_H265_10BIT : 0));
+ static int init_done = 0;
+ if (init_done == 0)
+ {
+ int result = hb_qsv_info_init();
+ if (result != 0)
+ {
+ init_done = -1;
+ hb_log("hb_qsv_available: hb_qsv_info_init failed");
+ return -1;
+ }
+ init_done = 1;
+ }
+ else if (init_done == -1)
+ {
+ hb_log("hb_qsv_available: hb_qsv_info_init failed");
+ return -1;
+ }
+
+ return ((hb_qsv_video_encoder_is_enabled(hb_qsv_get_adapter_index(), HB_VCODEC_QSV_H264) ? HB_VCODEC_QSV_H264 : 0) |
+ (hb_qsv_video_encoder_is_enabled(hb_qsv_get_adapter_index(), HB_VCODEC_QSV_H265) ? HB_VCODEC_QSV_H265 : 0) |
+ (hb_qsv_video_encoder_is_enabled(hb_qsv_get_adapter_index(), HB_VCODEC_QSV_H265_10BIT) ? HB_VCODEC_QSV_H265_10BIT : 0));
}
-int hb_qsv_video_encoder_is_enabled(int encoder)
+int hb_qsv_video_encoder_is_enabled(int adapter_index, int encoder)
{
- switch (encoder)
+ hb_qsv_adapter_details_t* details = hb_qsv_get_adapters_details_by_index(adapter_index);
+
+ if (details)
{
- case HB_VCODEC_QSV_H264:
- return hb_qsv_info_avc != NULL && hb_qsv_info_avc->available;
- case HB_VCODEC_QSV_H265_10BIT:
- if (qsv_hardware_generation(hb_get_cpu_platform()) < QSV_G6)
+ switch (encoder)
+ {
+ case HB_VCODEC_QSV_H264:
+ return details->hb_qsv_info_avc != NULL && details->hb_qsv_info_avc->available;
+ case HB_VCODEC_QSV_H265_10BIT:
+ if (hb_qsv_hardware_generation(hb_qsv_get_platform(adapter_index)) < QSV_G6)
+ return 0;
+ case HB_VCODEC_QSV_H265:
+ return details->hb_qsv_info_hevc != NULL && details->hb_qsv_info_hevc->available;
+ default:
return 0;
- case HB_VCODEC_QSV_H265:
- return hb_qsv_info_hevc != NULL && hb_qsv_info_hevc->available;
- default:
- return 0;
+ }
+ }
+ else
+ {
+ return 0;
}
}
@@ -283,7 +411,7 @@ static void init_ext_coding_option2(mfxExtCodingOption2 *extCodingOption2)
extCodingOption2->NumMbPerSlice = 2040; // 1920x1088/4
}
-static int query_capabilities(mfxSession session, mfxVersion version, hb_qsv_info_t *info, mfxAdaptersInfo* adapters_info)
+static int query_capabilities(mfxSession session, int index, mfxVersion version, hb_qsv_info_t *info)
{
/*
* MFXVideoENCODE_Query(mfxSession, mfxVideoParam *in, mfxVideoParam *out);
@@ -312,7 +440,7 @@ static int query_capabilities(mfxSession session, mfxVersion version, hb_qsv_inf
info->capabilities = 0;
/* Load required MFX plug-ins */
- if ((mfxPluginList = hb_qsv_load_plugins(info, session, version)) == NULL)
+ if ((mfxPluginList = hb_qsv_load_plugins(index, info, session, version)) == NULL)
{
return 0; // the required plugin(s) couldn't be loaded
}
@@ -360,7 +488,7 @@ static int query_capabilities(mfxSession session, mfxVersion version, hb_qsv_inf
* about it - however, it may fail for other encoders (ignore)
*/
fprintf(stderr,
- "hb_qsv_info_init: MFXVideoENCODE_Init failed"
+ "query_capabilities: MFXVideoENCODE_Init failed"
" (0x%"PRIX32", 0x%"PRIX32", %d)\n",
info->codec_id, info->implementation, status);
}
@@ -384,27 +512,17 @@ static int query_capabilities(mfxSession session, mfxVersion version, hb_qsv_inf
/* Implementation-specific features that can't be queried */
if (info->codec_id == MFX_CODEC_AVC || info->codec_id == MFX_CODEC_HEVC)
{
- if (qsv_implementation_is_hardware(info->implementation))
+ if (hb_qsv_implementation_is_hardware(info->implementation))
{
- if (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G3)
+ if (hb_qsv_hardware_generation(hb_qsv_get_platform(index)) >= QSV_G3)
{
info->capabilities |= HB_QSV_CAP_B_REF_PYRAMID;
}
if (info->codec_id == MFX_CODEC_HEVC &&
- (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G7))
+ (hb_qsv_hardware_generation(hb_qsv_get_platform(index)) >= QSV_G7))
{
info->capabilities |= HB_QSV_CAP_LOWPOWER_ENCODE;
}
-#if !defined(SYS_LINUX) && !defined(SYS_FREEBSD)
- if (info->codec_id == MFX_CODEC_HEVC &&
- (adapters_info->NumActual > 0))
- {
- if (adapters_info->Adapters[0].Platform.MediaAdapterType == MFX_MEDIA_DISCRETE)
- {
- info->capabilities |= HB_QSV_CAP_LOWPOWER_ENCODE;
- }
- }
-#endif
}
else
{
@@ -507,7 +625,7 @@ static int query_capabilities(mfxSession session, mfxVersion version, hb_qsv_inf
* about it - however, it may fail for other encoders (ignore)
*/
fprintf(stderr,
- "hb_qsv_info_init: mfxExtVideoSignalInfo check"
+ "query_capabilities: mfxExtVideoSignalInfo check"
" failed (0x%"PRIX32", 0x%"PRIX32", %d)\n",
info->codec_id, info->implementation, status);
}
@@ -539,7 +657,7 @@ static int query_capabilities(mfxSession session, mfxVersion version, hb_qsv_inf
* about it - however, it may fail for other encoders (ignore)
*/
fprintf(stderr,
- "hb_qsv_info_init: mfxExtCodingOption check"
+ "query_capabilities: mfxExtCodingOption check"
" failed (0x%"PRIX32", 0x%"PRIX32", %d)\n",
info->codec_id, info->implementation, status);
}
@@ -588,16 +706,16 @@ static int query_capabilities(mfxSession session, mfxVersion version, hb_qsv_inf
* - MBBRC requires G3 hardware (Haswell or equivalent)
* - ExtBRC requires G2 hardware (Ivy Bridge or equivalent)
*/
- if (qsv_implementation_is_hardware(info->implementation) &&
- qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G3)
+ if (hb_qsv_implementation_is_hardware(info->implementation) &&
+ hb_qsv_hardware_generation(hb_qsv_get_platform(index)) >= QSV_G3)
{
if (extCodingOption2.MBBRC)
{
info->capabilities |= HB_QSV_CAP_OPTION2_MBBRC;
}
}
- if (qsv_implementation_is_hardware(info->implementation) &&
- qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G2)
+ if (hb_qsv_implementation_is_hardware(info->implementation) &&
+ hb_qsv_hardware_generation(hb_qsv_get_platform(index)) >= QSV_G2)
{
if (extCodingOption2.ExtBRC)
{
@@ -612,8 +730,8 @@ static int query_capabilities(mfxSession session, mfxVersion version, hb_qsv_inf
*/
if (HB_CHECK_MFX_VERSION(version, 1, 7))
{
- if (qsv_implementation_is_hardware(info->implementation) &&
- qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G3)
+ if (hb_qsv_implementation_is_hardware(info->implementation) &&
+ hb_qsv_hardware_generation(hb_qsv_get_platform(index)) >= QSV_G3)
{
if (extCodingOption2.Trellis)
{
@@ -658,20 +776,20 @@ static int query_capabilities(mfxSession session, mfxVersion version, hb_qsv_inf
else
{
fprintf(stderr,
- "hb_qsv_info_init: mfxExtCodingOption2 check failed (0x%"PRIX32", 0x%"PRIX32", %d)\n",
+ "query_capabilities: mfxExtCodingOption2 check failed (0x%"PRIX32", 0x%"PRIX32", %d)\n",
info->codec_id, info->implementation, status);
}
}
if (HB_CHECK_MFX_VERSION(version, 1, 19))
{
- if (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G7)
+ if (hb_qsv_hardware_generation(hb_qsv_get_platform(index)) >= QSV_G7)
{
info->capabilities |= HB_QSV_CAP_VPP_SCALING;
}
}
if (HB_CHECK_MFX_VERSION(version, 1, 33))
{
- if (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G7)
+ if (hb_qsv_hardware_generation(hb_qsv_get_platform(index)) >= QSV_G7)
{
info->capabilities |= HB_QSV_CAP_VPP_INTERPOLATION;
}
@@ -692,124 +810,167 @@ hb_display_t * hb_qsv_display_init(void)
return hb_display_init(DRM_INTEL_DRIVER_NAME, VA_INTEL_DRIVER_NAMES);
}
-#if !defined(SYS_LINUX) && !defined(SYS_FREEBSD)
-static int hb_qsv_make_adapters_list(const mfxAdaptersInfo* adapters_info, hb_list_t **qsv_adapters_list);
+#if defined(_WIN32) || defined(__MINGW32__)
static int hb_qsv_query_adapters(mfxAdaptersInfo* adapters_info);
+static int hb_qsv_make_adapters_list(const mfxAdaptersInfo* adapters_info, hb_list_t **qsv_adapters_list);
+static int hb_qsv_make_adapters_details_list(const mfxAdaptersInfo* adapters_info, hb_list_t **hb_qsv_adapter_details_list);
#endif
-int hb_qsv_info_init()
+mfxIMPL hb_qsv_dx_index_to_impl(int dx_index)
{
- static int init_done = 0;
- if (init_done)
- return 0;
- init_done = 1;
+ mfxIMPL impl;
-#if !defined(SYS_LINUX) && !defined(SYS_FREEBSD)
- // Collect the information about qsv adapters
- qsv_adapters_info.Adapters = NULL;
- qsv_adapters_info.NumAlloc = 0;
- qsv_adapters_info.NumActual = 0;
- int err = hb_qsv_query_adapters(&qsv_adapters_info);
- if (!err)
+ switch (dx_index)
{
- hb_qsv_make_adapters_list(&qsv_adapters_info, &qsv_adapters_list);
- }
- else
- {
- hb_error("hb_qsv_info_init: failed to query qsv adapters");
- }
-#endif
- /*
- * First, check for any MSDK version to determine whether one or
- * more implementations are present; then check if we can use them.
- *
- * I've had issues using a NULL version with some combinations of
- * hardware and driver, so use a low version number (1.0) instead.
- */
- mfxSession session;
- mfxVersion version = { .Major = 1, .Minor = 0, };
-#if defined(SYS_LINUX) || defined(SYS_FREEBSD)
- mfxIMPL hw_preference = MFX_IMPL_VIA_ANY;
-#else
- mfxIMPL hw_preference = MFX_IMPL_VIA_D3D11;
-#endif
-
- // check for software fallback
- if (MFXInit(MFX_IMPL_SOFTWARE, &version, &session) == MFX_ERR_NONE)
- {
- // Media SDK software found, but check that our minimum is supported
- MFXQueryVersion(session, &qsv_software_version);
- if (HB_CHECK_MFX_VERSION(qsv_software_version,
- HB_QSV_MINVERSION_MAJOR,
- HB_QSV_MINVERSION_MINOR))
{
- query_capabilities(session, qsv_software_version, &qsv_software_info_avc, &qsv_adapters_info);
- query_capabilities(session, qsv_software_version, &qsv_software_info_hevc, &qsv_adapters_info);
- // now that we know which hardware encoders are
- // available, we can set the preferred implementation
- hb_qsv_impl_set_preferred("software");
+ case 0:
+ impl = MFX_IMPL_HARDWARE;
+ break;
+ case 1:
+ impl = MFX_IMPL_HARDWARE2;
+ break;
+ case 2:
+ impl = MFX_IMPL_HARDWARE3;
+ break;
+ case 3:
+ impl = MFX_IMPL_HARDWARE4;
+ break;
+
+ default:
+ // try searching on all display adapters
+ impl = MFX_IMPL_HARDWARE_ANY;
+ break;
}
- MFXClose(session);
}
+ return impl;
+}
- // check for actual hardware support
- do{
- if (MFXInit(MFX_IMPL_HARDWARE_ANY | hw_preference, &version, &session) == MFX_ERR_NONE)
- {
- // On linux, the handle to the VA display must be set.
- // This code is essentiall a NOP other platforms.
- hb_display_t * display = hb_qsv_display_init();
-
- if (display != NULL)
- {
- MFXVideoCORE_SetHandle(session, display->mfxType,
- (mfxHDL)display->handle);
- }
- // Media SDK hardware found, but check that our minimum is supported
- //
- // Note: this-party hardware (QSV_G0) is unsupported for the time being
- MFXQueryVersion(session, &qsv_hardware_version);
- if (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G1 &&
- HB_CHECK_MFX_VERSION(qsv_hardware_version,
- HB_QSV_MINVERSION_MAJOR,
- HB_QSV_MINVERSION_MINOR))
+static int hb_qsv_collect_adapters_details(hb_list_t *qsv_adapters_list, hb_list_t *hb_qsv_adapter_details_list)
+{
+ for (int i = 0; i < hb_list_count(hb_qsv_adapter_details_list); i++)
+ {
+ int *dx_index = (int *)hb_list_item(qsv_adapters_list, i);
+ hb_qsv_adapter_details_t *details = hb_list_item(hb_qsv_adapter_details_list, i);
+ details->index = *dx_index;
+ /*
+ * First, check for any MSDK version to determine whether one or
+ * more implementations are present; then check if we can use them.
+ *
+ * I've had issues using a NULL version with some combinations of
+ * hardware and driver, so use a low version number (1.0) instead.
+ */
+ mfxSession session;
+ mfxVersion version = { .Major = 1, .Minor = 0, };
+#if defined(_WIN32) || defined(__MINGW32__)
+ mfxIMPL hw_preference = MFX_IMPL_VIA_D3D11;
+#else
+ mfxIMPL hw_preference = MFX_IMPL_VIA_ANY;
+#endif
+ // check for software fallback
+ if (MFXInit(MFX_IMPL_SOFTWARE, &version, &session) == MFX_ERR_NONE)
+ {
+ // Media SDK software found, but check that our minimum is supported
+ MFXQueryVersion(session, &details->qsv_software_version);
+ if (HB_CHECK_MFX_VERSION(details->qsv_software_version,
+ HB_QSV_MINVERSION_MAJOR,
+ HB_QSV_MINVERSION_MINOR))
{
- query_capabilities(session, qsv_hardware_version, &qsv_hardware_info_avc, &qsv_adapters_info);
- qsv_hardware_info_avc.implementation = MFX_IMPL_HARDWARE_ANY | hw_preference;
- query_capabilities(session, qsv_hardware_version, &qsv_hardware_info_hevc, &qsv_adapters_info);
- qsv_hardware_info_hevc.implementation = MFX_IMPL_HARDWARE_ANY | hw_preference;
+ query_capabilities(session, details->index, details->qsv_software_version, &details->qsv_software_info_avc);
+ query_capabilities(session, details->index, details->qsv_software_version, &details->qsv_software_info_hevc);
// now that we know which hardware encoders are
// available, we can set the preferred implementation
- hb_qsv_impl_set_preferred("hardware");
+ qsv_impl_set_preferred(details, "software");
}
- hb_display_close(&display);
MFXClose(session);
- hw_preference = 0;
}
- else
- {
-#if !defined(SYS_LINUX) && !defined(SYS_FREEBSD)
- // Windows only: After D3D11 we will try D3D9
- if (hw_preference == MFX_IMPL_VIA_D3D11)
- hw_preference = MFX_IMPL_VIA_D3D9;
+ // check for actual hardware support
+ do{
+ if (MFXInit(hb_qsv_dx_index_to_impl(*dx_index) | hw_preference, &version, &session) == MFX_ERR_NONE)
+ {
+ // On linux, the handle to the VA display must be set.
+ // This code is essentiall a NOP other platforms.
+ hb_display_t * display = hb_qsv_display_init();
+
+ if (display != NULL)
+ {
+ MFXVideoCORE_SetHandle(session, display->mfxType,
+ (mfxHDL)display->handle);
+ }
+ // Media SDK hardware found, but check that our minimum is supported
+ //
+ // Note: this-party hardware (QSV_G0) is unsupported for the time being
+ MFXQueryVersion(session, &details->qsv_hardware_version);
+ if (hb_qsv_hardware_generation(hb_qsv_get_platform(*dx_index)) >= QSV_G1 &&
+ HB_CHECK_MFX_VERSION(details->qsv_hardware_version,
+ HB_QSV_MINVERSION_MAJOR,
+ HB_QSV_MINVERSION_MINOR))
+ {
+ query_capabilities(session, details->index, details->qsv_hardware_version, &details->qsv_hardware_info_avc);
+ details->qsv_hardware_info_avc.implementation = hb_qsv_dx_index_to_impl(*dx_index) | hw_preference;
+ query_capabilities(session, details->index, details->qsv_hardware_version, &details->qsv_hardware_info_hevc);
+ details->qsv_hardware_info_hevc.implementation = hb_qsv_dx_index_to_impl(*dx_index) | hw_preference;
+ // now that we know which hardware encoders are
+ // available, we can set the preferred implementation
+ qsv_impl_set_preferred(details, "hardware");
+ }
+ hb_display_close(&display);
+ MFXClose(session);
+ hw_preference = 0;
+ }
else
+ {
+#if defined(_WIN32) || defined(__MINGW32__)
+ // Windows only: After D3D11 we will try D3D9
+ if (hw_preference == MFX_IMPL_VIA_D3D11)
+ hw_preference = MFX_IMPL_VIA_D3D9;
+ else
#endif
- hw_preference = 0;
+ hw_preference = 0;
+ }
}
+ while(hw_preference != 0);
}
- while(hw_preference != 0);
-
- // success
return 0;
}
-static void log_capabilities(int log_level, uint64_t caps, const char *prefix)
+static void log_decoder_capabilities(int log_level, hb_qsv_adapter_details_t *adapter_details, const char *prefix)
+{
+ char buffer[128] = "";
+
+ if (hb_qsv_decode_h264_is_supported(adapter_details->index))
+ {
+ strcat(buffer, " h264");
+ }
+
+ if (hb_qsv_decode_h265_10_bit_is_supported(adapter_details->index))
+ {
+ strcat(buffer, " hevc (8bit: yes, 10bit: yes)");
+ }
+ else if (hb_qsv_decode_h265_is_supported(adapter_details->index))
+ {
+ strcat(buffer, " hevc (8bit: yes, 10bit: no)");
+ }
+
+ if (hb_qsv_decode_av1_is_supported(adapter_details->index))
+ {
+ strcat(buffer, " av1 (8bit: yes, 10bit: yes)");
+ }
+
+ hb_deep_log(log_level, "%s%s", prefix,
+ strnlen(buffer, 1) ? buffer : " no decode support");
+}
+
+static void log_encoder_capabilities(int log_level, uint64_t caps, const char *prefix)
{
/*
* Note: keep the string short, as it may be logged by default.
*/
char buffer[128] = "";
+ if (caps & HB_QSV_CAP_LOWPOWER_ENCODE)
+ {
+ strcat(buffer, " lowpower");
+ }
/* B-Pyramid, with or without direct control (BRefType) */
if (caps & HB_QSV_CAP_B_REF_PYRAMID)
{
@@ -885,19 +1046,81 @@ static void log_capabilities(int log_level, uint64_t caps, const char *prefix)
strnlen(buffer, 1) ? buffer : " standard feature set");
}
+static void hb_qsv_adapter_info_print(hb_qsv_adapter_details_t *adapter_details)
+{
+ if (adapter_details->qsv_hardware_version.Version)
+ {
+ hb_log(" - Intel Media SDK hardware: API %"PRIu16".%"PRIu16" (minimum: %"PRIu16".%"PRIu16")",
+ adapter_details->qsv_hardware_version.Major, adapter_details->qsv_hardware_version.Minor,
+ HB_QSV_MINVERSION_MAJOR, HB_QSV_MINVERSION_MINOR);
+ }
+
+ if (adapter_details->qsv_software_version.Version)
+ {
+ hb_deep_log(3, " - Intel Media SDK software: API %"PRIu16".%"PRIu16" (minimum: %"PRIu16".%"PRIu16")",
+ adapter_details->qsv_software_version.Major, adapter_details->qsv_software_version.Minor,
+ HB_QSV_MINVERSION_MAJOR, HB_QSV_MINVERSION_MINOR);
+ }
+
+ log_decoder_capabilities(1, adapter_details, " - Decode support: ");
+
+ if (adapter_details->hb_qsv_info_avc != NULL && adapter_details->hb_qsv_info_avc->available)
+ {
+ hb_log(" - H.264 encoder: yes");
+ hb_log(" - preferred implementation: %s %s",
+ hb_qsv_impl_get_name(adapter_details->hb_qsv_info_avc->implementation),
+ hb_qsv_impl_get_via_name(adapter_details->hb_qsv_info_avc->implementation));
+ if (adapter_details->qsv_hardware_info_avc.available)
+ {
+ log_encoder_capabilities(1, adapter_details->qsv_hardware_info_avc.capabilities,
+ " - capabilities (hardware): ");
+ }
+ if (adapter_details->qsv_software_info_avc.available)
+ {
+ log_encoder_capabilities(3, adapter_details->qsv_software_info_avc.capabilities,
+ " - capabilities (software): ");
+ }
+ }
+ else
+ {
+ hb_log(" - H.264 encoder: no");
+ }
+ if (adapter_details->hb_qsv_info_hevc != NULL && adapter_details->hb_qsv_info_hevc->available)
+ {
+ 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" );
+ hb_log(" - preferred implementation: %s %s",
+ hb_qsv_impl_get_name(adapter_details->hb_qsv_info_hevc->implementation),
+ hb_qsv_impl_get_via_name(adapter_details->hb_qsv_info_hevc->implementation));
+ if (adapter_details->qsv_hardware_info_hevc.available)
+ {
+ log_encoder_capabilities(1, adapter_details->qsv_hardware_info_hevc.capabilities,
+ " - capabilities (hardware): ");
+ }
+ if (adapter_details->qsv_software_info_hevc.available)
+ {
+ log_encoder_capabilities(3, adapter_details->qsv_software_info_hevc.capabilities,
+ " - capabilities (software): ");
+ }
+ }
+ else
+ {
+ hb_log(" - H.265 encoder: no");
+ }
+}
+
void hb_qsv_info_print()
{
// is QSV available and usable?
if (hb_qsv_available())
{
-#if !defined(SYS_LINUX) && !defined(SYS_FREEBSD)
- if (qsv_adapters_list && hb_list_count(qsv_adapters_list))
+#if defined(_WIN32) || defined(__MINGW32__)
+ if (g_qsv_adapters_list && hb_list_count(g_qsv_adapters_list))
{
char gpu_list_str[256] = "";
- for (int i = 0; i < hb_list_count(qsv_adapters_list); i++)
+ for (int i = 0; i < hb_list_count(g_qsv_adapters_list); i++)
{
char value_str[256];
- int *value = hb_list_item(qsv_adapters_list, i);
+ int *value = hb_list_item(g_qsv_adapters_list, i);
sprintf(value_str, "%d", *value);
if (i > 0)
strcat(gpu_list_str, ", ");
@@ -910,62 +1133,15 @@ void hb_qsv_info_print()
{
hb_log("Intel Quick Sync Video support: yes");
}
- // also print the details
- if (qsv_hardware_version.Version)
- {
- hb_log(" - Intel Media SDK hardware: API %"PRIu16".%"PRIu16" (minimum: %"PRIu16".%"PRIu16")",
- qsv_hardware_version.Major, qsv_hardware_version.Minor,
- HB_QSV_MINVERSION_MAJOR, HB_QSV_MINVERSION_MINOR);
- }
-
- if (qsv_software_version.Version)
- {
- hb_log(" - Intel Media SDK software: API %"PRIu16".%"PRIu16" (minimum: %"PRIu16".%"PRIu16")",
- qsv_software_version.Major, qsv_software_version.Minor,
- HB_QSV_MINVERSION_MAJOR, HB_QSV_MINVERSION_MINOR);
- }
-
- if (hb_qsv_info_avc != NULL && hb_qsv_info_avc->available)
- {
- hb_log(" - H.264 encoder: yes");
- hb_log(" - preferred implementation: %s %s",
- hb_qsv_impl_get_name(hb_qsv_info_avc->implementation),
- hb_qsv_impl_get_via_name(hb_qsv_info_avc->implementation));
- if (qsv_hardware_info_avc.available)
- {
- log_capabilities(1, qsv_hardware_info_avc.capabilities,
- " - capabilities (hardware): ");
- }
- if (qsv_software_info_avc.available)
- {
- log_capabilities(1, qsv_software_info_avc.capabilities,
- " - capabilities (software): ");
- }
- }
- else
- {
- hb_log(" - H.264 encoder: no");
- }
- if (hb_qsv_info_hevc != NULL && hb_qsv_info_hevc->available)
+ // also print the details about all QSV adapters
+ for (int i = 0; i < hb_list_count(g_qsv_adapters_details_list); i++)
{
- hb_log(" - H.265 encoder: yes (8bit: yes, 10bit: %s)", (qsv_hardware_generation(hb_get_cpu_platform()) < QSV_G6) ? "no" : "yes" );
- hb_log(" - preferred implementation: %s %s",
- hb_qsv_impl_get_name(hb_qsv_info_hevc->implementation),
- hb_qsv_impl_get_via_name(hb_qsv_info_hevc->implementation));
- if (qsv_hardware_info_hevc.available)
- {
- log_capabilities(1, qsv_hardware_info_hevc.capabilities,
- " - capabilities (hardware): ");
- }
- if (qsv_software_info_hevc.available)
- {
- log_capabilities(1, qsv_software_info_hevc.capabilities,
- " - capabilities (software): ");
- }
- }
- else
- {
- hb_log(" - H.265 encoder: no");
+ hb_qsv_adapter_details_t *details = hb_list_item(g_qsv_adapters_details_list, i);
+#if defined(_WIN32) || defined(__MINGW32__)
+ mfxAdapterInfo* info = &g_qsv_adapters_info.Adapters[i];
+ hb_log("Intel Quick Sync Video %s adapter with index %d", hb_qsv_get_adapter_type(info), details->index);
+#endif
+ hb_qsv_adapter_info_print(details);
}
}
else
@@ -974,21 +1150,27 @@ void hb_qsv_info_print()
}
}
-hb_qsv_info_t* hb_qsv_info_get(int encoder)
+hb_qsv_info_t* hb_qsv_encoder_info_get(int adapter_index, int encoder)
{
- switch (encoder)
+ hb_qsv_adapter_details_t* details = hb_qsv_get_adapters_details_by_index(adapter_index);
+
+ if (details)
{
- case HB_VCODEC_QSV_H264:
- return hb_qsv_info_avc;
- case HB_VCODEC_QSV_H265_10BIT:
- case HB_VCODEC_QSV_H265:
- return hb_qsv_info_hevc;
- default:
- return NULL;
+ switch (encoder)
+ {
+ case HB_VCODEC_QSV_H264:
+ return details->hb_qsv_info_avc;
+ case HB_VCODEC_QSV_H265_10BIT:
+ case HB_VCODEC_QSV_H265:
+ return details->hb_qsv_info_hevc;
+ default:
+ return NULL;
+ }
}
+ return NULL;
}
-hb_list_t* hb_qsv_load_plugins(hb_qsv_info_t *info, mfxSession session, mfxVersion version)
+hb_list_t* hb_qsv_load_plugins(int index, hb_qsv_info_t *info, mfxSession session, mfxVersion version)
{
hb_list_t *mfxPluginList = hb_list_init();
if (mfxPluginList == NULL)
@@ -999,10 +1181,10 @@ hb_list_t* hb_qsv_load_plugins(hb_qsv_info_t *info, mfxSession session, mfxVersi
if (HB_CHECK_MFX_VERSION(version, 1, 8))
{
- if (info->codec_id == MFX_CODEC_HEVC && !(qsv_hardware_generation(hb_get_cpu_platform()) < QSV_G5))
+ if (info->codec_id == MFX_CODEC_HEVC && !(hb_qsv_hardware_generation(hb_qsv_get_platform(index)) < QSV_G5))
{
if (HB_CHECK_MFX_VERSION(version, 1, 15) &&
- qsv_implementation_is_hardware(info->implementation))
+ hb_qsv_implementation_is_hardware(info->implementation))
{
if (MFXVideoUSER_Load(session, &MFX_PLUGINID_HEVCE_HW, 0) == MFX_ERR_NONE)
{
@@ -1065,12 +1247,91 @@ const char* hb_qsv_decode_get_codec_name(enum AVCodecID codec_id)
}
}
+int hb_qsv_decode_h264_is_supported(int adapter_index)
+{
+ return hb_qsv_hardware_generation(hb_qsv_get_platform(adapter_index)) >= QSV_G1;
+}
+
+int hb_qsv_decode_h265_is_supported(int adapter_index)
+{
+ return hb_qsv_hardware_generation(hb_qsv_get_platform(adapter_index)) >= QSV_G5;
+}
+
+int hb_qsv_decode_h265_10_bit_is_supported(int adapter_index)
+{
+ return hb_qsv_hardware_generation(hb_qsv_get_platform(adapter_index)) >= QSV_G6;
+}
+
+int hb_qsv_decode_av1_is_supported(int adapter_index)
+{
+ return hb_qsv_hardware_generation(hb_qsv_get_platform(adapter_index)) >= QSV_G8;
+}
+
+int hb_qsv_decode_codec_supported_codec(int adapter_index, int video_codec_param, int pix_fmt)
+{
+ switch (video_codec_param)
+ {
+ case AV_CODEC_ID_H264:
+ if (pix_fmt == AV_PIX_FMT_NV12 ||
+ pix_fmt == AV_PIX_FMT_YUV420P ||
+ pix_fmt == AV_PIX_FMT_YUVJ420P ||
+ pix_fmt == AV_PIX_FMT_YUV420P10LE)
+ {
+ return hb_qsv_decode_h264_is_supported(adapter_index);
+ }
+ break;
+ case AV_CODEC_ID_HEVC:
+ if (pix_fmt == AV_PIX_FMT_NV12 ||
+ pix_fmt == AV_PIX_FMT_YUV420P ||
+ pix_fmt == AV_PIX_FMT_YUVJ420P)
+ {
+ return hb_qsv_decode_h265_is_supported(adapter_index);
+ }
+ else if (pix_fmt == AV_PIX_FMT_YUV420P10LE)
+ {
+ return hb_qsv_decode_h265_10_bit_is_supported(adapter_index);
+ }
+ break;
+ case AV_CODEC_ID_AV1:
+ if (pix_fmt == AV_PIX_FMT_NV12 ||
+ pix_fmt == AV_PIX_FMT_YUV420P ||
+ pix_fmt == AV_PIX_FMT_YUVJ420P ||
+ pix_fmt == AV_PIX_FMT_YUV420P10LE)
+ {
+ return hb_qsv_decode_av1_is_supported(adapter_index);
+ }
+ break;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+int hb_qsv_setup_job(hb_job_t *job)
+{
+#if defined(_WIN32) || defined(__MINGW32__)
+ if (job->qsv.ctx->dx_index >= 0)
+ {
+ hb_qsv_param_parse_dx_index(job, job->qsv.ctx->dx_index);
+ }
+ hb_qsv_parse_adapter_index(job);
+#endif
+ int async_depth_default = hb_qsv_param_default_async_depth();
+ if (job->qsv.async_depth <= 0 || job->qsv.async_depth > async_depth_default)
+ {
+ job->qsv.async_depth = async_depth_default;
+ }
+ // Make sure QSV Decode is only True if the selected QSV adapter supports decode.
+ job->qsv.decode = job->qsv.decode && hb_qsv_available();
+ return 0;
+}
+
int hb_qsv_decode_is_enabled(hb_job_t *job)
{
return ((job != NULL && job->qsv.decode) &&
(job->title->video_decode_support & HB_DECODE_SUPPORT_QSV)) &&
- (job->vcodec == HB_VCODEC_QSV_H265 ? (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G5) : 1) &&
- (job->vcodec == HB_VCODEC_QSV_H265_10BIT ? (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G6) : 1);
+ hb_qsv_decode_codec_supported_codec(hb_qsv_get_adapter_index(),
+ job->title->video_codec_param, job->pix_fmt);
}
static int hb_dxva2_device_check();
@@ -1083,7 +1344,7 @@ int hb_qsv_hw_filters_are_enabled(hb_job_t *job)
int hb_qsv_is_enabled(hb_job_t *job)
{
- return hb_qsv_decode_is_enabled(job) || hb_qsv_info_get(job->vcodec);
+ return hb_qsv_decode_is_enabled(job) || hb_qsv_encoder_info_get(hb_qsv_get_adapter_index(), job->vcodec);
}
int hb_qsv_full_path_is_enabled(hb_job_t *job)
@@ -1092,6 +1353,7 @@ int hb_qsv_full_path_is_enabled(hb_job_t *job)
static int device_check_succeded = 0;
int codecs_exceptions = 0;
int qsv_full_path_is_enabled = 0;
+ hb_qsv_info_t *info = hb_qsv_encoder_info_get(hb_qsv_get_adapter_index(), job->vcodec);
if(!device_check_completed)
{
@@ -1102,19 +1364,24 @@ int hb_qsv_full_path_is_enabled(hb_job_t *job)
codecs_exceptions = (job->title->pix_fmt == AV_PIX_FMT_YUV420P10 && job->vcodec == HB_VCODEC_QSV_H264);
qsv_full_path_is_enabled = (hb_qsv_decode_is_enabled(job) &&
- hb_qsv_info_get(job->vcodec) &&
+ info && hb_qsv_implementation_is_hardware(info->implementation) &&
device_check_succeded && !job->qsv.ctx->num_cpu_filters) && !codecs_exceptions;
return qsv_full_path_is_enabled;
}
int hb_qsv_copyframe_is_slow(int encoder)
{
- hb_qsv_info_t *info = hb_qsv_info_get(encoder);
- if (info != NULL && qsv_implementation_is_hardware(info->implementation))
+ hb_qsv_info_t *info = hb_qsv_encoder_info_get(hb_qsv_get_adapter_index(), encoder);
+ if (info != NULL && hb_qsv_implementation_is_hardware(info->implementation))
{
- // we should really check the driver version, but since it's not
- // available, checking the API version is the best we can do :-(
- return !HB_CHECK_MFX_VERSION(qsv_hardware_version, 1, 7);
+ hb_qsv_adapter_details_t* details = hb_qsv_get_adapters_details_by_index(hb_qsv_get_adapter_index());
+ if (details)
+ {
+ // we should really check the driver version, but since it's not
+ // available, checking the API version is the best we can do :-(
+ return !HB_CHECK_MFX_VERSION(details->qsv_hardware_version, 1, 7);
+ }
+ return 0;
}
return 0;
}
@@ -1225,33 +1492,6 @@ float hb_qsv_atof(const char *str, int *err)
return v;
}
-int hb_qsv_param_parse_dx_index(hb_job_t *job, const int dx_index)
-{
- for (int i = 0; i < qsv_adapters_info.NumActual; i++)
- {
- mfxAdapterInfo* info = &qsv_adapters_info.Adapters[i];
- // find DirectX adapter with given index in list of QSV adapters
- // if -1 use first adapter with highest priority
- if (info && ((info->Number == dx_index) || (dx_index == -1)))
- {
- job->qsv.ctx->qsv_device = av_mallocz_array(32, sizeof(*job->qsv.ctx->qsv_device));
- if (!job->qsv.ctx->qsv_device)
- {
- hb_error("hb_qsv_param_parse_dx_index: failed to allocate memory for qsv device");
- return -1;
- }
- sprintf(job->qsv.ctx->qsv_device, "%u", info->Number);
- job->qsv.ctx->dx_index = info->Number;
- hb_log("qsv: %s qsv adapter with index %s has been selected",
- (info->Platform.MediaAdapterType == MFX_MEDIA_INTEGRATED) ? "integrated" :
- (info->Platform.MediaAdapterType == MFX_MEDIA_DISCRETE) ? "discrete" : "unknown", job->qsv.ctx->qsv_device);
- return 0;
- }
- }
- hb_error("qsv: incorrect qsv device index %d", dx_index);
- return -1;
-}
-
int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job,
const char *key, const char *value)
{
@@ -1737,6 +1977,7 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job
return HB_QSV_PARAM_UNSUPPORTED;
}
}
+#if defined(_WIN32) || defined(__MINGW32__)
else if (!strcasecmp(key, "gpu"))
{
// Check if was parsed already in decoder initialization
@@ -1749,6 +1990,7 @@ int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, hb_job_t *job
}
}
}
+#endif
else if (!strcasecmp(key, "scalingmode") ||
!strcasecmp(key, "vpp-sm"))
{
@@ -1815,7 +2057,7 @@ int hb_qsv_profile_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, const char
/* HEVC10 supported starting from KBL/G6 */
if (profile->value == MFX_PROFILE_HEVC_MAIN10 &&
- qsv_hardware_generation(hb_get_cpu_platform()) < QSV_G6)
+ hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) < QSV_G6)
{
hb_log("qsv: HEVC Main10 is not supported on this platform");
profile = NULL;
@@ -1836,7 +2078,7 @@ int hb_qsv_profile_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, const char
else if (((profile_key != NULL && !strcasecmp(profile_key, "auto")) || profile_key == NULL) &&
codec == HB_VCODEC_QSV_H265_10BIT &&
param->videoParam->mfx.CodecId == MFX_CODEC_HEVC &&
- qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G6)
+ hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) >= QSV_G6)
{
profile = &hb_qsv_h265_profiles[1];
param->videoParam->mfx.CodecProfile = profile->value;
@@ -1888,7 +2130,7 @@ int hb_qsv_level_parse(hb_qsv_param_t *param, hb_qsv_info_t *info, const char *l
const char* const* hb_qsv_preset_get_names()
{
- if (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G3)
+ if (hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) >= QSV_G3)
{
return hb_qsv_preset_names2;
}
@@ -1930,19 +2172,23 @@ const char* const* hb_qsv_level_get_names(int encoder)
const char* hb_qsv_video_quality_get_name(uint32_t codec)
{
uint64_t caps = 0;
- switch (codec)
+ hb_qsv_adapter_details_t* details = hb_qsv_get_adapters_details_by_index(hb_qsv_get_adapter_index());
+ if (details)
{
- case HB_VCODEC_QSV_H264:
- if (hb_qsv_info_avc != NULL) caps = hb_qsv_info_avc->capabilities;
- break;
+ switch (codec)
+ {
+ case HB_VCODEC_QSV_H264:
+ if (details->hb_qsv_info_avc != NULL) caps = details->hb_qsv_info_avc->capabilities;
+ break;
- case HB_VCODEC_QSV_H265_10BIT:
- case HB_VCODEC_QSV_H265:
- if (hb_qsv_info_hevc != NULL) caps = hb_qsv_info_hevc->capabilities;
- break;
+ case HB_VCODEC_QSV_H265_10BIT:
+ case HB_VCODEC_QSV_H265:
+ if (details->hb_qsv_info_hevc != NULL) caps = details->hb_qsv_info_hevc->capabilities;
+ break;
- default:
- break;
+ default:
+ break;
+ }
}
return (caps & HB_QSV_CAP_RATECONTROL_ICQ) ? "ICQ" : "QP";
}
@@ -1951,25 +2197,29 @@ void hb_qsv_video_quality_get_limits(uint32_t codec, float *low, float *high,
float *granularity, int *direction)
{
uint64_t caps = 0;
- switch (codec)
- {
- case HB_VCODEC_QSV_H265_10BIT:
- case HB_VCODEC_QSV_H265:
- if (hb_qsv_info_hevc != NULL) caps = hb_qsv_info_hevc->capabilities;
- *direction = 1;
- *granularity = 1.;
- *low = (caps & HB_QSV_CAP_RATECONTROL_ICQ) ? 1. : 0.;
- *high = 51.;
- break;
+ hb_qsv_adapter_details_t* details = hb_qsv_get_adapters_details_by_index(hb_qsv_get_adapter_index());
+ if (details)
+ {
+ switch (codec)
+ {
+ case HB_VCODEC_QSV_H265_10BIT:
+ case HB_VCODEC_QSV_H265:
+ if (details->hb_qsv_info_hevc != NULL) caps = details->hb_qsv_info_hevc->capabilities;
+ *direction = 1;
+ *granularity = 1.;
+ *low = (caps & HB_QSV_CAP_RATECONTROL_ICQ) ? 1. : 0.;
+ *high = 51.;
+ break;
- case HB_VCODEC_QSV_H264:
- default:
- if (hb_qsv_info_avc != NULL) caps = hb_qsv_info_avc->capabilities;
- *direction = 1;
- *granularity = 1.;
- *low = (caps & HB_QSV_CAP_RATECONTROL_ICQ) ? 1. : 0.;
- *high = 51.;
- break;
+ case HB_VCODEC_QSV_H264:
+ default:
+ if (details->hb_qsv_info_avc != NULL) caps = details->hb_qsv_info_avc->capabilities;
+ *direction = 1;
+ *granularity = 1.;
+ *low = (caps & HB_QSV_CAP_RATECONTROL_ICQ) ? 1. : 0.;
+ *high = 51.;
+ break;
+ }
}
}
@@ -1987,7 +2237,7 @@ int hb_qsv_param_default_preset(hb_qsv_param_t *param,
}
else
{
- hb_error("hb_qsv_param_default_preset: invalid pointer(s)");
+ hb_error("hb_qsv_param_default_preset: invalid pointer(s) param=%p videoParam=%p info=%p preset=%p", param, videoParam, info, preset);
return -1;
}
if (preset != NULL && preset[0] != '\0')
@@ -2021,7 +2271,7 @@ int hb_qsv_param_default_preset(hb_qsv_param_t *param,
* LookAhead: 0 (off)
* LookAheadDepth: Not Applicable
*/
- if (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G3)
+ if (hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) >= QSV_G3)
{
param->rc.lookahead = 0;
param->videoParam->mfx.NumRefFrame = 1;
@@ -2046,14 +2296,14 @@ int hb_qsv_param_default_preset(hb_qsv_param_t *param,
}
else if (!strcasecmp(preset, "speed"))
{
- if (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G7)
+ if (hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) >= QSV_G7)
{
// Since IceLake only
param->rc.lookahead = 0;
param->videoParam->mfx.NumRefFrame = 1;
param->videoParam->mfx.TargetUsage = MFX_TARGETUSAGE_7;
}
- else if (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G3)
+ else if (hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) >= QSV_G3)
{
/*
* HSW TargetUsage: 6
@@ -2101,7 +2351,7 @@ int hb_qsv_param_default_preset(hb_qsv_param_t *param,
int hb_qsv_param_default_async_depth()
{
- return qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G7 ? 6 : HB_QSV_ASYNC_DEPTH_DEFAULT;
+ return hb_qsv_hardware_generation(hb_qsv_get_platform(hb_qsv_get_adapter_index())) >= QSV_G7 ? 6 : HB_QSV_ASYNC_DEPTH_DEFAULT;
}
int hb_qsv_param_default(hb_qsv_param_t *param, mfxVideoParam *videoParam,
@@ -2389,39 +2639,6 @@ uint8_t hb_qsv_frametype_xlat(uint16_t qsv_frametype, uint16_t *out_flags)
return frametype;
}
-int hb_qsv_impl_set_preferred(const char *name)
-{
- if (name == NULL)
- {
- return -1;
- }
- if (!strcasecmp(name, "software"))
- {
- if (qsv_software_info_avc.available)
- {
- hb_qsv_info_avc = &qsv_software_info_avc;
- }
- if (qsv_software_info_hevc.available)
- {
- hb_qsv_info_hevc = &qsv_software_info_hevc;
- }
- return 0;
- }
- if (!strcasecmp(name, "hardware"))
- {
- if (qsv_hardware_info_avc.available)
- {
- hb_qsv_info_avc = &qsv_hardware_info_avc;
- }
- if (qsv_hardware_info_hevc.available)
- {
- hb_qsv_info_hevc = &qsv_hardware_info_hevc;
- }
- return 0;
- }
- return -1;
-}
-
const char* hb_qsv_impl_get_name(int impl)
{
switch (MFX_IMPL_BASETYPE(impl))
@@ -2466,10 +2683,14 @@ const char* hb_qsv_impl_get_via_name(int impl)
void hb_qsv_force_workarounds()
{
#define FORCE_WORKAROUNDS ~(HB_QSV_CAP_OPTION2_BREFTYPE)
- qsv_software_info_avc.capabilities &= FORCE_WORKAROUNDS;
- qsv_hardware_info_avc.capabilities &= FORCE_WORKAROUNDS;
- qsv_software_info_hevc.capabilities &= FORCE_WORKAROUNDS;
- qsv_hardware_info_hevc.capabilities &= FORCE_WORKAROUNDS;
+ hb_qsv_adapter_details_t* details = hb_qsv_get_adapters_details_by_index(hb_qsv_get_adapter_index());
+ if (details)
+ {
+ details->qsv_software_info_avc.capabilities &= FORCE_WORKAROUNDS;
+ details->qsv_hardware_info_avc.capabilities &= FORCE_WORKAROUNDS;
+ details->qsv_software_info_hevc.capabilities &= FORCE_WORKAROUNDS;
+ details->qsv_hardware_info_hevc.capabilities &= FORCE_WORKAROUNDS;
+ }
#undef FORCE_WORKAROUNDS
}
@@ -2494,6 +2715,164 @@ typedef IDirect3D9* WINAPI pDirect3DCreate9(UINT);
typedef HRESULT WINAPI pDirect3DCreate9Ex(UINT, IDirect3D9Ex **);
typedef HRESULT(WINAPI *HB_PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory);
+int hb_qsv_info_init()
+{
+ // Collect the information about qsv adapters
+ g_qsv_adapters_info.Adapters = NULL;
+ g_qsv_adapters_info.NumAlloc = 0;
+ g_qsv_adapters_info.NumActual = 0;
+ int err = hb_qsv_query_adapters(&g_qsv_adapters_info);
+ if (err)
+ {
+ hb_error("hb_qsv_info_init: failed to query qsv adapters");
+ return -1;
+ }
+ hb_qsv_make_adapters_list(&g_qsv_adapters_info, &g_qsv_adapters_list);
+ hb_qsv_make_adapters_details_list(&g_qsv_adapters_info, &g_qsv_adapters_details_list);
+ hb_qsv_collect_adapters_details(g_qsv_adapters_list, g_qsv_adapters_details_list);
+ return 0;
+}
+
+int hb_qsv_set_adapter_index(int adapter_index)
+{
+ for (int i = 0; i < g_qsv_adapters_info.NumActual; i++)
+ {
+ mfxAdapterInfo* info = &g_qsv_adapters_info.Adapters[i];
+ if (info && (info->Number == adapter_index))
+ {
+ g_adapter_index = adapter_index;
+ return 0;
+ }
+ }
+ hb_error("hb_qsv_set_adapter_index: incorrect qsv device index %d", adapter_index);
+ return -1;
+}
+
+int qsv_map_mfx_platform_codename(int mfx_platform_codename)
+{
+ int platform = HB_CPU_PLATFORM_UNSPECIFIED;
+
+ switch (mfx_platform_codename)
+ {
+ case MFX_PLATFORM_SANDYBRIDGE:
+ platform = HB_CPU_PLATFORM_INTEL_SNB;
+ break;
+ case MFX_PLATFORM_IVYBRIDGE:
+ platform = HB_CPU_PLATFORM_INTEL_IVB;
+ break;
+ case MFX_PLATFORM_HASWELL:
+ platform = HB_CPU_PLATFORM_INTEL_HSW;
+ break;
+ case MFX_PLATFORM_BAYTRAIL:
+ case MFX_PLATFORM_BROADWELL:
+ platform = HB_CPU_PLATFORM_INTEL_BDW;
+ break;
+ case MFX_PLATFORM_CHERRYTRAIL:
+ platform = HB_CPU_PLATFORM_INTEL_CHT;
+ break;
+ case MFX_PLATFORM_SKYLAKE:
+ platform = HB_CPU_PLATFORM_INTEL_SKL;
+ break;
+ case MFX_PLATFORM_APOLLOLAKE:
+ case MFX_PLATFORM_KABYLAKE:
+ platform = HB_CPU_PLATFORM_INTEL_KBL;
+ break;
+#if (MFX_VERSION >= 1025)
+ case MFX_PLATFORM_GEMINILAKE:
+ case MFX_PLATFORM_COFFEELAKE:
+ case MFX_PLATFORM_CANNONLAKE:
+ platform = HB_CPU_PLATFORM_INTEL_KBL;
+ break;
+#endif
+#if (MFX_VERSION >= 1027)
+ case MFX_PLATFORM_ICELAKE:
+ platform = HB_CPU_PLATFORM_INTEL_ICL;
+ break;
+#endif
+#if (MFX_VERSION >= 1031)
+ case MFX_PLATFORM_ELKHARTLAKE:
+ case MFX_PLATFORM_JASPERLAKE:
+ case MFX_PLATFORM_TIGERLAKE:
+ platform = HB_CPU_PLATFORM_INTEL_TGL;
+ break;
+ // TODO: update mfx_dispatch to add MFX_PLATFORM_ALDERLAKE_S
+ // case MFX_PLATFORM_ALDERLAKE_S:
+ // platform = HB_CPU_PLATFORM_INTEL_TGL;
+ // break;
+#endif
+ default:
+ platform = HB_CPU_PLATFORM_UNSPECIFIED;
+ }
+ return platform;
+}
+
+static void hb_qsv_free_adapters_details()
+{
+ for (int i = 0; i < hb_list_count(g_qsv_adapters_details_list); i++)
+ {
+ hb_qsv_adapter_details_t *details = hb_list_item(g_qsv_adapters_details_list, i);
+ if (details->index)
+ {
+ av_free(details);
+ }
+ }
+}
+
+static const char* hb_qsv_get_adapter_type(const mfxAdapterInfo* info)
+{
+ if (info)
+ {
+ return (info->Platform.MediaAdapterType == MFX_MEDIA_INTEGRATED) ? "integrated" :
+ (info->Platform.MediaAdapterType == MFX_MEDIA_DISCRETE) ? "discrete" : "unknown";
+ }
+ return NULL;
+}
+
+int hb_qsv_get_platform(int adapter_index)
+{
+ for (int i = 0; i < g_qsv_adapters_info.NumActual; i++)
+ {
+ mfxAdapterInfo* info = &g_qsv_adapters_info.Adapters[i];
+ // find DirectX adapter with given index in list of QSV adapters
+ // if -1 use first adapter with highest priority
+ if (info && ((info->Number == adapter_index) || (adapter_index == -1)))
+ {
+ return qsv_map_mfx_platform_codename(info->Platform.CodeName);
+ }
+ }
+ hb_error("qsv: incorrect qsv device index %d", adapter_index);
+ return HB_CPU_PLATFORM_UNSPECIFIED;
+}
+
+int hb_qsv_param_parse_dx_index(hb_job_t *job, const int dx_index)
+{
+ for (int i = 0; i < g_qsv_adapters_info.NumActual; i++)
+ {
+ mfxAdapterInfo* info = &g_qsv_adapters_info.Adapters[i];
+ // find DirectX adapter with given index in list of QSV adapters
+ // if -1 use first adapter with highest priority
+ if (info && ((info->Number == dx_index) || (dx_index == -1)))
+ {
+ if (!job->qsv.ctx->qsv_device)
+ {
+ job->qsv.ctx->qsv_device = av_mallocz_array(32, sizeof(*job->qsv.ctx->qsv_device));
+ if (!job->qsv.ctx->qsv_device)
+ {
+ hb_error("hb_qsv_param_parse_dx_index: failed to allocate memory for qsv device");
+ return -1;
+ }
+ }
+ sprintf(job->qsv.ctx->qsv_device, "%u", info->Number);
+ job->qsv.ctx->dx_index = info->Number;
+ hb_log("qsv: %s qsv adapter with index %s has been selected", hb_qsv_get_adapter_type(info), job->qsv.ctx->qsv_device);
+ hb_qsv_set_adapter_index(info->Number);
+ return 0;
+ }
+ }
+ hb_error("qsv: incorrect qsv device index %d", dx_index);
+ return -1;
+}
+
static int hb_dxva2_device_create9(HMODULE d3dlib, UINT adapter, IDirect3D9 **d3d9_out)
{
pDirect3DCreate9 *createD3D = (pDirect3DCreate9 *)hb_dlsym(d3dlib, "Direct3DCreate9");
@@ -2938,6 +3317,8 @@ static int hb_qsv_get_dx_device(hb_job_t *job)
static int hb_qsv_make_adapters_list(const mfxAdaptersInfo* adapters_info, hb_list_t **qsv_adapters_list)
{
+ int max_generation = QSV_G0;
+
if (!qsv_adapters_list)
{
hb_error("hb_qsv_make_adapters_list: destination pointer is NULL");
@@ -2959,6 +3340,13 @@ static int hb_qsv_make_adapters_list(const mfxAdaptersInfo* adapters_info, hb_li
mfxAdapterInfo* info = &adapters_info->Adapters[i];
if (info)
{
+ int generation = hb_qsv_hardware_generation(qsv_map_mfx_platform_codename(info->Platform.CodeName));
+ // select default QSV adapter
+ if (generation > max_generation || info->Platform.MediaAdapterType == MFX_MEDIA_DISCRETE)
+ {
+ max_generation = generation;
+ hb_qsv_set_adapter_index(info->Number);
+ }
hb_list_add(list, (void*)&info->Number);
}
}
@@ -2966,6 +3354,38 @@ static int hb_qsv_make_adapters_list(const mfxAdaptersInfo* adapters_info, hb_li
return 0;
}
+static int hb_qsv_make_adapters_details_list(const mfxAdaptersInfo* adapters_info, hb_list_t **hb_qsv_adapters_details_list)
+{
+ if (*hb_qsv_adapters_details_list)
+ {
+ hb_error("hb_qsv_make_adapters_details_list: hb_qsv_adapter_details_list is allocated already");
+ return -1;
+ }
+ hb_list_t *list = hb_list_init();
+ if (list == NULL)
+ {
+ hb_error("hb_qsv_make_adapters_details_list: hb_list_init() failed");
+ return -1;
+ }
+ for (int i = 0; i < adapters_info->NumActual; i++)
+ {
+ mfxAdapterInfo* info = &adapters_info->Adapters[i];
+ if (info)
+ {
+ hb_qsv_adapter_details_t* adapter_details = av_mallocz(sizeof(hb_qsv_adapter_details_t));
+ if (!adapter_details)
+ {
+ hb_error("hb_qsv_make_adapters_details_list: adapter_details allocation failed");
+ return -1;
+ }
+ init_adapter_details(adapter_details);
+ hb_list_add(list, (void*)adapter_details);
+ }
+ }
+ *hb_qsv_adapters_details_list = list;
+ return 0;
+}
+
static int hb_qsv_query_adapters(mfxAdaptersInfo* adapters_info)
{
// Get number of Intel graphics adapters
@@ -2991,17 +3411,6 @@ static int hb_qsv_query_adapters(mfxAdaptersInfo* adapters_info)
hb_error("hb_qsv_query_adapters: failed to collect information about Intel graphics adapters %d", sts);
return -1;
}
- // Reverse order to make dGPU higher priority
- int start = 0;
- int end = adapters_info->NumActual - 1;
- while (start < end)
- {
- mfxAdapterInfo temp = adapters_info->Adapters[start];
- adapters_info->Adapters[start] = adapters_info->Adapters[end];
- adapters_info->Adapters[end] = temp;
- start++;
- end--;
- }
}
}
return 0;
@@ -3247,6 +3656,37 @@ err_out:
return err;
}
+int hb_qsv_parse_adapter_index(hb_job_t *job)
+{
+ int ret = 0;
+
+ if (job->encoder_options != NULL && *job->encoder_options)
+ {
+ hb_dict_t *options_list;
+ options_list = hb_encopts_to_dict(job->encoder_options, job->vcodec);
+ hb_dict_iter_t iter;
+ for (iter = hb_dict_iter_init(options_list);
+ iter != HB_DICT_ITER_DONE;
+ iter = hb_dict_iter_next(options_list, iter))
+ {
+ const char *key = hb_dict_iter_key(iter);
+ if (!strcasecmp(key, "gpu"))
+ {
+ hb_value_t *value = hb_dict_iter_value(iter);
+ char *str = hb_value_get_string_xform(value);
+ int dx_index = hb_qsv_atoi(str, &ret);
+ free(str);
+ if (!ret)
+ {
+ hb_qsv_param_parse_dx_index(job, dx_index);
+ }
+ }
+ }
+ hb_dict_free(&options_list);
+ }
+ return 0;
+}
+
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)
{
AVHWFramesContext *frames_ctx;
@@ -3269,20 +3709,9 @@ int hb_create_ffmpeg_pool(hb_job_t *job, int coded_width, int coded_height, enum
iter = hb_dict_iter_next(options_list, iter))
{
const char *key = hb_dict_iter_key(iter);
- if (!strcasecmp(key, "gpu") && !job->qsv.ctx->qsv_device)
- {
- hb_value_t *value = hb_dict_iter_value(iter);
- char *str = hb_value_get_string_xform(value);
- int dx_index = hb_qsv_atoi(str, &ret);
- free(str);
- if (!ret)
- {
- hb_qsv_param_parse_dx_index(job, dx_index);
- }
- }
if ((!strcasecmp(key, "scalingmode") || !strcasecmp(key, "vpp-sm")) && hb_qsv_hw_filters_are_enabled(job))
{
- hb_qsv_info_t *info = hb_qsv_info_get(job->vcodec);
+ hb_qsv_info_t *info = hb_qsv_encoder_info_get(hb_qsv_get_adapter_index(), job->vcodec);
if (info && (info->capabilities & HB_QSV_CAP_VPP_SCALING))
{
hb_value_t *value = hb_dict_iter_value(iter);
@@ -3300,7 +3729,7 @@ int hb_create_ffmpeg_pool(hb_job_t *job, int coded_width, int coded_height, enum
}
if ((!strcasecmp(key, "interpolationmethod") || !strcasecmp(key, "vpp-im")) && hb_qsv_hw_filters_are_enabled(job))
{
- hb_qsv_info_t *info = hb_qsv_info_get(job->vcodec);
+ hb_qsv_info_t *info = hb_qsv_encoder_info_get(hb_qsv_get_adapter_index(), job->vcodec);
if (info && (info->capabilities & HB_QSV_CAP_VPP_INTERPOLATION))
{
hb_value_t *value = hb_dict_iter_value(iter);
@@ -3321,7 +3750,7 @@ int hb_create_ffmpeg_pool(hb_job_t *job, int coded_width, int coded_height, enum
}
if (!job->qsv.ctx->qsv_device)
- hb_qsv_param_parse_dx_index(job, -1);
+ hb_qsv_param_parse_dx_index(job, hb_qsv_get_adapter_index());
ret = qsv_device_init(job);
if (ret < 0)
@@ -3352,7 +3781,6 @@ int hb_create_ffmpeg_pool(hb_job_t *job, int coded_width, int coded_height, enum
hb_error("hb_create_ffmpeg_pool: av_hwframe_ctx_init failed %d", ret);
return ret;
}
-
return 0;
}
@@ -3529,12 +3957,45 @@ int hb_qsv_sanitize_filter_list(hb_job_t *job)
return 0;
}
-hb_list_t* hb_qsv_adapters_list()
+#else // other OS
+
+int hb_qsv_get_platform(int adapter_index)
{
- return qsv_adapters_list;
+ return hb_get_cpu_platform();
}
-#else // other OS
+int hb_qsv_info_init()
+{
+ if (g_qsv_adapters_list)
+ {
+ hb_error("hb_qsv_info_init: qsv_adapters_list is allocated already");
+ return -1;
+ }
+ g_qsv_adapters_list = hb_list_init();
+ if (g_qsv_adapters_list == NULL)
+ {
+ hb_error("hb_qsv_info_init: g_qsv_adapters_list allocation failed");
+ return -1;
+ }
+ if (g_qsv_adapters_details_list)
+ {
+ hb_error("hb_qsv_info_init: g_qsv_adapters_details_list is allocated already");
+ return -1;
+ }
+ g_qsv_adapters_details_list = hb_list_init();
+ if (g_qsv_adapters_details_list == NULL)
+ {
+ hb_error("hb_qsv_info_init: g_qsv_adapters_details_list allocation failed");
+ return -1;
+ }
+ static int adapter_index = -1;
+ static hb_qsv_adapter_details_t adapter_details;
+ init_adapter_details(&adapter_details);
+ hb_list_add(g_qsv_adapters_list, (void*)&adapter_index);
+ hb_list_add(g_qsv_adapters_details_list, (void*)&adapter_details);
+ hb_qsv_collect_adapters_details(g_qsv_adapters_list, g_qsv_adapters_details_list);
+ return 0;
+}
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)
{
@@ -3608,11 +4069,6 @@ int hb_qsv_release_surface_from_pool_by_surface_pointer(HBQSVFramesContext* hb_e
return -1;
}
-hb_list_t* hb_qsv_adapters_list()
-{
- return NULL;
-}
-
#endif
hb_qsv_context* hb_qsv_context_init()
@@ -3640,9 +4096,33 @@ void hb_qsv_context_uninit(hb_job_t *job)
hb_qsv_context_clean(ctx, hb_qsv_full_path_is_enabled(job));
av_free(ctx);
job->qsv.ctx = NULL;
+
+ if (g_qsv_adapters_details_list)
+ {
+#if defined(_WIN32) || defined(__MINGW32__)
+ hb_qsv_free_adapters_details(g_qsv_adapters_details_list);
+#endif
+ hb_list_close(&g_qsv_adapters_details_list);
+ g_qsv_adapters_details_list = NULL;
+ }
+ if (g_qsv_adapters_list)
+ {
+ hb_list_close(&g_qsv_adapters_list);
+ g_qsv_adapters_list = NULL;
+ }
+#if defined(_WIN32) || defined(__MINGW32__)
+ if (g_qsv_adapters_info.Adapters)
+ {
+ av_free(g_qsv_adapters_info.Adapters);
+ }
+ g_qsv_adapters_info.Adapters = NULL;
+ g_qsv_adapters_info.NumAlloc = 0;
+ g_qsv_adapters_info.NumActual = 0;
+#endif
+ g_adapter_index = -1;
}
-#else
+#else // HB_PROJECT_FEATURE_QSV
int hb_qsv_available()
{
diff --git a/libhb/qsv_libav.c b/libhb/qsv_libav.c
index b03b9830c..7a0a8f8d0 100644
--- a/libhb/qsv_libav.c
+++ b/libhb/qsv_libav.c
@@ -236,8 +236,11 @@ int hb_qsv_context_clean(hb_qsv_context * qsv, int full_job)
hb_qsv_pipe_list_clean(&qsv->pipes);
if (qsv->mfx_session && !full_job) {
+ // MFXClose() fails in the media_driver under Linux when encoding interrupted
+#if defined(_WIN32) || defined(__MINGW32__)
sts = MFXClose(qsv->mfx_session);
HB_QSV_CHECK_RESULT(sts, MFX_ERR_NONE, sts);
+#endif
qsv->mfx_session = 0;
}
}
diff --git a/libhb/sync.c b/libhb/sync.c
index 736f271b2..bf342d36a 100644
--- a/libhb/sync.c
+++ b/libhb/sync.c
@@ -2915,7 +2915,7 @@ static int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
// as currently for such support we cannot allocate >64 slices per texture
// due to MSFT limitation, not impacting other cases
if (pv->common->job->qsv.ctx && (pv->common->job->qsv.ctx->la_is_enabled == 1)
- && hb_qsv_full_path_is_enabled(pv->common->job))
+ && pv->common->job->qsv.ctx->full_path_is_enabled)
{
pv->stream->max_len = SYNC_MIN_VIDEO_QUEUE_LEN;
pv->common->job->qsv.ctx->la_is_enabled++;
diff --git a/libhb/work.c b/libhb/work.c
index 94ebe889b..65532361f 100644
--- a/libhb/work.c
+++ b/libhb/work.c
@@ -141,6 +141,9 @@ static void work_func( void * _work )
hb_job_close(&job);
job = new_job;
}
+#if HB_PROJECT_FEATURE_QSV
+ hb_qsv_setup_job(job);
+#endif
hb_job_setup_passes(job->h, job, passes);
hb_job_close(&job);
@@ -871,7 +874,7 @@ static int get_best_pix_ftm(hb_job_t * job)
{
int bit_depth = hb_get_bit_depth(job->title->pix_fmt);
#if HB_PROJECT_FEATURE_QSV && (defined( _WIN32 ) || defined( __MINGW32__ ))
- if (hb_qsv_info_get(job->vcodec))
+ if (hb_qsv_encoder_info_get(hb_qsv_get_adapter_index(), job->vcodec))
{
if (hb_qsv_full_path_is_enabled(job))
{
@@ -1461,7 +1464,6 @@ static void do_job(hb_job_t *job)
#if HB_PROJECT_FEATURE_QSV
if (hb_qsv_is_enabled(job))
{
- job->qsv.ctx = hb_qsv_context_init();
#if HB_PROJECT_FEATURE_QSV && (defined( _WIN32 ) || defined( __MINGW32__ ))
if (hb_qsv_full_path_is_enabled(job))
{
diff --git a/test/test.c b/test/test.c
index 9bf8e90bf..0aefedcc5 100644
--- a/test/test.c
+++ b/test/test.c
@@ -199,6 +199,7 @@ static int stop_at_frame = 0;
static uint64_t min_title_duration = 10;
#if HB_PROJECT_FEATURE_QSV
static int qsv_async_depth = -1;
+static int qsv_adapter = -1;
static int qsv_decode = -1;
#endif
@@ -1938,8 +1939,15 @@ if (hb_qsv_available())
" explicitly synchronized.\n"
" Omit 'number' for zero.\n"
" (default: 4)\n"
+ );
+#if defined(_WIN32) || defined(__MINGW32__)
+ fprintf( out,
+" --qsv-adapter[=index]\n"
+" Set QSV hardware graphics adapter index\n"
+" (default: QSV hardware graphics adapter with highest hardware generation)\n"
"\n"
);
+#endif
}
#endif
}
@@ -2146,36 +2154,36 @@ static int ParseOptions( int argc, char ** argv )
#define AUDIO_DITHER 294
#define QSV_BASELINE 295
#define QSV_ASYNC_DEPTH 296
- #define QSV_IMPLEMENTATION 297
- #define FILTER_NLMEANS 298
- #define FILTER_NLMEANS_TUNE 299
- #define AUDIO_LANG_LIST 300
- #define SUBTITLE_LANG_LIST 301
- #define PRESET_EXPORT 302
- #define PRESET_EXPORT_DESC 303
- #define PRESET_EXPORT_FILE 304
- #define PRESET_IMPORT 305
- #define PRESET_IMPORT_GUI 306
- #define VERSION 307
- #define DESCRIBE 308
- #define PAD 309
- #define FILTER_COMB_DETECT 310
- #define QUEUE_IMPORT 311
- #define FILTER_UNSHARP 312
- #define FILTER_UNSHARP_TUNE 313
- #define FILTER_LAPSHARP 314
- #define FILTER_LAPSHARP_TUNE 315
- #define JSON_LOGGING 316
- #define SSA_FILE 317
- #define SSA_OFFSET 318
- #define SSA_LANG 319
- #define SSA_DEFAULT 320
- #define SSA_BURN 321
- #define FILTER_CHROMA_SMOOTH 322
- #define FILTER_CHROMA_SMOOTH_TUNE 323
- #define FILTER_DEBLOCK_TUNE 324
- #define FILTER_COLORSPACE 325
-
+ #define QSV_ADAPTER 297
+ #define QSV_IMPLEMENTATION 298
+ #define FILTER_NLMEANS 299
+ #define FILTER_NLMEANS_TUNE 300
+ #define AUDIO_LANG_LIST 301
+ #define SUBTITLE_LANG_LIST 302
+ #define PRESET_EXPORT 303
+ #define PRESET_EXPORT_DESC 304
+ #define PRESET_EXPORT_FILE 305
+ #define PRESET_IMPORT 306
+ #define PRESET_IMPORT_GUI 307
+ #define VERSION 308
+ #define DESCRIBE 309
+ #define PAD 310
+ #define FILTER_COMB_DETECT 311
+ #define QUEUE_IMPORT 312
+ #define FILTER_UNSHARP 313
+ #define FILTER_UNSHARP_TUNE 314
+ #define FILTER_LAPSHARP 315
+ #define FILTER_LAPSHARP_TUNE 316
+ #define JSON_LOGGING 317
+ #define SSA_FILE 318
+ #define SSA_OFFSET 319
+ #define SSA_LANG 320
+ #define SSA_DEFAULT 321
+ #define SSA_BURN 322
+ #define FILTER_CHROMA_SMOOTH 323
+ #define FILTER_CHROMA_SMOOTH_TUNE 324
+ #define FILTER_DEBLOCK_TUNE 325
+ #define FILTER_COLORSPACE 326
for( ;; )
{
static struct option long_options[] =
@@ -2189,6 +2197,7 @@ static int ParseOptions( int argc, char ** argv )
#if HB_PROJECT_FEATURE_QSV
{ "qsv-baseline", no_argument, NULL, QSV_BASELINE, },
{ "qsv-async-depth", required_argument, NULL, QSV_ASYNC_DEPTH, },
+ { "qsv-adapter", required_argument, NULL, QSV_ADAPTER },
{ "qsv-implementation", required_argument, NULL, QSV_IMPLEMENTATION, },
{ "disable-qsv-decoding", no_argument, &qsv_decode, 0, },
{ "enable-qsv-decoding", no_argument, &qsv_decode, 1, },
@@ -3108,6 +3117,9 @@ static int ParseOptions( int argc, char ** argv )
case QSV_ASYNC_DEPTH:
qsv_async_depth = atoi(optarg);
break;
+ case QSV_ADAPTER:
+ qsv_adapter = atoi(optarg);
+ break;
case QSV_IMPLEMENTATION:
hb_qsv_impl_set_preferred(optarg);
break;
@@ -4212,6 +4224,11 @@ static hb_dict_t * PreparePreset(const char *preset_name)
hb_dict_set(preset, "VideoQSVAsyncDepth",
hb_value_int(qsv_async_depth));
}
+ if (qsv_adapter >= 0)
+ {
+ hb_dict_set(preset, "VideoQSVAdapterIndex",
+ hb_value_int(qsv_adapter));
+ }
if (qsv_decode != -1)
{
hb_dict_set(preset, "VideoQSVDecode", hb_value_int(qsv_decode));
diff --git a/win/CS/HandBrake.Interop/Interop/HandBrakeHardwareEncoderHelper.cs b/win/CS/HandBrake.Interop/Interop/HandBrakeHardwareEncoderHelper.cs
index 168b7773d..8a36224c2 100644
--- a/win/CS/HandBrake.Interop/Interop/HandBrakeHardwareEncoderHelper.cs
+++ b/win/CS/HandBrake.Interop/Interop/HandBrakeHardwareEncoderHelper.cs
@@ -99,8 +99,9 @@ namespace HandBrake.Interop.Interop
{
try
{
- int cpu_platform = HBFunctions.hb_get_cpu_platform();
- int hardware = HBFunctions.qsv_hardware_generation(cpu_platform);
+ int adapter_index = HBFunctions.hb_qsv_get_adapter_index();
+ int qsv_platform = HBFunctions.hb_qsv_get_platform(adapter_index);
+ int hardware = HBFunctions.hb_qsv_hardware_generation(qsv_platform);
return hardware;
}
catch (Exception exc)
diff --git a/win/CS/HandBrake.Interop/Interop/HbLib/HbFunctions.cs b/win/CS/HandBrake.Interop/Interop/HbLib/HbFunctions.cs
index 6f55ff9d5..4fd7dcd4e 100644
--- a/win/CS/HandBrake.Interop/Interop/HbLib/HbFunctions.cs
+++ b/win/CS/HandBrake.Interop/Interop/HbLib/HbFunctions.cs
@@ -305,8 +305,14 @@ namespace HandBrake.Interop.Interop.HbLib
[DllImport("hb", EntryPoint = "hb_get_cpu_platform", CallingConvention = CallingConvention.Cdecl)]
public static extern int hb_get_cpu_platform();
- [DllImport("hb", EntryPoint = "qsv_hardware_generation", CallingConvention = CallingConvention.Cdecl)]
- public static extern int qsv_hardware_generation(int cpu_platform);
+ [DllImport("hb", EntryPoint = "hb_qsv_get_platform", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int hb_qsv_get_platform(int adapter_index);
+
+ [DllImport("hb", EntryPoint = "hb_qsv_hardware_generation", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int hb_qsv_hardware_generation(int cpu_platform);
+
+ [DllImport("hb", EntryPoint = "hb_qsv_get_adapter_index", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int hb_qsv_get_adapter_index();
[DllImport("hb", EntryPoint = "hb_qsv_adapters_list", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr hb_qsv_adapters_list();