[x265] [PATCH] Extend gop boundary by doing gop lookahead
aruna at multicorewareinc.com
aruna at multicorewareinc.com
Fri Dec 1 06:16:08 CET 2017
# HG changeset patch
# User Aruna Matheswaran <aruna at multicorewareinc.com>
# Date 1511241504 -19800
# Tue Nov 21 10:48:24 2017 +0530
# Node ID 805ac1fd3e058a590ffc65126c884ceea0473b38
# Parent b1dfa312234ed72c3541831a15f307feaf79484d
Extend gop boundary by doing gop lookahead
diff -r b1dfa312234e -r 805ac1fd3e05 doc/reST/cli.rst
--- a/doc/reST/cli.rst Thu Nov 30 10:06:49 2017 +0530
+++ b/doc/reST/cli.rst Tue Nov 21 10:48:24 2017 +0530
@@ -1374,6 +1374,17 @@
**Range of values:** Between the maximum consecutive bframe count (:option:`--bframes`) and 250
+.. option:: --gop-lookahead <integer>
+
+ Number of frames for GOP boundary decision lookahead. If a scenecut frame is found
+ within this from the gop boundary set by `--keyint`, the GOP will be extented until such a point,
+ otherwise the GOP will be terminated as set by `--keyint`. Default 0.
+
+ **Range of values:** Between 0 and (`--rc-lookahead` - mini-GOP length)
+
+ It is recommended to have `--gop-lookahaed` less than `--min-keyint` as scenecuts beyond
+ `--min-keyint` are already being coded as keyframes.
+
.. option:: --lookahead-slices <0..16>
Use multiple worker threads to measure the estimated cost of each frame
diff -r b1dfa312234e -r 805ac1fd3e05 source/CMakeLists.txt
--- a/source/CMakeLists.txt Thu Nov 30 10:06:49 2017 +0530
+++ b/source/CMakeLists.txt Tue Nov 21 10:48:24 2017 +0530
@@ -29,7 +29,7 @@
option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF)
mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)
# X265_BUILD must be incremented each time the public API is changed
-set(X265_BUILD 146)
+set(X265_BUILD 147)
configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
"${PROJECT_BINARY_DIR}/x265.def")
configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
diff -r b1dfa312234e -r 805ac1fd3e05 source/common/param.cpp
--- a/source/common/param.cpp Thu Nov 30 10:06:49 2017 +0530
+++ b/source/common/param.cpp Tue Nov 21 10:48:24 2017 +0530
@@ -144,6 +144,7 @@
/* Coding Structure */
param->keyframeMin = 0;
param->keyframeMax = 250;
+ param->gopLookahead = 0;
param->bOpenGOP = 1;
param->bframes = 4;
param->lookaheadDepth = 20;
@@ -1004,6 +1005,7 @@
bError = true;
}
}
+ OPT("gop-lookahead") p->gopLookahead = atoi(value);
else
return X265_PARAM_BAD_NAME;
}
@@ -1314,6 +1316,8 @@
"Valid penalty for 32x32 intra TU in non-I slices. 0:disabled 1:RD-penalty 2:maximum");
CHECK(param->keyframeMax < -1,
"Invalid max IDR period in frames. value should be greater than -1");
+ CHECK(param->gopLookahead < -1,
+ "GOP lookahead must be greater than -1");
CHECK(param->decodedPictureHashSEI < 0 || param->decodedPictureHashSEI > 3,
"Invalid hash option. Decoded Picture Hash SEI 0: disabled, 1: MD5, 2: CRC, 3: Checksum");
CHECK(param->rc.vbvBufferSize < 0,
@@ -1561,6 +1565,7 @@
BOOL(p->bOpenGOP, "open-gop");
s += sprintf(s, " min-keyint=%d", p->keyframeMin);
s += sprintf(s, " keyint=%d", p->keyframeMax);
+ s += sprintf(s, " gop-lookahead=%d", p->gopLookahead);
s += sprintf(s, " bframes=%d", p->bframes);
s += sprintf(s, " b-adapt=%d", p->bFrameAdaptive);
BOOL(p->bBPyramid, "b-pyramid");
diff -r b1dfa312234e -r 805ac1fd3e05 source/encoder/slicetype.cpp
--- a/source/encoder/slicetype.cpp Thu Nov 30 10:06:49 2017 +0530
+++ b/source/encoder/slicetype.cpp Tue Nov 21 10:48:24 2017 +0530
@@ -589,6 +589,7 @@
m_outputSignalRequired = false;
m_isActive = true;
m_inputCount = 0;
+ m_extendGopBoundary = false;
m_8x8Height = ((m_param->sourceHeight / 2) + X265_LOWRES_CU_SIZE - 1) >> X265_LOWRES_CU_BITS;
m_8x8Width = ((m_param->sourceWidth / 2) + X265_LOWRES_CU_SIZE - 1) >> X265_LOWRES_CU_BITS;
@@ -647,6 +648,11 @@
m_numCoopSlices = 1;
}
+ if (param->gopLookahead && (param->gopLookahead > (param->lookaheadDepth - param->bframes - 2)))
+ {
+ param->gopLookahead = X265_MAX(0, param->lookaheadDepth - param->bframes - 2);
+ x265_log(param, X265_LOG_WARNING, "Gop-lookahead cannot be greater than (rc-lookahead - length of the mini-gop); Clipping gop-lookahead to %d\n", param->gopLookahead);
+ }
#if DETAILED_CU_STATS
m_slicetypeDecideElapsedTime = 0;
m_preLookaheadElapsedTime = 0;
@@ -1086,7 +1092,8 @@
x265_log(m_param, X265_LOG_WARNING, "B-ref at frame %d incompatible with B-pyramid and %d reference frames\n",
frm.sliceType, m_param->maxNumReferences);
}
- if ((!m_param->bIntraRefresh || frm.frameNum == 0) && frm.frameNum - m_lastKeyframe >= m_param->keyframeMax)
+ if ((!m_param->bIntraRefresh || frm.frameNum == 0) && frm.frameNum - m_lastKeyframe >= m_param->keyframeMax &&
+ (!m_extendGopBoundary || frm.frameNum - m_lastKeyframe >= m_param->keyframeMax + m_param->gopLookahead))
{
if (frm.sliceType == X265_TYPE_AUTO || frm.sliceType == X265_TYPE_I)
frm.sliceType = m_param->bOpenGOP && m_lastKeyframe >= 0 ? X265_TYPE_I : X265_TYPE_IDR;
@@ -1379,8 +1386,13 @@
}
frames[framecnt + 1] = NULL;
+ int keyFrameLimit = m_param->keyframeMax + m_lastKeyframe - frames[0]->frameNum - 1;
+ if (m_param->gopLookahead && keyFrameLimit <= m_param->bframes + 1)
+ keyintLimit = keyFrameLimit + m_param->gopLookahead;
+ else
+ keyintLimit = keyFrameLimit;
- keyintLimit = m_param->keyframeMax - frames[0]->frameNum + m_lastKeyframe - 1;
+
origNumFrames = numFrames = m_param->bIntraRefresh ? framecnt : X265_MIN(framecnt, keyintLimit);
if (bIsVbvLookahead)
@@ -1473,6 +1485,26 @@
return;
}
+ if (m_param->gopLookahead && (keyFrameLimit >= 0) && (keyFrameLimit <= m_param->bframes + 1))
+ {
+ bool sceneTransition = m_isSceneTransition;
+ m_extendGopBoundary = false;
+ for (int i = m_param->bframes + 1; i < origNumFrames; i += m_param->bframes + 1)
+ {
+ scenecut(frames, i, i + 1, true, origNumFrames);
+ for (int j = i + 1; j <= X265_MIN(i + m_param->bframes + 1, origNumFrames); j++)
+ {
+ if (frames[j]->bScenecut && scenecutInternal(frames, j - 1, j, true) )
+ {
+ m_extendGopBoundary = true;
+ break;
+ }
+ }
+ if (m_extendGopBoundary)
+ break;
+ }
+ m_isSceneTransition = sceneTransition;
+ }
if (m_param->bframes)
{
if (m_param->bFrameAdaptive == X265_B_ADAPT_TRELLIS)
@@ -1579,6 +1611,9 @@
if (m_param->rc.cuTree)
cuTree(frames, X265_MIN(numFrames, m_param->keyframeMax), bKeyframe);
+ if (m_param->gopLookahead && (keyFrameLimit >= 0) && (keyFrameLimit <= m_param->bframes + 1) && !m_extendGopBoundary)
+ keyintLimit = keyFrameLimit;
+
if (!m_param->bIntraRefresh)
for (int j = keyintLimit + 1; j <= numFrames; j += m_param->keyframeMax)
{
@@ -1589,7 +1624,8 @@
if (bIsVbvLookahead)
vbvLookahead(frames, numFrames, bKeyframe);
- int maxp1 = X265_MIN(m_param->bframes + 1, origNumFrames);
+ int maxp1 = X265_MIN(m_param->bframes + 1, origNumFrames);
+
/* Restore frame types for all frames that haven't actually been decided yet. */
for (int j = resetStart; j <= numFrames; j++)
{
@@ -1613,8 +1649,8 @@
bool fluctuate = false;
bool noScenecuts = false;
int64_t avgSatdCost = 0;
- if (frames[0]->costEst[1][0] > -1)
- avgSatdCost = frames[0]->costEst[1][0];
+ if (frames[p0]->costEst[p1 - p0][0] > -1)
+ avgSatdCost = frames[p0]->costEst[p1 - p0][0];
int cnt = 1;
/* Where A and B are scenes: AAAAAABBBAAAAAA
* If BBB is shorter than (maxp1-p0), it is detected as a flash
@@ -1703,7 +1739,7 @@
int64_t icost = frame->costEst[0][0];
int64_t pcost = frame->costEst[p1 - p0][0];
- int gopSize = frame->frameNum - m_lastKeyframe;
+ int gopSize = (frame->frameNum - m_lastKeyframe) % m_param->keyframeMax;
float threshMax = (float)(m_param->scenecutThreshold / 100.0);
/* magic numbers pulled out of thin air */
diff -r b1dfa312234e -r 805ac1fd3e05 source/encoder/slicetype.h
--- a/source/encoder/slicetype.h Thu Nov 30 10:06:49 2017 +0530
+++ b/source/encoder/slicetype.h Tue Nov 21 10:48:24 2017 +0530
@@ -132,6 +132,7 @@
bool m_filled;
bool m_isSceneTransition;
int m_numPools;
+ bool m_extendGopBoundary;
Lookahead(x265_param *param, ThreadPool *pool);
#if DETAILED_CU_STATS
int64_t m_slicetypeDecideElapsedTime;
diff -r b1dfa312234e -r 805ac1fd3e05 source/test/regression-tests.txt
--- a/source/test/regression-tests.txt Thu Nov 30 10:06:49 2017 +0530
+++ b/source/test/regression-tests.txt Tue Nov 21 10:48:24 2017 +0530
@@ -150,6 +150,7 @@
Kimono1_1920x1080_24_400.yuv,--preset medium --rdoq-level 0 --limit-refs 3 --slices 2
Kimono1_1920x1080_24_400.yuv,--preset veryslow --crf 4 --cu-lossless --slices 2 --limit-refs 3 --limit-modes
Kimono1_1920x1080_24_400.yuv,--preset placebo --ctu 32 --max-tu-size 8 --limit-tu 2
+big_buck_bunny_360p24.y4m, --keyint 60 --min-keyint 40 --gop-lookahead 20
# Main12 intraCost overflow bug test
720p50_parkrun_ter.y4m,--preset medium
diff -r b1dfa312234e -r 805ac1fd3e05 source/x265.h
--- a/source/x265.h Thu Nov 30 10:06:49 2017 +0530
+++ b/source/x265.h Tue Nov 21 10:48:24 2017 +0530
@@ -1535,6 +1535,11 @@
/* Allow the encoder to have a copy of the planes of x265_picture in Frame */
int bCopyPicToFrame;
+
+ /*Number of frames for GOP boundary decision lookahead.If a scenecut frame is found
+ * within this from the gop boundary set by keyint, the GOP will be extented until such a point,
+ * otherwise the GOP will be terminated as set by keyint*/
+ int gopLookahead;
} x265_param;
/* x265_param_alloc:
diff -r b1dfa312234e -r 805ac1fd3e05 source/x265cli.h
--- a/source/x265cli.h Thu Nov 30 10:06:49 2017 +0530
+++ b/source/x265cli.h Tue Nov 21 10:48:24 2017 +0530
@@ -119,6 +119,7 @@
{ "open-gop", no_argument, NULL, 0 },
{ "keyint", required_argument, NULL, 'I' },
{ "min-keyint", required_argument, NULL, 'i' },
+ { "gop-lookahead", required_argument, NULL, 0 },
{ "scenecut", required_argument, NULL, 0 },
{ "no-scenecut", no_argument, NULL, 0 },
{ "scenecut-bias", required_argument, NULL, 0 },
@@ -418,6 +419,7 @@
H0(" --[no-]open-gop Enable open-GOP, allows I slices to be non-IDR. Default %s\n", OPT(param->bOpenGOP));
H0("-I/--keyint <integer> Max IDR period in frames. -1 for infinite-gop. Default %d\n", param->keyframeMax);
H0("-i/--min-keyint <integer> Scenecuts closer together than this are coded as I, not IDR. Default: auto\n");
+ H0(" --gop-lookahead <integer> Extends gop boundary if a scenecut is found within this from keyint boundary. Default 0\n");
H0(" --no-scenecut Disable adaptive I-frame decision\n");
H0(" --scenecut <integer> How aggressively to insert extra I-frames. Default %d\n", param->scenecutThreshold);
H1(" --scenecut-bias <0..100.0> Bias for scenecut detection. Default %.2f\n", param->scenecutBias);
More information about the x265-devel
mailing list