[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