<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>