diff options
-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] ); |