diff options
author | Rodeo <[email protected]> | 2014-02-18 17:14:14 +0000 |
---|---|---|
committer | Rodeo <[email protected]> | 2014-02-18 17:14:14 +0000 |
commit | 681bdf52d5d2a9339c02c7a2b07358dc383681ec (patch) | |
tree | c9e8a5b5d5ed3547ec5b5b06e2ca3a807838df0a | |
parent | b3e905dde9dacd4129c05440cedbe5a1366d0243 (diff) |
QSV: API 1.8 support and related improvements
Optional feature detection now done via MFXVideoENCODE_Query. This should work better with future hardware and encoder implementations.
Optional API 1.8 features are not tested (not supported by the software implementation, and no drivers with API 1.8 support available yet).
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@6041 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r-- | libhb/common.c | 55 | ||||
-rw-r--r-- | libhb/decavcodec.c | 33 | ||||
-rw-r--r-- | libhb/enc_qsv.c | 211 | ||||
-rw-r--r-- | libhb/h264_common.h | 13 | ||||
-rw-r--r-- | libhb/qsv_common.c | 926 | ||||
-rw-r--r-- | libhb/qsv_common.h | 78 | ||||
-rw-r--r-- | libhb/work.c | 2 | ||||
-rw-r--r-- | test/test.c | 14 |
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(¶m->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*)¶m->codingOption; param->videoParam->ExtParam[param->videoParam->NumExtParam++] = (mfxExtBuffer*)¶m->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*)¶m->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] ); |