From: Rodeo Date: Sun, 23 Jun 2013 20:00:33 +0000 (+0000) Subject: QSV: enc_qsv, generate our own decode time stamps when they aren't available from... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c31a407cb5e08b2cd450b80e53eacad2a78a81ea;p=handbrake QSV: enc_qsv, generate our own decode time stamps when they aren't available from MediaSDK (API version < 1.6). This restores B-frame in MP4 support for Sandy Bridge. git-svn-id: svn://svn.handbrake.fr/HandBrake/branches/qsv@5601 b64f7644-9d1e-0410-96f1-a4d463321fa5 --- diff --git a/libhb/enc_qsv.c b/libhb/enc_qsv.c index c8c0e66e6..0ad08f2ec 100644 --- a/libhb/enc_qsv.c +++ b/libhb/enc_qsv.c @@ -98,6 +98,13 @@ struct hb_work_private_s uint32_t frames_in; uint32_t frames_out; +#define BFRM_DELAY_MAX 2 // for B-pyramid + // for DTS generation (when MSDK < 1.6) + int bfrm_delay; + int bfrm_workaround; + int64_t init_pts[BFRM_DELAY_MAX + 1]; + hb_list_t *list_dts; + mfxExtCodingOptionSPSPPS *sps_pps; int codec_profile; @@ -128,6 +135,35 @@ struct hb_work_private_s extern char* get_codec_id(hb_work_private_t *pv); +// for DTS generation (when MSDK < 1.6) +static void hb_qsv_add_new_dts(hb_list_t *list, int64_t new_dts) +{ + if (list != NULL) + { + int64_t *item = malloc(sizeof(int64_t)); + if (item != NULL) + { + *item = new_dts; + hb_list_add(list, item); + } + } +} +static int64_t hb_qsv_pop_next_dts(hb_list_t *list) +{ + int64_t next_dts = INT64_MIN; + if (list != NULL && hb_list_count(list) > 0) + { + int64_t *item = hb_list_item(list, 0); + if (item != NULL) + { + next_dts = *item; + hb_list_rem(list, item); + free(item); + } + } + return next_dts; +} + int qsv_enc_init( av_qsv_context* qsv, hb_work_private_t * pv ){ mfxStatus sts; int i = 0; @@ -574,6 +610,26 @@ int qsv_enc_init( av_qsv_context* qsv, hb_work_private_t * pv ){ pv->qsv_config.gop_ref_dist = videoParam.mfx.GopRefDist; + // check whether B-frames are used and compute the delay + pv->bfrm_delay = pv->codec_profile == MFX_PROFILE_AVC_BASELINE ? 0 : 1; + pv->bfrm_delay += !!(hb_qsv_info->capabilities & HB_QSV_CAP_BPYRAMID); + if (qsv_encode->m_mfxVideoParam.mfx.GopRefDist > 0) + { + pv->bfrm_delay = FFMIN(pv->bfrm_delay, + qsv_encode->m_mfxVideoParam.mfx.GopRefDist - 1); + } + if (qsv_encode->m_mfxVideoParam.mfx.GopPicSize > 0) + { + pv->bfrm_delay = FFMIN(pv->bfrm_delay, + qsv_encode->m_mfxVideoParam.mfx.GopPicSize - 2); + } + // sanitize + pv->bfrm_delay = FFMAX(pv->bfrm_delay, 0); + pv->bfrm_delay = FFMIN(pv->bfrm_delay, BFRM_DELAY_MAX); + // check whether we need to generate DTS ourselves (MSDK < 1.6) + pv->bfrm_workaround = pv->bfrm_delay && !(hb_qsv_info->capabilities & + HB_QSV_CAP_MSDK_1_6); + qsv_encode->is_init_done = 1; return 0; @@ -639,27 +695,6 @@ int encqsvInit( hb_work_object_t * w, hb_job_t * job ) pv->is_vpp_present = 0; - // FIXME: please let this be temporary - // note: MKV only has PTS so it's unaffected - if ((job->mux & HB_MUX_MASK_MP4) && - (profile != PROFILE_BASELINE) && - (hb_qsv_info->capabilities & HB_QSV_CAP_MSDK_1_6) == 0) - { - if (hb_qsv_info->cpu_platform == HB_CPU_PLATFORM_INTEL_SNB) - { - // hardware is too old, updating the driver won't help - hb_error("encqsvInit: MediaSDK < 1.6, B-frames in MP4 container not supported;" - " please try newer hardware, use the MKV container or Baseline profile"); - } - else - { - hb_error("encqsvInit: MediaSDK < 1.6, B-frames in MP4 container not supported;" - " please update your driver, use the MKV container or Baseline profile"); - } - *job->die = 1; - return -1; - } - return 0; } @@ -804,6 +839,28 @@ int encqsvWork( hb_work_object_t * w, hb_buffer_t ** buf_in, stage = av_qsv_get_last_stage( received_item ); work_surface = stage->out.p_surface; } + + /* + * Generate output DTS based on input PTS. + * + * Depends on the B-frame delay: + * + * 0 -> ipts0, ipts1, ipts2... + * 1 -> ipts0 - ipts1, ipts1 - ipts1, ipts1, ipts2... + * 2 -> ipts0 - ipts2, ipts1 - ipts2, ipts2 - ipts2, ipts1, ipts2... + */ + if (pv->bfrm_delay && pv->bfrm_workaround) + { + if (pv->frames_in <= pv->bfrm_delay) + { + pv->init_pts[pv->frames_in] = work_surface->Data.TimeStamp; + } + if (pv->frames_in) + { + hb_qsv_add_new_dts(pv->list_dts, + work_surface->Data.TimeStamp); + } + } } else{ work_surface = NULL; @@ -926,16 +983,35 @@ int encqsvWork( hb_work_object_t * w, hb_buffer_t ** buf_in, last_buf->next = buf; last_buf = buf; - // simple for now but check on TimeStampCalc from MSDK - int64_t duration = ((double)qsv_encode->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD / - (double)qsv_encode->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN) * 90000.; + // simple for now but check on TimeStampCalc from MSDK + int64_t duration = ((double)qsv_encode->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtD / + (double)qsv_encode->m_mfxVideoParam.mfx.FrameInfo.FrameRateExtN) * 90000.; - // start -> PTS - // renderOffset -> DTS - buf->s.start = buf->s.renderOffset = task->bs->TimeStamp; - buf->s.stop = buf->s.start + duration; - if (hb_qsv_info->capabilities & HB_QSV_CAP_MSDK_1_6) + // start -> PTS + // renderOffset -> DTS + buf->s.start = buf->s.renderOffset = task->bs->TimeStamp; + buf->s.stop = buf->s.start + duration; + buf->s.duration = duration; + if (pv->bfrm_delay) + { + if (!pv->bfrm_workaround) + { buf->s.renderOffset = task->bs->DecodeTimeStamp; + } + else + { + // MSDK API < 1.6, so generate our own DTS + if (pv->frames_out <= pv->bfrm_delay) + { + buf->s.renderOffset = (pv->init_pts[pv->frames_out] - + pv->init_pts[pv->bfrm_delay]); + } + else + { + buf->s.renderOffset = hb_qsv_pop_next_dts(pv->list_dts); + } + } + } if(pv->qsv_config.gop_ref_dist > 1) pv->qsv_config.gop_ref_dist--;