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

Steve Borho steve at borho.org
Thu Sep 19 18:38:59 CEST 2013


On Thu, Sep 19, 2013 at 4:33 AM, Deepthi Nandakumar <
deepthi at multicorewareinc.com> wrote:

>
>
> On Thu, Sep 19, 2013 at 3:35 AM, Steve Borho <steve at borho.org> wrote:
>
>> # 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;
>>
>
> _cfg typo here.
>

actually, that is correct, it is initialized to negative keyframeMax, to
force frame 0 to I

see
http://git.videolan.org/?p=x264.git;a=blob;f=encoder/encoder.c;h=78ad56ae3cd96eebe596c79367d428c2e9dbd7bd;hb=9e941d1fabb2de4b15f169057a07dc395307d2ce#l1439


>
>
>> +    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;
>>
>> _______________________________________________
>> x265-devel mailing list
>> x265-devel at videolan.org
>> https://mailman.videolan.org/listinfo/x265-devel
>>
>>
>
> _______________________________________________
> x265-devel mailing list
> x265-devel at videolan.org
> https://mailman.videolan.org/listinfo/x265-devel
>
>


-- 
Steve Borho
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20130919/f68b3ed5/attachment-0001.html>


More information about the x265-devel mailing list