<div dir="ltr"><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, Sep 19, 2013 at 3:35 AM, Steve Borho <span dir="ltr"><<a href="mailto:steve@borho.org" target="_blank">steve@borho.org</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"># HG changeset patch<br>
# User Steve Borho <<a href="mailto:steve@borho.org">steve@borho.org</a>><br>
# Date 1378869992 18000<br>
#      Tue Sep 10 22:26:32 2013 -0500<br>
# Node ID a5810b7397ddec0bbec0e885bc5e7fd9bd5a7040<br>
# Parent  5bab261d0dd7ac68c4af3837853d48d56017d4d6<br>
slicetype: fill in missing detail from slicetypeDecide()<br>
<br>
This moves slicetypeDecide() to make the file more readable. It also adds stubs<br>
for features that we do not support yet including weightp, B-pyramid, intra<br>
refresh, user-supplied slice types, etc<br>
<br>
diff -r 5bab261d0dd7 -r a5810b7397dd source/common/lowres.cpp<br>
--- a/source/common/lowres.cpp  Wed Sep 18 16:13:33 2013 -0500<br>
+++ b/source/common/lowres.cpp  Tue Sep 10 22:26:32 2013 -0500<br>
@@ -108,11 +108,13 @@<br>
 // (re) initialize lowres state<br>
 void Lowres::init(TComPicYuv *orig, int bframes)<br>
 {<br>
-    scenecut = 1;<br>
+    scenecut = true;<br>
     bIntraCalculated = false;<br>
+    bLastMiniGopBFrame = false;<br>
+    keyframe = false; // Not a keyframe unless identified by lookahead<br>
+    sliceType = X265_TYPE_AUTO;<br>
+    leadingBframes = 0;<br>
     memset(costEst, -1, sizeof(costEst));<br>
-    sliceType = X265_TYPE_AUTO;<br>
-    keyframe = 0; //Not a keyframe unless identified by lookahead<br>
     for (int y = 0; y < bframes + 2; y++)<br>
     {<br>
         for (int x = 0; x < bframes + 2; x++)<br>
diff -r 5bab261d0dd7 -r a5810b7397dd source/common/lowres.h<br>
--- a/source/common/lowres.h    Wed Sep 18 16:13:33 2013 -0500<br>
+++ b/source/common/lowres.h    Tue Sep 10 22:26:32 2013 -0500<br>
@@ -44,14 +44,17 @@<br>
 {<br>
     /* lowres buffers, sizes and strides */<br>
     pixel *buffer[4];<br>
-    int    width;    // width of lowres frame in pixels<br>
-    int    lines;    // height of lowres frame in pixel lines<br>
+    int    width;     // width of lowres frame in pixels<br>
+    int    lines;     // height of lowres frame in pixel lines<br>
+<br>
+    int    frameNum;  // Presentation frame number<br>
+    int    sliceType; // Slice type decided by lookahead<br>
+    int    leadingBframes; // number of leading B frames for P or I<br>
+<br>
     bool   bIntraCalculated;<br>
-    int    frameNum;  // Presentation frame number<br>
-    int    scenecut;  // Set to zero if the frame cannot possibly be part of a real scenecut.<br>
-<br>
-    int    sliceType; // Slice type decided by lookahead<br>
-    int    keyframe;<br>
+    bool   scenecut;  // Set to zero if the frame cannot possibly be part of a real scenecut.<br>
+    bool   keyframe;<br>
+    bool   bLastMiniGopBFrame;<br>
<br>
     /* lookahead output data */<br>
     int       costEst[X265_BFRAME_MAX + 2][X265_BFRAME_MAX + 2];<br>
diff -r 5bab261d0dd7 -r a5810b7397dd source/encoder/slicetype.cpp<br>
--- a/source/encoder/slicetype.cpp      Wed Sep 18 16:13:33 2013 -0500<br>
+++ b/source/encoder/slicetype.cpp      Tue Sep 10 22:26:32 2013 -0500<br>
@@ -66,6 +66,8 @@<br>
 {<br>
     this->cfg = _cfg;<br>
     numDecided = 0;<br>
+    lastKeyframe = -cfg->param.keyframeMax;<br></blockquote><div><br></div><div>_cfg typo here. <br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+    lastNonB = NULL;<br>
     predictions = (pixel*)X265_MALLOC(pixel, 35 * 8 * 8);<br>
     me.setQP(X265_LOOKAHEAD_QP);<br>
     me.setSearchMethod(X265_HEX_SEARCH);<br>
@@ -115,118 +117,6 @@<br>
         slicetypeDecide();<br>
 }<br>
<br>
-void Lookahead::slicetypeDecide()<br>
-{<br>
-    if (numDecided == 0)<br>
-    {<br>
-        // Special case for POC 0, send directly to output queue as I slice<br>
-        TComPic *pic = inputQueue.popFront();<br>
-        pic->m_lowres.sliceType = X265_TYPE_I;<br>
-        outputQueue.pushBack(pic);<br>
-        numDecided++;<br>
-        lastKeyframe = 0;<br>
-        pic->m_lowres.keyframe = 1;<br>
-        frames[0] = &(pic->m_lowres);<br>
-        return;<br>
-    }<br>
-    else if (cfg->param.bFrameAdaptive && cfg->param.lookaheadDepth && cfg->param.bframes)<br>
-    {<br>
-        slicetypeAnalyse(false);<br>
-<br>
-        int dframes;<br>
-        TComPic* picsAnalysed[X265_LOOKAHEAD_MAX];  //Used for sorting the pics into encode order<br>
-        int idx = 1;<br>
-<br>
-        for (dframes = 0; (frames[dframes + 1] != NULL) && (frames[dframes + 1]->sliceType != X265_TYPE_AUTO); dframes++)<br>
-        {<br>
-            if (frames[dframes + 1]->sliceType == X265_TYPE_I)<br>
-            {<br>
-                frames[dframes + 1]->keyframe = 1;<br>
-                lastKeyframe = frames[dframes]->frameNum;<br>
-                if (cfg->param.decodingRefreshType == 2 && dframes > 0) //If an IDR frame following a B<br>
-                {<br>
-                    frames[dframes]->sliceType = X265_TYPE_P;<br>
-                    dframes--;<br>
-                }<br>
-            }<br>
-            if (!IS_X265_TYPE_B(frames[dframes + 1]->sliceType))<br>
-            {<br>
-                dframes++;<br>
-                break;<br>
-            }<br>
-        }<br>
-<br>
-        TComPic *pic = NULL;<br>
-        for (int i = 1; i <= dframes && !inputQueue.empty(); i++)<br>
-        {<br>
-            pic = inputQueue.popFront();<br>
-            picsAnalysed[idx++] = pic;<br>
-        }<br>
-<br>
-        picsAnalysed[0] = pic;  //Move the P-frame following B-frames to the beginning<br>
-<br>
-        //Push pictures in encode order<br>
-        for (int i = 0; i < dframes; i++)<br>
-        {<br>
-            outputQueue.pushBack(picsAnalysed[i]);<br>
-        }<br>
-<br>
-        if (pic)<br>
-            frames[0] = &(pic->m_lowres); // last nonb<br>
-        return;<br>
-    }<br>
-<br>
-    // Fixed GOP structures for when B-Adapt and/or lookahead are disabled<br>
-    if (cfg->param.keyframeMax == 1)<br>
-    {<br>
-        TComPic *pic = inputQueue.popFront();<br>
-<br>
-        pic->m_lowres.sliceType = X265_TYPE_I;<br>
-        pic->m_lowres.keyframe = 1;<br>
-        outputQueue.pushBack(pic);<br>
-        numDecided++;<br>
-    }<br>
-    else if (cfg->param.bframes == 0 || inputQueue.size() == 1)<br>
-    {<br>
-        TComPic *pic = inputQueue.popFront();<br>
-<br>
-        bool forceIntra = (pic->getPOC() % cfg->param.keyframeMax) == 0;<br>
-        pic->m_lowres.sliceType = forceIntra ? X265_TYPE_I : X265_TYPE_P;<br>
-        pic->m_lowres.keyframe = forceIntra ? 1 : 0;<br>
-        outputQueue.pushBack(pic);<br>
-        numDecided++;<br>
-    }<br>
-    else<br>
-    {<br>
-        TComPic *picB = inputQueue.popFront();<br>
-        TComPic *picP = inputQueue.popFront();<br>
-<br>
-        bool forceIntra = (picP->getPOC() % cfg->param.keyframeMax) == 0 || (picB->getPOC() % cfg->param.keyframeMax) == 0;<br>
-        if (forceIntra)<br>
-        {<br>
-            picB->m_lowres.sliceType = (picB->getPOC() % cfg->param.keyframeMax) ? X265_TYPE_P : X265_TYPE_I;<br>
-            picB->m_lowres.keyframe = (picB->getPOC() % cfg->param.keyframeMax) ? 0 : 1;<br>
-            outputQueue.pushBack(picB);<br>
-            numDecided++;<br>
-<br>
-            picP->m_lowres.sliceType = (picP->getPOC() % cfg->param.keyframeMax) ? X265_TYPE_P : X265_TYPE_I;<br>
-            picP->m_lowres.keyframe = (picP->getPOC() % cfg->param.keyframeMax) ? 0 : 1;<br>
-            outputQueue.pushBack(picP);<br>
-            numDecided++;<br>
-        }<br>
-        else<br>
-        {<br>
-            picP->m_lowres.sliceType = X265_TYPE_P;<br>
-            outputQueue.pushBack(picP);<br>
-            numDecided++;<br>
-<br>
-            picB->m_lowres.sliceType = X265_TYPE_B;<br>
-            outputQueue.pushBack(picB);<br>
-            numDecided++;<br>
-        }<br>
-    }<br>
-}<br>
-<br>
 // Called by RateControl to get the estimated SATD cost for a given picture.<br>
 // It assumes dpb->prepareEncode() has already been called for the picture and<br>
 // all the references are established<br>
@@ -482,6 +372,219 @@<br>
     fenc->lowresCosts[b - p0][p1 - b][cuXY] = (uint16_t)(X265_MIN(bcost, LOWRES_COST_MASK) | (listused << LOWRES_COST_SHIFT));<br>
 }<br>
<br>
+void Lookahead::slicetypeDecide()<br>
+{<br>
+    if (cfg->param.bFrameAdaptive && cfg->param.lookaheadDepth && cfg->param.bframes)<br>
+    {<br>
+        slicetypeAnalyse(false);<br>
+<br>
+        TComPic *list[X265_LOOKAHEAD_MAX];<br>
+        TComList<TComPic*>::iterator iterPic = inputQueue.begin();<br>
+        int j;<br>
+        for (j = 0; j < cfg->param.bframes + 2 && iterPic != inputQueue.end(); iterPic++)<br>
+            list[j++] = (*iterPic);<br>
+        list[j] = NULL;<br>
+<br>
+        int bframes, brefs;<br>
+        for (bframes = 0, brefs = 0 ;; bframes++)<br>
+        {<br>
+            Lowres& frm = list[bframes]->m_lowres;<br>
+<br>
+            if (frm.sliceType == X265_TYPE_BREF<br>
+                /* && h->param.i_bframe_pyramid < X264_B_PYRAMID_NORMAL && brefs == h->param.i_bframe_pyramid*/)<br>
+            {<br>
+                frm.sliceType = X265_TYPE_B;<br>
+                x265_log(&cfg->param, X265_LOG_WARNING, "B-ref is not yet supported\n");<br>
+            }<br>
+            /* pyramid with multiple B-refs needs a big enough dpb that the preceding P-frame stays available.<br>
+               smaller dpb could be supported by smart enough use of mmco, but it's easier just to forbid it.<br>
+            else if (frm.sliceType == X265_TYPE_BREF && cfg->param.i_bframe_pyramid == X265_B_PYRAMID_NORMAL &&<br>
+                     brefs && cfg->param.i_frame_reference <= (brefs+3))<br>
+            {<br>
+                frm.sliceType = X265_TYPE_B;<br>
+                x265_log(&cfg->param, X265_LOG_WARNING, "B-ref at frame %d incompatible with B-pyramid %s and %d reference frames\n",<br>
+                          frm.sliceType, x264_b_pyramid_names[h->param.i_bframe_pyramid], h->param.i_frame_reference);<br>
+            } */<br>
+<br>
+            if (frm.sliceType == X265_TYPE_KEYFRAME)<br>
+                frm.sliceType = cfg->param.bOpenGOP ? X265_TYPE_I : X265_TYPE_IDR;<br>
+            if ((/* !cfg->param.intraRefresh || */ frm.frameNum == 0) && frm.frameNum - lastKeyframe >= cfg->param.keyframeMax)<br>
+            {<br>
+                if (frm.sliceType == X265_TYPE_AUTO || frm.sliceType == X265_TYPE_I)<br>
+                    frm.sliceType = cfg->param.bOpenGOP && lastKeyframe >= 0 ? X265_TYPE_I : X265_TYPE_IDR;<br>
+                bool warn = frm.sliceType != X265_TYPE_IDR;<br>
+                if (warn && cfg->param.bOpenGOP)<br>
+                    warn &= frm.sliceType != X265_TYPE_I;<br>
+                if (warn)<br>
+                {<br>
+                    x265_log(&cfg->param, X265_LOG_WARNING, "specified frame type (%d) at %d is not compatible with keyframe interval\n", frm.sliceType, frm.frameNum);<br>
+                    frm.sliceType = cfg->param.bOpenGOP && lastKeyframe >= 0 ? X265_TYPE_I : X265_TYPE_IDR;<br>
+                }<br>
+            }<br>
+            if (frm.sliceType == X265_TYPE_I && frm.sliceType - lastKeyframe >= cfg->param.keyframeMin)<br>
+            {<br>
+                if (cfg->param.bOpenGOP)<br>
+                {<br>
+                    lastKeyframe = frm.frameNum; // Use display order<br>
+                    frm.keyframe = true;<br>
+                }<br>
+                else<br>
+                    frm.sliceType = X265_TYPE_IDR;<br>
+            }<br>
+            if (frm.sliceType == X265_TYPE_IDR)<br>
+            {<br>
+                /* Close GOP */<br>
+                lastKeyframe = frm.frameNum;<br>
+                frm.keyframe = true;<br>
+                if (bframes > 0)<br>
+                {<br>
+                    frames[bframes]->sliceType = X265_TYPE_P;<br>
+                    bframes--;<br>
+                }<br>
+            }<br>
+<br>
+            if (bframes == cfg->param.bframes || !list[bframes+1])<br>
+            {<br>
+                if (IS_X265_TYPE_B(frm.sliceType))<br>
+                    x265_log(&cfg->param, X265_LOG_WARNING, "specified frame type is not compatible with max B-frames\n");<br>
+                if (frm.sliceType == X265_TYPE_AUTO || IS_X265_TYPE_B(frm.sliceType))<br>
+                    frm.sliceType = X265_TYPE_P;<br>
+            }<br>
+            if (frm.sliceType == X265_TYPE_BREF)<br>
+                brefs++;<br>
+            if (frm.sliceType == X265_TYPE_AUTO)<br>
+                frm.sliceType = X265_TYPE_B;<br>
+            else if (!IS_X265_TYPE_B(frm.sliceType))<br>
+                break;<br>
+        }<br>
+        if (bframes)<br>
+            list[bframes-1]->m_lowres.bLastMiniGopBFrame = true;<br>
+        list[bframes]->m_lowres.leadingBframes = bframes;<br>
+        lastNonB = &list[bframes]->m_lowres;<br>
+<br>
+        /* insert a bref into the sequence<br>
+        if (h->param.i_bframe_pyramid && bframes > 1 && !brefs)<br>
+        {<br>
+            h->lookahead->next.list[bframes/2]->i_type = X264_TYPE_BREF;<br>
+            brefs++;<br>
+        } */<br>
+<br>
+        /* calculate the frame costs ahead of time for x264_rc_analyse_slice while we still have lowres */<br>
+        if (cfg->param.rc.rateControlMode != X265_RC_CQP)<br>
+        {<br>
+            int p0, p1, b;<br>
+            p1 = b = bframes + 1;<br>
+<br>
+            frames[0] = lastNonB;<br>
+            if (IS_X265_TYPE_I(frames[bframes+1]->sliceType))<br>
+                p0 = bframes + 1;<br>
+            else // P<br>
+                p0 = 0;<br>
+<br>
+            estimateFrameCost(p0, p1, b, 0);<br>
+<br>
+            /*<br>
+            if ((p0 != p1 || bframes) && cfg->param.rc.i_vbv_buffer_size)<br>
+            {<br>
+                // We need the intra costs for row SATDs<br>
+                estimateFrameCost(b, b, b, 0);<br>
+<br>
+                // We need B-frame costs for row SATDs<br>
+                p0 = 0;<br>
+                for (b = 1; b <= bframes; b++)<br>
+                {<br>
+                    if (frames[b]->i_type == X265_TYPE_B)<br>
+                        for (p1 = b; frames[p1]->sliceType == X265_TYPE_B;)<br>
+                            p1++;<br>
+                    else<br>
+                        p1 = bframes + 1;<br>
+                    estimateFrameCost( p0, p1, b, 0 );<br>
+                    if (frames[b]->sliceType == X265_TYPE_BREF)<br>
+                        p0 = b;<br>
+                }<br>
+            } */<br>
+        }<br>
+        /* Analyse for weighted P frames<br>
+        if (!h->param.rc.b_stat_read && h->lookahead->next.list[bframes]->i_type == X264_TYPE_P<br>
+            && h->param.analyse.i_weighted_pred >= X264_WEIGHTP_SIMPLE)<br>
+        {<br>
+            x265_emms();<br>
+            x264_weights_analyse(h, h->lookahead->next.list[bframes], h->lookahead->last_nonb, 0);<br>
+        }*/<br>
+<br>
+        /* add to output queue in encode order */<br>
+        outputQueue.pushBack(list[bframes]);<br>
+        inputQueue.popFront();<br>
+        for (int i = 0; i < bframes; i++)<br>
+        {<br>
+            outputQueue.pushBack(list[i]);<br>
+            inputQueue.popFront();<br>
+        }<br>
+        return;<br>
+    }<br>
+<br>
+    // Fixed GOP structures for when B-Adapt and/or lookahead are disabled<br>
+    if (numDecided == 0)<br>
+    {<br>
+        // Special case for POC 0, send directly to output queue as I slice<br>
+        TComPic *pic = inputQueue.popFront();<br>
+        pic->m_lowres.sliceType = X265_TYPE_I;<br>
+        outputQueue.pushBack(pic);<br>
+        numDecided++;<br>
+        lastKeyframe = 0;<br>
+        pic->m_lowres.keyframe = 1;<br>
+        return;<br>
+    }<br>
+    else if (cfg->param.keyframeMax == 1)<br>
+    {<br>
+        TComPic *pic = inputQueue.popFront();<br>
+<br>
+        pic->m_lowres.sliceType = X265_TYPE_I;<br>
+        pic->m_lowres.keyframe = 1;<br>
+        outputQueue.pushBack(pic);<br>
+        numDecided++;<br>
+    }<br>
+    else if (cfg->param.bframes == 0 || inputQueue.size() == 1)<br>
+    {<br>
+        TComPic *pic = inputQueue.popFront();<br>
+<br>
+        bool forceIntra = (pic->getPOC() % cfg->param.keyframeMax) == 0;<br>
+        pic->m_lowres.sliceType = forceIntra ? X265_TYPE_I : X265_TYPE_P;<br>
+        pic->m_lowres.keyframe = forceIntra ? 1 : 0;<br>
+        outputQueue.pushBack(pic);<br>
+        numDecided++;<br>
+    }<br>
+    else<br>
+    {<br>
+        TComPic *picB = inputQueue.popFront();<br>
+        TComPic *picP = inputQueue.popFront();<br>
+<br>
+        bool forceIntra = (picP->getPOC() % cfg->param.keyframeMax) == 0 || (picB->getPOC() % cfg->param.keyframeMax) == 0;<br>
+        if (forceIntra)<br>
+        {<br>
+            picB->m_lowres.sliceType = (picB->getPOC() % cfg->param.keyframeMax) ? X265_TYPE_P : X265_TYPE_I;<br>
+            picB->m_lowres.keyframe = (picB->getPOC() % cfg->param.keyframeMax) ? 0 : 1;<br>
+            outputQueue.pushBack(picB);<br>
+            numDecided++;<br>
+<br>
+            picP->m_lowres.sliceType = (picP->getPOC() % cfg->param.keyframeMax) ? X265_TYPE_P : X265_TYPE_I;<br>
+            picP->m_lowres.keyframe = (picP->getPOC() % cfg->param.keyframeMax) ? 0 : 1;<br>
+            outputQueue.pushBack(picP);<br>
+            numDecided++;<br>
+        }<br>
+        else<br>
+        {<br>
+            picP->m_lowres.sliceType = X265_TYPE_P;<br>
+            outputQueue.pushBack(picP);<br>
+            numDecided++;<br>
+<br>
+            picB->m_lowres.sliceType = X265_TYPE_B;<br>
+            outputQueue.pushBack(picB);<br>
+            numDecided++;<br>
+        }<br>
+    }<br>
+}<br>
+<br>
 void Lookahead::slicetypeAnalyse(bool bKeyframe)<br>
 {<br>
     int num_frames, origNumFrames, keyint_limit, framecnt;<br>
@@ -489,8 +592,10 @@<br>
     int cuCount = NUM_CUS;<br>
     int cost1p0, cost2p0, cost1b1, cost2p1;<br>
     int reset_start;<br>
-    int vbv_lookahead = 0;<br>
<br>
+    if (!lastNonB)<br>
+        return;<br>
+    frames[0] = lastNonB;<br>
     TComList<TComPic*>::iterator iterPic = inputQueue.begin();<br>
     for (framecnt = 0; (framecnt < maxSearch) && (framecnt < (int)inputQueue.size()) && (*iterPic)->m_lowres.sliceType == X265_TYPE_AUTO; framecnt++)<br>
     {<br>
@@ -499,8 +604,7 @@<br>
<br>
     if (!framecnt)<br>
     {<br>
-        frames[1] = &((*iterPic)->m_lowres);<br>
-        frames[2] = NULL;<br>
+        // TODO: mb-tree<br>
         return;<br>
     }<br>
<br>
@@ -509,14 +613,7 @@<br>
     keyint_limit = cfg->param.keyframeMax - frames[1]->frameNum + lastKeyframe;<br>
     origNumFrames = num_frames = X265_MIN(framecnt, keyint_limit);<br>
<br>
-    /* This is important psy-wise: if we have a non-scenecut keyframe,<br>
-     * there will be significant visual artifacts if the frames just before<br>
-     * go down in quality due to being referenced less, despite it being<br>
-     * more RD-optimal. */<br>
-<br>
-    if (vbv_lookahead)<br>
-        num_frames = framecnt;<br>
-    else if (num_frames < framecnt)<br>
+    if (cfg->param.bOpenGOP && num_frames < framecnt)<br>
         num_frames++;<br>
     else if (num_frames == 0)<br>
     {<br>
@@ -641,7 +738,7 @@<br>
     }<br>
<br>
     // TODO if rc.b_mb_tree Enabled the need to call  x264_macroblock_tree currently Ignored the call<br>
-<br>
+    // if (!cfg->param.bIntraRefresh)<br>
     for (int j = keyint_limit + 1; j <= num_frames; j += cfg->param.keyframeMax)<br>
     {<br>
         frames[j]->sliceType = X265_TYPE_I;<br>
diff -r 5bab261d0dd7 -r a5810b7397dd source/encoder/slicetype.h<br>
--- a/source/encoder/slicetype.h        Wed Sep 18 16:13:33 2013 -0500<br>
+++ b/source/encoder/slicetype.h        Tue Sep 10 22:26:32 2013 -0500<br>
@@ -44,6 +44,7 @@<br>
     TEncCfg         *cfg;<br>
     pixel           *predictions;   // buffer for 35 intra predictions<br>
     Lowres          *frames[X265_LOOKAHEAD_MAX];<br>
+    Lowres          *lastNonB;<br>
     int              merange;<br>
     int              numDecided;<br>
     int              lastKeyframe;<br>
<br>_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
<br></blockquote></div><br></div></div>