[x265] [PATCH] Extend gop boundary by doing gop lookahead

Pradeep Ramachandran pradeep at multicorewareinc.com
Tue Nov 21 05:37:50 CET 2017


On Mon, Nov 20, 2017 at 11:12 AM, <aruna at multicorewareinc.com> wrote:

> # HG changeset patch
> # User Aruna Matheswaran <aruna at multicorewareinc.com>
> # Date 1511155419 -19800
> #      Mon Nov 20 10:53:39 2017 +0530
> # Node ID d37d703039dae201c5a7114ff71e6c4d4196347c
> # Parent  0f0d608e732be425d71169b4cf0563adbfb7729b
> Extend gop boundary by doing gop lookahead
>

Patch doesn't apply on default tip. Please fix and resend.


>
> diff -r 0f0d608e732b -r d37d703039da doc/reST/cli.rst
> --- a/doc/reST/cli.rst  Fri Nov 17 19:23:14 2017 +0530
> +++ b/doc/reST/cli.rst  Mon Nov 20 10:53:39 2017 +0530
> @@ -1373,6 +1373,14 @@
>         Default 20
>
>         **Range of values:** Between the maximum consecutive bframe count
> (:option:`--bframes`) and 250
> +
> +.. option:: --gop-lookahead <integer>
> +
> +       Number of frames for GOP boundary decision lookahead. If a
> scenecut frame is found
> +       within this from the gop boundary set by `--keyint`, the GOP will
> be extented until such a point,
> +       otherwise the GOP will be terminated as set by `--keyint`. Default
> 0.
> +
> +       **Range of values:** Between 0 and `--rc-lookahead`.
>
>  .. option:: --lookahead-slices <0..16>
>
> diff -r 0f0d608e732b -r d37d703039da source/CMakeLists.txt
> --- a/source/CMakeLists.txt     Fri Nov 17 19:23:14 2017 +0530
> +++ b/source/CMakeLists.txt     Mon Nov 20 10:53:39 2017 +0530
> @@ -29,7 +29,7 @@
>  option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF)
>  mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)
>  # X265_BUILD must be incremented each time the public API is changed
> -set(X265_BUILD 146)
> +set(X265_BUILD 147)
>  configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
>                 "${PROJECT_BINARY_DIR}/x265.def")
>  configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
> diff -r 0f0d608e732b -r d37d703039da source/common/param.cpp
> --- a/source/common/param.cpp   Fri Nov 17 19:23:14 2017 +0530
> +++ b/source/common/param.cpp   Mon Nov 20 10:53:39 2017 +0530
> @@ -144,6 +144,7 @@
>      /* Coding Structure */
>      param->keyframeMin = 0;
>      param->keyframeMax = 250;
> +    param->gopLookahead = 0;
>      param->bOpenGOP = 1;
>      param->bframes = 4;
>      param->lookaheadDepth = 20;
> @@ -1004,6 +1005,7 @@
>                  bError = true;
>              }
>           }
> +        OPT("gop-lookahead") p->gopLookahead = atoi(value);
>          else
>              return X265_PARAM_BAD_NAME;
>      }
> @@ -1314,6 +1316,8 @@
>            "Valid penalty for 32x32 intra TU in non-I slices. 0:disabled
> 1:RD-penalty 2:maximum");
>      CHECK(param->keyframeMax < -1,
>            "Invalid max IDR period in frames. value should be greater than
> -1");
> +    CHECK(param->gopLookahead < -1,
> +          "GOP lookahead must be greater than -1");
>      CHECK(param->decodedPictureHashSEI < 0 ||
> param->decodedPictureHashSEI > 3,
>            "Invalid hash option. Decoded Picture Hash SEI 0: disabled, 1:
> MD5, 2: CRC, 3: Checksum");
>      CHECK(param->rc.vbvBufferSize < 0,
> @@ -1561,6 +1565,7 @@
>      BOOL(p->bOpenGOP, "open-gop");
>      s += sprintf(s, " min-keyint=%d", p->keyframeMin);
>      s += sprintf(s, " keyint=%d", p->keyframeMax);
> +    s += sprintf(s, " gop-lookahead=%d", p->gopLookahead);
>      s += sprintf(s, " bframes=%d", p->bframes);
>      s += sprintf(s, " b-adapt=%d", p->bFrameAdaptive);
>      BOOL(p->bBPyramid, "b-pyramid");
> diff -r 0f0d608e732b -r d37d703039da source/encoder/slicetype.cpp
> --- a/source/encoder/slicetype.cpp      Fri Nov 17 19:23:14 2017 +0530
> +++ b/source/encoder/slicetype.cpp      Mon Nov 20 10:53:39 2017 +0530
> @@ -589,6 +589,7 @@
>      m_outputSignalRequired = false;
>      m_isActive = true;
>      m_inputCount = 0;
> +    m_extendGopBoundary = false;
>
>      m_8x8Height = ((m_param->sourceHeight / 2) + X265_LOWRES_CU_SIZE - 1)
> >> X265_LOWRES_CU_BITS;
>      m_8x8Width = ((m_param->sourceWidth / 2) + X265_LOWRES_CU_SIZE - 1)
> >> X265_LOWRES_CU_BITS;
> @@ -647,6 +648,12 @@
>          m_numCoopSlices = 1;
>      }
>
> +    if (param->gopLookahead > param->lookaheadDepth)
> +    {
> +        x265_log(param, X265_LOG_WARNING, "Gop-lookahead cannot be
> greater than rc-lookahead; Clipping gop-lookahead to rc-lookahead\n");
> +        param->gopLookahead = param->lookaheadDepth;
> +    }
> +
>  #if DETAILED_CU_STATS
>      m_slicetypeDecideElapsedTime = 0;
>      m_preLookaheadElapsedTime = 0;
> @@ -1086,7 +1093,8 @@
>              x265_log(m_param, X265_LOG_WARNING, "B-ref at frame %d
> incompatible with B-pyramid and %d reference frames\n",
>                       frm.sliceType, m_param->maxNumReferences);
>          }
> -        if ((!m_param->bIntraRefresh || frm.frameNum == 0) &&
> frm.frameNum - m_lastKeyframe >= m_param->keyframeMax)
> +        if ((!m_param->bIntraRefresh || frm.frameNum == 0) &&
> frm.frameNum - m_lastKeyframe >= m_param->keyframeMax &&
> +            (!m_extendGopBoundary || frm.frameNum - m_lastKeyframe >=
> m_param->keyframeMax + m_param->gopLookahead))
>          {
>              if (frm.sliceType == X265_TYPE_AUTO || frm.sliceType ==
> X265_TYPE_I)
>                  frm.sliceType = m_param->bOpenGOP && m_lastKeyframe >= 0
> ? X265_TYPE_I : X265_TYPE_IDR;
> @@ -1380,7 +1388,14 @@
>
>      frames[framecnt + 1] = NULL;
>
> -    keyintLimit = m_param->keyframeMax - frames[0]->frameNum +
> m_lastKeyframe - 1;
> +    int keyFrameLimit = m_param->keyframeMax + m_lastKeyframe -
> frames[1]->frameNum;
> +
> +    if (m_param->gopLookahead && keyFrameLimit < m_param->bframes + 2)
> +        keyintLimit = m_param->keyframeMax + m_param->gopLookahead -
> frames[0]->frameNum + m_lastKeyframe - 1;
> +    else
> +        keyintLimit = m_param->keyframeMax - frames[0]->frameNum +
> m_lastKeyframe - 1;
> +
> +
>

Use keyFrameLimit to evaluate keyintLimit so that the evaluation on the RHS
of the assignment can be simplified.

     origNumFrames = numFrames = m_param->bIntraRefresh ? framecnt :
> X265_MIN(framecnt, keyintLimit);
>
>      if (bIsVbvLookahead)
> @@ -1473,6 +1488,26 @@
>          return;
>      }
>
> +    if (m_param->gopLookahead && keyFrameLimit >= 0 && keyFrameLimit <
> m_param->bframes + 2)
>

Use parenthesis here to make each conditional check explicit.


> +    {
> +        bool sceneTransition = m_isSceneTransition;
> +        m_extendGopBoundary = false;
> +        for (int i = m_param->bframes + 1; i < origNumFrames; i +=
> m_param->bframes + 1)
> +        {
> +            scenecut(frames, i, i + 1, true, origNumFrames);
> +            for (int j = i + 1; j <= X265_MIN(i + m_param->bframes + 1,
> origNumFrames); j++)
> +            {
> +                if (frames[j]->bScenecut && m_isSceneTransition &&
> scenecut(frames, j - 1, j, false, origNumFrames))
> +                {
> +                    m_extendGopBoundary = true;
> +                    break;
> +                }
> +            }
> +            if (m_extendGopBoundary)
> +                break;
> +        }
> +        m_isSceneTransition = sceneTransition;
> +    }
>      if (m_param->bframes)
>      {
>          if (m_param->bFrameAdaptive == X265_B_ADAPT_TRELLIS)
> @@ -1579,6 +1614,9 @@
>      if (m_param->rc.cuTree)
>          cuTree(frames, X265_MIN(numFrames, m_param->keyframeMax),
> bKeyframe);
>
> +    if (m_param->gopLookahead && keyFrameLimit >= 0 && keyFrameLimit <
> m_param->bframes + 2 && !m_extendGopBoundary)
> +        keyintLimit = m_param->keyframeMax - frames[0]->frameNum +
> m_lastKeyframe - 1;
> +
>      if (!m_param->bIntraRefresh)
>          for (int j = keyintLimit + 1; j <= numFrames; j +=
> m_param->keyframeMax)
>          {
> @@ -1588,8 +1626,9 @@
>
>      if (bIsVbvLookahead)
>          vbvLookahead(frames, numFrames, bKeyframe);
> -
> -     int maxp1 = X265_MIN(m_param->bframes + 1, origNumFrames);
> +
> +    int maxp1 = X265_MIN(m_param->bframes + 1, origNumFrames);
> +
>      /* Restore frame types for all frames that haven't actually been
> decided yet. */
>      for (int j = resetStart; j <= numFrames; j++)
>      {
> @@ -1613,8 +1652,8 @@
>          bool fluctuate = false;
>          bool noScenecuts = false;
>          int64_t avgSatdCost = 0;
> -        if (frames[0]->costEst[1][0] > -1)
> -            avgSatdCost = frames[0]->costEst[1][0];
> +        if (frames[p0]->costEst[p1 - p0][0] > -1)
> +            avgSatdCost = frames[p0]->costEst[p1 - p0][0];
>          int cnt = 1;
>          /* Where A and B are scenes: AAAAAABBBAAAAAA
>           * If BBB is shorter than (maxp1-p0), it is detected as a flash
> @@ -1717,14 +1756,21 @@
>              bias = threshMin / 4;
>          else if (gopSize <= m_param->keyframeMin)
>              bias = threshMin * gopSize / m_param->keyframeMin;
> -        else
> +        else if (gopSize <= m_param->keyframeMax)
>          {
>              bias = threshMin
>                  + (threshMax - threshMin)
>                  * (gopSize - m_param->keyframeMin)
>                  / (m_param->keyframeMax - m_param->keyframeMin);
>          }
> -    }
> +        else
> +        {
> +            bias = threshMin
> +                + (threshMax - threshMin)
> +                * (gopSize - m_param->keyframeMax)
> +                / (m_param->gopLookahead);
> +        }
> + }
>      bool res = pcost >= (1.0 - bias) * icost;
>      if (res && bRealScenecut)
>      {
> diff -r 0f0d608e732b -r d37d703039da source/encoder/slicetype.h
> --- a/source/encoder/slicetype.h        Fri Nov 17 19:23:14 2017 +0530
> +++ b/source/encoder/slicetype.h        Mon Nov 20 10:53:39 2017 +0530
> @@ -132,6 +132,7 @@
>      bool          m_filled;
>      bool          m_isSceneTransition;
>      int           m_numPools;
> +    bool          m_extendGopBoundary;
>      Lookahead(x265_param *param, ThreadPool *pool);
>  #if DETAILED_CU_STATS
>      int64_t       m_slicetypeDecideElapsedTime;
> diff -r 0f0d608e732b -r d37d703039da source/test/regression-tests.txt
> --- a/source/test/regression-tests.txt  Fri Nov 17 19:23:14 2017 +0530
> +++ b/source/test/regression-tests.txt  Mon Nov 20 10:53:39 2017 +0530
> @@ -150,6 +150,7 @@
>  Kimono1_1920x1080_24_400.yuv,--preset medium --rdoq-level 0 --limit-refs
> 3 --slices 2
>  Kimono1_1920x1080_24_400.yuv,--preset veryslow --crf 4 --cu-lossless
> --slices 2 --limit-refs 3 --limit-modes
>  Kimono1_1920x1080_24_400.yuv,--preset placebo --ctu 32 --max-tu-size 8
> --limit-tu 2
> +big_buck_bunny_360p24.y4m, --keyint 60 --min-keyint 40 --gop-lookahead 20
>
>  # Main12 intraCost overflow bug test
>  720p50_parkrun_ter.y4m,--preset medium
> diff -r 0f0d608e732b -r d37d703039da source/test/smoke-tests.txt
> --- a/source/test/smoke-tests.txt       Fri Nov 17 19:23:14 2017 +0530
> +++ b/source/test/smoke-tests.txt       Mon Nov 20 10:53:39 2017 +0530
> @@ -20,5 +20,6 @@
>  DucksAndLegs_1920x1080_60_10bit_422.yuv,--preset=fast --weightb
> --interlace bff
>  DucksAndLegs_1920x1080_60_10bit_422.yuv,--preset=veryslow --limit-ref 1
> --limit-mode --tskip --limit-tu 1
>  CrowdRun_1920x1080_50_10bit_444.yuv,--preset=superfast --bitrate 7000
> --sao --limit-sao
> +RaceHorses_416x240_30_10bit.yuv, --preset=fast --bitrate 500
> --gop-lookahead 10
>

Lets not add a separate line in smoke test for this feature. Just
piggy-back on another command line to limit run-time of smoke tests. A
separate test in regression is ok.


>  # Main12 intraCost overflow bug test
>  720p50_parkrun_ter.y4m,--preset medium
> diff -r 0f0d608e732b -r d37d703039da source/x265.h
> --- a/source/x265.h     Fri Nov 17 19:23:14 2017 +0530
> +++ b/source/x265.h     Mon Nov 20 10:53:39 2017 +0530
> @@ -1535,6 +1535,11 @@
>
>      /* Allow the encoder to have a copy of the planes of x265_picture in
> Frame */
>      int       bCopyPicToFrame;
> +
> +    /*Number of frames for GOP boundary decision lookahead.If a scenecut
> frame is found
> +    * within this from the gop boundary set by keyint, the GOP will be
> extented until such a point,
> +    * otherwise the GOP will be terminated as set by keyint*/
> +    int       gopLookahead;
>  } x265_param;
>
>  /* x265_param_alloc:
> diff -r 0f0d608e732b -r d37d703039da source/x265cli.h
> --- a/source/x265cli.h  Fri Nov 17 19:23:14 2017 +0530
> +++ b/source/x265cli.h  Mon Nov 20 10:53:39 2017 +0530
> @@ -119,6 +119,7 @@
>      { "open-gop",             no_argument, NULL, 0 },
>      { "keyint",         required_argument, NULL, 'I' },
>      { "min-keyint",     required_argument, NULL, 'i' },
> +    { "gop-lookahead",  required_argument, NULL, 0 },
>      { "scenecut",       required_argument, NULL, 0 },
>      { "no-scenecut",          no_argument, NULL, 0 },
>      { "scenecut-bias",  required_argument, NULL, 0 },
> @@ -418,6 +419,7 @@
>      H0("   --[no-]open-gop               Enable open-GOP, allows I slices
> to be non-IDR. Default %s\n", OPT(param->bOpenGOP));
>      H0("-I/--keyint <integer>            Max IDR period in frames. -1 for
> infinite-gop. Default %d\n", param->keyframeMax);
>      H0("-i/--min-keyint <integer>        Scenecuts closer together than
> this are coded as I, not IDR. Default: auto\n");
> +    H0("   --gop-lookahead <integer>     Extends gop boundary if a
> scenecut is found within this from keyint boundary. Default 0\n");
>      H0("   --no-scenecut                 Disable adaptive I-frame
> decision\n");
>      H0("   --scenecut <integer>          How aggressively to insert extra
> I-frames. Default %d\n", param->scenecutThreshold);
>      H1("   --scenecut-bias <0..100.0>    Bias for scenecut detection.
> Default %.2f\n", param->scenecutBias);
>
> _______________________________________________
> x265-devel mailing list
> x265-devel at videolan.org
> https://mailman.videolan.org/listinfo/x265-devel
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20171121/3ffab329/attachment-0001.html>


More information about the x265-devel mailing list