<div dir="ltr">Updated X265_BUILD and pushed the patch into the<a href="https://bitbucket.org/multicoreware/x265_git/commits/38774073d45138b01a6abd0e2cfcecae01038a72"> master branch</a>.<br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Jun 22, 2020 at 11:38 AM Praveen Kumar Karadugattu <<a href="mailto:praveenkumar@multicorewareinc.com">praveenkumar@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"><div>From 44704e10a60ae314ecd13dfb84c0c4f82d6c1a55 Mon Sep 17 00:00:00 2001</div><div>From: Praveen Kumar Karadugattu <<a href="mailto:praveenkumar@multicorewareinc.com" target="_blank">praveenkumar@multicorewareinc.com</a>></div><div>Date: Wed, 17 Jun 2020 19:28:06 +0530</div><div>Subject: [PATCH] Fixed the normalization formula to ouput 0 to 1 and</div><div> considered max chroma histogram SAD in histogram based scene cut detection</div><div><br></div><div>---</div><div> doc/reST/cli.rst | 8 ++---</div><div> source/common/param.cpp | 4 +--</div><div> source/encoder/encoder.cpp | 75 ++++++++++++++++++++++------------------------</div><div> source/encoder/encoder.h | 6 ++--</div><div> source/x265cli.cpp | 2 +-</div><div> 5 files changed, 45 insertions(+), 50 deletions(-)</div><div><br></div><div>diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst</div><div>index eceec40..c9e288e 100644</div><div>--- a/doc/reST/cli.rst</div><div>+++ b/doc/reST/cli.rst</div><div>@@ -1462,13 +1462,13 @@ Slice decision options</div><div> .. option:: --hist-scenecut, --no-hist-scenecut</div><div> </div><div> <span style="white-space:pre-wrap"> </span>Indicates that scenecuts need to be detected using luma edge and chroma histograms.</div><div>-<span style="white-space:pre-wrap"> </span>:option: `--hist-scenecut` enables scenecut detection using the histograms and disables the default scene cut algorithm.</div><div>-<span style="white-space:pre-wrap"> </span>:option: `--no-hist-scenecut` disables histogram based scenecut algorithm.</div><div>+<span style="white-space:pre-wrap"> </span>:option:`--hist-scenecut` enables scenecut detection using the histograms and disables the default scene cut algorithm.</div><div>+<span style="white-space:pre-wrap"> </span>:option:`--no-hist-scenecut` disables histogram based scenecut algorithm.</div><div> <span style="white-space:pre-wrap"> </span></div><div>-.. option:: --hist-threshold <0.0..2.0></div><div>+.. option:: --hist-threshold <0.0..1.0></div><div> </div><div> <span style="white-space:pre-wrap"> </span>This value represents the threshold for normalized SAD of edge histograms used in scenecut detection.</div><div>-<span style="white-space:pre-wrap"> </span>This requires :option: `--hist-scenecut` to be enabled. For example, a value of 0.2 indicates that a frame with normalized SAD value </div><div>+<span style="white-space:pre-wrap"> </span>This requires :option:`--hist-scenecut` to be enabled. For example, a value of 0.2 indicates that a frame with normalized SAD value </div><div> <span style="white-space:pre-wrap"> </span>greater than 0.2 against the previous frame as scenecut. </div><div> <span style="white-space:pre-wrap"> </span>Default 0.01.</div><div> <span style="white-space:pre-wrap"> </span></div><div>diff --git a/source/common/param.cpp b/source/common/param.cpp</div><div>index fb7244e..925f0c4 100644</div><div>--- a/source/common/param.cpp</div><div>+++ b/source/common/param.cpp</div><div>@@ -1688,8 +1688,8 @@ int x265_check_params(x265_param* param)</div><div> "scenecutThreshold must be greater than 0");</div><div> CHECK(param->scenecutBias < 0 || 100 < param->scenecutBias,</div><div> "scenecut-bias must be between 0 and 100");</div><div>- CHECK(param->edgeTransitionThreshold < 0.0 || 2.0 < param->edgeTransitionThreshold,</div><div>- "hist-threshold must be between 0.0 and 2.0");</div><div>+ CHECK(param->edgeTransitionThreshold < 0.0 || 1.0 < param->edgeTransitionThreshold,</div><div>+ "hist-threshold must be between 0.0 and 1.0");</div><div> CHECK(param->radl < 0 || param->radl > param->bframes,</div><div> "radl must be between 0 and bframes");</div><div> CHECK(param->rdPenalty < 0 || param->rdPenalty > 2,</div><div>diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp</div><div>index 752e5b2..f6bc540 100644</div><div>--- a/source/encoder/encoder.cpp</div><div>+++ b/source/encoder/encoder.cpp</div><div>@@ -222,12 +222,9 @@ void Encoder::create()</div><div> uint32_t pixelbytes = m_param->internalBitDepth > 8 ? 2 : 1;</div><div> m_edgePic = X265_MALLOC(pixel, m_planeSizes[0] * pixelbytes);</div><div> m_edgeHistThreshold = m_param->edgeTransitionThreshold;</div><div>- m_chromaHistThreshold = m_edgeHistThreshold * 10.0;</div><div>- m_chromaHistThreshold = x265_min(m_chromaHistThreshold, MAX_SCENECUT_THRESHOLD);</div><div>- m_scaledEdgeThreshold = m_edgeHistThreshold * SCENECUT_STRENGTH_FACTOR;</div><div>- m_scaledEdgeThreshold = x265_min(m_scaledEdgeThreshold, MAX_SCENECUT_THRESHOLD);</div><div>- m_scaledChromaThreshold = m_chromaHistThreshold * SCENECUT_STRENGTH_FACTOR;</div><div>- m_scaledChromaThreshold = x265_min(m_scaledChromaThreshold, MAX_SCENECUT_THRESHOLD);</div><div>+ m_chromaHistThreshold = x265_min(m_edgeHistThreshold * 10.0, MAX_SCENECUT_THRESHOLD);</div><div>+ m_scaledEdgeThreshold = x265_min(m_edgeHistThreshold * SCENECUT_STRENGTH_FACTOR, MAX_SCENECUT_THRESHOLD);</div><div>+ m_scaledChromaThreshold = x265_min(m_chromaHistThreshold * SCENECUT_STRENGTH_FACTOR, MAX_SCENECUT_THRESHOLD);</div><div> if (m_param->sourceBitDepth != m_param->internalBitDepth)</div><div> {</div><div> int size = m_param->sourceWidth * m_param->sourceHeight;</div><div>@@ -1450,13 +1447,14 @@ bool Encoder::computeHistograms(x265_picture *pic)</div><div> memset(edgeHist, 0, EDGE_BINS * sizeof(int32_t));</div><div> for (uint32_t i = 0; i < m_planeSizes[0]; i++)</div><div> {</div><div>- if (!m_edgePic[i])</div><div>- edgeHist[0]++;</div><div>+ if (m_edgePic[i])</div><div>+ edgeHist[1]++;</div><div> else</div><div>- edgeHist[1]++;</div><div>+ edgeHist[0]++;</div><div> }</div><div>+</div><div> /* Y Histogram Calculation */</div><div>- int32_t* yHist = m_curYUVHist[0];</div><div>+ int32_t *yHist = m_curYUVHist[0];</div><div> memset(yHist, 0, HISTOGRAM_BINS * sizeof(int32_t));</div><div> for (uint32_t i = 0; i < m_planeSizes[0]; i++)</div><div> {</div><div>@@ -1468,7 +1466,7 @@ bool Encoder::computeHistograms(x265_picture *pic)</div><div> {</div><div> /* U Histogram Calculation */</div><div> int32_t *uHist = m_curYUVHist[1];</div><div>- memset(uHist, 0, HISTOGRAM_BINS * sizeof(int32_t));</div><div>+ memset(uHist, 0, sizeof(m_curYUVHist[1]));</div><div> for (uint32_t i = 0; i < m_planeSizes[1]; i++)</div><div> {</div><div> pixelVal = planeU[i];</div><div>@@ -1478,52 +1476,56 @@ bool Encoder::computeHistograms(x265_picture *pic)</div><div> /* V Histogram Calculation */</div><div> pixelVal = 0;</div><div> int32_t *vHist = m_curYUVHist[2];</div><div>- memset(vHist, 0, HISTOGRAM_BINS * sizeof(int32_t));</div><div>+ memset(vHist, 0, sizeof(m_curYUVHist[2]));</div><div> for (uint32_t i = 0; i < m_planeSizes[2]; i++)</div><div> {</div><div> pixelVal = planeV[i];</div><div> vHist[pixelVal]++;</div><div> }</div><div>- for (int i = 0; i < HISTOGRAM_BINS; i++)</div><div>- {</div><div>- m_curMaxUVHist[i] = x265_max(uHist[i], vHist[i]);</div><div>- }</div><div> }</div><div> return true;</div><div> }</div><div> </div><div>-void Encoder::computeHistogramSAD(double *maxUVNormalizedSad, double *edgeNormalizedSad, int curPoc)</div><div>+void Encoder::computeHistogramSAD(double *normalizedMaxUVSad, double *normalizedEdgeSad, int curPoc)</div><div> {</div><div> </div><div> if (curPoc == 0)</div><div> { /* first frame is scenecut by default no sad computation for the same. */</div><div>- *maxUVNormalizedSad = 0.0;</div><div>- *edgeNormalizedSad = 0.0;</div><div>+ *normalizedMaxUVSad = 0.0;</div><div>+ *normalizedEdgeSad = 0.0;</div><div> }</div><div> else</div><div> {</div><div>- /* compute sum of absolute difference of normalized histogram bins for maxUV and edge histograms. */</div><div>- int32_t edgefreqDiff = 0;</div><div>- int32_t maxUVfreqDiff = 0;</div><div>- double edgeProbabilityDiff = 0;</div><div>+ /* compute sum of absolute differences of histogram bins of chroma and luma edge response between the current and prev pictures. */</div><div>+ int32_t edgeHistSad = 0;</div><div>+ int32_t uHistSad = 0;</div><div>+ int32_t vHistSad = 0;</div><div>+ double normalizedUSad = 0.0;</div><div>+ double normalizedVSad = 0.0;</div><div> </div><div> for (int j = 0; j < HISTOGRAM_BINS; j++)</div><div> {</div><div> if (j < 2)</div><div> {</div><div>- edgefreqDiff = abs(m_curEdgeHist[j] - m_prevEdgeHist[j]);</div><div>- edgeProbabilityDiff = (double) edgefreqDiff / m_planeSizes[0];</div><div>- *edgeNormalizedSad += edgeProbabilityDiff;</div><div>+ edgeHistSad += abs(m_curEdgeHist[j] - m_prevEdgeHist[j]);</div><div> }</div><div>- maxUVfreqDiff = abs(m_curMaxUVHist[j] - m_prevMaxUVHist[j]);</div><div>- *maxUVNormalizedSad += (double)maxUVfreqDiff / m_planeSizes[2];</div><div>+ uHistSad += abs(m_curYUVHist[1][j] - m_prevYUVHist[1][j]);</div><div>+ vHistSad += abs(m_curYUVHist[2][j] - m_prevYUVHist[2][j]);</div><div> }</div><div>+ *normalizedEdgeSad = normalizeRange(edgeHistSad, 0, 2 * m_planeSizes[0], 0.0, 1.0);</div><div>+ normalizedUSad = normalizeRange(uHistSad, 0, 2 * m_planeSizes[1], 0.0, 1.0);</div><div>+ normalizedVSad = normalizeRange(vHistSad, 0, 2 * m_planeSizes[2], 0.0, 1.0);</div><div>+ *normalizedMaxUVSad = x265_max(normalizedUSad, normalizedVSad);</div><div> }</div><div> </div><div> /* store histograms of previous frame for reference */</div><div>- size_t bufsize = HISTOGRAM_BINS * sizeof(int32_t);</div><div>- memcpy(m_prevMaxUVHist, m_curMaxUVHist, bufsize);</div><div>- memcpy(m_prevEdgeHist, m_curEdgeHist, 2 * sizeof(int32_t));</div><div>+ memcpy(m_prevEdgeHist, m_curEdgeHist, sizeof(m_curEdgeHist));</div><div>+ memcpy(m_prevYUVHist, m_curYUVHist, sizeof(m_curYUVHist));</div><div>+}</div><div>+</div><div>+double Encoder::normalizeRange(int32_t value, int32_t minValue, int32_t maxValue, double rangeStart, double rangeEnd)</div><div>+{</div><div>+ return (double)(value - minValue) * (rangeEnd - rangeStart) / (maxValue - minValue) + rangeStart;</div><div> }</div><div> </div><div> void Encoder::findSceneCuts(x265_picture *pic, bool& bDup, double maxUVSad, double edgeSad)</div><div>@@ -1542,20 +1544,13 @@ void Encoder::findSceneCuts(x265_picture *pic, bool& bDup, double maxUVSad, doub</div><div> {</div><div> bDup = true;</div><div> }</div><div>- else if (edgeSad > m_edgeHistThreshold && maxUVSad >= m_chromaHistThreshold)</div><div>- {</div><div>- pic->frameData.bScenecut = true;</div><div>- bDup = false;</div><div>- }</div><div>- else if (edgeSad > m_scaledEdgeThreshold || maxUVSad >= m_scaledChromaThreshold)</div><div>+ else if (edgeSad > m_scaledEdgeThreshold || maxUVSad >= m_scaledChromaThreshold || (edgeSad > m_edgeHistThreshold && maxUVSad >= m_chromaHistThreshold))</div><div> {</div><div> pic->frameData.bScenecut = true;</div><div> bDup = false;</div><div>+ x265_log(m_param, X265_LOG_DEBUG, "scene cut at %d \n", pic->poc);</div><div> }</div><div> }</div><div>-</div><div>- if (pic->frameData.bScenecut)</div><div>- x265_log(m_param, X265_LOG_DEBUG, "scene cut at %d \n", pic->poc);</div><div> }</div><div> </div><div> /**</div><div>diff --git a/source/encoder/encoder.h b/source/encoder/encoder.h</div><div>index 2c45886..fd6b3e7 100644</div><div>--- a/source/encoder/encoder.h</div><div>+++ b/source/encoder/encoder.h</div><div>@@ -163,7 +163,7 @@ class RateControl;</div><div> class ThreadPool;</div><div> class FrameData;</div><div> </div><div>-#define MAX_SCENECUT_THRESHOLD 2.0</div><div>+#define MAX_SCENECUT_THRESHOLD 1.0</div><div> #define SCENECUT_STRENGTH_FACTOR 2.0</div><div> </div><div> class Encoder : public x265_encoder</div><div>@@ -257,8 +257,7 @@ public:</div><div> pixel* m_edgePic;</div><div> pixel* m_inputPic[3];</div><div> int32_t m_curYUVHist[3][HISTOGRAM_BINS];</div><div>- int32_t m_curMaxUVHist[HISTOGRAM_BINS];</div><div>- int32_t m_prevMaxUVHist[HISTOGRAM_BINS];</div><div>+ int32_t m_prevYUVHist[3][HISTOGRAM_BINS];</div><div> int32_t m_curEdgeHist[2];</div><div> int32_t m_prevEdgeHist[2];</div><div> uint32_t m_planeSizes[3];</div><div>@@ -373,6 +372,7 @@ public:</div><div> </div><div> bool computeHistograms(x265_picture *pic);</div><div> void computeHistogramSAD(double *maxUVNormalizedSAD, double *edgeNormalizedSAD, int curPoc);</div><div>+ double normalizeRange(int32_t value, int32_t minValue, int32_t maxValue, double rangeStart, double rangeEnd);</div><div> void findSceneCuts(x265_picture *pic, bool& bDup, double m_maxUVSADVal, double m_edgeSADVal);</div><div> </div><div> void initRefIdx();</div><div>diff --git a/source/x265cli.cpp b/source/x265cli.cpp</div><div>index 5b95698..b53dc2b 100644</div><div>--- a/source/x265cli.cpp</div><div>+++ b/source/x265cli.cpp</div><div>@@ -175,7 +175,7 @@ namespace X265_NS {</div><div> H1(" --scenecut-bias <0..100.0> Bias for scenecut detection. Default %.2f\n", param->scenecutBias);</div><div> H0(" --hist-scenecut Enables histogram based scene-cut detection using histogram based algorithm.\n");</div><div> H0(" --no-hist-scenecut Disables histogram based scene-cut detection using histogram based algorithm.\n");</div><div>- H1(" --hist-threshold <0.0..2.0> Luma Edge histogram's Normalized SAD threshold for histogram based scenecut detection Default %.2f\n", param->edgeTransitionThreshold);</div><div>+ H1(" --hist-threshold <0.0..1.0> Luma Edge histogram's Normalized SAD threshold for histogram based scenecut detection Default %.2f\n", param->edgeTransitionThreshold);</div><div> H0(" --[no-]fades Enable detection and handling of fade-in regions. Default %s\n", OPT(param->bEnableFades));</div><div> H1(" --[no-]scenecut-aware-qp Enable increasing QP for frames inside the scenecut window after scenecut. Default %s\n", OPT(param->bEnableSceneCutAwareQp));</div><div> H1(" --scenecut-window <0..1000> QP incremental duration(in milliseconds) when scenecut-aware-qp is enabled. Default %d\n", param->scenecutWindow);</div><div>-- </div><div>1.8.3.1</div><div><br></div></div></div>
</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>