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

Steve Borho steve at borho.org
Thu Sep 19 00:05:16 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 a5810b7397ddec0bbec0e885bc5e7fd9bd5a7040
# Parent  5bab261d0dd7ac68c4af3837853d48d56017d4d6
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 5bab261d0dd7 -r a5810b7397dd source/common/lowres.cpp
--- a/source/common/lowres.cpp	Wed Sep 18 16:13:33 2013 -0500
+++ b/source/common/lowres.cpp	Tue Sep 10 22:26:32 2013 -0500
@@ -108,11 +108,13 @@
 // (re) initialize lowres state
 void Lowres::init(TComPicYuv *orig, int bframes)
 {
-    scenecut = 1;
+    scenecut = true;
     bIntraCalculated = false;
+    bLastMiniGopBFrame = false;
+    keyframe = false; // Not a keyframe unless identified by lookahead
+    sliceType = X265_TYPE_AUTO;
+    leadingBframes = 0;
     memset(costEst, -1, sizeof(costEst));
-    sliceType = X265_TYPE_AUTO;
-    keyframe = 0; //Not a keyframe unless identified by lookahead
     for (int y = 0; y < bframes + 2; y++)
     {
         for (int x = 0; x < bframes + 2; x++)
diff -r 5bab261d0dd7 -r a5810b7397dd source/common/lowres.h
--- a/source/common/lowres.h	Wed Sep 18 16:13:33 2013 -0500
+++ b/source/common/lowres.h	Tue Sep 10 22:26:32 2013 -0500
@@ -44,14 +44,17 @@
 {
     /* 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;
-    int    frameNum;  // Presentation frame number 
-    int    scenecut;  // Set to zero if the frame cannot possibly be part of a real scenecut. 
-
-    int    sliceType; // Slice type decided by lookahead
-    int    keyframe;
+    bool   scenecut;  // Set to zero if the frame cannot possibly be part of a real scenecut. 
+    bool   keyframe;
+    bool   bLastMiniGopBFrame;
 
     /* lookahead output data */
     int       costEst[X265_BFRAME_MAX + 2][X265_BFRAME_MAX + 2];
diff -r 5bab261d0dd7 -r a5810b7397dd source/encoder/slicetype.cpp
--- a/source/encoder/slicetype.cpp	Wed Sep 18 16:13:33 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);
@@ -115,118 +117,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;
-        outputQueue.pushBack(pic);
-        numDecided++;
-        lastKeyframe = 0;
-        pic->m_lowres.keyframe = 1;
-        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]->keyframe = 1;
-                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.keyframe = 1;
-        outputQueue.pushBack(pic);
-        numDecided++;
-    }
-    else if (cfg->param.bframes == 0 || inputQueue.size() == 1)
-    {
-        TComPic *pic = inputQueue.popFront();
-
-        bool forceIntra = (pic->getPOC() % cfg->param.keyframeMax) == 0;
-        pic->m_lowres.sliceType = forceIntra ? X265_TYPE_I : X265_TYPE_P;
-        pic->m_lowres.keyframe = forceIntra ? 1 : 0;
-        outputQueue.pushBack(pic);
-        numDecided++;
-    }
-    else
-    {
-        TComPic *picB = inputQueue.popFront();
-        TComPic *picP = inputQueue.popFront();
-
-        bool forceIntra = (picP->getPOC() % cfg->param.keyframeMax) == 0 || (picB->getPOC() % cfg->param.keyframeMax) == 0;
-        if (forceIntra)
-        {
-            picB->m_lowres.sliceType = (picB->getPOC() % cfg->param.keyframeMax) ? X265_TYPE_P : X265_TYPE_I;
-            picB->m_lowres.keyframe = (picB->getPOC() % cfg->param.keyframeMax) ? 0 : 1;
-            outputQueue.pushBack(picB);
-            numDecided++;
-
-            picP->m_lowres.sliceType = (picP->getPOC() % cfg->param.keyframeMax) ? X265_TYPE_P : X265_TYPE_I;
-            picP->m_lowres.keyframe = (picP->getPOC() % cfg->param.keyframeMax) ? 0 : 1;
-            outputQueue.pushBack(picP);
-            numDecided++;
-        }
-        else
-        {
-            picP->m_lowres.sliceType = X265_TYPE_P;
-            outputQueue.pushBack(picP);
-            numDecided++;
-
-            picB->m_lowres.sliceType = X265_TYPE_B;
-            outputQueue.pushBack(picB);
-            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
@@ -482,6 +372,219 @@
     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];
+        TComList<TComPic*>::iterator iterPic = inputQueue.begin();
+        int j;
+        for (j = 0; j < cfg->param.bframes + 2 && iterPic != inputQueue.end(); iterPic++)
+            list[j++] = (*iterPic);
+        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.sliceType - lastKeyframe >= cfg->param.keyframeMin)
+            {
+                if (cfg->param.bOpenGOP)
+                { 
+                    lastKeyframe = frm.frameNum; // Use display order
+                    frm.keyframe = true;
+                }
+                else
+                    frm.sliceType = X265_TYPE_IDR;
+            }
+            if (frm.sliceType == X265_TYPE_IDR)
+            {
+                /* Close GOP */
+                lastKeyframe = frm.frameNum;
+                frm.keyframe = 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);
+        }*/
+
+        /* add to output queue in encode order */
+        outputQueue.pushBack(list[bframes]);
+        inputQueue.popFront();
+        for (int i = 0; i < bframes; i++)
+        {
+            outputQueue.pushBack(list[i]);
+            inputQueue.popFront();
+        }
+        return;
+    }
+
+    // Fixed GOP structures for when B-Adapt and/or lookahead are disabled
+    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;
+        outputQueue.pushBack(pic);
+        numDecided++;
+        lastKeyframe = 0;
+        pic->m_lowres.keyframe = 1;
+        return;
+    }
+    else if (cfg->param.keyframeMax == 1)
+    {
+        TComPic *pic = inputQueue.popFront();
+
+        pic->m_lowres.sliceType = X265_TYPE_I;
+        pic->m_lowres.keyframe = 1;
+        outputQueue.pushBack(pic);
+        numDecided++;
+    }
+    else if (cfg->param.bframes == 0 || inputQueue.size() == 1)
+    {
+        TComPic *pic = inputQueue.popFront();
+
+        bool forceIntra = (pic->getPOC() % cfg->param.keyframeMax) == 0;
+        pic->m_lowres.sliceType = forceIntra ? X265_TYPE_I : X265_TYPE_P;
+        pic->m_lowres.keyframe = forceIntra ? 1 : 0;
+        outputQueue.pushBack(pic);
+        numDecided++;
+    }
+    else
+    {
+        TComPic *picB = inputQueue.popFront();
+        TComPic *picP = inputQueue.popFront();
+
+        bool forceIntra = (picP->getPOC() % cfg->param.keyframeMax) == 0 || (picB->getPOC() % cfg->param.keyframeMax) == 0;
+        if (forceIntra)
+        {
+            picB->m_lowres.sliceType = (picB->getPOC() % cfg->param.keyframeMax) ? X265_TYPE_P : X265_TYPE_I;
+            picB->m_lowres.keyframe = (picB->getPOC() % cfg->param.keyframeMax) ? 0 : 1;
+            outputQueue.pushBack(picB);
+            numDecided++;
+
+            picP->m_lowres.sliceType = (picP->getPOC() % cfg->param.keyframeMax) ? X265_TYPE_P : X265_TYPE_I;
+            picP->m_lowres.keyframe = (picP->getPOC() % cfg->param.keyframeMax) ? 0 : 1;
+            outputQueue.pushBack(picP);
+            numDecided++;
+        }
+        else
+        {
+            picP->m_lowres.sliceType = X265_TYPE_P;
+            outputQueue.pushBack(picP);
+            numDecided++;
+
+            picB->m_lowres.sliceType = X265_TYPE_B;
+            outputQueue.pushBack(picB);
+            numDecided++;
+        }
+    }
+}
+
 void Lookahead::slicetypeAnalyse(bool bKeyframe)
 {
     int num_frames, origNumFrames, keyint_limit, framecnt;
@@ -489,8 +592,10 @@
     int cuCount = NUM_CUS;
     int cost1p0, cost2p0, cost1b1, cost2p1;
     int reset_start;
-    int vbv_lookahead = 0;
 
+    if (!lastNonB)
+        return;
+    frames[0] = lastNonB;
     TComList<TComPic*>::iterator iterPic = inputQueue.begin();
     for (framecnt = 0; (framecnt < maxSearch) && (framecnt < (int)inputQueue.size()) && (*iterPic)->m_lowres.sliceType == X265_TYPE_AUTO; framecnt++)
     {
@@ -499,8 +604,7 @@
 
     if (!framecnt)
     {
-        frames[1] = &((*iterPic)->m_lowres);
-        frames[2] = NULL;
+        // TODO: mb-tree
         return;
     }
 
@@ -509,14 +613,7 @@
     keyint_limit = cfg->param.keyframeMax - frames[1]->frameNum + lastKeyframe;
     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)
     {
@@ -641,7 +738,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 5bab261d0dd7 -r a5810b7397dd source/encoder/slicetype.h
--- a/source/encoder/slicetype.h	Wed Sep 18 16:13:33 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;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 4045.diff
Type: text/x-patch
Size: 17980 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20130918/19977b0c/attachment-0001.bin>


More information about the x265-devel mailing list