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 /libhb/enc_qsv.c | |
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
Diffstat (limited to 'libhb/enc_qsv.c')
-rw-r--r-- | libhb/enc_qsv.c | 211 |
1 files changed, 151 insertions, 60 deletions
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 |