<div dir="ltr">Pushed to master</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Sep 9, 2020 at 1:21 PM Kirithika Kalirathnam <<a href="mailto:kirithika@multicorewareinc.com">kirithika@multicorewareinc.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">From f83db031a5308bb6bc2ca54dd079e20630fc5701 Mon Sep 17 00:00:00 2001<br>From: Kirithika <<a href="mailto:kirithika@multicorewareinc.com" target="_blank">kirithika@multicorewareinc.com</a>><br>Date: Fri, 28 Aug 2020 09:20:47 +0530<br>Subject: [PATCH] Add real-time VBV fullness based QP tuning in VBV 2 pass<br><br>This commit enables real-time VBV fullness based 2nd pass QP  tuning.<br>Experimental feature.Default disabled<br>---<br> doc/reST/cli.rst               |  9 ++++<br> source/CMakeLists.txt          |  2 +-<br> source/common/param.cpp        | 13 +++++<br> source/encoder/ratecontrol.cpp | 98 +++++++++++++++++++---------------<br> source/encoder/slicetype.cpp   | 14 ++---<br> source/x265.h                  |  5 ++<br> source/x265cli.cpp             |  1 +<br> source/x265cli.h               |  2 +<br> 8 files changed, 93 insertions(+), 51 deletions(-)<br><br>diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst<br>index e6c628c36..7777ee49e 100755<br>--- a/doc/reST/cli.rst<br>+++ b/doc/reST/cli.rst<br>@@ -1977,6 +1977,15 @@ Quality, rate control and rate distortion options<br> <br>    **Range of values:**  0 to 10<br> <br>+.. option:: --vbv-live-multi-pass, --no-vbv-live-multi-pass<br>+<br>+   It enables the Qp tuning at frame level based on real time VBV Buffer fullness<br>+   in the ratecontrol 2nd pass of multi pass mode to reduce the VBV violations.<br>+   It could only be enabled with rate control stat-read encodes with VBV and ABR<br>+   rate control mode.<br>+<br>+   Default disabled. **Experimental feature**<br>+<br> Quantization Options<br> ====================<br> <br>diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt<br>index d9ed3983e..5738c861c 100755<br>--- a/source/CMakeLists.txt<br>+++ b/source/CMakeLists.txt<br>@@ -29,7 +29,7 @@ option(NATIVE_BUILD "Target the build CPU" OFF)<br> option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF)<br> mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)<br> # X265_BUILD must be incremented each time the public API is changed<br>-set(X265_BUILD 196)<br>+set(X265_BUILD 197)<br> configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265.def.in" target="_blank">x265.def.in</a>"<br>                "${PROJECT_BINARY_DIR}/x265.def")<br> configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265_config.h.in" target="_blank">x265_config.h.in</a>"<br>diff --git a/source/common/param.cpp b/source/common/param.cpp<br>index 845c38bd2..b3001fcf6 100755<br>--- a/source/common/param.cpp<br>+++ b/source/common/param.cpp<br>@@ -288,6 +288,7 @@ void x265_param_default(x265_param* param)<br>     param->bResetZoneConfig = 1;<br>     param->reconfigWindowSize = 0;<br>     param->decoderVbvMaxRate = 0;<br>+    param->bliveVBV2pass = 0;<br> <br>     /* Video Usability Information (VUI) */<br>     param->vui.aspectRatioIdc = 0;<br>@@ -1375,6 +1376,7 @@ int x265_param_parse(x265_param* p, const char* name, const char* value)<br>             sscanf(value, "%d,%d,%d", &p->hmeRange[0], &p->hmeRange[1], &p->hmeRange[2]);<br>             p->bEnableHME = true;<br>         }<br>+        OPT("vbv-live-multi-pass") p->bliveVBV2pass = atobool(value);<br>         else<br>             return X265_PARAM_BAD_NAME;<br>     }<br>@@ -1817,6 +1819,15 @@ int x265_check_params(x265_param* param)<br>     CHECK(param->confWinRightOffset < 0, "Conformance Window Right Offset must be 0 or greater");<br>     CHECK(param->confWinBottomOffset < 0, "Conformance Window Bottom Offset must be 0 or greater");<br>     CHECK(param->decoderVbvMaxRate < 0, "Invalid Decoder Vbv Maxrate. Value can not be less than zero");<br>+    if (param->bliveVBV2pass)<br>+    {<br>+        CHECK((param->rc.bStatRead == 0), "Live VBV in multi pass option requires rate control 2 pass to be enabled");<br>+        if ((param->rc.vbvMaxBitrate <= 0 || param->rc.vbvBufferSize <= 0))<br>+        {<br>+            param->bliveVBV2pass = 0;<br>+            x265_log(param, X265_LOG_WARNING, "Live VBV enabled without VBV settings.Disabling live VBV in 2 pass\n");<br>+        }<br>+    }<br>     return check_failed;<br> }<br> <br>@@ -2238,6 +2249,7 @@ char *x265_param2string(x265_param* p, int padx, int pady)<br>         s += sprintf(s, " scenecut-window=%d qp-delta-ref=%f qp-delta-nonref=%f", p->scenecutWindow, p->refQpDelta, p->nonRefQpDelta);<br>     s += sprintf(s, "conformance-window-offsets right=%d bottom=%d", p->confWinRightOffset, p->confWinBottomOffset);<br>     s += sprintf(s, " decoder-max-rate=%d", p->decoderVbvMaxRate);<br>+    BOOL(p->bliveVBV2pass, "vbv-live-multi-pass");<br> #undef BOOL<br>     return buf;<br> }<br>@@ -2593,6 +2605,7 @@ void x265_copy_params(x265_param* dst, x265_param* src)<br> <br>     dst->confWinRightOffset = src->confWinRightOffset;<br>     dst->confWinBottomOffset = src->confWinBottomOffset;<br>+    dst->bliveVBV2pass = src->bliveVBV2pass;<br> #ifdef SVT_HEVC<br>     memcpy(dst->svtHevcParam, src->svtHevcParam, sizeof(EB_H265_ENC_CONFIGURATION));<br> #endif<br>diff --git a/source/encoder/ratecontrol.cpp b/source/encoder/ratecontrol.cpp<br>index 82d7c4f2a..8e9187e8a 100644<br>--- a/source/encoder/ratecontrol.cpp<br>+++ b/source/encoder/ratecontrol.cpp<br>@@ -1755,34 +1755,32 @@ double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br>                      g_sliceTypeToChar[m_sliceType], g_sliceTypeToChar[rce->sliceType]);<br>         }<br>     }<br>-    else<br>+<br>+    if ((m_param->bliveVBV2pass && m_param->rc.rateControlMode == X265_RC_ABR) || m_isAbr)<br>     {<br>-        if (m_isAbr)<br>+        int pos = m_sliderPos % s_slidingWindowFrames;<br>+        int addPos = (pos + s_slidingWindowFrames - 1) % s_slidingWindowFrames;<br>+        if (m_sliderPos > s_slidingWindowFrames)<br>         {<br>-            int pos = m_sliderPos % s_slidingWindowFrames;<br>-            int addPos = (pos + s_slidingWindowFrames - 1) % s_slidingWindowFrames;<br>-            if (m_sliderPos > s_slidingWindowFrames)<br>-            {<br>-                const static double base = pow(0.5, s_slidingWindowFrames - 1);<br>-                m_movingAvgSum -= m_lastRemovedSatdCost * base;<br>-                m_movingAvgSum *= 0.5;<br>-                m_movingAvgSum += m_satdCostWindow[addPos];<br>-            }<br>-            else if (m_sliderPos == s_slidingWindowFrames)<br>-            {<br>-                m_movingAvgSum += m_satdCostWindow[addPos];<br>-            }<br>-            else if (m_sliderPos > 0)<br>-            {<br>-                m_movingAvgSum += m_satdCostWindow[addPos];<br>-                m_movingAvgSum *= 0.5;<br>-            }<br>-<br>-            rce->movingAvgSum = m_movingAvgSum;<br>-            m_lastRemovedSatdCost = m_satdCostWindow[pos];<br>-            m_satdCostWindow[pos] = rce->lastSatd;<br>-            m_sliderPos++;<br>+            const static double base = pow(0.5, s_slidingWindowFrames - 1);<br>+            m_movingAvgSum -= m_lastRemovedSatdCost * base;<br>+            m_movingAvgSum *= 0.5;<br>+            m_movingAvgSum += m_satdCostWindow[addPos];<br>+        }<br>+        else if (m_sliderPos == s_slidingWindowFrames)<br>+        {<br>+            m_movingAvgSum += m_satdCostWindow[addPos];<br>         }<br>+        else if (m_sliderPos > 0)<br>+        {<br>+            m_movingAvgSum += m_satdCostWindow[addPos];<br>+            m_movingAvgSum *= 0.5;<br>+        }<br>+<br>+        rce->movingAvgSum = m_movingAvgSum;<br>+        m_lastRemovedSatdCost = m_satdCostWindow[pos];<br>+        m_satdCostWindow[pos] = rce->lastSatd;<br>+        m_sliderPos++;<br>     }<br> <br>     if (m_sliceType == B_SLICE)<br>@@ -1887,7 +1885,7 @@ double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br>                 qScale = x265_clip3(lqmin, lqmax, qScale);<br>             }<br> <br>-            if (!m_2pass)<br>+            if (!m_2pass || m_param->bliveVBV2pass)<br>             {<br>                 /* clip qp to permissible range after vbv-lookahead estimation to avoid possible <br>                  * mispredictions by initial frame size predictors */<br>@@ -1955,7 +1953,9 @@ double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br>                 else<br>                     q /= zone->bitrateFactor;<br>             }<br>-            q /= x265_clip3(0.5, 2.0, (double)(abrBuffer - diff) / abrBuffer);<br>+            /*Existing ABR conformance check may not be valid with real time VBV*/<br>+            if(!m_param->bliveVBV2pass)<br>+                q /= x265_clip3(0.5, 2.0, (double)(abrBuffer - diff) / abrBuffer);<br>             if (m_expectedBitsSum > 0)<br>             {<br>                 /* Adjust quant based on the difference between<br>@@ -1988,24 +1988,34 @@ double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br> <br>             if (m_isVbv)<br>             {<br>-                /* Do not overflow vbv */<br>-                double expectedSize = qScale2bits(rce, q);<br>-                double expectedVbv = m_bufferFill + m_bufferRate - expectedSize;<br>-                double expectedFullness = rce->expectedVbv / m_bufferSize;<br>-                double qmax = q * (2 - expectedFullness);<br>-                double sizeConstraint = 1 + expectedFullness;<br>-                qmax = X265_MAX(qmax, rce->newQScale);<br>-                if (expectedFullness < .05)<br>-                    qmax = lmax;<br>-                qmax = X265_MIN(qmax, lmax);<br>-                while (((expectedVbv < rce->expectedVbv/sizeConstraint) && (q < qmax)) ||<br>+                if (!m_param->bliveVBV2pass)<br>+                {<br>+                    /* Do not overflow vbv */<br>+                    double expectedSize = qScale2bits(rce, q);<br>+                    double expectedVbv = m_bufferFill + m_bufferRate - expectedSize;<br>+                    double expectedFullness = rce->expectedVbv / m_bufferSize;<br>+                    double qmax = q * (2 - expectedFullness);<br>+                    double sizeConstraint = 1 + expectedFullness;<br>+                    qmax = X265_MAX(qmax, rce->newQScale);<br>+                    if (expectedFullness < .05)<br>+                        qmax = lmax;<br>+                    qmax = X265_MIN(qmax, lmax);<br>+                    while (((expectedVbv < rce->expectedVbv / sizeConstraint) && (q < qmax)) ||<br>                         ((expectedVbv < 0) && (q < lmax)))<br>+                    {<br>+                        q *= 1.05;<br>+                        expectedSize = qScale2bits(rce, q);<br>+                        expectedVbv = m_bufferFill + m_bufferRate - expectedSize;<br>+                    }<br>+                }<br>+                else<br>                 {<br>-                    q *= 1.05;<br>-                    expectedSize = qScale2bits(rce, q);<br>-                    expectedVbv = m_bufferFill + m_bufferRate - expectedSize;<br>+                        /*  clip qp to permissible range after vbv-lookahead estimation to avoid possible<br>+                        * mispredictions by Rate Control pass 1 statistics analysis */<br>+                        q = clipQscale(curFrame, rce, q);<br>                 }<br>             }<br>+<br>             q = x265_clip3(lmin, lmax, q);<br>         }<br>         else<br>@@ -2379,7 +2389,7 @@ double RateControl::clipQscale(Frame* curFrame, RateControlEntry* rce, double q)<br>                     }<br>                     /* Try to get the buffer not more than 80% filled, but don't set an impossible goal. */<br>                     targetFill = x265_clip3(m_bufferSize * (1 - 0.2 * finalDur), m_bufferSize, m_bufferFill - totalDuration * m_vbvMaxRate * 0.5);<br>-                    if (m_isCbr && bufferFillCur > targetFill && !m_isSceneTransition)<br>+                    if ((m_isCbr || m_2pass) && bufferFillCur > targetFill && !m_isSceneTransition)<br>                     {<br>                         q /= 1.01;<br>                         loopTerminate |= 2;<br>@@ -2432,7 +2442,7 @@ double RateControl::clipQscale(Frame* curFrame, RateControlEntry* rce, double q)<br>          * lookahead vbv reduces its qscale by half its value. Be on safer side and avoid drastic <br>          * qscale reductions for frames high in complexity */<br>         bool mispredCheck = rce->movingAvgSum && m_currentSatd >= rce->movingAvgSum && q <= q0 / 2;<br>-        if (!m_isCbr || (m_isAbr && mispredCheck))<br>+        if (!m_isCbr || ((m_isAbr || m_2pass) && mispredCheck))<br>             q = X265_MAX(q0, q);<br> <br>         if (m_rateFactorMaxIncrement)<br>@@ -2442,7 +2452,7 @@ double RateControl::clipQscale(Frame* curFrame, RateControlEntry* rce, double q)<br>             return x265_clip3(lmin, qmax, q);<br>         }<br>     }<br>-    if (m_2pass)<br>+    if (!curFrame && m_2pass)<br>     {<br>         double min = log(lmin);<br>         double max = log(lmax);<br>diff --git a/source/encoder/slicetype.cpp b/source/encoder/slicetype.cpp<br>index 4e52e584c..0adb0d0db 100644<br>--- a/source/encoder/slicetype.cpp<br>+++ b/source/encoder/slicetype.cpp<br>@@ -1497,14 +1497,15 @@ void Lookahead::slicetypeDecide()<br>         }<br>     }<br> <br>-    if (m_lastNonB && !m_param->rc.bStatRead &&<br>+    if (m_lastNonB &&<br>         ((m_param->bFrameAdaptive && m_param->bframes) ||<br>          m_param->rc.cuTree || m_param->scenecutThreshold || m_param->bHistBasedSceneCut ||<br>          (m_param->lookaheadDepth && m_param->rc.vbvBufferSize)))<br>     {<br>-        slicetypeAnalyse(frames, false);<br>+        if(!m_param->rc.bStatRead)<br>+            slicetypeAnalyse(frames, false);<br>         bool bIsVbv = m_param->rc.vbvBufferSize > 0 && m_param->rc.vbvMaxBitrate > 0;<br>-        if (m_param->analysisLoad && m_param->scaleFactor && bIsVbv)<br>+        if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv) || m_param->bliveVBV2pass)<br>         {<br>             int numFrames;<br>             for (numFrames = 0; numFrames < maxSearch; numFrames++)<br>@@ -1749,7 +1750,7 @@ void Lookahead::slicetypeDecide()<br>         }<br>     }<br> <br>-    bool isKeyFrameAnalyse = (m_param->rc.cuTree || (m_param->rc.vbvBufferSize && m_param->lookaheadDepth)) && !m_param->rc.bStatRead;<br>+    bool isKeyFrameAnalyse = (m_param->rc.cuTree || (m_param->rc.vbvBufferSize && m_param->lookaheadDepth));<br>     if (isKeyFrameAnalyse && IS_X265_TYPE_I(m_lastNonB->sliceType))<br>     {<br>         m_inputLock.acquire();<br>@@ -1764,9 +1765,10 @@ void Lookahead::slicetypeDecide()<br>         m_inputLock.release();<br> <br>         frames[j + 1] = NULL;<br>-        slicetypeAnalyse(frames, true);<br>+        if (!m_param->rc.bStatRead)<br>+            slicetypeAnalyse(frames, true);<br>         bool bIsVbv = m_param->rc.vbvBufferSize > 0 && m_param->rc.vbvMaxBitrate > 0;<br>-        if (m_param->analysisLoad && m_param->scaleFactor && bIsVbv)<br>+        if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv) || m_param->bliveVBV2pass)<br>         {<br>             int numFrames;<br>             for (numFrames = 0; numFrames < maxSearch; numFrames++)<br>diff --git a/source/x265.h b/source/x265.h<br>index 0ffa600b0..3fc464f6d 100644<br>--- a/source/x265.h<br>+++ b/source/x265.h<br>@@ -1920,6 +1920,11 @@ typedef struct x265_param<br> <br>     /* Maxrate that could be signaled to the decoder. Default 0. API only. */<br>     int      decoderVbvMaxRate;<br>+<br>+    /*Enables Qp tuning with respect to real time VBV buffer fullness in rate<br>+    control 2 pass. Experimental.Default is disabled*/<br>+    int      bliveVBV2pass;<br>+<br> } x265_param;<br> <br> /* x265_param_alloc:<br>diff --git a/source/x265cli.cpp b/source/x265cli.cpp<br>index 6e8e0e661..0cf2d815c 100755<br>--- a/source/x265cli.cpp<br>+++ b/source/x265cli.cpp<br>@@ -221,6 +221,7 @@ namespace X265_NS {<br>             "                                   - 3 : Nth pass, overwrites stats file\n");<br>         H0("   --[no-]multi-pass-opt-analysis   Refine analysis in 2 pass based on analysis information from pass 1\n");<br>         H0("   --[no-]multi-pass-opt-distortion Use distortion of CTU from pass 1 to refine qp in 2 pass\n");<br>+        H0("   --[no-]vbv-live-multi-pass    Enable realtime VBV in rate control 2 pass.Default %s\n", OPT(param->bliveVBV2pass));<br>         H0("   --stats                       Filename for stats file in multipass pass rate control. Default x265_2pass.log\n");<br>         H0("   --[no-]analyze-src-pics       Motion estimation uses source frame planes. Default disable\n");<br>         H0("   --[no-]slow-firstpass         Enable a slow first pass in a multipass rate control mode. Default %s\n", OPT(param->rc.bEnableSlowFirstPass));<br>diff --git a/source/x265cli.h b/source/x265cli.h<br>index 311f06935..3e2fd5e6d 100644<br>--- a/source/x265cli.h<br>+++ b/source/x265cli.h<br>@@ -284,6 +284,8 @@ static const struct option long_options[] =<br>     { "no-multi-pass-opt-analysis",    no_argument, NULL, 0 },<br>     { "multi-pass-opt-distortion",     no_argument, NULL, 0 },<br>     { "no-multi-pass-opt-distortion",  no_argument, NULL, 0 },<br>+    { "vbv-live-multi-pass",           no_argument, NULL, 0 },<br>+    { "no-vbv-live-multi-pass",        no_argument, NULL, 0 },<br>     { "slow-firstpass",       no_argument, NULL, 0 },<br>     { "no-slow-firstpass",    no_argument, NULL, 0 },<br>     { "multi-pass-opt-rps",   no_argument, NULL, 0 },<br>-- <br>2.28.0.windows.1<br><br><div><div dir="ltr"><div dir="ltr"><i>Thanks,</i><div><i>Kirithika</i></div></div></div></div><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Sep 9, 2020 at 10:52 AM Kirithika Kalirathnam <<a href="mailto:kirithika@multicorewareinc.com" target="_blank">kirithika@multicorewareinc.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr">On Mon, Sep 7, 2020 at 6:19 PM Aruna Matheswaran <<a href="mailto:aruna@multicorewareinc.com" target="_blank">aruna@multicorewareinc.com</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Sep 4, 2020 at 5:44 PM Kirithika Kalirathnam <<a href="mailto:kirithika@multicorewareinc.com" target="_blank">kirithika@multicorewareinc.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">From f1391f094c9c3c0502624532f751219d126905aa Mon Sep 17 00:00:00 2001<br>From: Kirithika <<a href="mailto:kirithika@multicorewareinc.com" target="_blank">kirithika@multicorewareinc.com</a>><br>Date: Fri, 28 Aug 2020 09:20:47 +0530<br>Subject: [PATCH] Add real-time VBV fullness based QP tuning in VBV 2 pass<br><br>This commit enables real-time VBV fullness based 2nd pass QP  tuning.<br>Experimental feature.Default disabled<br>---<br> doc/reST/cli.rst               |   9 +++<br> source/CMakeLists.txt          |   2 +-<br> source/common/param.cpp        |  12 ++++<br> source/encoder/ratecontrol.cpp | 100 ++++++++++++++++++---------------<br> source/encoder/slicetype.cpp   |  14 +++--<br> source/x265.h                  |   4 ++<br> source/x265cli.cpp             |   1 +<br> source/x265cli.h               |   2 +<br> 8 files changed, 92 insertions(+), 52 deletions(-)<br><br>diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst<br>index e6c628c36..2a4b25aca 100755<br>--- a/doc/reST/cli.rst<br>+++ b/doc/reST/cli.rst<br>@@ -1977,6 +1977,15 @@ Quality, rate control and rate distortion options<br> <br>    **Range of values:**  0 to 10<br> <br>+.. option:: --realtime-vbv-2pass, --no-realtime-vbv-2pass<br></div></blockquote><div>[AM] Can we find a better alternate for the CLI option? --real-time-vbv-2-pass looks a bit long. </div><div>The term 2pass is a little confusing. Technically it is multi-pass; not just 2pass.</div></div></div></blockquote><div>Ok.I shall update the name to vbv-live-multi-pass,as it is self-explanatory though it's a bit longer. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">+<br>+   It enables the Qp tuning at frame level based on real time VBV Buffer fullness<br>+   in the ratecontrol second pass to reduce the VBV violations.<br>+   It could only be enabled with rate control pass 2 encodes with VBV and ABR<br>+   rate control mode.<br>+<br></div></blockquote><div>[AM] why not for CRF rate-control mode? </div></div></div></blockquote><div>Currently,we have tested the feature only for ABR case.We shall extend this to CRF mode also in future. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">+   Default disabled. **Experimental feature**<br>+<br> Quantization Options<br> ====================<br> <br>diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt<br>index d9ed3983e..5738c861c 100755<br>--- a/source/CMakeLists.txt<br>+++ b/source/CMakeLists.txt<br>@@ -29,7 +29,7 @@ option(NATIVE_BUILD "Target the build CPU" OFF)<br> option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF)<br> mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)<br> # X265_BUILD must be incremented each time the public API is changed<br>-set(X265_BUILD 196)<br>+set(X265_BUILD 197)<br> configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265.def.in" target="_blank">x265.def.in</a>"<br>                "${PROJECT_BINARY_DIR}/x265.def")<br> configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265_config.h.in" target="_blank">x265_config.h.in</a>"<br>diff --git a/source/common/param.cpp b/source/common/param.cpp<br>index 845c38bd2..fc0425905 100755<br>--- a/source/common/param.cpp<br>+++ b/source/common/param.cpp<br>@@ -288,6 +288,7 @@ void x265_param_default(x265_param* param)<br>     param->bResetZoneConfig = 1;<br>     param->reconfigWindowSize = 0;<br>     param->decoderVbvMaxRate = 0;<br>+    param->rc.bRealtimeVBV2pass = 0;<br> <br>     /* Video Usability Information (VUI) */<br>     param->vui.aspectRatioIdc = 0;<br>@@ -1375,6 +1376,7 @@ int x265_param_parse(x265_param* p, const char* name, const char* value)<br>             sscanf(value, "%d,%d,%d", &p->hmeRange[0], &p->hmeRange[1], &p->hmeRange[2]);<br>             p->bEnableHME = true;<br>         }<br>+        OPT("realtime-vbv-2pass") p->rc.bRealtimeVBV2pass = atobool(value);<br>         else<br>             return X265_PARAM_BAD_NAME;<br>     }<br>@@ -1817,6 +1819,15 @@ int x265_check_params(x265_param* param)<br>     CHECK(param->confWinRightOffset < 0, "Conformance Window Right Offset must be 0 or greater");<br>     CHECK(param->confWinBottomOffset < 0, "Conformance Window Bottom Offset must be 0 or greater");<br>     CHECK(param->decoderVbvMaxRate < 0, "Invalid Decoder Vbv Maxrate. Value can not be less than zero");<br>+    if (param->rc.bRealtimeVBV2pass)<br>+    {<br>+        CHECK((param->rc.bStatRead == 0), "Real time VBV in 2 pass option requires rate control 2 pass to be enabled");<br>+        if ((param->rc.vbvMaxBitrate <= 0 || param->rc.vbvBufferSize <= 0))<br>+        {<br>+            param->rc.bRealtimeVBV2pass = 0;<br>+            x265_log(param, X265_LOG_WARNING, "Real time VBV enabled without VBV settings.Disabling real time VBV in 2 pass\n");<br>+        }<br>+    }<br>     return check_failed;<br> }<br> <br>@@ -2593,6 +2604,7 @@ void x265_copy_params(x265_param* dst, x265_param* src)<br> <br>     dst->confWinRightOffset = src->confWinRightOffset;<br>     dst->confWinBottomOffset = src->confWinBottomOffset;<br>+    dst->rc.bRealtimeVBV2pass = src->rc.bRealtimeVBV2pass;<br> #ifdef SVT_HEVC<br>     memcpy(dst->svtHevcParam, src->svtHevcParam, sizeof(EB_H265_ENC_CONFIGURATION));<br> #endif<br>diff --git a/source/encoder/ratecontrol.cpp b/source/encoder/ratecontrol.cpp<br>index 82d7c4f2a..ebf374759 100644<br>--- a/source/encoder/ratecontrol.cpp<br>+++ b/source/encoder/ratecontrol.cpp<br>@@ -1755,34 +1755,32 @@ double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br>                      g_sliceTypeToChar[m_sliceType], g_sliceTypeToChar[rce->sliceType]);<br>         }<br>     }<br>-    else<br>+<br>+    if ((m_param->rc.bRealtimeVBV2pass && m_param->rc.rateControlMode == X265_RC_ABR) || m_isAbr)<br>     {<br>-        if (m_isAbr)<br>+        int pos = m_sliderPos % s_slidingWindowFrames;<br>+        int addPos = (pos + s_slidingWindowFrames - 1) % s_slidingWindowFrames;<br>+        if (m_sliderPos > s_slidingWindowFrames)<br>         {<br>-            int pos = m_sliderPos % s_slidingWindowFrames;<br>-            int addPos = (pos + s_slidingWindowFrames - 1) % s_slidingWindowFrames;<br>-            if (m_sliderPos > s_slidingWindowFrames)<br>-            {<br>-                const static double base = pow(0.5, s_slidingWindowFrames - 1);<br>-                m_movingAvgSum -= m_lastRemovedSatdCost * base;<br>-                m_movingAvgSum *= 0.5;<br>-                m_movingAvgSum += m_satdCostWindow[addPos];<br>-            }<br>-            else if (m_sliderPos == s_slidingWindowFrames)<br>-            {<br>-                m_movingAvgSum += m_satdCostWindow[addPos];<br>-            }<br>-            else if (m_sliderPos > 0)<br>-            {<br>-                m_movingAvgSum += m_satdCostWindow[addPos];<br>-                m_movingAvgSum *= 0.5;<br>-            }<br>-<br>-            rce->movingAvgSum = m_movingAvgSum;<br>-            m_lastRemovedSatdCost = m_satdCostWindow[pos];<br>-            m_satdCostWindow[pos] = rce->lastSatd;<br>-            m_sliderPos++;<br>+            const static double base = pow(0.5, s_slidingWindowFrames - 1);<br>+            m_movingAvgSum -= m_lastRemovedSatdCost * base;<br>+            m_movingAvgSum *= 0.5;<br>+            m_movingAvgSum += m_satdCostWindow[addPos];<br>+        }<br>+        else if (m_sliderPos == s_slidingWindowFrames)<br>+        {<br>+            m_movingAvgSum += m_satdCostWindow[addPos];<br>         }<br>+        else if (m_sliderPos > 0)<br>+        {<br>+            m_movingAvgSum += m_satdCostWindow[addPos];<br>+            m_movingAvgSum *= 0.5;<br>+        }<br>+<br>+        rce->movingAvgSum = m_movingAvgSum;<br>+        m_lastRemovedSatdCost = m_satdCostWindow[pos];<br>+        m_satdCostWindow[pos] = rce->lastSatd;<br>+        m_sliderPos++;<br>     }<br> <br>     if (m_sliceType == B_SLICE)<br>@@ -1887,7 +1885,7 @@ double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br>                 qScale = x265_clip3(lqmin, lqmax, qScale);<br>             }<br> <br>-            if (!m_2pass)<br>+            if (!m_2pass || m_param->rc.bRealtimeVBV2pass)<br>             {<br>                 /* clip qp to permissible range after vbv-lookahead estimation to avoid possible <br>                  * mispredictions by initial frame size predictors */<br>@@ -1955,7 +1953,9 @@ double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br>                 else<br>                     q /= zone->bitrateFactor;<br>             }<br>-            q /= x265_clip3(0.5, 2.0, (double)(abrBuffer - diff) / abrBuffer);<br>+            /*Existing ABR conformance check may not be valid with real time VBV*/<br>+            if(!m_param->rc.bRealtimeVBV2pass)<br>+                q /= x265_clip3(0.5, 2.0, (double)(abrBuffer - diff) / abrBuffer);<br>             if (m_expectedBitsSum > 0)<br>             {<br>                 /* Adjust quant based on the difference between<br>@@ -1988,24 +1988,34 @@ double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br> <br>             if (m_isVbv)<br>             {<br>-                /* Do not overflow vbv */<br>-                double expectedSize = qScale2bits(rce, q);<br>-                double expectedVbv = m_bufferFill + m_bufferRate - expectedSize;<br>-                double expectedFullness = rce->expectedVbv / m_bufferSize;<br>-                double qmax = q * (2 - expectedFullness);<br>-                double sizeConstraint = 1 + expectedFullness;<br>-                qmax = X265_MAX(qmax, rce->newQScale);<br>-                if (expectedFullness < .05)<br>-                    qmax = lmax;<br>-                qmax = X265_MIN(qmax, lmax);<br>-                while (((expectedVbv < rce->expectedVbv/sizeConstraint) && (q < qmax)) ||<br>+                if (!m_param->rc.bRealtimeVBV2pass)<br>+                {<br>+                    /* Do not overflow vbv */<br>+                    double expectedSize = qScale2bits(rce, q);<br>+                    double expectedVbv = m_bufferFill + m_bufferRate - expectedSize;<br>+                    double expectedFullness = rce->expectedVbv / m_bufferSize;<br>+                    double qmax = q * (2 - expectedFullness);<br>+                    double sizeConstraint = 1 + expectedFullness;<br>+                    qmax = X265_MAX(qmax, rce->newQScale);<br>+                    if (expectedFullness < .05)<br>+                        qmax = lmax;<br>+                    qmax = X265_MIN(qmax, lmax);<br>+                    while (((expectedVbv < rce->expectedVbv / sizeConstraint) && (q < qmax)) ||<br>                         ((expectedVbv < 0) && (q < lmax)))<br>+                    {<br>+                        q *= 1.05;<br>+                        expectedSize = qScale2bits(rce, q);<br>+                        expectedVbv = m_bufferFill + m_bufferRate - expectedSize;<br>+                    }<br>+                }<br>+                else<br>                 {<br>-                    q *= 1.05;<br>-                    expectedSize = qScale2bits(rce, q);<br>-                    expectedVbv = m_bufferFill + m_bufferRate - expectedSize;<br>+                        /*  clip qp to permissible range after vbv-lookahead estimation to avoid possible<br>+                        * mispredictions by Rate Control pass 1 statistics analysis */<br>+                        q = clipQscale(curFrame, rce, q);<br>                 }<br>             }<br>+<br>             q = x265_clip3(lmin, lmax, q);<br>         }<br>         else<br>@@ -2301,7 +2311,7 @@ double RateControl::clipQscale(Frame* curFrame, RateControlEntry* rce, double q)<br>     double lmin = m_lmin[rce->sliceType];<br>     double lmax = m_lmax[rce->sliceType];<br>     double q0 = q;<br>-    if (m_isVbv && m_currentSatd > 0 && curFrame)<br>+    if ((m_isVbv || m_param->rc.bRealtimeVBV2pass) && curFrame && m_currentSatd > 0 )<br>     {<br></div></blockquote><div>[AM] Do we need to m_param->rc.bRealtimeVBV2pass check here? The call to clipQscale() is guarded by "m_param->rc.bRealtimeVBV2pass" from what I see.</div></div></div></blockquote><div>yeah,the check is redundant and I shall remove it. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">         if (m_param->lookaheadDepth || m_param->rc.cuTree ||<br>             (m_param->scenecutThreshold || m_param->bHistBasedSceneCut) ||<br>@@ -2379,7 +2389,7 @@ double RateControl::clipQscale(Frame* curFrame, RateControlEntry* rce, double q)<br>                     }<br>                     /* Try to get the buffer not more than 80% filled, but don't set an impossible goal. */<br>                     targetFill = x265_clip3(m_bufferSize * (1 - 0.2 * finalDur), m_bufferSize, m_bufferFill - totalDuration * m_vbvMaxRate * 0.5);<br>-                    if (m_isCbr && bufferFillCur > targetFill && !m_isSceneTransition)<br>+                    if ((m_isCbr || m_2pass) && bufferFillCur > targetFill && !m_isSceneTransition)<br>                     {<br>                         q /= 1.01;<br>                         loopTerminate |= 2;<br>@@ -2432,7 +2442,7 @@ double RateControl::clipQscale(Frame* curFrame, RateControlEntry* rce, double q)<br>          * lookahead vbv reduces its qscale by half its value. Be on safer side and avoid drastic <br>          * qscale reductions for frames high in complexity */<br>         bool mispredCheck = rce->movingAvgSum && m_currentSatd >= rce->movingAvgSum && q <= q0 / 2;<br>-        if (!m_isCbr || (m_isAbr && mispredCheck))<br>+        if (!m_isCbr || ((m_isAbr || m_2pass) && mispredCheck))<br></div></blockquote><div>[AM] Same question here. </div></div></div></blockquote><div>m_isAbr is not set with 2 pass encodes.Hence I have added an additional check here.</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">             q = X265_MAX(q0, q);<br> <br>         if (m_rateFactorMaxIncrement)<br>@@ -2442,7 +2452,7 @@ double RateControl::clipQscale(Frame* curFrame, RateControlEntry* rce, double q)<br>             return x265_clip3(lmin, qmax, q);<br>         }<br>     }<br>-    if (m_2pass)<br>+    if (!curFrame && m_2pass)<br>     {<br>         double min = log(lmin);<br>         double max = log(lmax);<br>diff --git a/source/encoder/slicetype.cpp b/source/encoder/slicetype.cpp<br>index 4e52e584c..69f3b0ad1 100644<br>--- a/source/encoder/slicetype.cpp<br>+++ b/source/encoder/slicetype.cpp<br>@@ -1497,14 +1497,15 @@ void Lookahead::slicetypeDecide()<br>         }<br>     }<br> <br>-    if (m_lastNonB && !m_param->rc.bStatRead &&<br>+    if (m_lastNonB &&<br>         ((m_param->bFrameAdaptive && m_param->bframes) ||<br>          m_param->rc.cuTree || m_param->scenecutThreshold || m_param->bHistBasedSceneCut ||<br>          (m_param->lookaheadDepth && m_param->rc.vbvBufferSize)))<br>     {<br>-        slicetypeAnalyse(frames, false);<br>+        if(!m_param->rc.bStatRead)<br>+            slicetypeAnalyse(frames, false);<br>         bool bIsVbv = m_param->rc.vbvBufferSize > 0 && m_param->rc.vbvMaxBitrate > 0;<br>-        if (m_param->analysisLoad && m_param->scaleFactor && bIsVbv)<br>+        if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv) || m_param->rc.bRealtimeVBV2pass)<br>         {<br>             int numFrames;<br>             for (numFrames = 0; numFrames < maxSearch; numFrames++)<br>@@ -1749,7 +1750,7 @@ void Lookahead::slicetypeDecide()<br>         }<br>     }<br> <br>-    bool isKeyFrameAnalyse = (m_param->rc.cuTree || (m_param->rc.vbvBufferSize && m_param->lookaheadDepth)) && !m_param->rc.bStatRead;<br>+    bool isKeyFrameAnalyse = (m_param->rc.cuTree || (m_param->rc.vbvBufferSize && m_param->lookaheadDepth));<br>     if (isKeyFrameAnalyse && IS_X265_TYPE_I(m_lastNonB->sliceType))<br>     {<br>         m_inputLock.acquire();<br>@@ -1764,9 +1765,10 @@ void Lookahead::slicetypeDecide()<br>         m_inputLock.release();<br> <br>         frames[j + 1] = NULL;<br>-        slicetypeAnalyse(frames, true);<br>+        if (!m_param->rc.bStatRead)<br>+            slicetypeAnalyse(frames, true);<br>         bool bIsVbv = m_param->rc.vbvBufferSize > 0 && m_param->rc.vbvMaxBitrate > 0;<br>-        if (m_param->analysisLoad && m_param->scaleFactor && bIsVbv)<br>+        if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv) || m_param->rc.bRealtimeVBV2pass)<br>         {<br>             int numFrames;<br>             for (numFrames = 0; numFrames < maxSearch; numFrames++)<br>diff --git a/source/x265.h b/source/x265.h<br>index 0ffa600b0..bcd1d4e58 100644<br>--- a/source/x265.h<br>+++ b/source/x265.h<br>@@ -1486,6 +1486,10 @@ typedef struct x265_param<br>         /* internally enable if tune grain is set */<br>         int      bEnableConstVbv;<br> <br>+        /*Enables Qp tuning with respect to real time VBV buffer fullness in rate<br>+        control 2 pass. Experimental.Default is disabled*/<br>+        int      bRealtimeVBV2pass;<br>+<br></div></blockquote><div>[AM] Always add new param options to the end of the structure. Nested structures shall break backward compatibility.</div></div></div></blockquote><div>Ok.I will add the new param at the end of param struct. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">     } rc;<br> <br>     /*== Video Usability Information ==*/<br>diff --git a/source/x265cli.cpp b/source/x265cli.cpp<br>index 6e8e0e661..0b17a8d3a 100755<br>--- a/source/x265cli.cpp<br>+++ b/source/x265cli.cpp<br>@@ -221,6 +221,7 @@ namespace X265_NS {<br>             "                                   - 3 : Nth pass, overwrites stats file\n");<br>         H0("   --[no-]multi-pass-opt-analysis   Refine analysis in 2 pass based on analysis information from pass 1\n");<br>         H0("   --[no-]multi-pass-opt-distortion Use distortion of CTU from pass 1 to refine qp in 2 pass\n");<br>+        H0("   --[no-]realtime-vbv-2pass     Enable realtime VBV in rate control 2 pass.Default %s\n", OPT(param->bLossless));<br>         H0("   --stats                       Filename for stats file in multipass pass rate control. Default x265_2pass.log\n");<br>         H0("   --[no-]analyze-src-pics       Motion estimation uses source frame planes. Default disable\n");<br>         H0("   --[no-]slow-firstpass         Enable a slow first pass in a multipass rate control mode. Default %s\n", OPT(param->rc.bEnableSlowFirstPass));<br>diff --git a/source/x265cli.h b/source/x265cli.h<br>index 311f06935..89840d9af 100644<br>--- a/source/x265cli.h<br>+++ b/source/x265cli.h<br>@@ -284,6 +284,8 @@ static const struct option long_options[] =<br>     { "no-multi-pass-opt-analysis",    no_argument, NULL, 0 },<br>     { "multi-pass-opt-distortion",     no_argument, NULL, 0 },<br>     { "no-multi-pass-opt-distortion",  no_argument, NULL, 0 },<br>+    { "realtime-vbv-2pass",           no_argument, NULL, 0 },<br>+    { "no-realtime-vbv-2pass",        no_argument, NULL, 0 },<br></div></blockquote><div>[AM] Please add an entry for the new option in x265_param2string(); This will keep the info SEI updated.</div></div></div></blockquote><div>Ok,will update </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">     { "slow-firstpass",       no_argument, NULL, 0 },<br>     { "no-slow-firstpass",    no_argument, NULL, 0 },<br>     { "multi-pass-opt-rps",   no_argument, NULL, 0 },<br>-- <br>2.28.0.windows.1<br><br><div><div dir="ltr"><div dir="ltr"><i>Thanks,</i><div><i>Kirithika</i></div></div></div></div></div>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org" target="_blank">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr"><div dir="ltr"><div><div dir="ltr"><div><div dir="ltr"><div><div dir="ltr"><font face="georgia, serif">Regards,</font><div><b><font face="georgia, serif">Aruna Matheswaran,</font></b></div><div><font face="georgia, serif">Video Codec Engineer,</font></div><div><font face="georgia, serif">Media & AI analytics BU,</font></div><div><span><span style="font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap"><span style="border:none;display:inline-block;overflow:hidden;width:153px;height:58px"><img src="https://lh5.googleusercontent.com/gjX5cPNIZgwUrhfqkTwQUZWztIKmmo0qs3kbwvkS5H-bDVE2ftte9pMTVnFLSjOcjYWLtfc6_OGpxW4vraLg2r5QAIf1Q3MpldFDgWtzK_gXi8ptw5B3joIbsGL6mxj-JRdjHzT5" width="96" height="36" style="margin-left: 0px; margin-top: 0px;"></span></span></span><font face="georgia, serif"><br></font></div><div><span><span style="font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap"><span style="border:none;display:inline-block;overflow:hidden;width:153px;height:58px"><img src="https://lh5.googleusercontent.com/gjX5cPNIZgwUrhfqkTwQUZWztIKmmo0qs3kbwvkS5H-bDVE2ftte9pMTVnFLSjOcjYWLtfc6_OGpxW4vraLg2r5QAIf1Q3MpldFDgWtzK_gXi8ptw5B3joIbsGL6mxj-JRdjHzT5" style="margin-left: 0px; margin-top: 0px;"></span></span></span><font face="georgia, serif"><br></font></div><div><font face="georgia, serif"><br></font></div></div></div></div></div></div></div></div></div></div>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org" target="_blank">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</blockquote></div></div>
</blockquote></div>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org" target="_blank">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div><div dir="ltr"><div><div dir="ltr"><font face="georgia, serif">Regards,</font><div><b><font face="georgia, serif">Aruna Matheswaran,</font></b></div><div><font face="georgia, serif">Video Codec Engineer,</font></div><div><font face="georgia, serif">Media & AI analytics BU,</font></div><div><span><span style="font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap"><span style="border:none;display:inline-block;overflow:hidden;width:153px;height:58px"><img src="https://lh5.googleusercontent.com/gjX5cPNIZgwUrhfqkTwQUZWztIKmmo0qs3kbwvkS5H-bDVE2ftte9pMTVnFLSjOcjYWLtfc6_OGpxW4vraLg2r5QAIf1Q3MpldFDgWtzK_gXi8ptw5B3joIbsGL6mxj-JRdjHzT5" width="96" height="36" style="margin-left: 0px; margin-top: 0px;"></span></span></span><font face="georgia, serif"><br></font></div><div><span><span style="font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap"><span style="border:none;display:inline-block;overflow:hidden;width:153px;height:58px"><img src="https://lh5.googleusercontent.com/gjX5cPNIZgwUrhfqkTwQUZWztIKmmo0qs3kbwvkS5H-bDVE2ftte9pMTVnFLSjOcjYWLtfc6_OGpxW4vraLg2r5QAIf1Q3MpldFDgWtzK_gXi8ptw5B3joIbsGL6mxj-JRdjHzT5" style="margin-left: 0px; margin-top: 0px;"></span></span></span><font face="georgia, serif"><br></font></div><div><font face="georgia, serif"><br></font></div></div></div></div></div></div></div></div></div>