<div dir="auto">Hi Alex, <div dir="auto"> </div><div dir="auto">Yes the features are independent irrespective of the underlying implementation. As per design, frame duplication will use sad computed by scene cut to identify duplicate frames if they are enabled together, if it's not detected by sad then only we compute the pnsr. </div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, 20 Nov, 2019, 02:12 Alex Giladi, <<a href="mailto:alex.giladi@gmail.com">alex.giladi@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div dir="auto">Hi Srikanth,</div></div><div dir="auto">Why would there be any relationship between scene cut detection method and frame duplication? </div><div dir="auto">Functionality-wise, they should be independent irrespective of the underlying implementation.</div><div dir="auto">Best,</div><div dir="auto">Alex.</div><div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Nov 19, 2019 at 3:13 AM Srikanth Kurapati <<a href="mailto:srikanth.kurapati@multicorewareinc.com" target="_blank" rel="noreferrer">srikanth.kurapati@multicorewareinc.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">1. Is this necessary? Can you make the latest option set to take effect? <br>Ans: Thats the normal behavior and how the cli is parsed. We had a discussion on this.<br>     1. to enable default method when user chooses both.<br>     2. or enable latest - user's last choice.<br>     3. to process only the users first choice.<br>     We choose the last option.<br>     That was how it was initially designed. <br>2. Will this work if --hist-scenecut is set after --hist-threshold in the CLI? <br>No. It's mentioned in the documentation how to use the new cli options that the method needs to be enabled before the threshold being set. <br>else in the case when only threshold is set and method is not enabled its unnecessarily being processed again and again though its nor used in the library.<br>Incase the user threshold is not read the default value will always be used for processing.<br>3. float point comparison; might result in rounding errors. <br>  - at the end of a high precision which is not the case for typical thresholds set by user upto to 2 to 3 decimal places.<br>4. Also, why are you checking p->edgeTransitionThreshold when naive scenecut algorithm is enabled?<br>  - to handle the case when user has configured the wrong threshold but since its unnecessary I will remove the same.<br>5. Please add one more CLI to test the functionality of hist-scenecut in the absence of frame duplication. <br>  - It has been discussed and decided to add only one for the full feature. Should I still add the same.<br>6. This will affect backward compatibility. May I know how ?<br>    Everywhere in the code we are setting the flags to true or false it should be of type bool.<br>  <br>Will address the rest of the valid comments.<br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Nov 18, 2019 at 11:06 PM Aruna Matheswaran <<a href="mailto:aruna@multicorewareinc.com" target="_blank" rel="noreferrer">aruna@multicorewareinc.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color: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 Mon, Nov 18, 2019 at 12:20 PM Srikanth Kurapati <<a href="mailto:srikanth.kurapati@multicorewareinc.com" target="_blank" rel="noreferrer">srikanth.kurapati@multicorewareinc.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr"># HG changeset patch<br># User Srikanth Kurapati <<a href="mailto:srikanth.kurapati@multicorewareinc.com" target="_blank" rel="noreferrer">srikanth.kurapati@multicorewareinc.com</a>><br># Date 1573649311 -19800<br>#      Wed Nov 13 18:18:31 2019 +0530<br># Node ID 40beab295ca274bf62cb2fd2e732da722d10eea3<br># Parent  04db2bfee5d628d931d1407355b909ac8ff1c898<br>Histogram based scenecut detection<br><br>This patch does the following.<br>1.Identifies scenecuts by thresholding against sad of edge and chroma histograms.<br>2.Add option "--hist-scenecut" to enable histogram based scenecut method.<br>3.Add option "--hist-threshold" to provide threshold for determining scene-cuts.<br>3.Optimizes frame duplication through reuse of sad for marking duplicate frames.<br><br>diff -r 04db2bfee5d6 -r 40beab295ca2 doc/reST/cli.rst<br>--- a/doc/reST/cli.rst     Thu Oct 31 16:23:27 2019 +0530<br>+++ b/doc/reST/cli.rst  Wed Nov 13 18:18:31 2019 +0530<br>@@ -1426,7 +1426,23 @@<br>       This value represents the percentage difference between the inter cost and<br>   intra cost of a frame used in scenecut detection. For example, a value of 5 indicates,<br>       if the inter cost of a frame is greater than or equal to 95 percent of the intra cost of the frame,<br>-  then detect this frame as scenecut. Values between 5 and 15 are recommended. Default 5.<br>+      then detect this frame as scenecut. Values between 5 and 15 are recommended. <br>+        This value is evaluated only when --scenecut is enabled else it is ignored. Default 5. <br>+<br>+.. option:: --hist-scenecut, --no-hist-scenecut<br>+<br>+      indicates that scenecuts need to be detected using luma edge and chroma histograms.<br></div></blockquote><div>Case issue in "indicates". </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">+  option: `--hist-scenecut` enables scenecut detection using the histograms and disables the default scene cut algorithm.<br>+      option: `--no-hist-scenecut` disables histogram based scenecut algorithm.<br>+    <br>+     Note that if --hist-scenecut and --scenecut are enabled together the first choice of user is considered for processing.<br>+      <br>+.. option:: --hist-threshold <0.0..2.0><br>+<br>+  This value represents the threshold for normalized SAD of edge histograms used in scenecut detection.<br>+        This requires hist-scenecut to be enabled. For example, a value of 0.2 indicates that a frame with normalized SAD value <br></div></blockquote><div>Add a link to hist-scenecut (option: `--hist-scenecut` )</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">+   greater than 0.2 against the previous frame as scenecut. <br>+    Default 0.01.<br>        <br> .. option:: --radl <integer><br>       <br>diff -r 04db2bfee5d6 -r 40beab295ca2 source/CMakeLists.txt<br>--- a/source/CMakeLists.txt       Thu Oct 31 16:23:27 2019 +0530<br>+++ b/source/CMakeLists.txt     Wed Nov 13 18:18:31 2019 +0530<br>@@ -29,7 +29,7 @@<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 182)<br>+set(X265_BUILD 183)<br> configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265.def.in" target="_blank" rel="noreferrer">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" rel="noreferrer">x265_config.h.in</a>"<br>diff -r 04db2bfee5d6 -r 40beab295ca2 source/common/common.h<br>--- a/source/common/common.h        Thu Oct 31 16:23:27 2019 +0530<br>+++ b/source/common/common.h    Wed Nov 13 18:18:31 2019 +0530<br>@@ -129,12 +129,16 @@<br> typedef uint64_t sum2_t;<br> typedef uint64_t pixel4;<br> typedef int64_t  ssum2_t;<br>+#define HISTOGRAM_BINS 1024<br>+#define SHIFT 1<br> #else<br> typedef uint8_t  pixel;<br> typedef uint16_t sum_t;<br> typedef uint32_t sum2_t;<br> typedef uint32_t pixel4;<br> typedef int32_t  ssum2_t; // Signed sum<br>+#define HISTOGRAM_BINS 256<br>+#define SHIFT 0<br> #endif // if HIGH_BIT_DEPTH<br> <br> #if X265_DEPTH < 10<br>diff -r 04db2bfee5d6 -r 40beab295ca2 source/common/param.cpp<br>--- a/source/common/param.cpp        Thu Oct 31 16:23:27 2019 +0530<br>+++ b/source/common/param.cpp   Wed Nov 13 18:18:31 2019 +0530<br>@@ -167,6 +167,8 @@<br>     param->bFrameAdaptive = X265_B_ADAPT_TRELLIS;<br>     param->bBPyramid = 1;<br>     param->scenecutThreshold = 40; /* Magic number pulled in from x264 */<br>+    param->edgeTransitionThreshold = 0.01;<br>+    param->bHistBasedSceneCut = false;<br>     param->lookaheadSlices = 8;<br>     param->lookaheadThreads = 0;<br>     param->scenecutBias = 5.0;<br>@@ -572,6 +574,7 @@<br>             param->bframes = 0;<br>             param->lookaheadDepth = 0;<br>             param->scenecutThreshold = 0;<br>+            param->bHistBasedSceneCut = false;<br>             param->rc.cuTree = 0;<br>             param->frameNumThreads = 1;<br>         }<br>@@ -614,7 +617,7 @@<br>     return 0;<br> }<br> <br>-static int x265_atobool(const char* str, bool& bError)<br>+static bool x265_atobool(const char* str, bool& bError)<br> {<br>     if (!strcmp(str, "1") ||<br>         !strcmp(str, "true") ||<br>@@ -764,6 +767,7 @@<br>     bool bNameWasBool = false;<br>     bool bValueWasNull = !value;<br>     bool bExtraParams = false;<br>+    static int scenecutChoice = -1;<br></div></blockquote><div>Is this necessary? Can you make the latest option set to take effect? </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">     char nameBuf[64];<br>     static int count;<br> <br>@@ -920,11 +924,16 @@<br>     OPT("lookahead-slices") p->lookaheadSlices = atoi(value);<br>     OPT("scenecut")<br>     {<br>-        p->scenecutThreshold = atobool(value);<br>-        if (bError || p->scenecutThreshold)<br>+        if (scenecutChoice == -1)<br>         {<br>-            bError = false;<br>-            p->scenecutThreshold = atoi(value);<br>+            p->scenecutThreshold = atobool(value);<br>+            if (bError || p->scenecutThreshold)<br>+            {<br>+                bError = false;<br>+                p->scenecutThreshold = atoi(value);<br>+                p->bHistBasedSceneCut = false;<br>+                scenecutChoice = 0;<br>+            }<br>         }<br>     }<br>     OPT("temporal-layers") p->bEnableTemporalSubLayers = atobool(value);<br>@@ -1191,6 +1200,46 @@<br>         OPT("opt-ref-list-length-pps") p->bOptRefListLengthPPS = atobool(value);<br>         OPT("multi-pass-opt-rps") p->bMultiPassOptRPS = atobool(value);<br>         OPT("scenecut-bias") p->scenecutBias = atof(value);<br>+        OPT("hist-scenecut")<br>+        {<br>+            if (scenecutChoice == -1)<br>+            {<br>+                p->bHistBasedSceneCut = atobool(value);<br>+                if (bError)<br>+                {<br>+                    bError = false;<br>+                    p->bHistBasedSceneCut = false;<br>+                }<br>+                if (p->bHistBasedSceneCut)<br>+                {<br>+                    bError = false;<br>+                    p->scenecutThreshold = 0;<br>+                    scenecutChoice = 1;<br>+                }<br>+            }<br>+            else<br>+            {<br>+                p->bHistBasedSceneCut = atobool(value);<br>+                p->bHistBasedSceneCut = false;<br>+            }<br>+        }<br>+        OPT("hist-threshold")<br>+        {<br>+            if (p->bHistBasedSceneCut)<br></div></blockquote><div>Will this work if --hist-scenecut is set after --hist-threshold in the CLI? </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">+            {<br>+                p->edgeTransitionThreshold = atof(value);<br>+                if (bError)<br>+                {<br>+                    bError = false;<br>+                    p->edgeTransitionThreshold = 0.01;<br>+                    x265_log(p, X265_LOG_INFO, "Using  default threshold %.2lf for scene cut detection\n", p->edgeTransitionThreshold);<br>+                }<br>+            }<br>+            else<br>+            {<br>+                x265_log(p, X265_LOG_WARNING, "Histogram based scene cut detection not enabled\n", p->edgeTransitionThreshold);<br>+            }<br>+        }<br>         OPT("lookahead-threads") p->lookaheadThreads = atoi(value);<br>         OPT("opt-cu-delta-qp") p->bOptCUDeltaQP = atobool(value);<br>         OPT("multi-pass-opt-analysis") p->analysisMultiPassRefine = atobool(value);<br>@@ -1631,8 +1680,16 @@<br>           "Valid Logging level -1:none 0:error 1:warning 2:info 3:debug 4:full");<br>     CHECK(param->scenecutThreshold < 0,<br>           "scenecutThreshold must be greater than 0");<br>-    CHECK(param->scenecutBias < 0 || 100 < param->scenecutBias,<br>-           "scenecut-bias must be between 0 and 100");<br>+    if (param->scenecutThreshold)<br>+    {<br>+        CHECK(param->scenecutBias < 0 || 100 < param->scenecutBias,<br>+            "scenecut-bias must be between 0 and 100");<br>+    }<br>+    else if (param->bHistBasedSceneCut)<br>+    {<br>+        CHECK(param->edgeTransitionThreshold < 0.0 || 2.0 < param->edgeTransitionThreshold,<br>+            "hist-threshold must be between 0.0 and 2.0");<br>+    }<br>     CHECK(param->radl < 0 || param->radl > param->bframes,<br>           "radl must be between 0 and bframes");<br>     CHECK(param->rdPenalty < 0 || param->rdPenalty > 2,<br>@@ -1792,9 +1849,13 @@<br>         x265_log(param, X265_LOG_INFO, "ME / range / subpel / merge         : %s / %d / %d / %d\n",<br>             x265_motion_est_names[param->searchMethod], param->searchRange, param->subpelRefine, param->maxNumMergeCand);<br> <br>-    if (param->keyframeMax != INT_MAX || param->scenecutThreshold)<br>-        x265_log(param, X265_LOG_INFO, "Keyframe min / max / scenecut / bias: %d / %d / %d / %.2lf\n", param->keyframeMin, param->keyframeMax, param->scenecutThreshold, param->scenecutBias * 100);<br>-    else<br>+    if (param->scenecutThreshold && param->keyframeMax != INT_MAX) <br>+        x265_log(param, X265_LOG_INFO, "Keyframe min / max / scenecut / bias  : %d / %d / %d / %.2lf \n",<br>+                 param->keyframeMin, param->keyframeMax, param->scenecutThreshold, param->scenecutBias * 100);<br>+    else if (param->bHistBasedSceneCut && param->keyframeMax != INT_MAX) <br>+        x265_log(param, X265_LOG_INFO, "Keyframe min / max / scenecut / edge threshold  : %d / %d / %d / %.2lf\n",<br>+                 param->keyframeMin, param->keyframeMax, param->bHistBasedSceneCut, param->edgeTransitionThreshold);<br>+    else if (param->keyframeMax == INT_MAX)<br>         x265_log(param, X265_LOG_INFO, "Keyframe min / max / scenecut       : disabled\n");<br> <br>     if (param->cbQpOffset || param->crQpOffset)<br>@@ -1961,6 +2022,8 @@<br>     s += sprintf(s, " rc-lookahead=%d", p->lookaheadDepth);<br>     s += sprintf(s, " lookahead-slices=%d", p->lookaheadSlices);<br>     s += sprintf(s, " scenecut=%d", p->scenecutThreshold);<br>+    s += sprintf(s, " hist-scenecut=%d", p->bHistBasedSceneCut);<br>+    s += sprintf(s, " hist-threshold=%.2f", p->edgeTransitionThreshold);<br>     s += sprintf(s, " radl=%d", p->radl);<br>     BOOL(p->bEnableHRDConcatFlag, "splice");<br>     BOOL(p->bIntraRefresh, "intra-refresh");<br>@@ -2108,6 +2171,8 @@<br>     BOOL(p->bOptRefListLengthPPS, "opt-ref-list-length-pps");<br>     BOOL(p->bMultiPassOptRPS, "multi-pass-opt-rps");<br>     s += sprintf(s, " scenecut-bias=%.2f", p->scenecutBias);<br>+    s += sprintf(s, " hist-threshold=%.2f", p->edgeTransitionThreshold);<br>+ </div></blockquote><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">Added twice; Please remove one.</div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">     BOOL(p->bOptCUDeltaQP, "opt-cu-delta-qp");<br>     BOOL(p->bAQMotion, "aq-motion");<br>     BOOL(p->bEmitHDRSEI, "hdr");<br>@@ -2261,6 +2326,7 @@<br>     dst->lookaheadSlices = src->lookaheadSlices;<br>     dst->lookaheadThreads = src->lookaheadThreads;<br>     dst->scenecutThreshold = src->scenecutThreshold;<br>+    dst->bHistBasedSceneCut = src->bHistBasedSceneCut;<br>     dst->bIntraRefresh = src->bIntraRefresh;<br>     dst->maxCUSize = src->maxCUSize;<br>     dst->minCUSize = src->minCUSize;<br>@@ -2420,6 +2486,7 @@<br>     dst->bOptRefListLengthPPS = src->bOptRefListLengthPPS;<br>     dst->bMultiPassOptRPS = src->bMultiPassOptRPS;<br>     dst->scenecutBias = src->scenecutBias;<br>+    dst->edgeTransitionThreshold = src->edgeTransitionThreshold;<br>     dst->gopLookahead = src->lookaheadDepth;<br>     dst->bOptCUDeltaQP = src->bOptCUDeltaQP;<br>     dst->analysisMultiPassDistortion = src->analysisMultiPassDistortion;<br>diff -r 04db2bfee5d6 -r 40beab295ca2 source/encoder/encoder.cpp<br>--- a/source/encoder/encoder.cpp Thu Oct 31 16:23:27 2019 +0530<br>+++ b/source/encoder/encoder.cpp        Wed Nov 13 18:18:31 2019 +0530<br>@@ -130,12 +130,17 @@<br> #if SVT_HEVC<br>     m_svtAppData = NULL;<br> #endif<br>-<br>     m_prevTonemapPayload.payload = NULL;<br>     m_startPoint = 0;<br>     m_saveCTUSize = 0;<br>+    m_edgePic = NULL;<br>+    m_edgeHistThreshold = 0;<br>+    m_chromaHistThreshold = 0.0;<br>+    m_scaledEdgeThreshold = 0.0;<br>+    m_scaledChromaThreshold = 0.0;<br>     m_zoneIndex = 0;<br> }<br>+<br> inline char *strcatFilename(const char *input, const char *suffix)<br> {<br>     char *output = X265_MALLOC(char, strlen(input) + strlen(suffix) + 1);<br>@@ -210,6 +215,24 @@<br>         }<br>     }<br> <br>+    if (m_param->bHistBasedSceneCut)<br>+    {<br>+        for (int i = 0; i < x265_cli_csps[m_param->internalCsp].planes; i++)<br>+        {<br>+            m_planeSizes[i] = m_param->sourceWidth * m_param->sourceHeight >> x265_cli_csps[m_param->internalCsp].height[i];<br>+        }<br>+        uint32_t pixelbytes = m_param->sourceBitDepth > 8 ? 2 : 1;<br>+        m_edgePic = X265_MALLOC(pixel, m_planeSizes[0]*pixelbytes);<br></div></blockquote><div>Indentation issue //

