[x265] [PATCH] slicetype: fill in missing detail from slicetypeDecide()
Steve Borho
steve at borho.org
Fri Oct 11 03:03:26 CEST 2013
# HG changeset patch
# User Steve Borho <steve at borho.org>
# Date 1378869992 18000
# Tue Sep 10 22:26:32 2013 -0500
# Node ID 3c97a8e40dba1bc571172b39dbf0083b9c324501
# Parent df2a611e831e945baf84100ab4ed979e5ce8ed43
slicetype: fill in missing detail from slicetypeDecide()
This moves slicetypeDecide() to make the file more readable. It also adds stubs
for features that we do not support yet including weightp, B-pyramid, intra
refresh, user-supplied slice types, etc
diff -r df2a611e831e -r 3c97a8e40dba source/common/lowres.cpp
--- a/source/common/lowres.cpp Thu Oct 10 17:21:36 2013 -0500
+++ b/source/common/lowres.cpp Tue Sep 10 22:26:32 2013 -0500
@@ -110,9 +110,11 @@
{
bScenecut = true;
bIntraCalculated = false;
+ bLastMiniGopBFrame = false;
bKeyframe = false; // Not a keyframe unless identified by lookahead
sliceType = type;
frameNum = poc;
+ leadingBframes = 0;
memset(costEst, -1, sizeof(costEst));
for (int y = 0; y < bframes + 2; y++)
{
diff -r df2a611e831e -r 3c97a8e40dba source/common/lowres.h
--- a/source/common/lowres.h Thu Oct 10 17:21:36 2013 -0500
+++ b/source/common/lowres.h Tue Sep 10 22:26:32 2013 -0500
@@ -44,14 +44,16 @@
{
/* lowres buffers, sizes and strides */
pixel *buffer[4];
- int width; // width of lowres frame in pixels
- int lines; // height of lowres frame in pixel lines
+ int width; // width of lowres frame in pixels
+ int lines; // height of lowres frame in pixel lines
int frameNum; // Presentation frame number
int sliceType; // Slice type decided by lookahead
+ int leadingBframes; // number of leading B frames for P or I
bool bIntraCalculated;
bool bScenecut; // Set to false if the frame cannot possibly be part of a real scenecut.
bool bKeyframe;
+ bool bLastMiniGopBFrame;
/* lookahead output data */
int costEst[X265_BFRAME_MAX + 2][X265_BFRAME_MAX + 2];
diff -r df2a611e831e -r 3c97a8e40dba source/encoder/slicetype.cpp
--- a/source/encoder/slicetype.cpp Thu Oct 10 17:21:36 2013 -0500
+++ b/source/encoder/slicetype.cpp Tue Sep 10 22:26:32 2013 -0500
@@ -66,6 +66,8 @@
{
this->cfg = _cfg;
numDecided = 0;
+ lastKeyframe = -cfg->param.keyframeMax;
+ lastNonB = NULL;
predictions = (pixel*)X265_MALLOC(pixel, 35 * 8 * 8);
me.setQP(X265_LOOKAHEAD_QP);
me.setSearchMethod(X265_HEX_SEARCH);
@@ -114,127 +116,6 @@
slicetypeDecide();
}
-void Lookahead::slicetypeDecide()
-{
- if (numDecided == 0)
- {
- // Special case for POC 0, send directly to output queue as I slice
- TComPic *pic = inputQueue.popFront();
- pic->m_lowres.sliceType = X265_TYPE_I;
- pic->m_lowres.bKeyframe = true;
- lastKeyframe = 0;
- outputQueue.pushBack(*pic);
- numDecided++;
- frames[0] = &(pic->m_lowres);
- return;
- }
- else if (cfg->param.bFrameAdaptive && cfg->param.lookaheadDepth && cfg->param.bframes)
- {
- slicetypeAnalyse(false);
-
- int dframes;
- TComPic* picsAnalysed[X265_LOOKAHEAD_MAX]; //Used for sorting the pics into encode order
- int idx = 1;
-
- for (dframes = 0; (frames[dframes + 1] != NULL) && (frames[dframes + 1]->sliceType != X265_TYPE_AUTO); dframes++)
- {
- if (frames[dframes + 1]->sliceType == X265_TYPE_I)
- {
- frames[dframes + 1]->bKeyframe = true;
- lastKeyframe = frames[dframes]->frameNum;
- if (cfg->param.decodingRefreshType == 2 && dframes > 0) //If an IDR frame following a B
- {
- frames[dframes]->sliceType = X265_TYPE_P;
- dframes--;
- }
- }
- if (!IS_X265_TYPE_B(frames[dframes + 1]->sliceType))
- {
- dframes++;
- break;
- }
- }
-
- TComPic *pic = NULL;
- for (int i = 1; i <= dframes && !inputQueue.empty(); i++)
- {
- pic = inputQueue.popFront();
- picsAnalysed[idx++] = pic;
- }
-
- picsAnalysed[0] = pic; //Move the P-frame following B-frames to the beginning
-
- //Push pictures in encode order
- for (int i = 0; i < dframes; i++)
- {
- outputQueue.pushBack(*picsAnalysed[i]);
- }
-
- if (pic)
- frames[0] = &(pic->m_lowres); // last nonb
- return;
- }
-
- // Fixed GOP structures for when B-Adapt and/or lookahead are disabled
- if (cfg->param.keyframeMax == 1)
- {
- TComPic *pic = inputQueue.popFront();
-
- pic->m_lowres.sliceType = X265_TYPE_I;
- pic->m_lowres.bKeyframe = true;
- lastKeyframe = pic->m_lowres.frameNum;
- outputQueue.pushBack(*pic);
- numDecided++;
- }
- else if (cfg->param.bframes == 0 || inputQueue.size() == 1)
- {
- TComPic *pic = inputQueue.popFront();
- if (pic->getPOC() % cfg->param.keyframeMax)
- pic->m_lowres.sliceType = X265_TYPE_P;
- else
- {
- pic->m_lowres.sliceType = X265_TYPE_I;
- pic->m_lowres.bKeyframe = true;
- lastKeyframe = pic->m_lowres.frameNum;
- }
- outputQueue.pushBack(*pic);
- numDecided++;
- }
- else
- {
- TComPic *list[X265_BFRAME_MAX+1];
- int j;
- for (j = 0; j <= cfg->param.bframes && !inputQueue.empty(); j++)
- {
- TComPic *pic = inputQueue.popFront();
- list[j] = pic;
- if (pic->m_lowres.frameNum >= lastKeyframe + cfg->param.keyframeMax)
- {
- pic->m_lowres.sliceType = X265_TYPE_I;
- pic->m_lowres.bKeyframe = true;
- lastKeyframe = pic->m_lowres.frameNum;
- if (j) list[j - 1]->m_lowres.sliceType = X265_TYPE_P;
- j++;
- break;
- }
- }
-
- TComPic *pic = list[j - 1];
- if (pic->m_lowres.sliceType == X265_TYPE_AUTO)
- pic->m_lowres.sliceType = X265_TYPE_P;
- outputQueue.pushBack(*pic);
- numDecided++;
- for (int i = 0; i < j - 1; i++)
- {
- pic = list[i];
- if (pic->m_lowres.sliceType == X265_TYPE_AUTO)
- pic->m_lowres.sliceType = X265_TYPE_B;
- outputQueue.pushBack(*pic);
- numDecided++;
- }
- }
-}
-
// Called by RateControl to get the estimated SATD cost for a given picture.
// It assumes dpb->prepareEncode() has already been called for the picture and
// all the references are established
@@ -253,7 +134,7 @@
return estimateFrameCost(0, 0, 0, false);
case P_SLICE:
d0 = poc - l0poc;
- frames[0] = &pic->getSlice()->getRefPic(REF_PIC_LIST_0, 0)->m_lowres;
+ frames[0] = lastNonB;
frames[d0] = &pic->m_lowres;
return estimateFrameCost(0, d0, d0, false);
case B_SLICE:
@@ -262,14 +143,14 @@
{
// L1 reference is truly in the future
d1 = l1poc - poc;
- frames[0] = &pic->getSlice()->getRefPic(REF_PIC_LIST_0, 0)->m_lowres;
+ frames[0] = lastNonB;
frames[d0] = &pic->m_lowres;
frames[d0 + d1] = &pic->getSlice()->getRefPic(REF_PIC_LIST_1, 0)->m_lowres;
return estimateFrameCost(0, d0 + d1, d0, false);
}
else
{
- frames[0] = &pic->getSlice()->getRefPic(REF_PIC_LIST_0, 0)->m_lowres;
+ frames[0] = lastNonB;
frames[d0] = &pic->m_lowres;
return estimateFrameCost(0, d0, d0, false);
}
@@ -552,6 +433,220 @@
fenc->lowresCosts[b - p0][p1 - b][cuXY] = (uint16_t)(X265_MIN(bcost, LOWRES_COST_MASK) | (listused << LOWRES_COST_SHIFT));
}
+void Lookahead::slicetypeDecide()
+{
+ if (cfg->param.bFrameAdaptive && cfg->param.lookaheadDepth && cfg->param.bframes)
+ {
+ slicetypeAnalyse(false);
+
+ TComPic *list[X265_LOOKAHEAD_MAX];
+ TComPic *ipic = inputQueue.first();
+ int j;
+ for (j = 0; ipic && j < cfg->param.bframes + 2; ipic = ipic->m_next)
+ list[j++] = ipic;
+ list[j] = NULL;
+
+ int bframes, brefs;
+ for (bframes = 0, brefs = 0 ;; bframes++)
+ {
+ Lowres& frm = list[bframes]->m_lowres;
+
+ if (frm.sliceType == X265_TYPE_BREF
+ /* && h->param.i_bframe_pyramid < X264_B_PYRAMID_NORMAL && brefs == h->param.i_bframe_pyramid*/)
+ {
+ frm.sliceType = X265_TYPE_B;
+ x265_log(&cfg->param, X265_LOG_WARNING, "B-ref is not yet supported\n");
+ }
+ /* pyramid with multiple B-refs needs a big enough dpb that the preceding P-frame stays available.
+ smaller dpb could be supported by smart enough use of mmco, but it's easier just to forbid it.
+ else if (frm.sliceType == X265_TYPE_BREF && cfg->param.i_bframe_pyramid == X265_B_PYRAMID_NORMAL &&
+ brefs && cfg->param.i_frame_reference <= (brefs+3))
+ {
+ frm.sliceType = X265_TYPE_B;
+ x265_log(&cfg->param, X265_LOG_WARNING, "B-ref at frame %d incompatible with B-pyramid %s and %d reference frames\n",
+ frm.sliceType, x264_b_pyramid_names[h->param.i_bframe_pyramid], h->param.i_frame_reference);
+ } */
+
+ if (frm.sliceType == X265_TYPE_KEYFRAME)
+ frm.sliceType = cfg->param.bOpenGOP ? X265_TYPE_I : X265_TYPE_IDR;
+ if ((/* !cfg->param.intraRefresh || */ frm.frameNum == 0) && frm.frameNum - lastKeyframe >= cfg->param.keyframeMax)
+ {
+ if (frm.sliceType == X265_TYPE_AUTO || frm.sliceType == X265_TYPE_I)
+ frm.sliceType = cfg->param.bOpenGOP && lastKeyframe >= 0 ? X265_TYPE_I : X265_TYPE_IDR;
+ bool warn = frm.sliceType != X265_TYPE_IDR;
+ if (warn && cfg->param.bOpenGOP)
+ warn &= frm.sliceType != X265_TYPE_I;
+ if (warn)
+ {
+ x265_log(&cfg->param, X265_LOG_WARNING, "specified frame type (%d) at %d is not compatible with keyframe interval\n", frm.sliceType, frm.frameNum);
+ frm.sliceType = cfg->param.bOpenGOP && lastKeyframe >= 0 ? X265_TYPE_I : X265_TYPE_IDR;
+ }
+ }
+ if (frm.sliceType == X265_TYPE_I && frm.frameNum - lastKeyframe >= cfg->param.keyframeMin)
+ {
+ if (cfg->param.bOpenGOP)
+ {
+ lastKeyframe = frm.frameNum;
+ frm.bKeyframe = true;
+ }
+ else
+ frm.sliceType = X265_TYPE_IDR;
+ }
+ if (frm.sliceType == X265_TYPE_IDR)
+ {
+ /* Closed GOP */
+ lastKeyframe = frm.frameNum;
+ frm.bKeyframe = true;
+ if (bframes > 0)
+ {
+ frames[bframes]->sliceType = X265_TYPE_P;
+ bframes--;
+ }
+ }
+
+ if (bframes == cfg->param.bframes || !list[bframes+1])
+ {
+ if (IS_X265_TYPE_B(frm.sliceType))
+ x265_log(&cfg->param, X265_LOG_WARNING, "specified frame type is not compatible with max B-frames\n");
+ if (frm.sliceType == X265_TYPE_AUTO || IS_X265_TYPE_B(frm.sliceType))
+ frm.sliceType = X265_TYPE_P;
+ }
+ if (frm.sliceType == X265_TYPE_BREF)
+ brefs++;
+ if (frm.sliceType == X265_TYPE_AUTO)
+ frm.sliceType = X265_TYPE_B;
+ else if (!IS_X265_TYPE_B(frm.sliceType))
+ break;
+ }
+ if (bframes)
+ list[bframes-1]->m_lowres.bLastMiniGopBFrame = true;
+ list[bframes]->m_lowres.leadingBframes = bframes;
+ lastNonB = &list[bframes]->m_lowres;
+
+ /* insert a bref into the sequence
+ if (h->param.i_bframe_pyramid && bframes > 1 && !brefs)
+ {
+ h->lookahead->next.list[bframes/2]->i_type = X264_TYPE_BREF;
+ brefs++;
+ } */
+
+ /* calculate the frame costs ahead of time for x264_rc_analyse_slice while we still have lowres */
+ if (cfg->param.rc.rateControlMode != X265_RC_CQP)
+ {
+ int p0, p1, b;
+ p1 = b = bframes + 1;
+
+ frames[0] = lastNonB;
+ if (IS_X265_TYPE_I(frames[bframes+1]->sliceType))
+ p0 = bframes + 1;
+ else // P
+ p0 = 0;
+
+ estimateFrameCost(p0, p1, b, 0);
+
+ /*
+ if ((p0 != p1 || bframes) && cfg->param.rc.i_vbv_buffer_size)
+ {
+ // We need the intra costs for row SATDs
+ estimateFrameCost(b, b, b, 0);
+
+ // We need B-frame costs for row SATDs
+ p0 = 0;
+ for (b = 1; b <= bframes; b++)
+ {
+ if (frames[b]->i_type == X265_TYPE_B)
+ for (p1 = b; frames[p1]->sliceType == X265_TYPE_B;)
+ p1++;
+ else
+ p1 = bframes + 1;
+ estimateFrameCost( p0, p1, b, 0 );
+ if (frames[b]->sliceType == X265_TYPE_BREF)
+ p0 = b;
+ }
+ } */
+ }
+ /* Analyse for weighted P frames
+ if (!h->param.rc.b_stat_read && h->lookahead->next.list[bframes]->i_type == X264_TYPE_P
+ && h->param.analyse.i_weighted_pred >= X264_WEIGHTP_SIMPLE)
+ {
+ x265_emms();
+ x264_weights_analyse(h, h->lookahead->next.list[bframes], h->lookahead->last_nonb, 0);
+ }*/
+
+ /* dequeue all frames from inputQueue that are about to be enqueued
+ * in the output queue. The order is important because TComPic can
+ * only be in one list at a time */
+ for (int i = 0; i <= bframes; i++)
+ inputQueue.popFront();
+
+ /* add non-B to output queue */
+ outputQueue.pushBack(*list[bframes]);
+ /* add B frames to output queue */
+ for (int i = 0; i < bframes; i++)
+ outputQueue.pushBack(*list[i]);
+ return;
+ }
+
+ // Fixed GOP structures for when B-Adapt and/or lookahead are disabled
+ if (numDecided == 0 || cfg->param.keyframeMax == 1)
+ {
+ TComPic *pic = inputQueue.popFront();
+ pic->m_lowres.sliceType = X265_TYPE_I;
+ pic->m_lowres.bKeyframe = true;
+ lastKeyframe = pic->m_lowres.frameNum;
+ lastNonB = &pic->m_lowres;
+ numDecided++;
+ outputQueue.pushBack(*pic);
+ }
+ else if (cfg->param.bframes == 0 || inputQueue.size() == 1)
+ {
+ TComPic *pic = inputQueue.popFront();
+ if (pic->getPOC() % cfg->param.keyframeMax)
+ pic->m_lowres.sliceType = X265_TYPE_P;
+ else
+ {
+ pic->m_lowres.sliceType = X265_TYPE_I;
+ pic->m_lowres.bKeyframe = true;
+ lastKeyframe = pic->m_lowres.frameNum;
+ }
+ outputQueue.pushBack(*pic);
+ numDecided++;
+ }
+ else
+ {
+ TComPic *list[X265_BFRAME_MAX+1];
+ int j;
+ for (j = 0; j <= cfg->param.bframes && !inputQueue.empty(); j++)
+ {
+ TComPic *pic = inputQueue.popFront();
+ list[j] = pic;
+ if (pic->m_lowres.frameNum >= lastKeyframe + cfg->param.keyframeMax)
+ {
+ pic->m_lowres.sliceType = X265_TYPE_I;
+ pic->m_lowres.bKeyframe = true;
+ lastKeyframe = pic->m_lowres.frameNum;
+ if (j) list[j - 1]->m_lowres.sliceType = X265_TYPE_P;
+ j++;
+ break;
+ }
+ }
+
+ TComPic *pic = list[j - 1];
+ if (pic->m_lowres.sliceType == X265_TYPE_AUTO)
+ pic->m_lowres.sliceType = X265_TYPE_P;
+ outputQueue.pushBack(*pic);
+ numDecided++;
+ for (int i = 0; i < j - 1; i++)
+ {
+ pic = list[i];
+ if (pic->m_lowres.sliceType == X265_TYPE_AUTO)
+ pic->m_lowres.sliceType = X265_TYPE_B;
+ outputQueue.pushBack(*pic);
+ numDecided++;
+ }
+ }
+}
+
void Lookahead::slicetypeAnalyse(bool bKeyframe)
{
int num_frames, origNumFrames, keyint_limit, framecnt;
@@ -559,10 +654,12 @@
int cuCount = NUM_CUS;
int cost1p0, cost2p0, cost1b1, cost2p1;
int reset_start;
- int vbv_lookahead = 0;
+ if (!lastNonB)
+ return;
+ frames[0] = lastNonB;
TComPic* pic = inputQueue.first();
- for (framecnt = 0; (framecnt < maxSearch) && (framecnt < (int)inputQueue.size()) && pic->m_lowres.sliceType == X265_TYPE_AUTO; framecnt++)
+ for (framecnt = 0; (framecnt < maxSearch) && pic && pic->m_lowres.sliceType == X265_TYPE_AUTO; framecnt++)
{
frames[framecnt + 1] = &pic->m_lowres;
pic = pic->m_next;
@@ -570,24 +667,16 @@
if (!framecnt)
{
- frames[1] = &pic->m_lowres;
- frames[2] = NULL;
+ // TODO: mb-tree
return;
}
frames[framecnt + 1] = NULL;
- keyint_limit = cfg->param.keyframeMax - frames[1]->frameNum + lastKeyframe;
+ keyint_limit = cfg->param.keyframeMax - frames[0]->frameNum + lastKeyframe - 1;
origNumFrames = num_frames = X265_MIN(framecnt, keyint_limit);
- /* This is important psy-wise: if we have a non-scenecut keyframe,
- * there will be significant visual artifacts if the frames just before
- * go down in quality due to being referenced less, despite it being
- * more RD-optimal. */
-
- if (vbv_lookahead)
- num_frames = framecnt;
- else if (num_frames < framecnt)
+ if (cfg->param.bOpenGOP && num_frames < framecnt)
num_frames++;
else if (num_frames == 0)
{
@@ -712,7 +801,7 @@
}
// TODO if rc.b_mb_tree Enabled the need to call x264_macroblock_tree currently Ignored the call
-
+ // if (!cfg->param.bIntraRefresh)
for (int j = keyint_limit + 1; j <= num_frames; j += cfg->param.keyframeMax)
{
frames[j]->sliceType = X265_TYPE_I;
diff -r df2a611e831e -r 3c97a8e40dba source/encoder/slicetype.h
--- a/source/encoder/slicetype.h Thu Oct 10 17:21:36 2013 -0500
+++ b/source/encoder/slicetype.h Tue Sep 10 22:26:32 2013 -0500
@@ -44,6 +44,7 @@
TEncCfg *cfg;
pixel *predictions; // buffer for 35 intra predictions
Lowres *frames[X265_LOOKAHEAD_MAX];
+ Lowres *lastNonB;
int merange;
int numDecided;
int lastKeyframe;
More information about the x265-devel
mailing list