[x265] [PATCH] frameencoder: remove second encodeCU() pass over CTUs when SAO is disabled

Deepthi Nandakumar deepthi at multicorewareinc.com
Mon Sep 8 10:05:25 CEST 2014


On Sat, Sep 6, 2014 at 10:08 PM, Steve Borho <steve at borho.org> wrote:

> # HG changeset patch
> # User Steve Borho <steve at borho.org>
> # Date 1409932577 -7200
> #      Fri Sep 05 17:56:17 2014 +0200
> # Node ID 07d69bce1760a28be1b1ee1821dfeb3335602422
> # Parent  795878af39730deb24e2ee0e585c625084bb031b
> frameencoder: remove second encodeCU() pass over CTUs when SAO is disabled
>
> This is a performance optimization, it allows the encoder to generate the
> final
> bitstream of each CTU as it is compressed and cache hot.
>
> When SAO is enabled, SAO analysis must be performed and coded at the start
> of
> the CTU but SAO analysis currently requires surrounding CTUs to be encoded
> making the second pass unavoidable.
>
> diff -r 795878af3973 -r 07d69bce1760 source/encoder/frameencoder.cpp
> --- a/source/encoder/frameencoder.cpp   Fri Sep 05 16:03:44 2014 +0200
> +++ b/source/encoder/frameencoder.cpp   Fri Sep 05 17:56:17 2014 +0200
> @@ -192,16 +192,6 @@
>          }
>      }
>
> -    uint32_t numSubstreams = m_param->bEnableWavefront ?
> m_frame->getPicSym()->getFrameHeightInCU() : 1;
> -    if (!m_outStreams)
> -    {
> -        m_outStreams = new Bitstream[numSubstreams];
> -        m_substreamSizes = X265_MALLOC(uint32_t, numSubstreams);
> -    }
> -    else
> -        for (uint32_t i = 0; i < numSubstreams; i++)
> -            m_outStreams[i].resetBits();
> -
>      /* Get the QP for this frame from rate control. This call may block
> until
>       * frames ahead of it in encode order have called rateControlEnd() */
>      int qp = m_top->m_rateControl->rateControlStart(m_frame, &m_rce,
> m_top);
> @@ -214,6 +204,24 @@
>
>      m_frameFilter.start(m_frame, m_initSliceContext, qp);
>
> +    // reset entropy coders
> +    m_entropyCoder.load(m_initSliceContext);
> +    for (int i = 0; i < m_numRows; i++)
> +        m_rows[i].init(m_initSliceContext);
> +
> +    uint32_t numSubstreams = m_param->bEnableWavefront ?
> m_frame->getPicSym()->getFrameHeightInCU() : 1;
> +    if (!m_outStreams)
> +    {
> +        m_outStreams = new Bitstream[numSubstreams];
> +        m_substreamSizes = X265_MALLOC(uint32_t, numSubstreams);
> +        if (!m_param->bEnableSAO)
> +            for (uint32_t i = 0; i < numSubstreams; i++)
> +
> m_rows[i].rdEntropyCoders[0][CI_CURR_BEST].setBitstream(&m_outStreams[i]);
> +    }
> +    else
> +        for (uint32_t i = 0; i < numSubstreams; i++)
> +            m_outStreams[i].resetBits();
> +
>      if (m_frame->m_lowres.bKeyframe)
>      {
>          if (m_param->bEmitHRDSEI)
> @@ -328,7 +336,7 @@
>      m_entropyCoder.setBitstream(&m_bs);
>      m_entropyCoder.codeSliceHeader(slice);
>
> -    // re-encode each row of CUs for the final time (TODO: get rid of
> this second pass)
> +    // finish encode of each CTU row
>      encodeSlice();
>
>      // serialize each row, record final lengths in slice header
> @@ -409,8 +417,40 @@
>      const uint32_t widthInLCUs =
> m_frame->getPicSym()->getFrameWidthInCU();
>      const uint32_t lastCUAddr = (slice->m_endCUAddr +
> m_frame->getNumPartInCU() - 1) / m_frame->getNumPartInCU();
>      const int numSubstreams = m_param->bEnableWavefront ?
> m_frame->getPicSym()->getFrameHeightInCU() : 1;
> +
> +    if (!m_param->bEnableSAO)
> +    {
> +        /* terminate each row and collect stats */
> +        for (uint32_t cuAddr = 0; cuAddr < lastCUAddr; cuAddr++)
> +        {
> +            uint32_t col = cuAddr % widthInLCUs;
> +
> +            if (m_param->bEnableWavefront && col == widthInLCUs - 1)
> +            {
> +                uint32_t lin = cuAddr / widthInLCUs;
> +                uint32_t subStrm = lin % numSubstreams;
> +
> m_rows[subStrm].rdEntropyCoders[0][CI_CURR_BEST].codeTerminatingBit(1);
> +
> m_rows[subStrm].rdEntropyCoders[0][CI_CURR_BEST].codeSliceFinish();
> +                m_outStreams[subStrm].writeByteAlignment();
> +            }
> +
> +            // Collect Frame Stats for 2 pass
> +            TComDataCU* cu = m_frame->getCU(cuAddr);
> +            m_frameStats.mvBits += cu->m_mvBits;
> +            m_frameStats.coeffBits += cu->m_coeffBits;
> +            m_frameStats.miscBits += cu->m_totalBits - (cu->m_mvBits +
> cu->m_coeffBits);
> +        }
> +        if (!m_param->bEnableWavefront)
> +        {
> +
> m_rows[0].rdEntropyCoders[0][CI_CURR_BEST].codeTerminatingBit(1);
> +            m_rows[0].rdEntropyCoders[0][CI_CURR_BEST].codeSliceFinish();
> +            m_outStreams[0].writeByteAlignment();
> +        }
> +
> +        return;
> +    }
> +
>      SAOParam *saoParam = slice->m_pic->getPicSym()->m_saoParam;
> -
>      for (uint32_t cuAddr = 0; cuAddr < lastCUAddr; cuAddr++)
>      {
>          uint32_t col = cuAddr % widthInLCUs;
> @@ -487,11 +527,6 @@
>      PPAScopeEvent(FrameEncoder_compressRows);
>      Slice* slice = m_frame->m_picSym->m_slice;
>
> -    // reset entropy coders
> -    m_entropyCoder.load(m_initSliceContext);
> -    for (int i = 0; i < m_numRows; i++)
> -        m_rows[i].init(m_initSliceContext);
> -
>      m_bAllRowsStop = false;
>      m_vbvResetTriggerRow = -1;
>
> @@ -672,15 +707,17 @@
>          }
>
>          if (m_param->bEnableWavefront && col == 0 && row > 0)
> +        {
>              // Load SBAC coder context from previous row.
> +
> curRow.rdEntropyCoders[0][CI_CURR_BEST].copyState(m_initSliceContext);
>
>  curRow.rdEntropyCoders[0][CI_CURR_BEST].loadContexts(m_rows[row -
> 1].bufferEntropyCoder);
>

It's the same thing in encodeSlice as well, but why are we copying State
from m_initSliceContext, and context from the saved previous row Coder?
Shouldnt both state and context be copied from the previous row coder?


> +        }
>
>          tld.cuCoder.m_quant.setQPforQuant(cu);
>          tld.cuCoder.compressCU(cu); // Does all the CU analysis
>
>          /* advance top-level CI_CURR_BEST to include the context of this
> CTU.
> -         * Note that if SAO was disabled this could directly write to a
> -         * bitstream object and we could skip most of encodeSlice() */
> +         * if SAO is disabled, this writes final CTU bitstream */
>          curRow.rdEntropyCoders[0][CI_CURR_BEST].encodeCU(cu);
>
>          if (m_param->bEnableWavefront && col == 1)
> _______________________________________________
> 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/20140908/ee525e33/attachment-0001.html>


More information about the x265-devel mailing list