m_planeSizes[0]*pixelbytes

</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">+        double strengthFactor = 2.0;<br></div></blockquote><div>Replace the constant with a macro </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">+        m_edgeHistThreshold = m_param->edgeTransitionThreshold;<br>+        m_chromaHistThreshold = m_edgeHistThreshold * 10.0;<br>+        m_chromaHistThreshold = x265_min(m_chromaHistThreshold, MAX_SCENECUT_THRESHOLD);<br>+        m_scaledEdgeThreshold = m_edgeHistThreshold * strengthFactor;<br>+        m_scaledEdgeThreshold = x265_min(m_scaledEdgeThreshold, MAX_SCENECUT_THRESHOLD);<br>+        m_scaledChromaThreshold = m_chromaHistThreshold * strengthFactor;<br>+        m_scaledChromaThreshold = x265_min(m_scaledChromaThreshold, MAX_SCENECUT_THRESHOLD);<br>+    }<br>+<br>     // Do not allow WPP if only one row or fewer than 3 columns, it is pointless and unstable<br>     if (rows == 1 || cols < 3)<br>     {<br>@@ -854,6 +877,12 @@<br>         }<br>     }<br> <br>+    if (m_param->bHistBasedSceneCut)<br>+    {<br>+        if(m_edgePic != NULL)<br>+           X265_FREE_ZERO(m_edgePic);<br>+    }<br>+<br>     for (int i = 0; i < m_param->frameNumThreads; i++)<br>     {<br>         if (m_frameEncoder[i])<br>@@ -1313,6 +1342,141 @@<br>     dest->planes[2] = (char*)dest->planes[1] + src->stride[1] * (src->height >> x265_cli_csps[src->colorSpace].height[1]);<br> }<br> <br>+bool Encoder::computeHistograms(x265_picture *pic)<br>+{<br>+    pixel *src = (pixel*)pic->planes[0];<br>+    size_t bufSize = sizeof(pixel) * m_planeSizes[0];<br>+    int32_t planeCount = x265_cli_csps[m_param->internalCsp].planes;<br>+    int32_t numBytes = m_param->sourceBitDepth > 8 ? 2 : 1;<br>+    memset(m_edgePic, 0, bufSize*numBytes);<br>+<br>+    if (!computeEdge(m_edgePic, src, NULL, pic->width, pic->height, pic->width, false))<br>+    {<br>+       x265_log(m_param, X265_LOG_ERROR, "Failed edge computation!");<br>+       return false;<br>+    }<br>+<br>+    pixel pixelVal;<br>+    int64_t size = pic->height * (pic->stride[0] >> SHIFT);<br>+    int32_t *edgeHist = m_curEdgeHist;<br>+    memset(edgeHist, 0, 2 * sizeof(int32_t));<br>+    for (int64_t i = 0; i < size; i++)<br>+    {<br>+        if (!m_edgePic[i])<br>+           edgeHist[0]++;<br>+        else<br>+           edgeHist[1]++;<br>+    }<br>+<br>+    /*U Histogram Calculation*/<br>+    int32_t HeightL = (pic->height >> x265_cli_csps[pic->colorSpace].height[1]);<br>+    size = HeightL * (pic->stride[1] >> SHIFT);<br>+    int32_t *uHist = m_curUVHist[0];<br>+    pixel *chromaPlane = (pixel *)pic->planes[1];<br></div></blockquote><div>Encoder crashes with X265_CSP_I400 input; You need to check the CSP type before accessing the UV planes.<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">+ </div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">+    memset(uHist, 0, HISTOGRAM_BINS * sizeof(int32_t));<br>+<br>+    for (int64_t i = 0; i < size; i++)<br>+    {<br>+        pixelVal = chromaPlane[i];<br>+        uHist[pixelVal]++;<br>+    }<br>+<br>+    /*V Histogram Calculation */<br>+    if (planeCount == 3)</div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">+    {<br>+        pixelVal = 0;<br>+        int32_t heightV = (pic->height >> x265_cli_csps[pic->colorSpace].height[2]);<br>+        size = heightV * (pic->stride[2] >> SHIFT);<br>+        int32_t *vHist = m_curUVHist[1];<br>+        chromaPlane = (pixel *)pic->planes[2];<br>+<br>+        memset(vHist, 0, HISTOGRAM_BINS * sizeof(int32_t));<br>+        for (int64_t i = 0; i < size; i++)<br>+        {<br>+            pixelVal = chromaPlane[i];<br>+            vHist[pixelVal]++;<br>+        }<br>+        for (int i = 0; i < HISTOGRAM_BINS; i++)<br>+        {<br>+            m_curMaxUVHist[i] = x265_max(uHist[i],vHist[i]);<br></div></blockquote><div>Intendation issue </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">+        }<br>+    }<br>+    else<br>+    {   /* in case of bi planar color space */<br>+        memcpy(m_curMaxUVHist,m_curUVHist[0],HISTOGRAM_BINS*sizeof(int32_t));<br></div></blockquote><div>Intendation issue </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">+    }<br>+<br>+    return true;<br>+}<br>+<br>+void Encoder::computeHistogramSAD(double *maxUVNormalizedSad, double *edgeNormalizedSad, int curPoc)<br>+{<br>+<br>+    if (curPoc == 0)<br>+    {  /* first frame is scenecut by default no sad computation for the same. */<br>+       *maxUVNormalizedSad = 0.0;<br>+       *edgeNormalizedSad  = 0.0;<br>+    }<br>+    else<br>+    {<br>+        /* compute sum of absolute difference of normalized histogram bins for maxUV and edge histograms. */<br>+        int32_t edgefreqDiff = 0;<br>+        int32_t maxUVfreqDiff = 0;<br>+        double  edgeProbabilityDiff = 0;<br>+<br>+        for (int j = 0; j < HISTOGRAM_BINS; j++)<br>+        {<br>+            if (j < 2 )<br></div></blockquote><div>indentation issue </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">+            {<br>+               edgefreqDiff = abs(m_curEdgeHist[j] - m_prevEdgeHist[j]);<br>+               edgeProbabilityDiff = (double) edgefreqDiff / m_planeSizes[0];<br>+               *edgeNormalizedSad += edgeProbabilityDiff;<br>+            }<br>+            maxUVfreqDiff = abs(m_curMaxUVHist[j] - m_prevMaxUVHist[j]);<br>+            *maxUVNormalizedSad += (double)maxUVfreqDiff / m_planeSizes[2];<br>+        }<br>+    }<br>+<br>+    /* store histograms of previous frame for reference */<br>+    size_t bufsize = HISTOGRAM_BINS * sizeof(int32_t);<br>+    memcpy(m_prevMaxUVHist, m_curMaxUVHist, bufsize);<br>+    memcpy(m_prevEdgeHist, m_curEdgeHist, 2*sizeof(int32_t));<br></div></blockquote><div>

