[x265-commits] [x265] slicetype: fill in missing detail from slicetypeDecide()

Steve Borho steve at borho.org
Mon Oct 14 05:36:51 CEST 2013


details:   http://hg.videolan.org/x265/rev/9bdff3310321
branches:  
changeset: 4441:9bdff3310321
user:      Steve Borho <steve at borho.org>
date:      Tue Sep 10 22:26:32 2013 -0500
description:
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
Subject: [x265] common: sanity check some lookahead settings

details:   http://hg.videolan.org/x265/rev/eb0aa9c42bba
branches:  
changeset: 4442:eb0aa9c42bba
user:      Steve Borho <steve at borho.org>
date:      Sun Oct 13 22:25:24 2013 -0500
description:
common: sanity check some lookahead settings

diffstat:

 source/common/common.cpp     |    4 +
 source/common/common.h       |   12 +
 source/common/lowres.cpp     |    2 +
 source/common/lowres.h       |   13 +-
 source/encoder/slicetype.cpp |  365 ++++++++++++++++++++++++++----------------
 source/encoder/slicetype.h   |    6 +-
 6 files changed, 251 insertions(+), 151 deletions(-)

diffs (truncated from 546 to 300 lines):

diff -r 8011064113f7 -r eb0aa9c42bba source/common/common.cpp
--- a/source/common/common.cpp	Sun Oct 13 11:53:20 2013 -0500
+++ b/source/common/common.cpp	Sun Oct 13 22:25:24 2013 -0500
@@ -289,6 +289,10 @@ int x265_check_params(x265_param_t *para
           "RD Level is out of range");
     CHECK(param->bframes > param->lookaheadDepth,
           "Lookahead depth must be greater than the max consecutive bframe count");
+    CHECK(param->bframes > X265_BFRAME_MAX,
+        "max consecutive bframe count must be 16 or smaller");
+    CHECK(param->lookaheadDepth > X265_LOOKAHEAD_MAX,
+        "Lookahead depth must be less than 256");
 
     // max CU size should be power of 2
     uint32_t i = param->maxCUSize;
diff -r 8011064113f7 -r eb0aa9c42bba source/common/common.h
--- a/source/common/common.h	Sun Oct 13 11:53:20 2013 -0500
+++ b/source/common/common.h	Sun Oct 13 22:25:24 2013 -0500
@@ -58,6 +58,18 @@
 #define X265_MIN4(a, b, c, d) X265_MIN((a), X265_MIN3((b), (c), (d)))
 #define X265_MAX4(a, b, c, d) X265_MAX((a), X265_MAX3((b), (c), (d)))
 #define QP_BD_OFFSET (6*(X265_DEPTH-8))
+
+// arbitrary, but low because SATD scores are 1/4 normal
+#define X265_LOOKAHEAD_QP (12 + QP_BD_OFFSET)
+#define X265_LOOKAHEAD_MAX 250
+
+// Use the same size blocks as x264.  Using larger blocks seems to give artificially
+// high cost estimates (intra and inter both suffer)
+#define X265_LOWRES_CU_SIZE   8
+#define X265_LOWRES_CU_BITS   3
+
+#define X265_BFRAME_MAX      16
+
 #define MAX_NAL_UNITS 5
 #define MIN_FIFO_SIZE 1000
 #define EMULATION_SIZE 1000
diff -r 8011064113f7 -r eb0aa9c42bba source/common/lowres.cpp
--- a/source/common/lowres.cpp	Sun Oct 13 11:53:20 2013 -0500
+++ b/source/common/lowres.cpp	Sun Oct 13 22:25:24 2013 -0500
@@ -110,9 +110,11 @@ void Lowres::init(TComPicYuv *orig, int 
 {
     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 8011064113f7 -r eb0aa9c42bba source/common/lowres.h
--- a/source/common/lowres.h	Sun Oct 13 11:53:20 2013 -0500
+++ b/source/common/lowres.h	Sun Oct 13 22:25:24 2013 -0500
@@ -33,25 +33,20 @@ namespace x265 {
 
 class TComPic;
 
-// Use the same size blocks as x264.  Using larger blocks seems to give artificially
-// high cost estimates (intra and inter both suffer)
-#define X265_LOWRES_CU_SIZE   8
-#define X265_LOWRES_CU_BITS   3
-
-#define X265_BFRAME_MAX      16
-
 struct Lowres : public ReferencePlanes
 {
     /* 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 8011064113f7 -r eb0aa9c42bba source/encoder/slicetype.cpp
--- a/source/encoder/slicetype.cpp	Sun Oct 13 11:53:20 2013 -0500
+++ b/source/encoder/slicetype.cpp	Sun Oct 13 22:25:24 2013 -0500
@@ -66,6 +66,8 @@ Lookahead::Lookahead(TEncCfg *_cfg)
 {
     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 @@ void Lookahead::flush()
         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 @@ int Lookahead::getEstimatedPictureCost(T
         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 @@ int Lookahead::getEstimatedPictureCost(T
         {
             // 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 @@ void Lookahead::estimateCUCost(int cux, 
     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);


More information about the x265-commits mailing list