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