<div dir="ltr"><div dir="ltr">From 095b73ef10eaf0600f0078cbae433ecc0942cb46 Mon Sep 17 00:00:00 2001<br>From: Pooja Venkatesan <<a href="mailto:pooja@multicorewareinc.com" target="_blank">pooja@multicorewareinc.com</a>><br>Date: Mon, 29 Jun 2020 17:13:34 +0530<br>Subject: [PATCH] Add support for RADL pictures at IDR scenecuts<br><br>---<br> doc/reST/cli.rst             |  5 ++++-<br> source/common/lowres.cpp     |  1 +<br> source/common/lowres.h       |  1 +<br> source/encoder/encoder.cpp   | 14 ++++++++++----<br> source/encoder/encoder.h     |  2 +-<br> source/encoder/slicetype.cpp | 12 +++++++++++-<br> 6 files changed, 28 insertions(+), 7 deletions(-)<br><br>diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst<br>index 23b74c3d8..3b8a6e2e6 100644<br>--- a/doc/reST/cli.rst<br>+++ b/doc/reST/cli.rst<br>@@ -1475,7 +1475,10 @@ Slice decision options<br>   <br> .. option:: --radl <integer><br>       <br>-     Number of RADL pictures allowed infront of IDR. Requires fixed keyframe interval.<br>+    Number of RADL pictures allowed infront of IDR. Requires closed gop interval.<br>+        If enabled for fixed keyframe interval, inserts RADL at every IDR.<br>+   If enabled for closed gop interval, in case of :option:`--hist-scenecut` inserts RADL at every hard scenecut<br>+ whereas for the :option:`--scenecut`, inserts RADL at every scenecut.<br>        Recommended value is 2-3. Default 0 (disabled).<br>      <br>     **Range of values: Between 0 and `--bframes`<br>diff --git a/source/common/lowres.cpp b/source/common/lowres.cpp<br>index db1c2d159..578981d64 100644<br>--- a/source/common/lowres.cpp<br>+++ b/source/common/lowres.cpp<br>@@ -269,6 +269,7 @@ void Lowres::init(PicYuv *origPic, int poc)<br>     interPCostPercDiff = 0.0;<br>     intraCostPercDiff = 0.0;<br>     m_bIsMaxThres = false;<br>+    m_bIsHardScenecut = false;<br> <br>     if (qpAqOffset && invQscaleFactor)<br>         memset(costEstAq, -1, sizeof(costEstAq));<br>diff --git a/source/common/lowres.h b/source/common/lowres.h<br>index 200b1f032..2a7497258 100644<br>--- a/source/common/lowres.h<br>+++ b/source/common/lowres.h<br>@@ -238,6 +238,7 @@ struct Lowres : public ReferencePlanes<br>     bool   m_bIsMaxThres;<br>     double interPCostPercDiff;<br>     double intraCostPercDiff;<br>+    bool   m_bIsHardScenecut;<br> <br>     bool create(x265_param* param, PicYuv *origPic, uint32_t qgSize);<br>     void destroy();<br>diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp<br>index 0c6fd80bf..6101eeacd 100644<br>--- a/source/encoder/encoder.cpp<br>+++ b/source/encoder/encoder.cpp<br>@@ -1528,7 +1528,7 @@ double Encoder::normalizeRange(int32_t value, int32_t minValue, int32_t maxValue<br>     return (double)(value - minValue) * (rangeEnd - rangeStart) / (maxValue - minValue) + rangeStart;<br> }<br> <br>-void Encoder::findSceneCuts(x265_picture *pic, bool& bDup, double maxUVSad, double edgeSad, bool& isMaxThres)<br>+void Encoder::findSceneCuts(x265_picture *pic, bool& bDup, double maxUVSad, double edgeSad, bool& isMaxThres, bool& isHardSC)<br> {<br>     double minEdgeT = m_edgeHistThreshold * MIN_EDGE_FACTOR;<br>     double minChromaT = minEdgeT * SCENECUT_CHROMA_FACTOR;<br>@@ -1556,12 +1556,15 @@ void Encoder::findSceneCuts(x265_picture *pic, bool& bDup, double maxUVSad, doub<br>         {<br>             pic->frameData.bScenecut = true;<br>             isMaxThres = true;<br>+            isHardSC = true;<br>         }<br>         else if (edgeSad > m_scaledEdgeThreshold || maxUVSad >= m_scaledChromaThreshold<br>                  || (edgeSad > m_edgeHistThreshold && maxUVSad >= m_chromaHistThreshold))<br>         {<br>             pic->frameData.bScenecut = true;<br>             bDup = false;<br>+            if (edgeSad > m_scaledEdgeThreshold || maxUVSad >= m_scaledChromaThreshold)<br>+                isHardSC = true;<br>         }<br>     }<br> }<br>@@ -1595,6 +1598,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>     bool bdropFrame = false;<br>     bool dropflag = false;<br>     bool isMaxThres = false;<br>+    bool isHardSC = false;<br> <br>     if (m_exportedPic)<br>     {<br>@@ -1621,7 +1625,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>             {<br>                 double maxUVSad = 0.0, edgeSad = 0.0;<br>                 computeHistogramSAD(&maxUVSad, &edgeSad, pic_in->poc);<br>-                findSceneCuts(pic, bdropFrame, maxUVSad, edgeSad, isMaxThres);<br>+                findSceneCuts(pic, bdropFrame, maxUVSad, edgeSad, isMaxThres, isHardSC);<br>             }<br>         }<br> <br>@@ -1801,6 +1805,8 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>         {<br>             inFrame->m_lowres.bScenecut = (inputPic->frameData.bScenecut == 1) ? true : false;<br>             inFrame->m_lowres.m_bIsMaxThres = isMaxThres;<br>+            if (m_param->radl && m_param->keyframeMax != m_param->keyframeMin)<br>+                inFrame->m_lowres.m_bIsHardScenecut = isHardSC;<br>         }<br>         if (m_param->bHistBasedSceneCut && m_param->analysisSave)<br>         {<br>@@ -4218,10 +4224,10 @@ void Encoder::configure(x265_param *p)<br>     p->unitSizeDepth = p->maxLog2CUSize - LOG2_UNIT_SIZE;<br>     p->num4x4Partitions = (1U << (p->unitSizeDepth << 1));<br> <br>-    if (p->radl && (p->keyframeMax != p->keyframeMin))<br>+    if (p->radl && p->bOpenGOP)<br>     {<br>         p->radl = 0;<br>-        x265_log(p, X265_LOG_WARNING, "Radl requires fixed gop-length (keyint == min-keyint). Disabling radl.\n");<br>+        x265_log(p, X265_LOG_WARNING, "Radl requires closed gop structure. Disabling radl.\n");<br>     }<br> <br>     if ((p->chunkStart || p->chunkEnd) && p->bOpenGOP && m_param->bResetZoneConfig)<br>diff --git a/source/encoder/encoder.h b/source/encoder/encoder.h<br>index 507c42d5e..ecb6e153f 100644<br>--- a/source/encoder/encoder.h<br>+++ b/source/encoder/encoder.h<br>@@ -376,7 +376,7 @@ public:<br>     bool computeHistograms(x265_picture *pic);<br>     void computeHistogramSAD(double *maxUVNormalizedSAD, double *edgeNormalizedSAD, int curPoc);<br>     double normalizeRange(int32_t value, int32_t minValue, int32_t maxValue, double rangeStart, double rangeEnd);<br>-    void findSceneCuts(x265_picture *pic, bool& bDup, double m_maxUVSADVal, double m_edgeSADVal, bool& isMaxThres);<br>+    void findSceneCuts(x265_picture *pic, bool& bDup, double m_maxUVSADVal, double m_edgeSADVal, bool& isMaxThres, bool& isHardSC);<br> <br>     void initRefIdx();<br>     void analyseRefIdx(int *numRefIdx);<br>diff --git a/source/encoder/slicetype.cpp b/source/encoder/slicetype.cpp<br>index d3783cfe1..5292473b1 100644<br>--- a/source/encoder/slicetype.cpp<br>+++ b/source/encoder/slicetype.cpp<br>@@ -1520,6 +1520,7 @@ void Lookahead::slicetypeDecide()<br>     int bframes, brefs;<br>     if (!m_param->analysisLoad || m_param->bAnalysisType == HEVC_INFO)<br>     {<br>+        bool isClosedGopRadl = m_param->radl && (m_param->keyframeMax != m_param->keyframeMin);<br>         for (bframes = 0, brefs = 0;; bframes++)<br>         {<br>             Lowres& frm = list[bframes]->m_lowres;<br>@@ -1579,6 +1580,15 @@ void Lookahead::slicetypeDecide()<br>                 else<br>                     frm.sliceType = X265_TYPE_IDR;<br>             }<br>+            if (frm.sliceType == X265_TYPE_IDR && frm.bScenecut && isClosedGopRadl)<br>+            {<br>+                if (!m_param->bHistBasedSceneCut || (m_param->bHistBasedSceneCut && frm.m_bIsHardScenecut))<br>+                {<br>+                    for (int i = bframes; i < bframes + m_param->radl; i++)<br>+                        list[i]->m_lowres.sliceType = X265_TYPE_B;<br>+                    list[(bframes + m_param->radl)]->m_lowres.sliceType = X265_TYPE_IDR;<br>+                }<br>+            }<br>             if (frm.sliceType == X265_TYPE_IDR)<br>             {<br>                 /* Closed GOP */<br>@@ -2147,7 +2157,7 @@ void Lookahead::slicetypeAnalyse(Lowres **frames, bool bKeyframe)<br>         }<br> <br>         int zoneRadl = m_param->rc.zonefileCount && m_param->bResetZoneConfig ? m_param->rc.zones->zoneParam->radl : 0;<br>-        bool bForceRADL = (m_param->radl || zoneRadl) && !m_param->bOpenGOP;<br>+        bool bForceRADL = zoneRadl || (m_param->radl && (m_param->keyframeMax == m_param->keyframeMin));<br>         bool bLastMiniGop = (framecnt >= m_param->bframes + 1) ? false : true;<br>         int radl = m_param->radl ? m_param->radl : zoneRadl;<br>         int preRADL = m_lastKeyframe + m_param->keyframeMax - radl - 1; /*Frame preceeding RADL in POC order*/<br>-- <br>2.24.0.windows.2<br><br><div><div dir="ltr" data-smartmail="gmail_signature"><div dir="ltr"><font color="#073763"><br></font></div><div dir="ltr"><font color="#073763">Regards, <br><b>Pooja Venkatesan</b>, <br>Video Codec Engineer, <br>Media & AI analytics BU</font><br><font size="1"><img src="https://docs.google.com/uc?export=download&id=1d95Qlxmd7GpR09YzmNH0gdIVV6O9kvWD&revid=0B0mq5CBCJeT-Uk04LzZtMkJob0dUMTFsTjlkSzlQQkhFaTIwPQ" width="109" height="15" style="margin-right:0px"></font><br></div></div></div><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Jun 25, 2020 at 9:00 PM Pooja Venkatesan <<a href="mailto:pooja@multicorewareinc.com" target="_blank">pooja@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 9d8c8657374b1154cab1a75ac6e23d04be58015c Mon Sep 17 00:00:00 2001<br>From: Pooja Venkatesan <<a href="mailto:pooja@multicorewareinc.com" target="_blank">pooja@multicorewareinc.com</a>><br>Date: Thu, 25 Jun 2020 20:48:22 +0530<br>Subject: [PATCH] Add support for RADL pictures at IDR scenecuts.<br><br>---<br> source/common/lowres.h       |  1 +<br> source/encoder/encoder.cpp   | 21 +++++++++++++--------<br> source/encoder/encoder.h     |  2 +-<br> source/encoder/slicetype.cpp | 13 ++++++++++++-<br> 4 files changed, 27 insertions(+), 10 deletions(-)<br><br>diff --git a/source/common/lowres.h b/source/common/lowres.h<br>index 200b1f032..a0ec05b25 100644<br>--- a/source/common/lowres.h<br>+++ b/source/common/lowres.h<br>@@ -238,6 +238,7 @@ struct Lowres : public ReferencePlanes<br>     bool   m_bIsMaxThres;<br>     double interPCostPercDiff;<br>     double intraCostPercDiff;<br>+    bool m_bIsHardScenecut;<br> <br>     bool create(x265_param* param, PicYuv *origPic, uint32_t qgSize);<br>     void destroy();<br>diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp<br>index bec7ff5c0..c9bcf2664 100644<br>--- a/source/encoder/encoder.cpp<br>+++ b/source/encoder/encoder.cpp<br>@@ -1528,11 +1528,11 @@ double Encoder::normalizeRange(int32_t value, int32_t minValue, int32_t maxValue<br>     return (double)(value - minValue) * (rangeEnd - rangeStart) / (maxValue - minValue) + rangeStart;<br> }<br> <br>-void Encoder::findSceneCuts(x265_picture *pic, bool& isMax, bool& bDup, double maxUVSad, double edgeSad)<br>+void Encoder::findSceneCuts(x265_picture *pic, bool& isMax, bool& isHardSC, bool& bDup, double maxUVSad, double edgeSad)<br> {<br>-    double minEdgeT = m_edgeHistThreshold * 0.5;<br>-    double minChromaT = minEdgeT * 10.0;<br>-    double maxEdgeT = m_edgeHistThreshold * 1.5;<br>+    double minEdgeT = m_edgeHistThreshold * 0.5;<br>+    double minChromaT = minEdgeT * 10.0;<br>+    double maxEdgeT = m_edgeHistThreshold * 1.5;<br>     double maxChromaT = maxEdgeT * 10.0;<br>     pic->frameData.bScenecut = false;<br> <br>@@ -1555,11 +1555,14 @@ void Encoder::findSceneCuts(x265_picture *pic, bool& isMax, bool& bDup, double m<br>         else if (edgeSad > maxEdgeT && maxUVSad > maxChromaT)<br>         {<br>             pic->frameData.bScenecut = true;<br>+            isHardSC = true;<br>             isMax = true;<br>         }<br>         else if (edgeSad > m_scaledEdgeThreshold || maxUVSad >= m_scaledChromaThreshold<br>                  || (edgeSad > m_edgeHistThreshold && maxUVSad >= m_chromaHistThreshold))<br>         {<br>+            if (edgeSad > m_scaledEdgeThreshold || maxUVSad >= m_scaledChromaThreshold)<br>+                isHardSC = true;<br>             pic->frameData.bScenecut = true;<br>             bDup = false;<br>         }<br>@@ -1594,7 +1597,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>     bool dontRead = false;<br>     bool bdropFrame = false;<br>     bool dropflag = false;<br>-    bool isMaxThreshold = false;<br>+    bool isMaxThreshold = false, isHardSC = false;<br> <br>     if (m_exportedPic)<br>     {<br>@@ -1621,7 +1624,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>             {<br>                 double maxUVSad = 0.0, edgeSad = 0.0;<br>                 computeHistogramSAD(&maxUVSad, &edgeSad, pic_in->poc);<br>-                findSceneCuts(pic, isMaxThreshold, bdropFrame, maxUVSad, edgeSad);<br>+                findSceneCuts(pic, isMaxThreshold, isHardSC, bdropFrame, maxUVSad, edgeSad);<br>             }<br>         }<br> <br>@@ -1801,6 +1804,8 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>         {<br>             inFrame->m_lowres.bScenecut = (inputPic->frameData.bScenecut == 1) ? true : false;<br>             inFrame->m_lowres.m_bIsMaxThres = isMaxThreshold;<br>+            if (m_param->radl && m_param->keyframeMax != m_param->keyframeMin)<br>+                inFrame->m_lowres.m_bIsHardScenecut = isHardSC;<br>         }<br>         if (m_param->bHistBasedSceneCut && m_param->analysisSave)<br>         {<br>@@ -4218,10 +4223,10 @@ void Encoder::configure(x265_param *p)<br>     p->unitSizeDepth = p->maxLog2CUSize - LOG2_UNIT_SIZE;<br>     p->num4x4Partitions = (1U << (p->unitSizeDepth << 1));<br> <br>-    if (p->radl && (p->keyframeMax != p->keyframeMin))<br>+    if (p->radl && p->bOpenGOP)<br>     {<br>         p->radl = 0;<br>-        x265_log(p, X265_LOG_WARNING, "Radl requires fixed gop-length (keyint == min-keyint). Disabling radl.\n");<br>+        x265_log(p, X265_LOG_WARNING, "Radl requires closed gop structure. Disabling radl.\n");<br>     }<br> <br>     if ((p->chunkStart || p->chunkEnd) && p->bOpenGOP && m_param->bResetZoneConfig)<br>diff --git a/source/encoder/encoder.h b/source/encoder/encoder.h<br>index 1d4fe2476..4fbd234c2 100644<br>--- a/source/encoder/encoder.h<br>+++ b/source/encoder/encoder.h<br>@@ -373,7 +373,7 @@ public:<br>     bool computeHistograms(x265_picture *pic);<br>     void computeHistogramSAD(double *maxUVNormalizedSAD, double *edgeNormalizedSAD, int curPoc);<br>     double normalizeRange(int32_t value, int32_t minValue, int32_t maxValue, double rangeStart, double rangeEnd);<br>-    void findSceneCuts(x265_picture *pic, bool& isMax, bool& bDup, double m_maxUVSADVal, double m_edgeSADVal);<br>+    void findSceneCuts(x265_picture *pic, bool& isMax, bool& isHardSC, bool& bDup, double m_maxUVSADVal, double m_edgeSADVal);<br> <br>     void initRefIdx();<br>     void analyseRefIdx(int *numRefIdx);<br>diff --git a/source/encoder/slicetype.cpp b/source/encoder/slicetype.cpp<br>index 27052ca4e..2006fd434 100644<br>--- a/source/encoder/slicetype.cpp<br>+++ b/source/encoder/slicetype.cpp<br>@@ -1520,6 +1520,7 @@ void Lookahead::slicetypeDecide()<br>     int bframes, brefs;<br>     if (!m_param->analysisLoad || m_param->bAnalysisType == HEVC_INFO)<br>     {<br>+        bool isClosedGopRadl = m_param->radl && m_param->keyframeMax != m_param->keyframeMin;<br>         for (bframes = 0, brefs = 0;; bframes++)<br>         {<br>             Lowres& frm = list[bframes]->m_lowres;<br>@@ -1579,6 +1580,16 @@ void Lookahead::slicetypeDecide()<br>                 else<br>                     frm.sliceType = X265_TYPE_IDR;<br>             }<br>+            if (frm.sliceType == X265_TYPE_IDR && frm.bScenecut && isClosedGopRadl)<br>+            {<br>+                if ((m_param->bHistBasedSceneCut && frm.m_bIsHardScenecut) ||<br>+                    !m_param->bHistBasedSceneCut)<br>+                {<br>+                    for (int i = bframes; i < bframes + m_param->radl; i++)<br>+                        list[i]->m_lowres.sliceType = X265_TYPE_B;<br>+                    list[(bframes + m_param->radl)]->m_lowres.sliceType = X265_TYPE_IDR;<br>+                }<br>+            }<br>             if (frm.sliceType == X265_TYPE_IDR)<br>             {<br>                 /* Closed GOP */<br>@@ -2146,7 +2157,7 @@ void Lookahead::slicetypeAnalyse(Lowres **frames, bool bKeyframe)<br>         }<br> <br>         int zoneRadl = m_param->rc.zonefileCount && m_param->bResetZoneConfig ? m_param->rc.zones->zoneParam->radl : 0;<br>-        bool bForceRADL = (m_param->radl || zoneRadl) && !m_param->bOpenGOP;<br>+        bool bForceRADL = ((m_param->radl && m_param->keyframeMax == m_param->keyframeMin) || zoneRadl) && !m_param->bOpenGOP;<br>         bool bLastMiniGop = (framecnt >= m_param->bframes + 1) ? false : true;<br>         int radl = m_param->radl ? m_param->radl : zoneRadl;<br>         int preRADL = m_lastKeyframe + m_param->keyframeMax - radl - 1; /*Frame preceeding RADL in POC order*/<br>-- <br>2.24.0.windows.2<br><br></div>
</blockquote></div>
</div>