indentation issue 

 </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">+<br>+}<br>+<br>+void Encoder::findSceneCuts(x265_picture * pic, bool& bDup, double maxUVSad, double edgeSad)<br>+{<br>+    pic->frameData.bScenecut = false;<br>+<br>+    if (pic->poc == 0)<br>+    {<br>+       /* for first frame */<br>+       pic->frameData.bScenecut = false;<br>+       bDup = false;<br>+    }<br>+    else<br>+    {<br>+        if (edgeSad == 0.0 && maxUVSad == 0.0)<br>+        {<br>+           bDup = true;<br>+        }<br>+        else if (edgeSad > m_edgeHistThreshold && maxUVSad >= m_chromaHistThreshold)<br>+        {<br>+             pic->frameData.bScenecut = true;<br>+             bDup = false;<br>+        }<br>+        else if (edgeSad > m_scaledEdgeThreshold || maxUVSad >= m_scaledChromaThreshold)<br>+        {<br>+             pic->frameData.bScenecut = true;<br>+             bDup = false;<br>+        }<br>+    }<br>+<br>+    if (pic->frameData.bScenecut)<br>+       x265_log(m_param, X265_LOG_DEBUG, "scene cut at %d \n",pic->poc);<br></div></blockquote><div>

indentation issue 

 </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">+}<br>+<br> /**<br>  * Feed one new input frame into the encoder, get one frame out. If pic_in is<br>  * NULL, a flush condition is implied and pic_in must be NULL for all subsequent<br>@@ -1339,6 +1503,8 @@<br>     const x265_picture* inputPic = NULL;<br>     static int written = 0, read = 0;<br>     bool dontRead = false;<br>+    bool bdropFrame = false;<br>+    bool dropflag = false;<br> <br>     if (m_exportedPic)<br>     {<br>@@ -1350,6 +1516,17 @@<br>     }<br>     if ((pic_in && (!m_param->chunkEnd || (m_encodedFrameNum < m_param->chunkEnd))) || (m_param->bEnableFrameDuplication && !pic_in && (read < written)))<br>     {<br>+        if (m_param->bHistBasedSceneCut && pic_in)<br>+        {<br>+            x265_picture *pic = (x265_picture *) pic_in;<br>+            if (computeHistograms(pic))<br>+            {<br>+               double  maxUVSad = 0.0, edgeSad = 0.0;<br>+               computeHistogramSAD(&maxUVSad, &edgeSad,pic_in->poc);<br></div></blockquote><div>indentation issue. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">+               findSceneCuts(pic, bdropFrame, maxUVSad, edgeSad);<br>+            }<br>+        }<br>+<br>         if ((m_param->bEnableFrameDuplication && !pic_in && (read < written)))<br>             dontRead = true;<br>         else<br>@@ -1393,9 +1570,27 @@<br>                     written++;<br>                 }<br> <br>-                psnrWeight = ComputePSNR(m_dupBuffer[0]->dupPic, m_dupBuffer[1]->dupPic, m_param);<br>-<br>-                if (psnrWeight >= m_param->dupThreshold)<br>+                if (m_param->bEnableFrameDuplication && m_param->bHistBasedSceneCut)<br>+                {<br>+                    if (!bdropFrame && m_dupBuffer[1]->dupPic->frameData.bScenecut == false)<br>+                    {<br>+                       psnrWeight = ComputePSNR(m_dupBuffer[0]->dupPic, m_dupBuffer[1]->dupPic, m_param);<br>+                       if (psnrWeight >= m_param->dupThreshold)<br>+                          dropflag = true;<br>+                    }<br>+                    else<br>+                    {<br>+                       dropflag = true;<br>+                    }<br>+                }<br>+                else if (m_param->bEnableFrameDuplication)<br>+                {<br>+                    psnrWeight = ComputePSNR(m_dupBuffer[0]->dupPic, m_dupBuffer[1]->dupPic, m_param);<br>+                    if (psnrWeight >= m_param->dupThreshold)<br>+                       dropflag = true;<br>+                }<br>+<br>+                if (dropflag)<br>                 {<br>                     if (m_dupBuffer[0]->bDup)<br>                     {<br>@@ -1498,6 +1693,10 @@<br>         inFrame->m_poc       = ++m_pocLast;<br>         inFrame->m_userData  = inputPic->userData;<br>         inFrame->m_pts       = inputPic->pts;<br>+        if (m_param->bHistBasedSceneCut)<br>+        {<br>+           inFrame->m_lowres.bScenecut = inputPic->frameData.bScenecut;<br>+        }<br>         inFrame->m_forceqp   = inputPic->forceqp;<br>         inFrame->m_param     = (m_reconfigure || m_reconfigureRc) ? m_latestParam : m_param;<br>         inFrame->m_picStruct = inputPic->picStruct;<br>@@ -3209,6 +3408,7 @@<br>          * adaptive I frame placement */<br>         p->keyframeMax = INT_MAX;<br>         p->scenecutThreshold = 0;<br>+        p->bHistBasedSceneCut = 0;<br>     }<br>     else if (p->keyframeMax <= 1)<br>     {<br>@@ -3222,6 +3422,7 @@<br>         p->lookaheadDepth = 0;<br>         p->bframes = 0;<br>         p->scenecutThreshold = 0;<br>+        p->bHistBasedSceneCut = 0;<br>         p->bFrameAdaptive = 0;<br>         p->rc.cuTree = 0;<br>         p->bEnableWeightedPred = 0;<br>@@ -3881,6 +4082,17 @@<br>             m_param->searchMethod = m_param->hmeSearchMethod[2];<br>         }<br>     }<br>+<br>+    if (p->scenecutThreshold && p->edgeTransitionThreshold != 0.01)<br>+    {<br></div></blockquote><div>float point comparison; might result in rounding errors. <br></div><div>Also, why are you checking 

 p->edgeTransitionThreshold when naive scenecut algorithm is enabled?</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">+       x265_log(p, X265_LOG_WARNING, "using default scenecut-bias %.2lf for scene cut detection\n",p->scenecutBias);<br>+    }<br>+    else if (p->bHistBasedSceneCut && p->edgeTransitionThreshold == 0.0)<br></div></blockquote><div>

float point comparison; might result in rounding errors. 

 </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">+    {<br>+         p->edgeTransitionThreshold = 0.01;<br>+         x265_log(p, X265_LOG_WARNING, "using  default threshold %.2lf for scene cut detection\n", p->edgeTransitionThreshold);<br>+    }<br>+<br> }<br> <br> void Encoder::readAnalysisFile(x265_analysis_data* analysis, int curPoc, const x265_picture* picIn, int paramBytes)<br>diff -r 04db2bfee5d6 -r 40beab295ca2 source/encoder/encoder.h<br>--- a/source/encoder/encoder.h Thu Oct 31 16:23:27 2019 +0530<br>+++ b/source/encoder/encoder.h  Wed Nov 13 18:18:31 2019 +0530<br>@@ -156,7 +156,6 @@<br>     bool bDup;<br> };<br> <br>-<br> class FrameEncoder;<br> class DPB;<br> class Lookahead;<br>@@ -164,6 +163,8 @@<br> class ThreadPool;<br> class FrameData;<br> <br>+#define MAX_SCENECUT_THRESHOLD 2.0<br>+<br> class Encoder : public x265_encoder<br> {<br> public:<br>@@ -228,7 +229,7 @@<br>     bool               m_reconfigureRc;<br>     bool               m_reconfigureZone;<br> <br>-    int               m_saveCtuDistortionLevel;<br>+    int                m_saveCtuDistortionLevel;<br> <br>     /* Begin intra refresh when one not in progress or else begin one as soon as the current <br>      * one is done. Requires bIntraRefresh to be set.*/<br>@@ -245,11 +246,24 @@<br>     Lock               m_rpsInSpsLock;<br>     int                m_rpsInSpsCount;<br>     /* For HDR*/<br>-    double                m_cB;<br>-    double                m_cR;<br>+    double             m_cB;<br>+    double             m_cR;<br>+<br>+    int                m_bToneMap; // Enables tone-mapping<br>+    int                m_enableNal;<br> <br>-    int                     m_bToneMap; // Enables tone-mapping<br>-    int                     m_enableNal;<br>+    /* For histogram based scene-cut detection */<br>+    pixel*             m_edgePic;<br>+    int32_t            m_curUVHist[2][HISTOGRAM_BINS];<br>+    int32_t            m_curMaxUVHist[HISTOGRAM_BINS];<br>+    int32_t            m_prevMaxUVHist[HISTOGRAM_BINS];<br>+    int32_t            m_curEdgeHist[2];<br>+    int32_t            m_prevEdgeHist[2];<br>+    uint32_t           m_planeSizes[3];<br>+    double             m_edgeHistThreshold;<br>+    double             m_chromaHistThreshold;<br>+    double             m_scaledEdgeThreshold;<br>+    double             m_scaledChromaThreshold;<br> <br> #ifdef ENABLE_HDR10_PLUS<br>     const hdr10plus_api     *m_hdr10plus_api;<br>@@ -355,6 +369,10 @@<br> <br>     void copyPicture(x265_picture *dest, const x265_picture *src);<br> <br>+    bool computeHistograms(x265_picture *pic);<br>+    void computeHistogramSAD(double *maxUVNormalizedSAD, double *edgeNormalizedSAD, int curPoc);<br>+    void findSceneCuts(x265_picture * pic, bool& bDup, double m_maxUVSADVal, double m_edgeSADVal);<br>+<br>     void initRefIdx();<br>     void analyseRefIdx(int *numRefIdx);<br>     void updateRefIdx();<br>diff -r 04db2bfee5d6 -r 40beab295ca2 source/encoder/ratecontrol.cpp<br>--- a/source/encoder/ratecontrol.cpp    Thu Oct 31 16:23:27 2019 +0530<br>+++ b/source/encoder/ratecontrol.cpp    Wed Nov 13 18:18:31 2019 +0530<br>@@ -508,6 +508,7 @@<br>                 CMP_OPT_FIRST_PASS("open-gop", m_param->bOpenGOP);<br>                 CMP_OPT_FIRST_PASS(" keyint", m_param->keyframeMax);<br>                 CMP_OPT_FIRST_PASS("scenecut", m_param->scenecutThreshold);<br>+                CMP_OPT_FIRST_PASS("hist-threshold", m_param->edgeTransitionThreshold);<br>                 CMP_OPT_FIRST_PASS("intra-refresh", m_param->bIntraRefresh);<br>                 if (m_param->bMultiPassOptRPS)<br>                 {<br>@@ -1200,6 +1201,7 @@<br>             m_param->rc.bStatRead = 0;<br>             m_param->bFrameAdaptive = 0;<br>             m_param->scenecutThreshold = 0;<br>+            m_param->bHistBasedSceneCut = false;<br>             m_param->rc.cuTree = 0;<br>             if (m_param->bframes > 1)<br>                 m_param->bframes = 1;<br>@@ -2284,7 +2286,7 @@<br>     if (m_isVbv && m_currentSatd > 0 && curFrame)<br>     {<br>         if (m_param->lookaheadDepth || m_param->rc.cuTree ||<br>-            m_param->scenecutThreshold ||<br>+            (m_param->scenecutThreshold || m_param->bHistBasedSceneCut) ||<br>             (m_param->bFrameAdaptive && m_param->bframes))<br>         {<br>            /* Lookahead VBV: If lookahead is done, raise the quantizer as necessary<br>diff -r 04db2bfee5d6 -r 40beab295ca2 source/encoder/slicetype.cpp<br>--- a/source/encoder/slicetype.cpp     Thu Oct 31 16:23:27 2019 +0530<br>+++ b/source/encoder/slicetype.cpp      Wed Nov 13 18:18:31 2019 +0530<br>@@ -85,6 +85,69 @@<br> <br> } // end anonymous namespace<br> <br>+namespace X265_NS {<br>+<br>+bool computeEdge(pixel *edgePic, pixel *refPic, pixel *edgeTheta, intptr_t stride, int height, int width, bool bcalcTheta)<br>+{<br>+    intptr_t rowOne = 0, rowTwo = 0, rowThree = 0, colOne = 0, colTwo = 0, colThree = 0;<br>+    intptr_t middle = 0, topLeft = 0, topRight = 0, bottomLeft = 0, bottomRight = 0;<br>+<br>+    const int startIndex = 1;<br>+<br>+    if (!edgePic || !refPic || (!edgeTheta && bcalcTheta))<br>+    {<br>+        return false;<br>+    }<br>+    else<br>+    {<br>+        float gradientH = 0, gradientV = 0, radians = 0, theta = 0;<br>+        float gradientMagnitude = 0;<br>+        pixel blackPixel = 0;<br>+<br>+        //Applying Sobel filter expect for border pixels<br>+        height = height - startIndex;<br>+        width = width - startIndex;<br>+        for (int rowNum = startIndex; rowNum < height; rowNum++)<br>+        {<br>+            rowTwo = rowNum * stride;<br>+            rowOne = rowTwo - stride;<br>+            rowThree = rowTwo + stride;<br>+<br>+            for (int colNum = startIndex; colNum < width; colNum++)<br>+            {<br>+<br>+                /* Horizontal and vertical gradients<br>+                [ -3   0   3 ]        [-3   -10  -3 ]<br>+            gH =[ -10  0   10]   gV = [ 0    0    0 ]<br>+                [ -3   0   3 ]        [ 3    10   3 ] */<br>+<br>+                colTwo = colNum;<br>+                colOne = colTwo - startIndex;<br>+                colThree = colTwo + startIndex;<br>+                middle = rowTwo + colTwo;<br>+                topLeft = rowOne + colOne;<br>+                topRight = rowOne + colThree;<br>+                bottomLeft = rowThree + colOne;<br>+                bottomRight = rowThree + colThree;<br>+                gradientH = (float)(-3 * refPic[topLeft] + 3 * refPic[topRight] - 10 * refPic[rowTwo + colOne] + 10 * refPic[rowTwo + colThree] - 3 * refPic[bottomLeft] + 3 * refPic[bottomRight]);<br>+                gradientV = (float)(-3 * refPic[topLeft] - 10 * refPic[rowOne + colTwo] - 3 * refPic[topRight] + 3 * refPic[bottomLeft] + 10 * refPic[rowThree + colTwo] + 3 * refPic[bottomRight]);<br>+                gradientMagnitude = sqrtf(gradientH * gradientH + gradientV * gradientV);<br>+                if(bcalcTheta) <br>+                  {<br>+                    edgeTheta[middle] = 0;<br>+                    radians = atan2(gradientV, gradientH);<br>+                    theta = (float)((radians * 180) / PI);<br>+                    if (theta < 0)<br>+                       theta = 180 + theta;<br>+                    edgeTheta[middle] = (pixel)theta;<br>+                  }<br>+                edgePic[middle] = (pixel)(gradientMagnitude >= edgeThreshold ? edgeThreshold : blackPixel);<br>+            }<br>+        }<br>+        return true;<br>+    }<br>+}<br>+<br> void edgeFilter(Frame *curFrame, x265_param* param)<br> {<br>     int height = curFrame->m_fencPic->m_picHeight;<br>@@ -114,6 +177,7 @@<br>     //Applying Gaussian filter on the picture<br>     src = (pixel*)curFrame->m_fencPic->m_picOrg[0];<br>     refPic = curFrame->m_gaussianPic + curFrame->m_fencPic->m_lumaMarginY * stride + curFrame->m_fencPic->m_lumaMarginX;<br>+    edgePic = curFrame->m_edgePic + curFrame->m_fencPic->m_lumaMarginY * stride + curFrame->m_fencPic->m_lumaMarginX;<br>     pixel pixelValue = 0;<br> <br>     for (int rowNum = 0; rowNum < height; rowNum++)<br>@@ -146,51 +210,8 @@<br>         }<br>     }<br> <br>-#if HIGH_BIT_DEPTH //10-bit build<br>-    float threshold = 1023;<br>-    pixel whitePixel = 1023;<br>-#else<br>-    float threshold = 255;<br>-    pixel whitePixel = 255;<br>-#endif<br>-#define PI 3.14159265 <br>-<br>-    float gradientH = 0, gradientV = 0, radians = 0, theta = 0;<br>-    float gradientMagnitude = 0;<br>-    pixel blackPixel = 0;<br>-    edgePic = curFrame->m_edgePic + curFrame->m_fencPic->m_lumaMarginY * stride + curFrame->m_fencPic->m_lumaMarginX;<br>-    //Applying Sobel filter on the gaussian filtered picture<br>-    for (int rowNum = 0; rowNum < height; rowNum++)<br>-    {<br>-        for (int colNum = 0; colNum < width; colNum++)<br>-        {<br>-            edgeTheta[(rowNum*stride) + colNum] = 0;<br>-            if ((rowNum != 0) && (colNum != 0) && (rowNum != height - 1) && (colNum != width - 1)) //Ignoring the border pixels of the picture<br>-            {<br>-                /*Horizontal and vertical gradients<br>-                       [ -3   0   3 ]        [-3   -10  -3 ]<br>-                  gH = [ -10  0   10]   gV = [ 0    0    0 ]<br>-                       [ -3   0   3 ]        [ 3    10   3 ]*/<br>-<br>-                const intptr_t rowOne = (rowNum - 1)*stride, colOne = colNum -1;<br>-                const intptr_t rowTwo = rowNum * stride, colTwo = colNum;<br>-                const intptr_t rowThree = (rowNum + 1)*stride, colThree = colNum + 1;<br>-                const intptr_t index = (rowNum*stride) + colNum;<br>-<br>-                gradientH = (float)(-3 * refPic[rowOne + colOne] + 3 * refPic[rowOne + colThree] - 10 * refPic[rowTwo + colOne] + 10 * refPic[rowTwo + colThree] - 3 * refPic[rowThree + colOne] + 3 * refPic[rowThree + colThree]);<br>-                gradientV = (float)(-3 * refPic[rowOne + colOne] - 10 * refPic[rowOne + colTwo] - 3 * refPic[rowOne + colThree] + 3 * refPic[rowThree + colOne] + 10 * refPic[rowThree + colTwo] + 3 * refPic[rowThree + colThree]);<br>-<br>-                gradientMagnitude = sqrtf(gradientH * gradientH + gradientV * gradientV);<br>-                radians = atan2(gradientV, gradientH);<br>-                theta = (float)((radians * 180) / PI);<br>-                if (theta < 0)<br>-                    theta = 180 + theta;<br>-                edgeTheta[(rowNum*stride) + colNum] = (pixel)theta;<br>-<br>-                edgePic[index] = gradientMagnitude >= threshold ? whitePixel : blackPixel;<br>-            }<br>-        }<br>-    }<br>+    if(!computeEdge(edgePic, refPic, edgeTheta, stride, height, width, true))<br>+        x265_log(NULL, X265_LOG_ERROR, "Failed edge computation!");<br> }<br> <br> //Find the angle of a block by averaging the pixel angles <br>@@ -1471,7 +1492,7 @@<br> <br>     if (m_lastNonB && !m_param->rc.bStatRead &&<br>         ((m_param->bFrameAdaptive && m_param->bframes) ||<br>-         m_param->rc.cuTree || m_param->scenecutThreshold ||<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>@@ -1971,10 +1992,15 @@<br> <br>     int numBFrames = 0;<br>     int numAnalyzed = numFrames;<br>-    bool isScenecut = scenecut(frames, 0, 1, true, origNumFrames);<br>+    bool isScenecut = false;<br> <br>     /* When scenecut threshold is set, use scenecut detection for I frame placements */<br>-    if (m_param->scenecutThreshold && isScenecut)<br>+    if (m_param->scenecutThreshold)<br>+        isScenecut = scenecut(frames, 0, 1, true, origNumFrames);<br>+    else if (m_param->bHistBasedSceneCut)<br>+        isScenecut = frames[1]->bScenecut;<br>+<br>+    if (isScenecut)<br>     {<br>         frames[1]->sliceType = X265_TYPE_I;<br>         return;<br>@@ -1985,14 +2011,17 @@<br>         m_extendGopBoundary = false;<br>         for (int i = m_param->bframes + 1; i < origNumFrames; i += m_param->bframes + 1)<br>         {<br>-            scenecut(frames, i, i + 1, true, origNumFrames);<br>+            if (m_param->scenecutThreshold)<br>+               scenecut(frames, i, i + 1, true, origNumFrames);<br>+<br>             for (int j = i + 1; j <= X265_MIN(i + m_param->bframes + 1, origNumFrames); j++)<br>             {<br>-                if (frames[j]->bScenecut && scenecutInternal(frames, j - 1, j, true) )<br>-                {<br>-                    m_extendGopBoundary = true;<br>-                    break;<br>-                }<br>+                if (( m_param->scenecutThreshold && frames[j]->bScenecut && scenecutInternal(frames, j - 1, j, true)) || <br>+                    (m_param->bHistBasedSceneCut && frames[j]->bScenecut))<br>+                    {<br>+                        m_extendGopBoundary = true;<br>+                        break;<br>+                    }<br>             }<br>             if (m_extendGopBoundary)<br>                 break;<br>@@ -2097,13 +2126,14 @@<br>         {<br>             for (int j = 1; j < numBFrames + 1; j++)<br>             {<br>-                if (scenecut(frames, j, j + 1, false, origNumFrames) || <br>+                if ((m_param->scenecutThreshold && scenecut(frames, j, j + 1, false, origNumFrames)) ||<br>+                    (m_param->bHistBasedSceneCut && frames[j + 1]->bScenecut) ||<br>                     (bForceRADL && (frames[j]->frameNum == preRADL)))<br>-                {<br>-                    frames[j]->sliceType = X265_TYPE_P;<br>-                    numAnalyzed = j;<br>-                    break;<br>-                }<br>+                    {<br>+                        frames[j]->sliceType = X265_TYPE_P;<br>+                        numAnalyzed = j;<br>+                        break;<br>+                    }<br>             }<br>         }<br>         resetStart = bKeyframe ? 1 : X265_MIN(numBFrames + 2, numAnalyzed + 1);<br>@@ -3289,3 +3319,5 @@<br>     fenc->rowSatds[b - p0][p1 - b][cuY] += bcostAq;<br>     fenc->lowresCosts[b - p0][p1 - b][cuXY] = (uint16_t)(X265_MIN(bcost, LOWRES_COST_MASK) | (listused << LOWRES_COST_SHIFT));<br> }<br>+<br>+}<br>diff -r 04db2bfee5d6 -r 40beab295ca2 source/encoder/slicetype.h<br>--- a/source/encoder/slicetype.h    Thu Oct 31 16:23:27 2019 +0530<br>+++ b/source/encoder/slicetype.h        Wed Nov 13 18:18:31 2019 +0530<br>@@ -43,6 +43,13 @@<br> #define AQ_EDGE_BIAS 0.5<br> #define EDGE_INCLINATION 45<br> <br>+#ifdef HIGH_BIT_DEPTH<br>+#define edgeThreshold 1023.0<br>+#else<br>+#define edgeThreshold 255.0<br>+#endif<br>+#define PI 3.14159265<br>+<br> /* Thread local data for lookahead tasks */<br> struct LookaheadTLD<br> {<br>@@ -258,6 +265,7 @@<br>     CostEstimateGroup& operator=(const CostEstimateGroup&);<br> };<br> <br>-}<br>+bool computeEdge(pixel *edgePic, pixel *refPic, pixel *edgeTheta, intptr_t stride, int height, int width, bool bcalcTheta);<br> <br>+}<br> #endif // ifndef X265_SLICETYPE_H<br>diff -r 04db2bfee5d6 -r 40beab295ca2 source/test/regression-tests.txt<br>--- a/source/test/regression-tests.txt     Thu Oct 31 16:23:27 2019 +0530<br>+++ b/source/test/regression-tests.txt  Wed Nov 13 18:18:31 2019 +0530<br>@@ -159,6 +159,7 @@<br> Traffic_4096x2048_30p.y4m, --preset medium --frame-dup --dup-threshold 60 --hrd --bitrate 10000 --vbv-bufsize 15000 --vbv-maxrate 12000<br> Kimono1_1920x1080_24_400.yuv,--preset superfast --qp 28 --zones 0,139,q=32<br> Island_960x540_420p_8bit_24fps.yuv,--no-cutree --aq-mode 0 --bitrate 6000 --scenecut-aware-qp<br>+sintel_trailer_2k_1920x1080_24.yuv, --preset medium --hist-scenecut --hist-threshold 0.02 --frame-dup --dup-threshold 60 --hrd --bitrate 10000 --vbv-bufsize 15000 --vbv-maxrate 12000<br></div></blockquote><div>Please add one more CLI to test the functionality of hist-scenecut in the absence of frame duplication. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr"> <br> # Main12 intraCost overflow bug test<br> 720p50_parkrun_ter.y4m,--preset medium<br>diff -r 04db2bfee5d6 -r 40beab295ca2 source/x265.h<br>--- a/source/x265.h        Thu Oct 31 16:23:27 2019 +0530<br>+++ b/source/x265.h     Wed Nov 13 18:18:31 2019 +0530<br>@@ -211,7 +211,7 @@<br>     uint32_t                          numCUsInFrame;<br>     uint32_t                          numPartitions;<br>     uint32_t                          depthBytes;<br>-    int                               bScenecut;<br>+    bool                              bScenecut;<br></div></blockquote><div>This will affect backward compatibility. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">     x265_weight_param*                wt;<br>     x265_analysis_inter_data*         interData;<br>     x265_analysis_intra_data*         intraData;<br>@@ -294,7 +294,7 @@<br>     double           avgChromaVLevel;<br> <br>     char             sliceType;<br>-    int              bScenecut;<br>+    bool             bScenecut;<br></div></blockquote><div>Affects backward compatibility. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr">     double           ipCostRatio;<br>     int              frameLatency;<br>     x265_cu_stats    cuStats;<br>@@ -1024,7 +1024,8 @@<br>     int       lookaheadSlices;<br> <br>     /* An arbitrary threshold which determines how aggressively the lookahead<br>-     * should detect scene cuts. The default (40) is recommended. */<br>+     * should detect scene cuts for cost based scenecut detection. <br>+     * The default (40) is recommended. */<br>     int       scenecutThreshold;<br> <br>     /* Replace keyframes by using a column of intra blocks that move across the video<br>@@ -1846,6 +1847,16 @@<br>     /* The offset by which QP is incremented for inter-frames when bEnableSceneCutAwareQp is set.<br>      * Default is +5. */<br>     int       maxQpDelta;<br>+ <br>+    /* A genuine threshold used for histogram based scene cut detection.<br>+      * This threshold determines whether a frame is a scenecut or not<br>+      * when compared against the edge and chroma histogram sad values.<br>+      * Default 0.01. Range: Real number in the interval (0,2). */<br>+      double    edgeTransitionThreshold;<br>+<br>+    /* Enables histogram based scenecut detection algorithm to detect scenecuts. */<br>+      bool      bHistBasedSceneCut;<br>+<br></div></blockquote><div>Indentation issue </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="ltr"> } x265_param;<br> /* x265_param_alloc:<br>  *  Allocates an x265_param instance. The returned param structure is not<br>diff -r 04db2bfee5d6 -r 40beab295ca2 source/x265cli.h<br>--- a/source/x265cli.h     Thu Oct 31 16:23:27 2019 +0530<br>+++ b/source/x265cli.h  Wed Nov 13 18:18:31 2019 +0530<br>@@ -129,6 +129,9 @@<br>     { "scenecut",       required_argument, NULL, 0 },<br>     { "no-scenecut",          no_argument, NULL, 0 },<br>     { "scenecut-bias",  required_argument, NULL, 0 },<br>+    { "hist-scenecut",        no_argument, NULL, 0},<br>+    { "no-hist-scenecut",     no_argument, NULL, 0},<br>+    { "hist-threshold", required_argument, NULL, 0},<br>     { "fades",                no_argument, NULL, 0 },<br>     { "no-fades",             no_argument, NULL, 0 },<br>     { "scenecut-aware-qp",    no_argument, NULL, 0 },<br>@@ -489,7 +492,10 @@<br>     H0("   --gop-lookahead <integer>     Extends gop boundary if a scenecut is found within this from keyint boundary. Default 0\n");<br>     H0("   --no-scenecut                 Disable adaptive I-frame decision\n");<br>     H0("   --scenecut <integer>          How aggressively to insert extra I-frames. Default %d\n", param->scenecutThreshold);<br>-    H1("   --scenecut-bias <0..100.0>    Bias for scenecut detection. Default %.2f\n", param->scenecutBias);<br>+    H1("   --scenecut-bias <0..100.0>    Bias for scenecut detection. Default %.2f\n", param->scenecutBias); <br>+    H0("   --hist-scenecut               Enables histogram based scene-cut detection using histogram based algorithm.\n");<br>+    H0("   --no-hist-scenecut            Disables histogram based scene-cut detection using histogram based algorithm.\n");<br>+    H1("   --hist-threshold <0.0..2.0>   Luma Edge histogram's Normalized SAD threshold for histogram based scenecut detection Default %.2f\n", param->edgeTransitionThreshold);<br>     H0("   --[no-]fades                  Enable detection and handling of fade-in regions. Default %s\n", OPT(param->bEnableFades));<br>     H1("   --[no-]scenecut-aware-qp      Enable increasing QP for frames inside the scenecut window after scenecut. Default %s\n", OPT(param->bEnableSceneCutAwareQp));<br>     H1("   --scenecut-window <0..1000>   QP incremental duration(in milliseconds) when scenecut-aware-qp is enabled. Default %d\n", param->scenecutWindow);<br><div><br></div>-- <br><div dir="ltr"><div dir="ltr"><b style="background-color:rgb(255,255,255)"><font color="#0b5394">With Regards,</font></b><div><b style="background-color:rgb(255,255,255)"><font color="#0b5394">Srikanth Kurapati.</font></b></div></div></div></div>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org" target="_blank" rel="noreferrer">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" rel="noreferrer 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 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 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" rel="noreferrer">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" rel="noreferrer 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"><b style="background-color:rgb(255,255,255)"><font color="#0b5394">With Regards,</font></b><div><b style="background-color:rgb(255,255,255)"><font color="#0b5394">Srikanth Kurapati.</font></b></div></div></div>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org" target="_blank" rel="noreferrer">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" rel="noreferrer noreferrer" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</blockquote></div></div>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org" target="_blank" rel="noreferrer">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" rel="noreferrer noreferrer" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</blockquote></div>