summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libhb/common.c55
-rw-r--r--libhb/decavcodec.c33
-rw-r--r--libhb/enc_qsv.c211
-rw-r--r--libhb/h264_common.h13
-rw-r--r--libhb/qsv_common.c926
-rw-r--r--libhb/qsv_common.h78
-rw-r--r--libhb/work.c2
-rw-r--r--test/test.c14
8 files changed, 1026 insertions, 306 deletions
diff --git a/libhb/common.c b/libhb/common.c
index 6dbdde75c..3ca5c58b5 100644
--- a/libhb/common.c
+++ b/libhb/common.c
@@ -215,13 +215,14 @@ hb_encoder_internal_t hb_video_encoders[] =
int hb_video_encoders_count = sizeof(hb_video_encoders) / sizeof(hb_video_encoders[0]);
static int hb_video_encoder_is_enabled(int encoder)
{
- switch (encoder)
- {
#ifdef USE_QSV
- case HB_VCODEC_QSV_H264:
- return hb_qsv_available();
+ if (encoder & HB_VCODEC_QSV_MASK)
+ {
+ return hb_qsv_video_encoder_is_enabled(encoder);
+ }
#endif
-
+ switch (encoder)
+ {
// the following encoders are always enabled
case HB_VCODEC_X264:
case HB_VCODEC_THEORA:
@@ -1119,6 +1120,14 @@ const hb_rate_t* hb_audio_bitrate_get_next(const hb_rate_t *last)
void hb_video_quality_get_limits(uint32_t codec, float *low, float *high,
float *granularity, int *direction)
{
+#ifdef USE_QSV
+ if (codec & HB_VCODEC_QSV_MASK)
+ {
+ return hb_qsv_video_quality_get_limits(codec, low, high, granularity,
+ direction);
+ }
+#endif
+
switch (codec)
{
case HB_VCODEC_X264:
@@ -1151,6 +1160,13 @@ void hb_video_quality_get_limits(uint32_t codec, float *low, float *high,
const char* hb_video_quality_get_name(uint32_t codec)
{
+#ifdef USE_QSV
+ if (codec & HB_VCODEC_QSV_MASK)
+ {
+ return hb_qsv_video_quality_get_name(codec);
+ }
+#endif
+
switch (codec)
{
case HB_VCODEC_X264:
@@ -1166,16 +1182,18 @@ const char* hb_video_quality_get_name(uint32_t codec)
const char* const* hb_video_encoder_get_presets(int encoder)
{
+#ifdef USE_QSV
+ if (encoder & HB_VCODEC_QSV_MASK)
+ {
+ return hb_qsv_preset_get_names();
+ }
+#endif
+
switch (encoder)
{
case HB_VCODEC_X264:
return x264_preset_names;
-#ifdef USE_QSV
- case HB_VCODEC_QSV_H264:
- return hb_qsv_preset_get_names();
-#endif
-
#ifdef USE_X265
case HB_VCODEC_X265:
return x265_preset_names;
@@ -1203,10 +1221,16 @@ const char* const* hb_video_encoder_get_tunes(int encoder)
const char* const* hb_video_encoder_get_profiles(int encoder)
{
+#ifdef USE_QSV
+ if (encoder & HB_VCODEC_QSV_MASK)
+ {
+ return hb_qsv_profile_get_names(encoder);
+ }
+#endif
+
switch (encoder)
{
case HB_VCODEC_X264:
- case HB_VCODEC_QSV_H264:
return hb_h264_profile_names;
#ifdef USE_X265
@@ -1220,10 +1244,16 @@ const char* const* hb_video_encoder_get_profiles(int encoder)
const char* const* hb_video_encoder_get_levels(int encoder)
{
+#ifdef USE_QSV
+ if (encoder & HB_VCODEC_QSV_MASK)
+ {
+ return hb_qsv_level_get_names(encoder);
+ }
+#endif
+
switch (encoder)
{
case HB_VCODEC_X264:
- case HB_VCODEC_QSV_H264:
return hb_h264_level_names;
default:
@@ -3050,7 +3080,6 @@ static void job_setup( hb_job_t * job, hb_title_t * title )
#ifdef USE_QSV
job->qsv.enc_info.is_init_done = 0;
- job->qsv.preset = NULL;
job->qsv.async_depth = AV_QSV_ASYNC_DEPTH_DEFAULT;
job->qsv.decode = !!(title->video_decode_support &
HB_DECODE_SUPPORT_QSV);
diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c
index c158bcf1b..410283e4f 100644
--- a/libhb/decavcodec.c
+++ b/libhb/decavcodec.c
@@ -1518,20 +1518,25 @@ static int decavcodecvInit( hb_work_object_t * w, hb_job_t * job )
#ifdef USE_QSV
if (hb_qsv_decode_is_enabled(job))
{
- // setup the QSV configuration
- pv->qsv.config.io_pattern = MFX_IOPATTERN_OUT_OPAQUE_MEMORY;
- pv->qsv.config.impl_requested = hb_qsv_impl_get_preferred();
- pv->qsv.config.async_depth = job->qsv.async_depth;
- pv->qsv.config.sync_need = 0;
- pv->qsv.config.usage_threaded = 1;
- pv->qsv.config.additional_buffers = 64; // FIFO_LARGE
- if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_LOOKAHEAD)
- {
- // more surfaces may be needed for the lookahead
- pv->qsv.config.additional_buffers = 160;
- }
- pv->qsv.codec_name = hb_qsv_decode_get_codec_name(w->codec_param);
- pv->qsv.decode = 1;
+ // determine which encoder we're using
+ hb_qsv_info_t *info = hb_qsv_info_get(job->vcodec);
+ pv->qsv.decode = info != NULL;
+ if (pv->qsv.decode)
+ {
+ // setup the QSV configuration
+ pv->qsv.config.io_pattern = MFX_IOPATTERN_OUT_OPAQUE_MEMORY;
+ pv->qsv.config.impl_requested = info->implementation;
+ pv->qsv.config.async_depth = job->qsv.async_depth;
+ pv->qsv.config.sync_need = 0;
+ pv->qsv.config.usage_threaded = 1;
+ pv->qsv.config.additional_buffers = 64; // FIFO_LARGE
+ if (info->capabilities & HB_QSV_CAP_RATECONTROL_LA)
+ {
+ // more surfaces may be needed for the lookahead
+ pv->qsv.config.additional_buffers = 160;
+ }
+ pv->qsv.codec_name = hb_qsv_decode_get_codec_name(w->codec_param);
+ }
}
else
{
diff --git a/libhb/enc_qsv.c b/libhb/enc_qsv.c
index 3b745744a..c3129b749 100644
--- a/libhb/enc_qsv.c
+++ b/libhb/enc_qsv.c
@@ -56,6 +56,7 @@ struct hb_work_private_s
hb_qsv_param_t param;
av_qsv_space enc_space;
+ hb_qsv_info_t *qsv_info;
mfxEncodeCtrl force_keyframe;
hb_list_t *delayed_chapters;
@@ -361,6 +362,7 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
pv->job = job;
pv->is_sys_mem = !hb_qsv_decode_is_enabled(job);
+ pv->qsv_info = hb_qsv_info_get(job->vcodec);
pv->delayed_processing = hb_list_init();
pv->last_start = INT64_MIN;
pv->frames_in = 0;
@@ -381,7 +383,7 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
// default encoding parameters
if (hb_qsv_param_default_preset(&pv->param, &pv->enc_space.m_mfxVideoParam,
- job->encoder_preset))
+ pv->qsv_info, job->encoder_preset))
{
hb_error("encqsvInit: hb_qsv_param_default_preset failed");
return -1;
@@ -434,8 +436,8 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
options_list = hb_encopts_to_dict(job->encoder_options, job->vcodec);
while ((option = hb_dict_next(options_list, option)) != NULL)
{
- switch (hb_qsv_param_parse(&pv->param,
- option->key, option->value, job->vcodec))
+ switch (hb_qsv_param_parse(&pv->param, pv->qsv_info,
+ option->key, option->value))
{
case HB_QSV_PARAM_OK:
break;
@@ -551,7 +553,7 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
hb_error("encqsvInit: bad level %s", job->encoder_level);
return -1;
}
- else if (hb_qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6)
+ else if (pv->qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6)
{
pv->param.videoParam->mfx.CodecLevel = HB_QSV_CLIP3(MFX_LEVEL_AVC_1,
MFX_LEVEL_AVC_52,
@@ -587,46 +589,91 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
}
}
- // set rate control paremeters
- if (job->vquality >= 0)
+ // sanitize ICQ
+ if (!(pv->qsv_info->capabilities & HB_QSV_CAP_RATECONTROL_ICQ))
{
- // introduced in API 1.1
- pv->param.videoParam->mfx.RateControlMethod = MFX_RATECONTROL_CQP;
- pv->param.videoParam->mfx.QPI = HB_QSV_CLIP3(0, 51, job->vquality + pv->param.rc.cqp_offsets[0]);
- pv->param.videoParam->mfx.QPP = HB_QSV_CLIP3(0, 51, job->vquality + pv->param.rc.cqp_offsets[1]);
- pv->param.videoParam->mfx.QPB = HB_QSV_CLIP3(0, 51, job->vquality + pv->param.rc.cqp_offsets[2]);
- // CQP + ExtBRC can cause bad output
- pv->param.codingOption2.ExtBRC = MFX_CODINGOPTION_OFF;
+ // ICQ not supported
+ pv->param.rc.icq = 0;
}
- else if (job->vbitrate > 0)
+ else
+ {
+ pv->param.rc.icq = !!pv->param.rc.icq;
+ }
+
+ // sanitize lookahead
+ if (!(pv->qsv_info->capabilities & HB_QSV_CAP_RATECONTROL_LA))
+ {
+ // lookahead not supported
+ pv->param.rc.lookahead = 0;
+ }
+ else if ((pv->param.rc.lookahead) &&
+ (pv->qsv_info->capabilities & HB_QSV_CAP_RATECONTROL_LAi) == 0 &&
+ (pv->param.videoParam->mfx.FrameInfo.PicStruct != MFX_PICSTRUCT_PROGRESSIVE))
{
- // sanitize lookahead
- if (!(hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_LOOKAHEAD))
+ // lookahead enabled but we can't use it
+ hb_log("encqsvInit: LookAhead not used (LookAhead is progressive-only)");
+ pv->param.rc.lookahead = 0;
+ }
+ else
+ {
+ pv->param.rc.lookahead = !!pv->param.rc.lookahead;
+ }
+
+ // set VBV here (this will be overridden for CQP and ignored for LA)
+ // only set BufferSizeInKB, InitialDelayInKB and MaxKbps if we have
+ // them - otheriwse Media SDK will pick values for us automatically
+ if (pv->param.rc.vbv_buffer_size > 0)
+ {
+ if (pv->param.rc.vbv_buffer_init > 1.0)
+ {
+ pv->param.videoParam->mfx.InitialDelayInKB = (pv->param.rc.vbv_buffer_init / 8);
+ }
+ else if (pv->param.rc.vbv_buffer_init > 0.0)
{
- // lookahead not supported
- pv->param.rc.lookahead = 0;
+ pv->param.videoParam->mfx.InitialDelayInKB = (pv->param.rc.vbv_buffer_size *
+ pv->param.rc.vbv_buffer_init / 8);
}
- else if (pv->param.rc.lookahead &&
- pv->param.videoParam->mfx.FrameInfo.PicStruct != MFX_PICSTRUCT_PROGRESSIVE)
+ pv->param.videoParam->mfx.BufferSizeInKB = (pv->param.rc.vbv_buffer_size / 8);
+ }
+ if (pv->param.rc.vbv_max_bitrate > 0)
+ {
+ pv->param.videoParam->mfx.MaxKbps = pv->param.rc.vbv_max_bitrate;
+ }
+
+ // set rate control paremeters
+ if (job->vquality >= 0)
+ {
+ if (pv->param.rc.icq)
{
- // lookahead enabled but we can't use it
- hb_log("encqsvInit: MFX_RATECONTROL_LA not used (LookAhead is progressive-only)");
- pv->param.rc.lookahead = 0;
+ // introduced in API 1.8
+ if (pv->param.rc.lookahead)
+ {
+ pv->param.videoParam->mfx.RateControlMethod = MFX_RATECONTROL_LA_ICQ;
+ }
+ else
+ {
+ pv->param.videoParam->mfx.RateControlMethod = MFX_RATECONTROL_ICQ;
+ }
+ pv->param.videoParam->mfx.ICQQuality = HB_QSV_CLIP3(1, 51, job->vquality);
}
else
{
- pv->param.rc.lookahead = !!pv->param.rc.lookahead;
+ // introduced in API 1.1
+ pv->param.videoParam->mfx.RateControlMethod = MFX_RATECONTROL_CQP;
+ pv->param.videoParam->mfx.QPI = HB_QSV_CLIP3(0, 51, job->vquality + pv->param.rc.cqp_offsets[0]);
+ pv->param.videoParam->mfx.QPP = HB_QSV_CLIP3(0, 51, job->vquality + pv->param.rc.cqp_offsets[1]);
+ pv->param.videoParam->mfx.QPB = HB_QSV_CLIP3(0, 51, job->vquality + pv->param.rc.cqp_offsets[2]);
+ // CQP + ExtBRC can cause bad output
+ pv->param.codingOption2.ExtBRC = MFX_CODINGOPTION_OFF;
}
+ }
+ else if (job->vbitrate > 0)
+ {
if (pv->param.rc.lookahead)
{
// introduced in API 1.7
pv->param.videoParam->mfx.RateControlMethod = MFX_RATECONTROL_LA;
pv->param.videoParam->mfx.TargetKbps = job->vbitrate;
- if (pv->param.rc.vbv_max_bitrate > 0 ||
- pv->param.rc.vbv_buffer_size > 0)
- {
- hb_log("encqsvInit: MFX_RATECONTROL_LA, ignoring VBV");
- }
// ignored, but some drivers will change AsyncDepth because of it
pv->param.codingOption2.ExtBRC = MFX_CODINGOPTION_OFF;
}
@@ -641,25 +688,6 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
{
pv->param.videoParam->mfx.RateControlMethod = MFX_RATECONTROL_VBR;
}
- // only set BufferSizeInKB, InitialDelayInKB and MaxKbps if we have
- // them - otheriwse Media SDK will pick values for us automatically
- if (pv->param.rc.vbv_buffer_size > 0)
- {
- if (pv->param.rc.vbv_buffer_init > 1.0)
- {
- pv->param.videoParam->mfx.InitialDelayInKB = (pv->param.rc.vbv_buffer_init / 8);
- }
- else if (pv->param.rc.vbv_buffer_init > 0.0)
- {
- pv->param.videoParam->mfx.InitialDelayInKB = (pv->param.rc.vbv_buffer_size *
- pv->param.rc.vbv_buffer_init / 8);
- }
- pv->param.videoParam->mfx.BufferSizeInKB = (pv->param.rc.vbv_buffer_size / 8);
- }
- if (pv->param.rc.vbv_max_bitrate > 0)
- {
- pv->param.videoParam->mfx.MaxKbps = pv->param.rc.vbv_max_bitrate;
- }
pv->param.videoParam->mfx.TargetKbps = job->vbitrate;
}
}
@@ -670,6 +698,23 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
return -1;
}
+ // if VBV is enabled but ignored, log it
+ if (pv->param.rc.vbv_max_bitrate > 0 || pv->param.rc.vbv_buffer_size > 0)
+ {
+ switch (pv->param.videoParam->mfx.RateControlMethod)
+ {
+ case MFX_RATECONTROL_LA:
+ case MFX_RATECONTROL_LA_ICQ:
+ hb_log("encqsvInit: LookAhead enabled, ignoring VBV");
+ break;
+ case MFX_RATECONTROL_ICQ:
+ hb_log("encqsvInit: ICQ rate control, ignoring VBV");
+ break;
+ default:
+ break;
+ }
+ }
+
// set B-pyramid
if (pv->param.gop.b_pyramid < 0)
{
@@ -733,7 +778,7 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
pv->param.rc.lookahead ? 60 : 0);
}
- if ((hb_qsv_info->capabilities & HB_QSV_CAP_H264_BPYRAMID) &&
+ if ((pv->qsv_info->capabilities & HB_QSV_CAP_B_REF_PYRAMID) &&
(pv->param.videoParam->mfx.CodecProfile != MFX_PROFILE_AVC_BASELINE &&
pv->param.videoParam->mfx.CodecProfile != MFX_PROFILE_AVC_CONSTRAINED_HIGH &&
pv->param.videoParam->mfx.CodecProfile != MFX_PROFILE_AVC_CONSTRAINED_BASELINE))
@@ -838,7 +883,7 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
mfxExtCodingOptionSPSPPS sps_pps_buf, *sps_pps = &sps_pps_buf;
version.Major = HB_QSV_MINVERSION_MAJOR;
version.Minor = HB_QSV_MINVERSION_MINOR;
- err = MFXInit(hb_qsv_impl_get_preferred(), &version, &session);
+ err = MFXInit(pv->qsv_info->implementation, &version, &session);
if (err != MFX_ERR_NONE)
{
hb_error("encqsvInit: MFXInit failed (%d)", err);
@@ -886,7 +931,7 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
memset(option2, 0, sizeof(mfxExtCodingOption2));
option2->Header.BufferId = MFX_EXTBUFF_CODING_OPTION2;
option2->Header.BufferSz = sizeof(mfxExtCodingOption2);
- if (hb_qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6)
+ if (pv->qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6)
{
// attach to get the final output mfxExtCodingOption2 settings
videoParam.ExtParam[videoParam.NumExtParam++] = (mfxExtBuffer*)option2;
@@ -949,7 +994,7 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
// let the muxer know whether to expect B-frames or not
job->areBframes = !!pv->bfrm_delay;
// check whether we need to generate DTS ourselves (MSDK API < 1.6 or VFR)
- pv->bfrm_workaround = job->cfr != 1 || !(hb_qsv_info->capabilities &
+ pv->bfrm_workaround = job->cfr != 1 || !(pv->qsv_info->capabilities &
HB_QSV_CAP_MSDK_API_1_6);
if (pv->bfrm_delay && pv->bfrm_workaround)
{
@@ -969,7 +1014,7 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
videoParam.mfx.TargetUsage, videoParam.AsyncDepth);
hb_log("encqsvInit: GopRefDist %"PRIu16" GopPicSize %"PRIu16" NumRefFrame %"PRIu16"",
videoParam.mfx.GopRefDist, videoParam.mfx.GopPicSize, videoParam.mfx.NumRefFrame);
- if (hb_qsv_info->capabilities & HB_QSV_CAP_H264_BPYRAMID)
+ if (pv->qsv_info->capabilities & HB_QSV_CAP_B_REF_PYRAMID)
{
hb_log("encqsvInit: BFrames %s BPyramid %s",
pv->bfrm_delay ? "on" : "off",
@@ -979,6 +1024,20 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
{
hb_log("encqsvInit: BFrames %s", pv->bfrm_delay ? "on" : "off");
}
+ if (pv->qsv_info->capabilities & HB_QSV_CAP_OPTION2_IB_ADAPT)
+ {
+ if (pv->bfrm_delay > 0)
+ {
+ hb_log("encqsvInit: AdaptiveI %s AdaptiveB %s",
+ hb_qsv_codingoption_get_name(option2->AdaptiveI),
+ hb_qsv_codingoption_get_name(option2->AdaptiveB));
+ }
+ else
+ {
+ hb_log("encqsvInit: AdaptiveI %s",
+ hb_qsv_codingoption_get_name(option2->AdaptiveI));
+ }
+ }
if (videoParam.mfx.RateControlMethod == MFX_RATECONTROL_CQP)
{
char qpi[7], qpp[9], qpb[9];
@@ -997,6 +1056,14 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
hb_log("encqsvInit: RateControlMethod LA TargetKbps %"PRIu16" LookAheadDepth %"PRIu16"",
videoParam.mfx.TargetKbps, option2->LookAheadDepth);
break;
+ case MFX_RATECONTROL_LA_ICQ:
+ hb_log("encqsvInit: RateControlMethod LA_ICQ ICQQuality %"PRIu16" LookAheadDepth %"PRIu16"",
+ videoParam.mfx.ICQQuality, option2->LookAheadDepth);
+ break;
+ case MFX_RATECONTROL_ICQ:
+ hb_log("encqsvInit: RateControlMethod ICQ ICQQuality %"PRIu16"",
+ videoParam.mfx.ICQQuality);
+ break;
case MFX_RATECONTROL_CBR:
case MFX_RATECONTROL_VBR:
hb_log("encqsvInit: RateControlMethod %s TargetKbps %"PRIu16" MaxKbps %"PRIu16" BufferSizeInKB %"PRIu16" InitialDelayInKB %"PRIu16"",
@@ -1010,6 +1077,30 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
return -1;
}
}
+ if ((pv->qsv_info->capabilities & HB_QSV_CAP_OPTION2_LA_DOWNS) &&
+ (videoParam.mfx.RateControlMethod == MFX_RATECONTROL_LA ||
+ videoParam.mfx.RateControlMethod == MFX_RATECONTROL_LA_ICQ))
+ {
+ switch (option2->LookAheadDS)
+ {
+ case MFX_LOOKAHEAD_DS_UNKNOWN:
+ hb_log("encqsvInit: LookAheadDS unknown (auto)");
+ break;
+ case MFX_LOOKAHEAD_DS_OFF:
+ hb_log("encqsvInit: LookAheadDS off");
+ break;
+ case MFX_LOOKAHEAD_DS_2x:
+ hb_log("encqsvInit: LookAheadDS 2x");
+ break;
+ case MFX_LOOKAHEAD_DS_4x:
+ hb_log("encqsvInit: LookAheadDS 4x");
+ break;
+ default:
+ hb_log("encqsvInit: invalid LookAheadDS value 0x%"PRIx16"",
+ option2->LookAheadDS);
+ break;
+ }
+ }
switch (videoParam.mfx.FrameInfo.PicStruct)
{
// quiet, most people don't care
@@ -1029,22 +1120,22 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
}
hb_log("encqsvInit: CAVLC %s",
hb_qsv_codingoption_get_name(option1->CAVLC));
- if (videoParam.mfx.RateControlMethod != MFX_RATECONTROL_LA &&
+ if (pv->param.rc.lookahead == 0 &&
videoParam.mfx.RateControlMethod != MFX_RATECONTROL_CQP)
{
// LA/CQP and ExtBRC/MBBRC are mutually exclusive
- if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_EXTBRC)
+ if (pv->qsv_info->capabilities & HB_QSV_CAP_OPTION2_EXTBRC)
{
hb_log("encqsvInit: ExtBRC %s",
hb_qsv_codingoption_get_name(option2->ExtBRC));
}
- if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_MBBRC)
+ if (pv->qsv_info->capabilities & HB_QSV_CAP_OPTION2_MBBRC)
{
hb_log("encqsvInit: MBBRC %s",
hb_qsv_codingoption_get_name(option2->MBBRC));
}
}
- if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_TRELLIS)
+ if (pv->qsv_info->capabilities & HB_QSV_CAP_OPTION2_TRELLIS)
{
switch (option2->Trellis)
{
@@ -1453,9 +1544,9 @@ int encqsvWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
buf->s.duration = duration;
if (pv->bfrm_delay)
{
- if ((pv->frames_out == 0) &&
- (hb_qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6) &&
- (hb_qsv_info->capabilities & HB_QSV_CAP_H264_BPYRAMID))
+ if ((pv->frames_out == 0) &&
+ (pv->qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6) &&
+ (pv->qsv_info->capabilities & HB_QSV_CAP_B_REF_PYRAMID))
{
// with B-pyramid, the delay may be more than 1 frame,
// so compute the actual delay based on the initial DTS
diff --git a/libhb/h264_common.h b/libhb/h264_common.h
index febe1965f..bc64cf928 100644
--- a/libhb/h264_common.h
+++ b/libhb/h264_common.h
@@ -10,8 +10,15 @@
#ifndef HB_H264_COMMON_H
#define HB_H264_COMMON_H
-static const char * const hb_h264_profile_names[] = { "auto", "high", "main", "baseline", NULL, };
-static const char * const hb_h264_level_names[] = { "auto", "1.0", "1b", "1.1", "1.2", "1.3", "2.0", "2.1", "2.2", "3.0", "3.1", "3.2", "4.0", "4.1", "4.2", "5.0", "5.1", "5.2", NULL, };
-static const int const hb_h264_level_values[] = { -1, 10, 9, 11, 12, 13, 20, 21, 22, 30, 31, 32, 40, 41, 42, 50, 51, 52, 0, };
+static const char * const hb_h264_profile_names[] = { "auto", "high", "main", "baseline", NULL, };
+static const char * const hb_h264_level_names[] = { "auto", "1.0", "1b", "1.1", "1.2", "1.3", "2.0", "2.1", "2.2", "3.0", "3.1", "3.2", "4.0", "4.1", "4.2", "5.0", "5.1", "5.2", NULL, };
+static const int const hb_h264_level_values[] = { -1, 10, 9, 11, 12, 13, 20, 21, 22, 30, 31, 32, 40, 41, 42, 50, 51, 52, 0, };
+
+// stolen from libx264's x264.h
+static const char * const hb_h264_fullrange_names[] = { "off", "on", NULL, };
+static const char * const hb_h264_vidformat_names[] = { "component", "pal", "ntsc", "secam", "mac", "undef", NULL, };
+static const char * const hb_h264_colorprim_names[] = { "", "bt709", "undef", "", "bt470m", "bt470bg", "smpte170m", "smpte240m", "film", "bt2020", NULL, };
+static const char * const hb_h264_transfer_names[] = { "", "bt709", "undef", "", "bt470m", "bt470bg", "smpte170m", "smpte240m", "linear", "log100", "log316", "iec61966-2-4", "bt1361e", "iec61966-2-1", "bt2020-10", "bt2020-12", NULL, };
+static const char * const hb_h264_colmatrix_names[] = { "GBR", "bt709", "undef", "", "fcc", "bt470bg", "smpte170m", "smpte240m", "YCgCo", "bt2020nc", "bt2020c", NULL, };
#endif //HB_H264_COMMON_H
diff --git a/libhb/qsv_common.c b/libhb/qsv_common.c
index 195845200..9a21af411 100644
--- a/libhb/qsv_common.c
+++ b/libhb/qsv_common.c
@@ -9,6 +9,8 @@
#ifdef USE_QSV
+#include <stdio.h>
+
#include "hb.h"
#include "ports.h"
#include "common.h"
@@ -16,167 +18,582 @@
#include "qsv_common.h"
#include "h264_common.h"
-// for x264_vidformat_names etc.
-#include "x264.h"
-
-// avoids a warning
-#include "libavutil/cpu.h"
-extern void ff_cpu_cpuid(int index, int *eax, int *ebx, int *ecx, int *edx);
-
-// make the Intel QSV information available to the UIs
-hb_qsv_info_t *hb_qsv_info = NULL;
-
-// availability and versions
-static mfxIMPL preferred_implementation;
-static mfxVersion qsv_hardware_version;
-static mfxVersion qsv_software_version;
-static mfxVersion qsv_minimum_version;
-static int qsv_hardware_available = 0;
-static int qsv_software_available = 0;
+// 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 mfxPluginUID qsv_encode_plugin_hevc = { .Data = { 0x2F, 0xCA, 0x99, 0x74, 0x9F, 0xDB, 0x49, 0xAE, 0xB1, 0x21, 0xA5, 0xB6, 0x3E, 0xF5, 0x68, 0xF7 } };
+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, };
// check available Intel Media SDK version against a minimum
#define HB_CHECK_MFX_VERSION(MFX_VERSION, MAJOR, MINOR) \
(MFX_VERSION.Major == MAJOR && MFX_VERSION.Minor >= MINOR)
+/*
+ * Determine the "generation" of QSV hardware based on the CPU microarchitecture.
+ * Anything unknown is assumed to be more recent than the latest known generation.
+ * This avoids having to order the hb_cpu_platform enum depending on QSV hardware.
+ */
+enum
+{
+ QSV_G0, // third party hardware
+ QSV_G1, // Sandy Bridge or equivalent
+ QSV_G2, // Ivy Bridge or equivalent
+ QSV_G3, // Haswell or equivalent
+};
+static int qsv_hardware_generation(int cpu_platform)
+{
+ switch (cpu_platform)
+ {
+ case HB_CPU_PLATFORM_INTEL_BNL:
+ return QSV_G0;
+ case HB_CPU_PLATFORM_INTEL_SNB:
+ return QSV_G1;
+ case HB_CPU_PLATFORM_INTEL_IVB:
+ case HB_CPU_PLATFORM_INTEL_SLM:
+ return QSV_G2;
+ case HB_CPU_PLATFORM_INTEL_HSW:
+ default:
+ return QSV_G3;
+ }
+}
+
+/*
+ * Determine whether a given mfxIMPL is hardware-accelerated.
+ */
+static int qsv_implementation_is_hardware(mfxIMPL implementation)
+{
+ return MFX_IMPL_BASETYPE(implementation) != MFX_IMPL_SOFTWARE;
+}
+
int hb_qsv_available()
{
- return hb_qsv_info != NULL && (qsv_hardware_available ||
- qsv_software_available);
+ return hb_qsv_video_encoder_is_enabled(HB_VCODEC_QSV_H264);
}
-int hb_qsv_info_init()
+int hb_qsv_video_encoder_is_enabled(int encoder)
{
- static int init_done = 0;
- if (init_done)
- return (hb_qsv_info == NULL);
- init_done = 1;
+ switch (encoder)
+ {
+ case HB_VCODEC_QSV_H264:
+ return hb_qsv_info_avc != NULL && hb_qsv_info_avc->available;
+ default:
+ return 0;
+ }
+}
- hb_qsv_info = calloc(1, sizeof(*hb_qsv_info));
- if (hb_qsv_info == NULL)
+int hb_qsv_audio_encoder_is_enabled(int encoder)
+{
+ switch (encoder)
{
- hb_error("hb_qsv_info_init: alloc failure");
- return -1;
+ default:
+ return 0;
}
+}
- mfxSession session;
- qsv_minimum_version.Major = HB_QSV_MINVERSION_MAJOR;
- qsv_minimum_version.Minor = HB_QSV_MINVERSION_MINOR;
+static void init_video_param(mfxVideoParam *videoParam)
+{
+ if (videoParam == NULL)
+ {
+ return;
+ }
- // check for software fallback
- if (MFXInit(MFX_IMPL_SOFTWARE,
- &qsv_minimum_version, &session) == MFX_ERR_NONE)
+ memset(videoParam, 0, sizeof(mfxVideoParam));
+ videoParam->mfx.CodecId = MFX_CODEC_AVC;
+ videoParam->mfx.CodecLevel = MFX_LEVEL_UNKNOWN;
+ videoParam->mfx.CodecProfile = MFX_PROFILE_UNKNOWN;
+ videoParam->mfx.RateControlMethod = MFX_RATECONTROL_VBR;
+ videoParam->mfx.TargetUsage = MFX_TARGETUSAGE_BALANCED;
+ videoParam->mfx.TargetKbps = 5000;
+ videoParam->mfx.GopOptFlag = MFX_GOP_CLOSED;
+ videoParam->mfx.FrameInfo.FourCC = MFX_FOURCC_NV12;
+ videoParam->mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420;
+ videoParam->mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
+ videoParam->mfx.FrameInfo.FrameRateExtN = 25;
+ videoParam->mfx.FrameInfo.FrameRateExtD = 1;
+ videoParam->mfx.FrameInfo.Width = 1920;
+ videoParam->mfx.FrameInfo.CropW = 1920;
+ videoParam->mfx.FrameInfo.AspectRatioW = 1;
+ videoParam->mfx.FrameInfo.Height = 1088;
+ videoParam->mfx.FrameInfo.CropH = 1080;
+ videoParam->mfx.FrameInfo.AspectRatioH = 1;
+ videoParam->AsyncDepth = AV_QSV_ASYNC_DEPTH_DEFAULT;
+ videoParam->IOPattern = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
+}
+
+static void init_ext_coding_option2(mfxExtCodingOption2 *extCodingOption2)
+{
+ if (extCodingOption2 == NULL)
{
- qsv_software_available = 1;
- preferred_implementation = MFX_IMPL_SOFTWARE;
- // our minimum is supported, but query the actual version
- MFXQueryVersion(session, &qsv_software_version);
- MFXClose(session);
+ return;
}
- // check for actual hardware support
- if (MFXInit(MFX_IMPL_HARDWARE_ANY|MFX_IMPL_VIA_ANY,
- &qsv_minimum_version, &session) == MFX_ERR_NONE)
+ memset(extCodingOption2, 0, sizeof(mfxExtCodingOption2));
+ extCodingOption2->Header.BufferId = MFX_EXTBUFF_CODING_OPTION2;
+ extCodingOption2->Header.BufferSz = sizeof(mfxExtCodingOption2);
+ extCodingOption2->MBBRC = MFX_CODINGOPTION_ON;
+ extCodingOption2->ExtBRC = MFX_CODINGOPTION_ON;
+ extCodingOption2->Trellis = MFX_TRELLIS_I|MFX_TRELLIS_P|MFX_TRELLIS_B;
+ extCodingOption2->RepeatPPS = MFX_CODINGOPTION_ON;
+ extCodingOption2->BRefType = MFX_B_REF_PYRAMID;
+ extCodingOption2->AdaptiveI = MFX_CODINGOPTION_ON;
+ extCodingOption2->AdaptiveB = MFX_CODINGOPTION_ON;
+ extCodingOption2->LookAheadDS = MFX_LOOKAHEAD_DS_4x;
+ extCodingOption2->NumMbPerSlice = 2040; // 1920x1088/4
+}
+
+static int query_capabilities(mfxSession session, mfxVersion version, hb_qsv_info_t *info)
+{
+ /*
+ * MFXVideoENCODE_Query(mfxSession, mfxVideoParam *in, mfxVideoParam *out);
+ *
+ * Mode 1:
+ * - in is NULL
+ * - out has the parameters we want to query set to 1
+ * - out->mfx.CodecId field has to be set (mandatory)
+ * - MFXVideoENCODE_Query should zero out all unsupported parameters
+ *
+ * Mode 2:
+ * - the paramaters we want to query are set for in
+ * - in ->mfx.CodecId field has to be set (mandatory)
+ * - out->mfx.CodecId field has to be set (mandatory)
+ * - MFXVideoENCODE_Query should sanitize all unsupported parameters
+ */
+ mfxStatus status;
+ mfxPluginUID *pluginUID;
+ mfxExtBuffer *videoExtParam[1];
+ mfxVideoParam videoParam, inputParam;
+ mfxExtCodingOption2 extCodingOption2;
+
+ /* Reset capabilities before querying */
+ info->capabilities = 0;
+
+ /* Load optional codec plug-ins */
+ switch (info->codec_id)
+ {
+ case MFX_CODEC_HEVC:
+ pluginUID = &qsv_encode_plugin_hevc;
+ break;
+ default:
+ pluginUID = NULL;
+ break;
+ }
+ if (pluginUID != NULL && HB_CHECK_MFX_VERSION(version, 1, 8) &&
+ MFXVideoUSER_Load(session, pluginUID, 0) < MFX_ERR_NONE)
{
- // Cloverview (Bonnell microarchitecture) supports MSDK via third-party
- // hardware - we don't support this configuration for the time being
- if (hb_get_cpu_platform() != HB_CPU_PLATFORM_INTEL_BNL)
+ // couldn't load plugin successfully
+ return 0;
+ }
+
+ /*
+ * First of all, check availability of an encoder for
+ * this combination of a codec ID and implementation.
+ *
+ * Note: can error out rather than sanitizing
+ * unsupported codec IDs, so don't log errors.
+ */
+ if (HB_CHECK_MFX_VERSION(version, HB_QSV_MINVERSION_MAJOR, HB_QSV_MINVERSION_MINOR))
+ {
+ if (info->implementation & MFX_IMPL_AUDIO)
{
- qsv_hardware_available = 1;
- preferred_implementation = MFX_IMPL_HARDWARE_ANY|MFX_IMPL_VIA_ANY;
- // our minimum is supported, but query the actual version
- MFXQueryVersion(session, &qsv_hardware_version);
+ /* Not yet supported */
+ return 0;
+ }
+ else
+ {
+ init_video_param(&inputParam);
+ inputParam.mfx.CodecId = info->codec_id;
+
+ memset(&videoParam, 0, sizeof(mfxVideoParam));
+ videoParam.mfx.CodecId = inputParam.mfx.CodecId;
+
+ if (MFXVideoENCODE_Query(session, &inputParam, &videoParam) >= MFX_ERR_NONE &&
+ videoParam.mfx.CodecId == info->codec_id)
+ {
+ info->available = 1;
+ }
}
- MFXClose(session);
+ }
+ if (!info->available)
+ {
+ /* Don't check capabilities for unavailable encoders */
+ return 0;
}
- // check for version-specific or hardware-specific capabilities
- // we only use software as a fallback, so check hardware first
- if (qsv_hardware_available)
+ if (info->implementation & MFX_IMPL_AUDIO)
+ {
+ /* We don't have any audio capability checks yet */
+ return 0;
+ }
+ else
{
- if (HB_CHECK_MFX_VERSION(qsv_hardware_version, 1, 6))
+ /* Implementation-specific features that can't be queried */
+ if (qsv_implementation_is_hardware(info->implementation))
{
- hb_qsv_info->capabilities |= HB_QSV_CAP_MSDK_API_1_6;
- hb_qsv_info->capabilities |= HB_QSV_CAP_OPTION2_EXTBRC;
+ if (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G3)
+ {
+ info->capabilities |= HB_QSV_CAP_B_REF_PYRAMID;
+ }
}
- if (HB_CHECK_MFX_VERSION(qsv_hardware_version, 1, 7))
+ else
{
- // we should really check the driver version, but since that's not
- // available here, checking the API version is the best we can do :-(
- hb_qsv_info->capabilities |= HB_QSV_CAP_CORE_COPYFRAME;
+ if (HB_CHECK_MFX_VERSION(version, 1, 6))
+ {
+ info->capabilities |= HB_QSV_CAP_B_REF_PYRAMID;
+ }
}
- if (hb_get_cpu_platform() == HB_CPU_PLATFORM_INTEL_HSW)
+
+ /* API-specific features that can't be queried */
+ if (HB_CHECK_MFX_VERSION(version, 1, 6))
{
- if (HB_CHECK_MFX_VERSION(qsv_hardware_version, 1, 6))
+ // API >= 1.6 (mfxBitstream::DecodeTimeStamp, mfxExtCodingOption2)
+ info->capabilities |= HB_QSV_CAP_MSDK_API_1_6;
+ }
+
+ /*
+ * Check availability of optional rate control methods.
+ *
+ * Mode 2 tends to error out, but mode 1 gives false negatives, which
+ * is worse. So use mode 2 and assume an error means it's unsupported.
+ *
+ * Also assume that LA and ICQ combined imply LA_ICQ is
+ * supported, so we don't need to check the latter too.
+ */
+ if (HB_CHECK_MFX_VERSION(version, 1, 7))
+ {
+ init_video_param(&inputParam);
+ inputParam.mfx.CodecId = info->codec_id;
+ inputParam.mfx.RateControlMethod = MFX_RATECONTROL_LA;
+
+ memset(&videoParam, 0, sizeof(mfxVideoParam));
+ videoParam.mfx.CodecId = inputParam.mfx.CodecId;
+
+ if (MFXVideoENCODE_Query(session, &inputParam, &videoParam) >= MFX_ERR_NONE &&
+ videoParam.mfx.RateControlMethod == MFX_RATECONTROL_LA)
+ {
+ info->capabilities |= HB_QSV_CAP_RATECONTROL_LA;
+
+ // also check for LA + interlaced support
+ init_video_param(&inputParam);
+ inputParam.mfx.CodecId = info->codec_id;
+ inputParam.mfx.RateControlMethod = MFX_RATECONTROL_LA;
+ inputParam.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_FIELD_TFF;
+
+ memset(&videoParam, 0, sizeof(mfxVideoParam));
+ videoParam.mfx.CodecId = inputParam.mfx.CodecId;
+
+ if (MFXVideoENCODE_Query(session, &inputParam, &videoParam) >= MFX_ERR_NONE &&
+ videoParam.mfx.FrameInfo.PicStruct == MFX_PICSTRUCT_FIELD_TFF &&
+ videoParam.mfx.RateControlMethod == MFX_RATECONTROL_LA)
+ {
+ info->capabilities |= HB_QSV_CAP_RATECONTROL_LAi;
+ }
+ }
+ }
+ if (HB_CHECK_MFX_VERSION(version, 1, 8))
+ {
+ init_video_param(&inputParam);
+ inputParam.mfx.CodecId = info->codec_id;
+ inputParam.mfx.RateControlMethod = MFX_RATECONTROL_ICQ;
+
+ memset(&videoParam, 0, sizeof(mfxVideoParam));
+ videoParam.mfx.CodecId = inputParam.mfx.CodecId;
+
+ if (MFXVideoENCODE_Query(session, &inputParam, &videoParam) >= MFX_ERR_NONE &&
+ videoParam.mfx.RateControlMethod == MFX_RATECONTROL_ICQ)
+ {
+ info->capabilities |= HB_QSV_CAP_RATECONTROL_ICQ;
+ }
+ }
+
+ /*
+ * Check mfxExtCodingOption2 fields.
+ *
+ * Mode 2 suffers from false negatives with some drivers, whereas mode 1
+ * suffers from false positives instead. The latter is probably easier
+ * and/or safer to sanitize for us, so use mode 1.
+ */
+ if (HB_CHECK_MFX_VERSION(version, 1, 6))
+ {
+ init_video_param(&videoParam);
+ videoParam.mfx.CodecId = info->codec_id;
+
+ init_ext_coding_option2(&extCodingOption2);
+ videoParam.ExtParam = videoExtParam;
+ videoParam.ExtParam[0] = (mfxExtBuffer*)&extCodingOption2;
+ videoParam.NumExtParam = 1;
+
+ status = MFXVideoENCODE_Query(session, NULL, &videoParam);
+ if (status >= MFX_ERR_NONE)
{
- hb_qsv_info->capabilities |= HB_QSV_CAP_OPTION2_MBBRC;
+#if 0
+ // testing code that could come in handy
+ fprintf(stderr, "-------------------\n");
+ fprintf(stderr, "MBBRC: 0x%02X\n", extCodingOption2.MBBRC);
+ fprintf(stderr, "ExtBRC: 0x%02X\n", extCodingOption2.ExtBRC);
+ fprintf(stderr, "Trellis: 0x%02X\n", extCodingOption2.Trellis);
+ fprintf(stderr, "RepeatPPS: 0x%02X\n", extCodingOption2.RepeatPPS);
+ fprintf(stderr, "BRefType: %4"PRIu16"\n", extCodingOption2.BRefType);
+ fprintf(stderr, "AdaptiveI: 0x%02X\n", extCodingOption2.AdaptiveI);
+ fprintf(stderr, "AdaptiveB: 0x%02X\n", extCodingOption2.AdaptiveB);
+ fprintf(stderr, "LookAheadDS: %4"PRIu16"\n", extCodingOption2.LookAheadDS);
+ fprintf(stderr, "-------------------\n");
+#endif
+
+ /*
+ * Sanitize API 1.6 fields:
+ *
+ * - 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 (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 (extCodingOption2.ExtBRC)
+ {
+ info->capabilities |= HB_QSV_CAP_OPTION2_EXTBRC;
+ }
+ }
+
+ /*
+ * Sanitize API 1.7 fields:
+ *
+ * - Trellis requires G3 hardware (Haswell or equivalent)
+ */
+ 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 (extCodingOption2.Trellis)
+ {
+ info->capabilities |= HB_QSV_CAP_OPTION2_TRELLIS;
+ }
+ }
+ }
+
+ /*
+ * Sanitize API 1.8 fields:
+ *
+ * - BRefType requires B-pyramid support
+ * - LookAheadDS requires lookahead support
+ * - AdaptiveI, AdaptiveB, NumMbPerSlice unknown (trust Query)
+ */
+ if (HB_CHECK_MFX_VERSION(version, 1, 8))
+ {
+ if (info->capabilities & HB_QSV_CAP_B_REF_PYRAMID)
+ {
+ if (extCodingOption2.BRefType)
+ {
+ info->capabilities |= HB_QSV_CAP_OPTION2_BREFTYPE;
+ }
+ }
+ if (info->capabilities & HB_QSV_CAP_RATECONTROL_LA)
+ {
+ if (extCodingOption2.LookAheadDS)
+ {
+ info->capabilities |= HB_QSV_CAP_OPTION2_LA_DOWNS;
+ }
+ }
+ if (extCodingOption2.AdaptiveI && extCodingOption2.AdaptiveB)
+ {
+ info->capabilities |= HB_QSV_CAP_OPTION2_IB_ADAPT;
+ }
+ if (extCodingOption2.NumMbPerSlice)
+ {
+ info->capabilities |= HB_QSV_CAP_OPTION2_NMBSLICE;
+ }
+ }
}
- if (HB_CHECK_MFX_VERSION(qsv_hardware_version, 1, 7))
+ else
{
- hb_qsv_info->capabilities |= HB_QSV_CAP_OPTION2_TRELLIS;
- hb_qsv_info->capabilities |= HB_QSV_CAP_OPTION2_LOOKAHEAD;
+ fprintf(stderr,
+ "hb_qsv_info_init: mfxExtCodingOption2 check failed (0x%"PRIX32", 0x%"PRIX32", %d)\n",
+ info->codec_id, info->implementation, status);
}
- hb_qsv_info->capabilities |= HB_QSV_CAP_H264_BPYRAMID;
}
}
- else if (qsv_software_available)
+
+ /* Unload optional codec plug-ins */
+ if (pluginUID != NULL && HB_CHECK_MFX_VERSION(version, 1, 8))
+ {
+ MFXVideoUSER_UnLoad(session, pluginUID);
+ }
+
+ return 0;
+}
+
+int hb_qsv_info_init()
+{
+ static int init_done = 0;
+ if (init_done)
+ return 0;
+ init_done = 1;
+
+ /*
+ * 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, };
+
+ // check for software fallback
+ if (MFXInit(MFX_IMPL_SOFTWARE, &version, &session) == MFX_ERR_NONE)
{
- if (HB_CHECK_MFX_VERSION(qsv_software_version, 1, 6))
+ // 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))
{
- hb_qsv_info->capabilities |= HB_QSV_CAP_MSDK_API_1_6;
- hb_qsv_info->capabilities |= HB_QSV_CAP_H264_BPYRAMID;
+ query_capabilities(session, qsv_software_version, &qsv_software_info_avc);
+ query_capabilities(session, qsv_software_version, &qsv_software_info_hevc);
+ // now that we know which hardware encoders are
+ // available, we can set the preferred implementation
+ hb_qsv_impl_set_preferred("software");
}
- hb_qsv_info->capabilities |= HB_QSV_CAP_CORE_COPYFRAME;
+ MFXClose(session);
}
- // note: we pass a pointer to MFXInit but it never gets modified
- // let's make sure of it just to be safe though
- if (qsv_minimum_version.Major != HB_QSV_MINVERSION_MAJOR ||
- qsv_minimum_version.Minor != HB_QSV_MINVERSION_MINOR)
- {
- hb_error("hb_qsv_info_init: minimum version (%d.%d) was modified",
- qsv_minimum_version.Major,
- qsv_minimum_version.Minor);
+ // check for actual hardware support
+ if (MFXInit(MFX_IMPL_HARDWARE_ANY, &version, &session) == MFX_ERR_NONE)
+ {
+ // 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))
+ {
+ query_capabilities(session, qsv_hardware_version, &qsv_hardware_info_avc);
+ query_capabilities(session, qsv_hardware_version, &qsv_hardware_info_hevc);
+ // now that we know which hardware encoders are
+ // available, we can set the preferred implementation
+ hb_qsv_impl_set_preferred("hardware");
+ }
+ MFXClose(session);
}
// success
return 0;
}
-// we don't need it beyond this point
-#undef HB_CHECK_MFX_VERSION
-
-void hb_qsv_info_print()
+static void log_capabilities(int log_level, uint64_t caps, const char *prefix)
{
- if (hb_qsv_info == NULL)
+ if (!caps)
{
- hb_error("hb_qsv_info_print: QSV info not initialized!");
+ hb_deep_log(log_level, "%s none (standard feature set)", prefix);
}
+ else
+ {
+ hb_deep_log(log_level, "%s%s%s%s%s%s%s%s%s%s%s%s%s", prefix,
+ !(caps & HB_QSV_CAP_MSDK_API_1_6) ? "" : " api1.6",
+ !(caps & HB_QSV_CAP_B_REF_PYRAMID) ? "" : " bpyramid",
+ !(caps & HB_QSV_CAP_OPTION2_BREFTYPE) ? "" : " breftype",
+ !(caps & HB_QSV_CAP_RATECONTROL_LA) ? "" : " lookahead",
+ !(caps & HB_QSV_CAP_RATECONTROL_LAi) ? "" : " lookaheadi",
+ !(caps & HB_QSV_CAP_OPTION2_LA_DOWNS) ? "" : " lookaheadds",
+ !(caps & HB_QSV_CAP_RATECONTROL_ICQ) ? "" : " icq",
+ !(caps & HB_QSV_CAP_OPTION2_MBBRC) ? "" : " mbbrc",
+ !(caps & HB_QSV_CAP_OPTION2_EXTBRC) ? "" : " extbrc",
+ !(caps & HB_QSV_CAP_OPTION2_TRELLIS) ? "" : " trellis",
+ !(caps & HB_QSV_CAP_OPTION2_IB_ADAPT) ? "" : " adaptivei adaptiveb",
+ !(caps & HB_QSV_CAP_OPTION2_NMBSLICE) ? "" : " nummbperslice");
+ }
+}
- // is QSV available?
+void hb_qsv_info_print()
+{
+ // is QSV available and usable?
hb_log("Intel Quick Sync Video support: %s",
hb_qsv_available() ? "yes": "no");
- // if we have Quick Sync Video support, also print the details
+ // 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_available())
{
- if (qsv_hardware_available)
+ if (hb_qsv_info_avc != NULL && hb_qsv_info_avc->available)
{
- hb_log(" - Intel Media SDK hardware: API %d.%d (minimum: %d.%d)",
- qsv_hardware_version.Major,
- qsv_hardware_version.Minor,
- qsv_minimum_version.Major,
- qsv_minimum_version.Minor);
+ hb_log(" - H.264 encoder: yes");
+ hb_log(" - preferred implementation: %s",
+ hb_qsv_impl_get_name(hb_qsv_info_avc->implementation));
+ if (qsv_hardware_info_avc.available)
+ {
+ log_capabilities(2, qsv_hardware_info_avc.capabilities,
+ " - capabilities (hardware): ");
+ }
+ if (qsv_software_info_avc.available)
+ {
+ log_capabilities(2, qsv_software_info_avc.capabilities,
+ " - capabilities (software): ");
+ }
}
- if (qsv_software_available)
+ else
{
- hb_log(" - Intel Media SDK software: API %d.%d (minimum: %d.%d)",
- qsv_software_version.Major,
- qsv_software_version.Minor,
- qsv_minimum_version.Major,
- qsv_minimum_version.Minor);
+ hb_log(" - H.264 encoder: no");
+ }
+ if (hb_qsv_info_hevc != NULL && hb_qsv_info_hevc->available)
+ {
+ hb_log(" - H.265 encoder: yes (unsupported)");
+ hb_log(" - preferred implementation: %s",
+ hb_qsv_impl_get_name(hb_qsv_info_hevc->implementation));
+ if (qsv_hardware_info_hevc.available)
+ {
+ log_capabilities(2, qsv_hardware_info_hevc.capabilities,
+ " - capabilities (hardware): ");
+ }
+ if (qsv_software_info_hevc.available)
+ {
+ log_capabilities(2, qsv_software_info_hevc.capabilities,
+ " - capabilities (software): ");
+ }
+ }
+ else
+ {
+ hb_log(" - H.265 encoder: no");
}
- hb_log(" - Preferred implementation: %s",
- hb_qsv_impl_get_name(preferred_implementation));
+ }
+}
+
+hb_qsv_info_t* hb_qsv_info_get(int encoder)
+{
+ switch (encoder)
+ {
+ case HB_VCODEC_QSV_H264:
+ return hb_qsv_info_avc;
+ default:
+ return NULL;
}
}
@@ -199,6 +616,18 @@ int hb_qsv_decode_is_enabled(hb_job_t *job)
(job->title->video_decode_support & HB_DECODE_SUPPORT_QSV));
}
+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))
+ {
+ // 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);
+ }
+ return 0;
+}
+
int hb_qsv_codingoption_xlat(int val)
{
switch (HB_QSV_CLIP3(-1, 2, val))
@@ -305,12 +734,12 @@ float hb_qsv_atof(const char *str, int *err)
return v;
}
-int hb_qsv_param_parse(hb_qsv_param_t *param,
- const char *key, const char *value, int vcodec)
+int hb_qsv_param_parse(hb_qsv_param_t *param, hb_qsv_info_t *info,
+ const char *key, const char *value)
{
float fvalue;
int ivalue, error = 0;
- if (param == NULL)
+ if (param == NULL || info == NULL)
{
return HB_QSV_PARAM_ERROR;
}
@@ -374,16 +803,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param,
}
else if (!strcasecmp(key, "b-pyramid"))
{
- if (hb_qsv_info->capabilities & HB_QSV_CAP_H264_BPYRAMID)
+ if (info->capabilities & HB_QSV_CAP_B_REF_PYRAMID)
{
- switch (vcodec)
- {
- case HB_VCODEC_QSV_H264:
- ivalue = hb_qsv_atoi(value, &error);
- break;
- default:
- return HB_QSV_PARAM_UNSUPPORTED;
- }
+ ivalue = hb_qsv_atoi(value, &error);
if (!error)
{
param->gop.b_pyramid = HB_QSV_CLIP3(-1, 1, ivalue);
@@ -409,6 +831,46 @@ int hb_qsv_param_parse(hb_qsv_param_t *param,
}
}
}
+ else if (!strcasecmp(key, "adaptive-i") ||
+ !strcasecmp(key, "i-adapt"))
+ {
+ if (info->capabilities & HB_QSV_CAP_OPTION2_IB_ADAPT)
+ {
+ ivalue = hb_qsv_atobool(value, &error);
+ if (!error)
+ {
+ param->codingOption2.AdaptiveI = hb_qsv_codingoption_xlat(ivalue);
+ }
+ }
+ else
+ {
+ return HB_QSV_PARAM_UNSUPPORTED;
+ }
+ }
+ else if (!strcasecmp(key, "adaptive-b") ||
+ !strcasecmp(key, "b-adapt"))
+ {
+ if (info->capabilities & HB_QSV_CAP_OPTION2_IB_ADAPT)
+ {
+ ivalue = hb_qsv_atobool(value, &error);
+ if (!error)
+ {
+ param->codingOption2.AdaptiveB = hb_qsv_codingoption_xlat(ivalue);
+ }
+ }
+ else
+ {
+ return HB_QSV_PARAM_UNSUPPORTED;
+ }
+ }
+ else if (!strcasecmp(key, "force-cqp"))
+ {
+ ivalue = hb_qsv_atobool(value, &error);
+ if (!error)
+ {
+ param->rc.icq = !ivalue;
+ }
+ }
else if (!strcasecmp(key, "cqp-offset-i"))
{
ivalue = hb_qsv_atoi(value, &error);
@@ -459,9 +921,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param,
}
else if (!strcasecmp(key, "cavlc") || !strcasecmp(key, "cabac"))
{
- switch (vcodec)
+ switch (info->codec_id)
{
- case HB_VCODEC_QSV_H264:
+ case MFX_CODEC_AVC:
ivalue = hb_qsv_atobool(value, &error);
break;
default:
@@ -478,10 +940,10 @@ int hb_qsv_param_parse(hb_qsv_param_t *param,
}
else if (!strcasecmp(key, "videoformat"))
{
- switch (vcodec)
+ switch (info->codec_id)
{
- case HB_VCODEC_QSV_H264:
- ivalue = hb_qsv_atoindex(x264_vidformat_names, value, &error);
+ case MFX_CODEC_AVC:
+ ivalue = hb_qsv_atoindex(hb_h264_vidformat_names, value, &error);
break;
default:
return HB_QSV_PARAM_UNSUPPORTED;
@@ -493,10 +955,10 @@ int hb_qsv_param_parse(hb_qsv_param_t *param,
}
else if (!strcasecmp(key, "fullrange"))
{
- switch (vcodec)
+ switch (info->codec_id)
{
- case HB_VCODEC_QSV_H264:
- ivalue = hb_qsv_atoindex(x264_fullrange_names, value, &error);
+ case MFX_CODEC_AVC:
+ ivalue = hb_qsv_atoindex(hb_h264_fullrange_names, value, &error);
break;
default:
return HB_QSV_PARAM_UNSUPPORTED;
@@ -508,10 +970,10 @@ int hb_qsv_param_parse(hb_qsv_param_t *param,
}
else if (!strcasecmp(key, "colorprim"))
{
- switch (vcodec)
+ switch (info->codec_id)
{
- case HB_VCODEC_QSV_H264:
- ivalue = hb_qsv_atoindex(x264_colorprim_names, value, &error);
+ case MFX_CODEC_AVC:
+ ivalue = hb_qsv_atoindex(hb_h264_colorprim_names, value, &error);
break;
default:
return HB_QSV_PARAM_UNSUPPORTED;
@@ -524,10 +986,10 @@ int hb_qsv_param_parse(hb_qsv_param_t *param,
}
else if (!strcasecmp(key, "transfer"))
{
- switch (vcodec)
+ switch (info->codec_id)
{
- case HB_VCODEC_QSV_H264:
- ivalue = hb_qsv_atoindex(x264_transfer_names, value, &error);
+ case MFX_CODEC_AVC:
+ ivalue = hb_qsv_atoindex(hb_h264_transfer_names, value, &error);
break;
default:
return HB_QSV_PARAM_UNSUPPORTED;
@@ -540,10 +1002,10 @@ int hb_qsv_param_parse(hb_qsv_param_t *param,
}
else if (!strcasecmp(key, "colormatrix"))
{
- switch (vcodec)
+ switch (info->codec_id)
{
- case HB_VCODEC_QSV_H264:
- ivalue = hb_qsv_atoindex(x264_colmatrix_names, value, &error);
+ case MFX_CODEC_AVC:
+ ivalue = hb_qsv_atoindex(hb_h264_colmatrix_names, value, &error);
break;
default:
return HB_QSV_PARAM_UNSUPPORTED;
@@ -557,9 +1019,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param,
else if (!strcasecmp(key, "tff") ||
!strcasecmp(key, "interlaced"))
{
- switch (vcodec)
+ switch (info->codec_id)
{
- case HB_VCODEC_QSV_H264:
+ case MFX_CODEC_AVC:
ivalue = hb_qsv_atobool(value, &error);
break;
default:
@@ -574,9 +1036,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param,
}
else if (!strcasecmp(key, "bff"))
{
- switch (vcodec)
+ switch (info->codec_id)
{
- case HB_VCODEC_QSV_H264:
+ case MFX_CODEC_AVC:
ivalue = hb_qsv_atobool(value, &error);
break;
default:
@@ -591,7 +1053,7 @@ int hb_qsv_param_parse(hb_qsv_param_t *param,
}
else if (!strcasecmp(key, "mbbrc"))
{
- if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_MBBRC)
+ if (info->capabilities & HB_QSV_CAP_OPTION2_MBBRC)
{
ivalue = hb_qsv_atobool(value, &error);
if (!error)
@@ -606,7 +1068,7 @@ int hb_qsv_param_parse(hb_qsv_param_t *param,
}
else if (!strcasecmp(key, "extbrc"))
{
- if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_EXTBRC)
+ if (info->capabilities & HB_QSV_CAP_OPTION2_EXTBRC)
{
ivalue = hb_qsv_atobool(value, &error);
if (!error)
@@ -622,16 +1084,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param,
else if (!strcasecmp(key, "lookahead") ||
!strcasecmp(key, "la"))
{
- switch (vcodec)
- {
- case HB_VCODEC_QSV_H264:
- ivalue = hb_qsv_atobool(value, &error);
- break;
- default:
- return HB_QSV_PARAM_UNSUPPORTED;
- }
- if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_LOOKAHEAD)
+ if (info->capabilities & HB_QSV_CAP_RATECONTROL_LA)
{
+ ivalue = hb_qsv_atobool(value, &error);
if (!error)
{
param->rc.lookahead = ivalue;
@@ -645,16 +1100,9 @@ int hb_qsv_param_parse(hb_qsv_param_t *param,
else if (!strcasecmp(key, "lookahead-depth") ||
!strcasecmp(key, "la-depth"))
{
- switch (vcodec)
- {
- case HB_VCODEC_QSV_H264:
- ivalue = hb_qsv_atoi(value, &error);
- break;
- default:
- return HB_QSV_PARAM_UNSUPPORTED;
- }
- if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_LOOKAHEAD)
+ if (info->capabilities & HB_QSV_CAP_RATECONTROL_LA)
{
+ ivalue = hb_qsv_atoi(value, &error);
if (!error)
{
// LookAheadDepth 10 will cause a hang with some driver versions
@@ -667,18 +1115,29 @@ int hb_qsv_param_parse(hb_qsv_param_t *param,
return HB_QSV_PARAM_UNSUPPORTED;
}
}
- else if (!strcasecmp(key, "trellis"))
+ else if (!strcasecmp(key, "lookahead-ds") ||
+ !strcasecmp(key, "la-ds"))
{
- switch (vcodec)
+ if (info->capabilities & HB_QSV_CAP_OPTION2_LA_DOWNS)
{
- case HB_VCODEC_QSV_H264:
- ivalue = hb_qsv_atoi(value, &error);
- break;
- default:
- return HB_QSV_PARAM_UNSUPPORTED;
+ ivalue = hb_qsv_atoi(value, &error);
+ if (!error)
+ {
+ param->codingOption2.LookAheadDS = HB_QSV_CLIP3(MFX_LOOKAHEAD_DS_UNKNOWN,
+ MFX_LOOKAHEAD_DS_4x,
+ ivalue);
+ }
+ }
+ else
+ {
+ return HB_QSV_PARAM_UNSUPPORTED;
}
- if (hb_qsv_info->capabilities & HB_QSV_CAP_OPTION2_TRELLIS)
+ }
+ else if (!strcasecmp(key, "trellis"))
+ {
+ if (info->capabilities & HB_QSV_CAP_OPTION2_TRELLIS)
{
+ ivalue = hb_qsv_atoi(value, &error);
if (!error)
{
param->codingOption2.Trellis = hb_qsv_trellisvalue_xlat(ivalue);
@@ -693,7 +1152,7 @@ int hb_qsv_param_parse(hb_qsv_param_t *param,
{
/*
* TODO:
- * - slice count control
+ * - slice count (num-slice/slices, num-mb-per-slice/slice-max-mbs)
* - open-gop
* - fake-interlaced (mfxExtCodingOption.FramePicture???)
* - intra-refresh
@@ -703,31 +1162,91 @@ int hb_qsv_param_parse(hb_qsv_param_t *param,
return error ? HB_QSV_PARAM_BAD_VALUE : HB_QSV_PARAM_OK;
}
+#ifdef HB_API_OLD_PRESET_GETTERS
+const char* const* hb_qsv_presets()
+{
+ return hb_qsv_preset_get_names();
+}
+#endif
+
const char* const* hb_qsv_preset_get_names()
{
- if (hb_get_cpu_platform() >= HB_CPU_PLATFORM_INTEL_HSW)
+ if (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G3)
{
return hb_qsv_preset_names2;
}
else
{
- return hb_qsv_preset_names1;
+ return hb_qsv_preset_names2;
}
}
-#ifdef HB_API_OLD_PRESET_GETTERS
-const char* const* hb_qsv_presets()
+const char* const* hb_qsv_profile_get_names(int encoder)
{
- return hb_qsv_preset_get_names();
+ switch (encoder)
+ {
+ case HB_VCODEC_QSV_H264:
+ return hb_h264_profile_names;
+ default:
+ return NULL;
+ }
+}
+
+const char* const* hb_qsv_level_get_names(int encoder)
+{
+ switch (encoder)
+ {
+ case HB_VCODEC_QSV_H264:
+ return hb_h264_level_names;
+ default:
+ return NULL;
+ }
+}
+
+const char* hb_qsv_video_quality_get_name(uint32_t codec)
+{
+ uint64_t caps;
+ switch (codec)
+ {
+ case HB_VCODEC_QSV_H264:
+ caps = hb_qsv_info_avc != NULL ? hb_qsv_info_avc->capabilities : 0;
+ return (caps & HB_QSV_CAP_RATECONTROL_ICQ) ? "ICQ" : "QP";
+
+ default:
+ return "QP";
+ }
+}
+
+void hb_qsv_video_quality_get_limits(uint32_t codec, float *low, float *high,
+ float *granularity, int *direction)
+{
+ uint64_t caps;
+ switch (codec)
+ {
+ case HB_VCODEC_QSV_H264:
+ caps = hb_qsv_info_avc != NULL ? hb_qsv_info_avc->capabilities : 0;
+ *direction = 1;
+ *granularity = 1.;
+ *low = (caps & HB_QSV_CAP_RATECONTROL_ICQ) ? 1. : 0.;
+ *high = 51.;
+ break;
+
+ default:
+ *direction = 1;
+ *granularity = 1.;
+ *low = 0.;
+ *high = 51.;
+ break;
+ }
}
-#endif
int hb_qsv_param_default_preset(hb_qsv_param_t *param,
- mfxVideoParam *videoParam, const char *preset)
+ mfxVideoParam *videoParam,
+ hb_qsv_info_t *info, const char *preset)
{
- if (param != NULL && videoParam != NULL)
+ if (param != NULL && videoParam != NULL && info != NULL)
{
- int ret = hb_qsv_param_default(param, videoParam);
+ int ret = hb_qsv_param_default(param, videoParam, info);
if (ret)
{
return ret;
@@ -769,7 +1288,7 @@ int hb_qsv_param_default_preset(hb_qsv_param_t *param,
* LookAhead: 0 (off)
* LookAheadDepth: Not Applicable
*/
- if (hb_get_cpu_platform() >= HB_CPU_PLATFORM_INTEL_HSW)
+ if (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G3)
{
param->rc.lookahead = 0;
param->videoParam->mfx.NumRefFrame = 1;
@@ -794,7 +1313,7 @@ int hb_qsv_param_default_preset(hb_qsv_param_t *param,
}
else if (!strcasecmp(preset, "speed"))
{
- if (hb_get_cpu_platform() >= HB_CPU_PLATFORM_INTEL_HSW)
+ if (qsv_hardware_generation(hb_get_cpu_platform()) >= QSV_G3)
{
/*
* HSW TargetUsage: 6
@@ -840,9 +1359,10 @@ int hb_qsv_param_default_preset(hb_qsv_param_t *param,
return 0;
}
-int hb_qsv_param_default(hb_qsv_param_t *param, mfxVideoParam *videoParam)
+int hb_qsv_param_default(hb_qsv_param_t *param, mfxVideoParam *videoParam,
+ hb_qsv_info_t *info)
{
- if (param != NULL && videoParam != NULL)
+ if (param != NULL && videoParam != NULL && info != NULL)
{
// introduced in API 1.0
memset(&param->codingOption, 0, sizeof(mfxExtCodingOption));
@@ -902,13 +1422,21 @@ int hb_qsv_param_default(hb_qsv_param_t *param, mfxVideoParam *videoParam)
// introduced in API 1.7
param->codingOption2.LookAheadDepth = 40;
param->codingOption2.Trellis = MFX_TRELLIS_OFF;
+ // introduced in API 1.8
+ param->codingOption2.RepeatPPS = MFX_CODINGOPTION_ON;
+ param->codingOption2.BRefType = MFX_B_REF_UNKNOWN; // controlled via gop.b_pyramid
+ param->codingOption2.AdaptiveI = MFX_CODINGOPTION_ON;
+ param->codingOption2.AdaptiveB = MFX_CODINGOPTION_ON;
+ param->codingOption2.LookAheadDS = MFX_LOOKAHEAD_DS_OFF;
+ param->codingOption2.NumMbPerSlice = 0;
// GOP & rate control
param->gop.b_pyramid = -1; // set automatically
param->gop.gop_pic_size = -1; // set automatically
param->gop.gop_ref_dist = -1; // set automatically
param->gop.int_ref_cycle_size = -1; // set automatically
- param->rc.lookahead = 1;
+ param->rc.icq = 1; // enabled by default (if supported)
+ param->rc.lookahead = 1; // enabled by default (if supported)
param->rc.cqp_offsets[0] = 0;
param->rc.cqp_offsets[1] = 2;
param->rc.cqp_offsets[2] = 4;
@@ -944,7 +1472,7 @@ int hb_qsv_param_default(hb_qsv_param_t *param, mfxVideoParam *videoParam)
param->videoParam->ExtParam = param->ExtParamArray;
param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)&param->codingOption;
param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)&param->videoSignalInfo;
- if (hb_qsv_info->capabilities & HB_QSV_CAP_MSDK_API_1_6)
+ if (info->capabilities & HB_QSV_CAP_MSDK_API_1_6)
{
param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)&param->codingOption2;
}
@@ -1015,9 +1543,37 @@ uint8_t hb_qsv_frametype_xlat(uint16_t qsv_frametype, uint16_t *out_flags)
return frametype;
}
-mfxIMPL hb_qsv_impl_get_preferred()
+int hb_qsv_impl_set_preferred(const char *name)
{
- return preferred_implementation;
+ 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)
@@ -1048,4 +1604,12 @@ const char* hb_qsv_impl_get_name(int impl)
}
}
+void hb_qsv_force_workarounds()
+{
+ qsv_software_info_avc.capabilities &= ~HB_QSV_CAP_MSDK_API_1_6;
+ qsv_hardware_info_avc.capabilities &= ~HB_QSV_CAP_MSDK_API_1_6;
+ qsv_software_info_hevc.capabilities &= ~HB_QSV_CAP_MSDK_API_1_6;
+ qsv_hardware_info_hevc.capabilities &= ~HB_QSV_CAP_MSDK_API_1_6;
+}
+
#endif // USE_QSV
diff --git a/libhb/qsv_common.h b/libhb/qsv_common.h
index c79cd2aa1..da879e548 100644
--- a/libhb/qsv_common.h
+++ b/libhb/qsv_common.h
@@ -11,6 +11,7 @@
#define HB_QSV_COMMON_H
#include "msdk/mfxvideo.h"
+#include "msdk/mfxplugin.h"
#include "libavcodec/avcodec.h"
/* Minimum Intel Media SDK version (currently 1.3, for Sandy Bridge support) */
@@ -28,34 +29,53 @@
*/
typedef struct hb_qsv_info_s
{
- // supported version-specific or hardware-specific capabilities
- int capabilities;
-#define HB_QSV_CAP_H264_BPYRAMID (1 << 0) // H.264: reference B-frames
-#define HB_QSV_CAP_MSDK_API_1_6 (1 << 1) // Support for API 1.6 or later
-#define HB_QSV_CAP_OPTION2_EXTBRC (1 << 2) // mfxExtCodingOption2: ExtBRC
-#define HB_QSV_CAP_OPTION2_MBBRC (1 << 3) // mfxExtCodingOption2: MBBRC
-#define HB_QSV_CAP_OPTION2_LOOKAHEAD (1 << 4) // mfxExtCodingOption2: LookAhead
-#define HB_QSV_CAP_OPTION2_TRELLIS (1 << 5) // mfxExtCodingOption2: Trellis
-// mfxCoreInterface: CopyFrame has a bug which prevents us from using it, but
-// the bug is fixed in newer drivers, we can use this cap to determine usability
-#define HB_QSV_CAP_CORE_COPYFRAME (1 << 6)
-
- // TODO: add available decoders, filters, encoders,
- // maximum decode and encode resolution, etc.
+ // each info struct only corresponds to one CodecId and implementation combo
+ const mfxU32 codec_id;
+ const mfxIMPL implementation;
+
+ // whether the encoder is available for this implementation
+ int available;
+
+ // version-specific or hardware-specific capabilities
+ uint64_t capabilities;
+ // support for API 1.6 or later
+#define HB_QSV_CAP_MSDK_API_1_6 (1LL << 0)
+ // H.264, H.265: B-frames can be used as references
+#define HB_QSV_CAP_B_REF_PYRAMID (1LL << 1)
+ // optional rate control methods
+#define HB_QSV_CAP_RATECONTROL_LA (1LL << 10)
+#define HB_QSV_CAP_RATECONTROL_LAi (1LL << 11)
+#define HB_QSV_CAP_RATECONTROL_ICQ (1LL << 12)
+ // mfxExtCodingOption2 fields
+#define HB_QSV_CAP_OPTION2_MBBRC (1LL << 20)
+#define HB_QSV_CAP_OPTION2_EXTBRC (1LL << 21)
+#define HB_QSV_CAP_OPTION2_TRELLIS (1LL << 22)
+#define HB_QSV_CAP_OPTION2_BREFTYPE (1LL << 23)
+#define HB_QSV_CAP_OPTION2_IB_ADAPT (1LL << 24)
+#define HB_QSV_CAP_OPTION2_LA_DOWNS (1LL << 25)
+#define HB_QSV_CAP_OPTION2_NMBSLICE (1LL << 26)
+
+ // TODO: add maximum encode resolution, etc.
} hb_qsv_info_t;
-/* Global Intel QSV information for use by the UIs */
-extern hb_qsv_info_t *hb_qsv_info;
-
/* Intel Quick Sync Video utilities */
-int hb_qsv_available();
-int hb_qsv_info_init();
-void hb_qsv_info_print();
+int hb_qsv_available();
+int hb_qsv_video_encoder_is_enabled(int encoder);
+int hb_qsv_audio_encoder_is_enabled(int encoder);
+int hb_qsv_info_init();
+void hb_qsv_info_print();
+hb_qsv_info_t* hb_qsv_info_get(int encoder);
/* Intel Quick Sync Video DECODE utilities */
const char* hb_qsv_decode_get_codec_name(enum AVCodecID codec_id);
int hb_qsv_decode_is_enabled(hb_job_t *job);
+/*
+ * mfxCoreInterface::CopyFrame had a bug preventing us from using it, but
+ * it was fixed in newer drivers - we can use this to determine usability
+ */
+int hb_qsv_copyframe_is_slow(int encoder);
+
/* Media SDK parameters handling */
enum
{
@@ -99,6 +119,7 @@ typedef struct
} gop;
struct
{
+ int icq;
int lookahead;
int cqp_offsets[3];
int vbv_max_bitrate;
@@ -110,9 +131,14 @@ typedef struct
mfxVideoParam *videoParam;
} hb_qsv_param_t;
-const char* const* hb_qsv_preset_get_names();
static const char* const hb_qsv_preset_names1[] = { "speed", "balanced", NULL, };
static const char* const hb_qsv_preset_names2[] = { "speed", "balanced", "quality", NULL, };
+const char* const* hb_qsv_preset_get_names();
+const char* const* hb_qsv_profile_get_names(int encoder);
+const char* const* hb_qsv_level_get_names(int encoder);
+
+const char* hb_qsv_video_quality_get_name(uint32_t codec);
+void hb_qsv_video_quality_get_limits(uint32_t codec, float *low, float *high, float *granularity, int *direction);
#define HB_QSV_CLIP3(min, max, val) ((val < min) ? min : (val > max) ? max : val)
int hb_qsv_codingoption_xlat (int val);
@@ -124,14 +150,16 @@ int hb_qsv_atobool (const char *str, int *err);
int hb_qsv_atoi (const char *str, int *err);
float hb_qsv_atof (const char *str, int *err);
-int hb_qsv_param_default_preset(hb_qsv_param_t *param, mfxVideoParam *videoParam, const char *preset);
-int hb_qsv_param_default (hb_qsv_param_t *param, mfxVideoParam *videoParam);
-int hb_qsv_param_parse (hb_qsv_param_t *param, const char *key, const char *value, int vcodec);
+int hb_qsv_param_default_preset(hb_qsv_param_t *param, mfxVideoParam *videoParam, hb_qsv_info_t *info, const char *preset);
+int hb_qsv_param_default (hb_qsv_param_t *param, mfxVideoParam *videoParam, hb_qsv_info_t *info);
+int hb_qsv_param_parse (hb_qsv_param_t *param, hb_qsv_info_t *info, const char *key, const char *value);
const char* hb_qsv_frametype_name(uint16_t qsv_frametype);
uint8_t hb_qsv_frametype_xlat(uint16_t qsv_frametype, uint16_t *out_flags);
-mfxIMPL hb_qsv_impl_get_preferred();
+int hb_qsv_impl_set_preferred(const char *name);
const char* hb_qsv_impl_get_name(int impl);
+void hb_qsv_force_workarounds(); // for developers only
+
#endif
diff --git a/libhb/work.c b/libhb/work.c
index 96f5016f0..dd047a20a 100644
--- a/libhb/work.c
+++ b/libhb/work.c
@@ -734,7 +734,7 @@ static void do_job(hb_job_t *job)
* the list and we can't use CopyFrame, disable QSV decoding until a
* better solution is implemented.
*/
- if (!(hb_qsv_info->capabilities & HB_QSV_CAP_CORE_COPYFRAME))
+ if (hb_qsv_copyframe_is_slow(job->vcodec))
{
if (job->list_filter != NULL)
{
diff --git a/test/test.c b/test/test.c
index cd414e221..a595a9d58 100644
--- a/test/test.c
+++ b/test/test.c
@@ -3687,6 +3687,7 @@ static int ParseOptions( int argc, char ** argv )
#define AUDIO_DITHER 289
#define QSV_BASELINE 290
#define QSV_ASYNC_DEPTH 291
+ #define QSV_IMPLEMENTATION 292
for( ;; )
{
@@ -4339,19 +4340,14 @@ static int ParseOptions( int argc, char ** argv )
break;
#ifdef USE_QSV
case QSV_BASELINE:
- if (hb_qsv_available())
- {
- /* XXX: for testing workarounds */
- hb_qsv_info->capabilities &= ~HB_QSV_CAP_MSDK_API_1_6;
- hb_qsv_info->capabilities &= ~HB_QSV_CAP_OPTION2_MBBRC;
- hb_qsv_info->capabilities &= ~HB_QSV_CAP_OPTION2_EXTBRC;
- hb_qsv_info->capabilities &= ~HB_QSV_CAP_OPTION2_TRELLIS;
- hb_qsv_info->capabilities &= ~HB_QSV_CAP_OPTION2_LOOKAHEAD;
- }
+ hb_qsv_force_workarounds();
break;
case QSV_ASYNC_DEPTH:
qsv_async_depth = atoi(optarg);
break;
+ case QSV_IMPLEMENTATION:
+ hb_qsv_impl_set_preferred(optarg);
+ break;
#endif
default:
fprintf( stderr, "unknown option (%s)\n", argv[cur_optind] );