summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRodeo <[email protected]>2015-02-01 01:23:59 +0000
committerRodeo <[email protected]>2015-02-01 01:23:59 +0000
commit0ed67774efe54e9036ed56738df66b90fd3a7841 (patch)
tree00ab5069cf6aaee56a9cd907a2392ee31df7a3e9
parentd75dadf6d4816c87753d5e4b0cf765109ff68cd5 (diff)
QSV: improve B-Pyramid handling.
Newer drivers support enabling/disabling it via a dedicated option without having to modify other GOP parameters. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@6847 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r--libhb/enc_qsv.c249
1 files changed, 139 insertions, 110 deletions
diff --git a/libhb/enc_qsv.c b/libhb/enc_qsv.c
index a1ba9d5f2..5f3b9310a 100644
--- a/libhb/enc_qsv.c
+++ b/libhb/enc_qsv.c
@@ -189,6 +189,127 @@ static const char* qsv_h264_level_xlat(int level)
return NULL;
}
+static void qsv_handle_breftype(hb_work_private_t *pv)
+{
+ /*
+ * If B-pyramid is not possible (not supported, incompatible profile, etc.)
+ * we don't need to adjust any settings, just sanitize it to off and return.
+ */
+ if (!(pv->qsv_info->capabilities & HB_QSV_CAP_B_REF_PYRAMID))
+ {
+ /* B-pyramid support not implemented */
+ goto unsupported;
+ }
+ else if (pv->param.videoParam->mfx.GopPicSize &&
+ pv->param.videoParam->mfx.GopPicSize <= 3)
+ {
+ /* GOP size must be at least 4 for B-pyramid */
+ goto unsupported;
+ }
+ else if (pv->param.videoParam->mfx.GopRefDist &&
+ pv->param.videoParam->mfx.GopRefDist <= 2)
+ {
+ /* We need 2 consecutive B-frames for B-pyramid (GopRefDist >= 3) */
+ goto unsupported;
+ }
+ else if (pv->qsv_info->codec_id == MFX_CODEC_AVC)
+ {
+ switch (pv->param.videoParam->mfx.CodecProfile)
+ {
+ case MFX_PROFILE_AVC_BASELINE:
+ case MFX_PROFILE_AVC_CONSTRAINED_HIGH:
+ case MFX_PROFILE_AVC_CONSTRAINED_BASELINE:
+ goto unsupported; // B-frames not allowed by profile
+ default:
+ break;
+ }
+ }
+
+ /* Handle B-pyramid auto (on for CQP, off otherwise) */
+ if (pv->param.gop.b_pyramid < 0)
+ {
+ pv->param.gop.b_pyramid = pv->param.videoParam->mfx.RateControlMethod == MFX_RATECONTROL_CQP;
+ }
+
+ if (pv->qsv_info->capabilities & HB_QSV_CAP_OPTION2_BREFTYPE)
+ {
+ /* B-pyramid can be controlled directly */
+ if (pv->param.gop.b_pyramid)
+ {
+ pv->param.codingOption2.BRefType = MFX_B_REF_PYRAMID;
+ }
+ else
+ {
+ pv->param.codingOption2.BRefType = MFX_B_REF_OFF;
+ }
+ }
+ else
+ {
+ /*
+ * We can't control B-pyramid directly, do it indirectly by
+ * adjusting GopRefDist, GopPicSize and NumRefFrame instead.
+ */
+ pv->param.codingOption2.BRefType = MFX_B_REF_UNKNOWN;
+
+ /*
+ * pyramid_ref_dist is the closest B-pyramid compatible
+ * value (multiple of 2, >= 4) to the requested GopRefDist.
+ */
+ int pyramid_ref_dist = 4;
+ while (pv->param.videoParam->mfx.GopRefDist > pyramid_ref_dist)
+ {
+ pyramid_ref_dist *= 2;
+ }
+
+ if (pv->param.gop.b_pyramid)
+ {
+ /* GopRefDist must be B-pyramid compatible */
+ pv->param.videoParam->mfx.GopRefDist = pyramid_ref_dist;
+
+ /*
+ * GopPicSize must be a multiple of GopRefDist.
+ *
+ * Note: GopPicSize == 0 should always result in a value
+ * that doesn't cause Media SDK to disable B-pyramid.
+ */
+ if (pv->param.videoParam->mfx.GopPicSize)
+ {
+ pv->param.videoParam->mfx.GopPicSize = FFALIGN(pv->param.videoParam->mfx.GopPicSize,
+ pv->param.videoParam->mfx.GopRefDist);
+ }
+
+ /*
+ * NumRefFrame must be greater than 3 and than half of GopRefDist.
+ * Otherwise, Media SDK may sometimes decide to disable B-pyramid
+ * (whereas sometimes it will simply sanitize NumRefFrame instead).
+ *
+ * Note: Media SDK handles the NumRefFrame == 0 case for us.
+ */
+ if (pv->param.videoParam->mfx.NumRefFrame)
+ {
+ pv->param.videoParam->mfx.NumRefFrame = FFMAX(pv->param.videoParam->mfx.NumRefFrame,
+ pv->param.videoParam->mfx.GopRefDist / 2);
+ pv->param.videoParam->mfx.NumRefFrame = FFMAX(pv->param.videoParam->mfx.NumRefFrame, 3);
+ }
+ }
+ else if (pv->param.videoParam->mfx.GopRefDist == 0 ||
+ pv->param.videoParam->mfx.GopRefDist == pyramid_ref_dist)
+ {
+ /*
+ * GopRefDist is either B-pyramid compatible or unknown (and thus
+ * potentially compatible), so adjust it to force-disable B-pyramid.
+ */
+ pv->param.videoParam->mfx.GopRefDist = pyramid_ref_dist - 1;
+ }
+ }
+
+ return;
+
+unsupported:
+ pv->param.gop.b_pyramid = 0;
+ pv->param.codingOption2.BRefType = MFX_B_REF_OFF;
+}
+
int qsv_enc_init(hb_work_private_t *pv)
{
av_qsv_context *qsv = pv->job->qsv.ctx;
@@ -735,20 +856,6 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
}
}
- // set B-pyramid
- if (pv->param.gop.b_pyramid < 0)
- {
- if (pv->param.videoParam->mfx.RateControlMethod == MFX_RATECONTROL_CQP)
- {
- pv->param.gop.b_pyramid = 1;
- }
- else
- {
- pv->param.gop.b_pyramid = 0;
- }
- }
- pv->param.gop.b_pyramid = !!pv->param.gop.b_pyramid;
-
// set the GOP structure
if (pv->param.gop.gop_ref_dist < 0)
{
@@ -798,94 +905,11 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
pv->param.rc.lookahead ? 60 : 0);
}
- 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))
- {
- int gop_ref_dist = 4;
- /*
- * B-pyramid is supported.
- *
- * Set gop_ref_dist to a power of two, >= 4 and <= GopRefDist to ensure
- * Media SDK will not disable B-pyramid if we end up using it below.
- */
- while (pv->param.videoParam->mfx.GopRefDist >= gop_ref_dist * 2)
- {
- gop_ref_dist *= 2;
- }
- if ((pv->param.gop.b_pyramid) &&
- (pv->param.videoParam->mfx.GopPicSize == 0 ||
- pv->param.videoParam->mfx.GopPicSize > gop_ref_dist))
- {
- /*
- * B-pyramid enabled and GopPicSize is long enough for gop_ref_dist.
- *
- * Use gop_ref_dist. GopPicSize must be a multiple of GopRefDist.
- * NumRefFrame should be >= (GopRefDist / 2) and >= 3, otherwise
- * Media SDK may sometimes decide to disable B-pyramid too (whereas
- * sometimes it will just sanitize NumrefFrame instead).
- *
- * Notes: Media SDK handles the NumRefFrame == 0 case for us.
- * Also, GopPicSize == 0 should always result in a value that
- * does NOT cause Media SDK to disable B-pyramid, so it's OK.
- */
- pv->param.videoParam->mfx.GopRefDist = gop_ref_dist;
- pv->param.videoParam->mfx.GopPicSize = (pv->param.videoParam->mfx.GopPicSize /
- pv->param.videoParam->mfx.GopRefDist *
- pv->param.videoParam->mfx.GopRefDist);
- if (pv->param.videoParam->mfx.NumRefFrame)
- {
- pv->param.videoParam->mfx.NumRefFrame = FFMAX(pv->param.videoParam->mfx.NumRefFrame,
- pv->param.videoParam->mfx.GopRefDist / 2);
- pv->param.videoParam->mfx.NumRefFrame = FFMAX(pv->param.videoParam->mfx.NumRefFrame, 3);
- }
- }
- else
- {
- /*
- * B-pyramid disabled or not possible (GopPicSize too short).
- * Sanitize gop.b_pyramid to 0 (off/disabled).
- */
- pv->param.gop.b_pyramid = 0;
- /* Then, adjust settings to actually disable it. */
- if (pv->param.videoParam->mfx.GopRefDist == 0)
- {
- /*
- * GopRefDist == 0 means the value will be set by Media SDK.
- * Since we can't be sure what the actual value would be, we
- * have to make sure that GopRefDist is set explicitly.
- */
- pv->param.videoParam->mfx.GopRefDist = gop_ref_dist - 1;
- }
- else if (pv->param.videoParam->mfx.GopRefDist == gop_ref_dist)
- {
- /* GopRefDist is compatible with Media SDK's B-pyramid. */
- if (pv->param.videoParam->mfx.GopPicSize == 0)
- {
- /*
- * GopPicSize is unknown and could be a multiple of
- * GopRefDist. Decrement the latter to disable B-pyramid.
- */
- pv->param.videoParam->mfx.GopRefDist--;
- }
- else if (pv->param.videoParam->mfx.GopPicSize %
- pv->param.videoParam->mfx.GopRefDist == 0)
- {
- /*
- * GopPicSize is a multiple of GopRefDist.
- * Increment the former to disable B-pyramid.
- */
- pv->param.videoParam->mfx.GopPicSize++;
- }
- }
- }
- }
- else
- {
- /* B-pyramid not supported. */
- pv->param.gop.b_pyramid = 0;
- }
+ /*
+ * We may need to adjust GopRefDist, GopPicSize and
+ * NumRefFrame to enable or disable B-pyramid, so do it last.
+ */
+ qsv_handle_breftype(pv);
/*
* init a dummy encode-only session to get the SPS/PPS
@@ -995,9 +1019,8 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
MFXClose(session);
}
- /* check whether B-frames are used */
- int bframes = videoParam.mfx.GopRefDist > 1 && videoParam.mfx.GopPicSize > 2;
- if (bframes)
+ /* B-frame related setup */
+ if (videoParam.mfx.GopRefDist > 1)
{
/* the muxer needs to know to the init_delay */
switch (pv->qsv_info->codec_id)
@@ -1025,17 +1048,20 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
videoParam.mfx.GopRefDist, videoParam.mfx.GopPicSize, videoParam.mfx.NumRefFrame);
if (pv->qsv_info->capabilities & HB_QSV_CAP_B_REF_PYRAMID)
{
- hb_log("encqsvInit: BFrames %s BPyramid %s",
- bframes ? "on" : "off",
- bframes && pv->param.gop.b_pyramid ? "on" : "off");
+ hb_log("encqsvInit: BFramesMax %d BRefType %s",
+ videoParam.mfx.GopRefDist > 1 ?
+ videoParam.mfx.GopRefDist - 1 : 0,
+ pv->param.gop.b_pyramid ? "pyramid" : "off");
}
else
{
- hb_log("encqsvInit: BFrames %s", bframes ? "on" : "off");
+ hb_log("encqsvInit: BFramesMax %d",
+ videoParam.mfx.GopRefDist > 1 ?
+ videoParam.mfx.GopRefDist - 1 : 0);
}
if (pv->qsv_info->capabilities & HB_QSV_CAP_OPTION2_IB_ADAPT)
{
- if (bframes)
+ if (videoParam.mfx.GopRefDist > 1)
{
hb_log("encqsvInit: AdaptiveI %s AdaptiveB %s",
hb_qsv_codingoption_get_name(option2->AdaptiveI),
@@ -1434,6 +1460,9 @@ static void compute_init_delay(hb_work_private_t *pv, mfxBitstream *bs)
pv->init_delay[0] = pv->init_pts[1] - pv->init_pts[0];
}
+ /* This can come in handy */
+ hb_deep_log(2, "compute_init_delay: %"PRId64" (%d frames)", pv->init_delay[0], pv->bfrm_delay);
+
/* The delay only needs to be set once. */
pv->init_delay = NULL;
}