summaryrefslogtreecommitdiffstats
path: root/libhb
diff options
context:
space:
mode:
authorRodeo <[email protected]>2013-09-05 20:30:07 +0000
committerRodeo <[email protected]>2013-09-05 20:30:07 +0000
commitd8729498fb53e8fe761c1c47af2415ffd847bd3a (patch)
tree9ed13843033a3adcb36a792de3d01a074073c762 /libhb
parent7fad76dfdaa73ff0e178e00d34643370b88f5136 (diff)
QSV: add an option to control B-pyramid.
Since there is no way to control it directly, output settings need to be adjusted a bit. Disabled by default for improved compatibility. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@5768 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb')
-rw-r--r--libhb/enc_qsv.c163
-rw-r--r--libhb/qsv_common.c25
-rw-r--r--libhb/qsv_common.h1
3 files changed, 156 insertions, 33 deletions
diff --git a/libhb/enc_qsv.c b/libhb/enc_qsv.c
index 395f32b41..66825baab 100644
--- a/libhb/enc_qsv.c
+++ b/libhb/enc_qsv.c
@@ -716,6 +716,95 @@ 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) &&
+ (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 != 0)
+ {
+ 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;
+ }
+
/*
* init a dummy encode-only session to get the SPS/PPS
* and the final output settings sanitized by Media SDK
@@ -792,6 +881,38 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
return -1;
}
+ // check whether B-frames are used
+ switch (videoParam.mfx.CodecProfile)
+ {
+ case MFX_PROFILE_AVC_BASELINE:
+ case MFX_PROFILE_AVC_CONSTRAINED_HIGH:
+ case MFX_PROFILE_AVC_CONSTRAINED_BASELINE:
+ pv->bfrm_delay = 0;
+ break;
+ default:
+ pv->bfrm_delay = 1;
+ break;
+ }
+ // sanitize
+ pv->bfrm_delay = FFMIN(pv->bfrm_delay, videoParam.mfx.GopRefDist - 1);
+ pv->bfrm_delay = FFMIN(pv->bfrm_delay, videoParam.mfx.GopPicSize - 2);
+ pv->bfrm_delay = FFMAX(pv->bfrm_delay, 0);
+ // 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 &
+ HB_QSV_CAP_MSDK_API_1_6);
+ if (pv->bfrm_delay && pv->bfrm_workaround)
+ {
+ pv->bfrm_workaround = 1;
+ pv->list_dts = hb_list_init();
+ }
+ else
+ {
+ pv->bfrm_workaround = 0;
+ pv->list_dts = NULL;
+ }
+
// log code path and main output settings
hb_log("encqsvInit: using %s path",
pv->is_sys_mem ? "encode-only" : "full QSV");
@@ -799,6 +920,9 @@ 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);
+ hb_log("encqsvInit: BFrames %s BPyramid %s",
+ pv->bfrm_delay ? "on" : "off",
+ pv->bfrm_delay && pv->param.gop.b_pyramid ? "on" : "off");
if (videoParam.mfx.RateControlMethod == MFX_RATECONTROL_CQP)
{
char qpi[7], qpp[9], qpb[9];
@@ -881,38 +1005,6 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
pv->max_async_depth = videoParam.AsyncDepth;
pv->async_depth = 0;
- // check whether B-frames are used
- switch (videoParam.mfx.CodecProfile)
- {
- case MFX_PROFILE_AVC_BASELINE:
- case MFX_PROFILE_AVC_CONSTRAINED_HIGH:
- case MFX_PROFILE_AVC_CONSTRAINED_BASELINE:
- pv->bfrm_delay = 0;
- break;
- default:
- pv->bfrm_delay = 1;
- break;
- }
- // sanitize
- pv->bfrm_delay = FFMIN(pv->bfrm_delay, videoParam.mfx.GopRefDist - 1);
- pv->bfrm_delay = FFMIN(pv->bfrm_delay, videoParam.mfx.GopPicSize - 2);
- pv->bfrm_delay = FFMAX(pv->bfrm_delay, 0);
- // 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 &
- HB_QSV_CAP_MSDK_API_1_6);
- if (pv->bfrm_delay && pv->bfrm_workaround)
- {
- pv->bfrm_workaround = 1;
- pv->list_dts = hb_list_init();
- }
- else
- {
- pv->bfrm_workaround = 0;
- pv->list_dts = NULL;
- }
-
return 0;
}
@@ -1302,6 +1394,13 @@ int encqsvWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
(duration / 2)) / duration);
pv->bfrm_delay = FFMAX(pv->bfrm_delay, 1);
pv->bfrm_delay = FFMIN(pv->bfrm_delay, BFRM_DELAY_MAX);
+ // check whether b_pyramid is respected, log if needed
+ if ((pv->param.gop.b_pyramid != 0 && pv->bfrm_delay <= 1) ||
+ (pv->param.gop.b_pyramid == 0 && pv->bfrm_delay >= 2))
+ {
+ hb_log("encqsvWork: b_pyramid %d not respected (delay: %d)",
+ pv->param.gop.b_pyramid, pv->bfrm_delay);
+ }
}
/*
* Generate VFR-compatible output DTS based on input PTS.
diff --git a/libhb/qsv_common.c b/libhb/qsv_common.c
index 210a91388..949176f0a 100644
--- a/libhb/qsv_common.c
+++ b/libhb/qsv_common.c
@@ -368,6 +368,28 @@ int hb_qsv_param_parse(hb_qsv_param_t *param,
param->gop.gop_pic_size = HB_QSV_CLIP3(-1, UINT16_MAX, ivalue);
}
}
+ else if (!strcasecmp(key, "b-pyramid"))
+ {
+ if (hb_qsv_info->capabilities & HB_QSV_CAP_H264_BPYRAMID)
+ {
+ switch (vcodec)
+ {
+ case HB_VCODEC_QSV_H264:
+ ivalue = hb_qsv_atobool(value, &error);
+ break;
+ default:
+ return HB_QSV_PARAM_UNSUPPORTED;
+ }
+ if (!error)
+ {
+ param->gop.b_pyramid = ivalue;
+ }
+ }
+ else
+ {
+ return HB_QSV_PARAM_UNSUPPORTED;
+ }
+ }
else if (!strcasecmp(key, "scenecut"))
{
ivalue = hb_qsv_atobool(value, &error);
@@ -752,6 +774,7 @@ int hb_qsv_param_default(hb_qsv_param_t *param, mfxVideoParam *videoParam)
param->codingOption2.Trellis = MFX_TRELLIS_UNKNOWN;
// GOP & rate control
+ param->gop.b_pyramid = 0;
param->gop.gop_pic_size = -1; // set automatically
param->gop.int_ref_cycle_size = -1; // set automatically
param->rc.lookahead = -1; // set automatically
@@ -776,7 +799,7 @@ int hb_qsv_param_default(hb_qsv_param_t *param, mfxVideoParam *videoParam)
param->videoParam->mfx.NumSlice = 0; // use Media SDK default
param->videoParam->mfx.NumRefFrame = 0; // use Media SDK default
param->videoParam->mfx.GopPicSize = 0; // use Media SDK default
- param->videoParam->mfx.GopRefDist = 4; // power of 2, >= 4: B-pyramid
+ param->videoParam->mfx.GopRefDist = 0; // use Media SDK default
// introduced in API 1.1
param->videoParam->AsyncDepth = AV_QSV_ASYNC_DEPTH_DEFAULT;
// introduced in API 1.3
diff --git a/libhb/qsv_common.h b/libhb/qsv_common.h
index 57b7c1685..418180432 100644
--- a/libhb/qsv_common.h
+++ b/libhb/qsv_common.h
@@ -89,6 +89,7 @@ typedef struct
mfxExtVideoSignalInfo videoSignalInfo;
struct
{
+ int b_pyramid;
int gop_pic_size;
int int_ref_cycle_size;
} gop;