<div dir="ltr">This patch fails to build on the latest default; Please fix that and resend the patch.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Oct 15, 2019 at 12:25 PM <<a href="mailto:gopi.satykrishna@multicorewareinc.com">gopi.satykrishna@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"># HG changeset patch<br>
# User gopi Satykrishna Akisetty<br>
# Date 1571121977 -19800<br>
#      Tue Oct 15 12:16:17 2019 +0530<br>
# Node ID deaecadc43060ba37a85d9724a1a306a86433432<br>
# Parent  37648fca915b389bafe923d8443818359e80ebf2<br>
Improved scenecut detection<br>
<br>
This patch does the following.<br>
1. identifies scenecuts using sad of edge and chroma histogram based thresholding.<br>
2. Add option "--hist-scenecut" and "--hist-threshold' to enable improved scenecut method for slice type decisions,rate control and a threshold for determining scene-cuts.<br>
3. Removed duplicate edgefilter code and created a global function for use in scene cut detection and aq in Lookahead.<br>
<br>
diff -r 37648fca915b -r deaecadc4306 doc/reST/cli.rst<br>
--- a/doc/reST/cli.rst  Fri Oct 11 12:45:52 2019 +0530<br>
+++ b/doc/reST/cli.rst  Tue Oct 15 12:16:17 2019 +0530<br>
@@ -1427,6 +1427,18 @@<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>
+<br>
+.. option:: --hist-scenecut, --no-hist-scenecut<br>
+<br>
+       indicates that I-frames need to be inserted using edge and color histogram based scenecut algorithm.<br>
+       option: `--hist-scencut` 1 enables adaptive I frame placement using this method and disables the default scene cut algorithm.<br>
+       option:`--no-hist-scenecut` adaptive I frame placement.<br>
+       <br>
+.. option:: --hist-threshold <0.0..2.0><br>
+<br>
+       This value represents the threshold for SAD for edge histograms used in scenecut detection. This requires hist-scenecut to be enabled.<br>
+       For example, a value of 0.2 indicates that a frame with SAD value greater than 0.2 against the previous frame  as scenecut.<br>
+       Values between 0.0 and 2.0 are recommended. Default 0.1.<br>
<br>
 .. option:: --radl <integer><br>
<br>
diff -r 37648fca915b -r deaecadc4306 source/CMakeLists.txt<br>
--- a/source/CMakeLists.txt     Fri Oct 11 12:45:52 2019 +0530<br>
+++ b/source/CMakeLists.txt     Tue Oct 15 12:16:17 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 180)<br>
+set(X265_BUILD 181)<br>
 configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265.def.in" rel="noreferrer" target="_blank">x265.def.in</a>"<br>
                "${PROJECT_BINARY_DIR}/x265.def")<br>
 configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265_config.h.in" rel="noreferrer" target="_blank">x265_config.h.in</a>"<br>
diff -r 37648fca915b -r deaecadc4306 source/common/CMakeLists.txt<br>
--- a/source/common/CMakeLists.txt      Fri Oct 11 12:45:52 2019 +0530<br>
+++ b/source/common/CMakeLists.txt      Tue Oct 15 12:16:17 2019 +0530<br>
@@ -151,4 +151,5 @@<br>
     predict.cpp  predict.h<br>
     scalinglist.cpp scalinglist.h<br>
     quant.cpp quant.h contexts.h<br>
-    deblock.cpp deblock.h)<br>
+    deblock.cpp deblock.h<br>
+    scenecut.h scenecut.cpp)<br>
diff -r 37648fca915b -r deaecadc4306 source/common/common.h<br>
--- a/source/common/common.h    Fri Oct 11 12:45:52 2019 +0530<br>
+++ b/source/common/common.h    Tue Oct 15 12:16:17 2019 +0530<br>
@@ -129,14 +129,20 @@<br>
 typedef uint64_t sum2_t;<br>
 typedef uint64_t pixel4;<br>
 typedef int64_t  ssum2_t;<br>
+#define HISTOGRAM_SIZE 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_SIZE 256<br>
+#define SHIFT 0<br>
 #endif // if HIGH_BIT_DEPTH<br>
<br>
+#define PI 3.14159265<br>
+<br>
 #if X265_DEPTH < 10<br>
 typedef uint32_t sse_t;<br>
 #else<br>
diff -r 37648fca915b -r deaecadc4306 source/common/param.cpp<br>
--- a/source/common/param.cpp   Fri Oct 11 12:45:52 2019 +0530<br>
+++ b/source/common/param.cpp   Tue Oct 15 12:16:17 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>
@@ -567,6 +569,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>
@@ -609,7 +612,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>
@@ -920,6 +923,7 @@<br>
         {<br>
             bError = false;<br>
             p->scenecutThreshold = atoi(value);<br>
+            p->bHistbasedScenecut = false;<br>
         }<br>
     }<br>
     OPT("temporal-layers") p->bEnableTemporalSubLayers = atobool(value);<br>
@@ -1186,6 +1190,31 @@<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>
+            p->bHistbasedScenecut = atobool(value);<br>
+<br>
+            if (bError)<br>
+            {<br>
+                bError = false;<br>
+                p->bHistbasedScenecut = false;<br>
+            }<br>
+<br>
+            if (p->bHistbasedScenecut) {<br>
+                bError = false;<br>
+                p->scenecutThreshold = 0;<br>
+            }<br>
+<br>
+        }<br>
+        OPT("hist-threshold") {<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>
         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>
@@ -1623,8 +1652,14 @@<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>
+        CHECK(param->scenecutBias < 0 || 100 < param->scenecutBias,<br>
+            "scenecut-bias must be between 0 and 100");<br>
+    }<br>
+    else if (param->bHistbasedScenecut) {<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>
@@ -1780,10 +1815,20 @@<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>
+    if (param->scenecutThreshold && param->keyframeMax != INT_MAX) <br>
+        param->edgeTransitionThreshold = 0.0;<br>
+    else if (param->bHistbasedScenecut && param->keyframeMax != INT_MAX) <br>
+        param->scenecutBias = 0.0;<br>
+    else if (param->keyframeMax != INT_MAX) {<br>
+        param->edgeTransitionThreshold = 0.0;<br>
+        param->scenecutBias = 0.0;<br>
+    }<br>
+        <br>
+    if (param->keyframeMax == INT_MAX)<br>
+        x265_log(param, X265_LOG_INFO, "Keyframe min / max / scenecut       : disabled\n");<br>
     else<br>
-        x265_log(param, X265_LOG_INFO, "Keyframe min / max / scenecut       : disabled\n");<br>
+        x265_log(param, X265_LOG_INFO, "Keyframe min / max / scenecut / bias / threshold  : %d / %d / %d / %.2lf / %.2lf\n", param->keyframeMin, param->keyframeMax, ( param->bHistbasedScenecut || param->scenecutThreshold ), param->scenecutBias * 100, param->edgeTransitionThreshold);<br>
+<br>
<br>
     if (param->cbQpOffset || param->crQpOffset)<br>
         x265_log(param, X265_LOG_INFO, "Cb/Cr QP Offset                     : %d / %d\n", param->cbQpOffset, param->crQpOffset);<br>
@@ -1949,6 +1994,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>
@@ -2096,6 +2143,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>
+    <br>
     BOOL(p->bOptCUDeltaQP, "opt-cu-delta-qp");<br>
     BOOL(p->bAQMotion, "aq-motion");<br>
     BOOL(p->bEmitHDRSEI, "hdr");<br>
@@ -2246,6 +2295,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>
@@ -2403,6 +2453,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 37648fca915b -r deaecadc4306 source/common/scenecut.cpp<br>
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000<br>
+++ b/source/common/scenecut.cpp        Tue Oct 15 12:16:17 2019 +0530<br>
@@ -0,0 +1,674 @@<br>
+#include <iostream><br>
+#include <sstream><br>
+#include <vector><br>
+#include <algorithm><br>
+#include <math.h><br>
+#include "encoder.h"<br>
+#include "scenecut.h"<br>
+#include "slicetype.h"<br>
+<br>
+using namespace std;<br>
+using namespace X265_NS;<br>
+<br>
+#define EDGE_PLANE_COUNT 1<br>
+<br>
+namespace X265_NS {<br>
+<br>
+void computeEdge(pixel * edgePic, pixel *refPic, pixel * edgeTheta, intptr_t stride, int height, int width)<br>
+    {<br>
+        float gradientH = 0, gradientV = 0, radians = 0, theta = 0;<br>
+        float gradientMagnitude = 0;<br>
+        pixel blackPixel = 0;<br>
+<br>
+        //Applying Sobel filter<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] = (pixel)(gradientMagnitude >= edge_threshold ? whitePixel : blackPixel);<br>
+                }<br>
+            }<br>
+        }<br>
+    }<br>
+<br>
+    Histogram::Histogram() <br>
+    {<br>
+        memset(frequency_distribution, 0, HISTOGRAM_SIZE * sizeof(int32_t));<br>
+    }<br>
+<br>
+    Histogram::Histogram(Histogram const& hist) {<br>
+        memset(frequency_distribution, 0, HISTOGRAM_SIZE * sizeof(int32_t));<br>
+        for (int i = 0; i < HISTOGRAM_SIZE; i++) {<br>
+            frequency_distribution[i] = hist.frequency_distribution[i];<br>
+        }<br>
+    }<br>
+<br>
+    Histogram & Histogram::operator=(Histogram const& hist)<br>
+    {<br>
+        memset(frequency_distribution, 0, HISTOGRAM_SIZE * sizeof(int32_t));<br>
+        memcpy(frequency_distribution, hist.frequency_distribution, sizeof(int32_t)*HISTOGRAM_SIZE);<br>
+        return *this;<br>
+    }<br>
+<br>
+    Histogram::~Histogram() {}<br>
+<br>
+    YuvHistogram::YuvHistogram() {}<br>
+<br>
+    void YuvHistogram::initHistograms(int32_t planecount) {<br>
+        this->plane_count = planecount;<br>
+        m_isalloc = false;<br>
+        bisUpdated = false;<br>
+        param = NULL;<br>
+<br>
+        yuv_hist = edge_hist = NULL;<br>
+        plane_sizes = plane_heights = plane_widths = NULL;<br>
+        edgePic =  edgeThetaPic = NULL;<br>
+<br>
+        plane_sizes = X265_MALLOC(int32_t, plane_count);<br>
+        plane_heights = X265_MALLOC(int32_t, plane_count);<br>
+        plane_widths = X265_MALLOC(int32_t, plane_count);<br>
+<br>
+        if (!plane_sizes || !plane_heights || !plane_widths) {<br>
+            x265_log(param, X265_LOG_ERROR, "unable to allocate memory for plane dimensions\n");<br>
+            m_isalloc &= false;<br>
+        }<br>
+        else {<br>
+            memset(plane_sizes, 0, plane_count * sizeof(int32_t));<br>
+            memset(plane_heights, 0, plane_count * sizeof(int32_t));<br>
+            memset(plane_widths, 0, plane_count * sizeof(int32_t));<br>
+            m_isalloc &= true;<br>
+        }<br>
+<br>
+        yuv_hist = X265_MALLOC(Histogram, plane_count);<br>
+        edge_hist = X265_MALLOC(Histogram, plane_count);<br>
+<br>
+        if (!yuv_hist || !edge_hist) {<br>
+            m_isalloc &= false;<br>
+            x265_log(param, X265_LOG_ERROR, "unable to allocate memory for histograms\n");<br>
+        }<br>
+<br>
+    }<br>
+<br>
+    void YuvHistogram::initHistograms(x265_param *p) {<br>
+        param = p;<br>
+        plane_count = x265_cli_csps[param->internalCsp].planes;<br>
+        bisUpdated = false;<br>
+        m_isalloc = false;<br>
+<br>
+        yuv_hist = edge_hist = NULL;<br>
+        plane_sizes = plane_heights = plane_widths = NULL;<br>
+        edgePic = edgeThetaPic = NULL;<br>
+<br>
+        plane_sizes = X265_MALLOC(int32_t, plane_count);<br>
+        plane_heights = X265_MALLOC(int32_t, plane_count);<br>
+        plane_widths = X265_MALLOC(int32_t, plane_count);<br>
+<br>
+        if (!plane_sizes || !plane_heights || !plane_widths) {<br>
+            x265_log(param, X265_LOG_ERROR, "unable to allocate memory for plane dimensions\n");<br>
+            m_isalloc &= false;<br>
+        }<br>
+        else {<br>
+            memset(plane_sizes, 0, plane_count * sizeof(int32_t));<br>
+            memset(plane_heights, 0, plane_count * sizeof(int32_t));<br>
+            memset(plane_widths, 0, plane_count * sizeof(int32_t));<br>
+            m_isalloc &= true;<br>
+        }<br>
+<br>
+        yuv_hist = X265_MALLOC(Histogram, plane_count);<br>
+        edge_hist = X265_MALLOC(Histogram, plane_count);<br>
+<br>
+        if (!yuv_hist || !edge_hist) {<br>
+            m_isalloc &= false;<br>
+            x265_log(param, X265_LOG_ERROR, "unable to allocate memory for histograms\n");<br>
+        }<br>
+<br>
+    }<br>
+<br>
+    bool YuvHistogram::allocHistogramBuffers() {<br>
+        //allocate memory for edge filter output and histograms<br>
+        bool isalloc = true;<br>
+<br>
+        edgePic = X265_MALLOC(pixel*, plane_count);<br>
+        edgeThetaPic = X265_MALLOC(pixel*, plane_count);<br>
+<br>
+        if (!edgePic || !edgeThetaPic) {<br>
+            isalloc &= false;<br>
+            x265_log(param, X265_LOG_ERROR, "unable to allocate memory for edge buffers\n");<br>
+            return isalloc;<br>
+        }<br>
+<br>
+         for (int i = 0; i < plane_count; i++) {<br>
+<br>
+            edgePic[i] = edgeThetaPic[i] = NULL;<br>
+            edgePic[i] = X265_MALLOC(pixel, plane_sizes[i]);<br>
+            edgeThetaPic[i] = X265_MALLOC(pixel, plane_sizes[i]);<br>
+<br>
+            if (edgePic[i] && edgeThetaPic[i]) {<br>
+                memset(edgePic[i], 0, plane_sizes[i] * sizeof(pixel));<br>
+                memset(edgeThetaPic[i], 0, plane_sizes[i] * sizeof(pixel));<br>
+                isalloc &= true;<br>
+            }<br>
+            else<br>
+                isalloc &= false;<br>
+        }<br>
+        return isalloc;<br>
+    }<br>
+<br>
+    YuvHistogram::~YuvHistogram()<br>
+    {<br>
+        freeHistogramBuffers(); //change implementation based on allocation changes <br>
+    }<br>
+<br>
+    YuvHistogram::YuvHistogram(YuvHistogram const& hist) {<br>
+<br>
+        maxuv_hist = hist.maxuv_hist;<br>
+        plane_count = hist.plane_count;<br>
+        bisUpdated = hist.bisUpdated;<br>
+        param = hist.param;<br>
+        memcpy(plane_sizes, hist.plane_sizes, plane_count * sizeof(int32_t));<br>
+        memcpy(plane_heights, hist.plane_heights, plane_count * sizeof(int32_t));<br>
+        memcpy(plane_widths, hist.plane_widths, plane_count * sizeof(int32_t));<br>
+        memcpy(yuv_hist, hist.yuv_hist, plane_count * sizeof(Histogram));<br>
+        memcpy(edge_hist, hist.edge_hist, plane_count * sizeof(Histogram));<br>
+<br>
+        if (!m_isalloc) {<br>
+            m_isalloc = false;<br>
+            m_isalloc = allocHistogramBuffers();<br>
+        }<br>
+<br>
+        if (m_isalloc) {<br>
+            for (int i = 0; i < plane_count; i++) {<br>
+                if (edgePic[i] && edgeThetaPic[i]) {<br>
+                    memcpy(edgePic[i], hist.edgePic[i], plane_sizes[i] * sizeof(pixel));<br>
+                    memcpy(edgeThetaPic[i], hist.edgeThetaPic[i], plane_sizes[i] * sizeof(pixel));<br>
+                }<br>
+            }<br>
+        }<br>
+<br>
+    }<br>
+<br>
+    YuvHistogram & YuvHistogram ::operator=(const YuvHistogram & copy_hist)<br>
+    {<br>
+        maxuv_hist = copy_hist.maxuv_hist;<br>
+        plane_count = copy_hist.plane_count;<br>
+        bisUpdated = copy_hist.bisUpdated;<br>
+        param = copy_hist.param;<br>
+        memcpy(plane_sizes, copy_hist.plane_sizes, plane_count * sizeof(int32_t));<br>
+        memcpy(plane_heights, copy_hist.plane_heights, plane_count * sizeof(int32_t));<br>
+        memcpy(plane_widths, copy_hist.plane_widths, plane_count * sizeof(int32_t));<br>
+        memcpy(yuv_hist, copy_hist.yuv_hist, plane_count * sizeof(Histogram));<br>
+        memcpy(edge_hist, copy_hist.edge_hist, plane_count * sizeof(Histogram));<br>
+<br>
+        if (!m_isalloc) {<br>
+            m_isalloc = false;<br>
+            m_isalloc = allocHistogramBuffers();<br>
+        }<br>
+<br>
+        if (m_isalloc) {<br>
+            for (int i = 0; i < plane_count; i++) {<br>
+                if (edgePic[i] && edgeThetaPic[i]) {<br>
+                    memcpy(edgePic[i], copy_hist.edgePic[i], plane_sizes[i] * sizeof(pixel));<br>
+                    memcpy(edgeThetaPic[i], copy_hist.edgeThetaPic[i], plane_sizes[i] * sizeof(pixel));<br>
+                }<br>
+            }<br>
+        }<br>
+<br>
+        return *this;<br>
+    }<br>
+<br>
+    void YuvHistogram::initFrameDimensions(x265_picture & pic) {<br>
+<br>
+        for (int i = 0; i < plane_count; i++) {<br>
+            plane_widths[i] = pic.width;<br>
+            plane_heights[i] = pic.height >> x265_cli_csps[pic.colorSpace].height[i];<br>
+            plane_sizes[i] = plane_widths[i] * plane_heights[i];<br>
+        }<br>
+    }<br>
+<br>
+    void YuvHistogram::freeHistogramBuffers() {<br>
+        //de allocate memory for histograms and edge filtered output <br>
+        if (edgePic && edgeThetaPic) {<br>
+            for (int i = 0; i < plane_count; i++) {<br>
+                if (edgePic[i] && edgeThetaPic[i]) {<br>
+                    X265_FREE_ZERO(edgePic[i]);<br>
+                    X265_FREE_ZERO(edgeThetaPic[i]);<br>
+                }<br>
+            }<br>
+            X265_FREE_ZERO(edgePic);<br>
+            X265_FREE_ZERO(edgeThetaPic);<br>
+        }<br>
+<br>
+        if (plane_sizes && plane_heights && plane_widths) {<br>
+            X265_FREE_ZERO(plane_sizes);<br>
+            X265_FREE_ZERO(plane_heights);<br>
+            X265_FREE_ZERO(plane_widths);<br>
+        }<br>
+ <br>
+        if (yuv_hist && edge_hist) {<br>
+            X265_FREE_ZERO(yuv_hist);<br>
+            X265_FREE_ZERO(edge_hist);<br>
+        }<br>
+    }<br>
+<br>
+    bool YuvHistogram::edgeFilter(x265_picture *frame) {<br>
+<br>
+        if (!m_isalloc) {<br>
+            initFrameDimensions(*frame);<br>
+            m_isalloc = allocHistogramBuffers();<br>
+        }<br>
+<br>
+        if (m_isalloc) {<br>
+            for (int idx = 0; idx < EDGE_PLANE_COUNT; idx++) {<br>
+<br>
+               memset(edgePic[idx], 0, sizeof(pixel) * plane_sizes[idx]);<br>
+               memset(edgeThetaPic[idx], 0, sizeof(pixel) * plane_sizes[idx]);<br>
+<br>
+                pixel *src = (pixel*)frame->planes[idx];<br>
+                pixel *edge_pic = edgePic[idx];<br>
+                pixel *ref_pic = src;<br>
+                pixel *edge_theta = edgeThetaPic[idx];<br>
+<br>
+                assert(edge_pic != NULL);<br>
+                assert(ref_pic != NULL);<br>
+                memcpy(edge_pic, src, plane_sizes[idx] * sizeof(pixel));<br>
+                memcpy(ref_pic, src, plane_sizes[idx] * sizeof(pixel));<br>
+<br>
+                computeEdge(edge_pic, ref_pic, edge_theta,plane_widths[idx], plane_heights[idx], plane_widths[idx]);<br>
+            }<br>
+            return true;<br>
+        }<br>
+        else {<br>
+            return false;<br>
+        }<br>
+    }<br>
+<br>
+    bool YuvHistogram::computeHistograms(x265_picture &cur_frame) {<br>
+<br>
+        bool bsuccess = false;<br>
+        bsuccess = computeLumaEdgeHistogram(cur_frame);<br>
+        if (bsuccess) {<br>
+            if (plane_count > 1) {<br>
+                bsuccess &= computeChromaHistogram(cur_frame);<br>
+            }<br>
+            return bsuccess;<br>
+        }<br>
+        else {<br>
+            return bsuccess;<br>
+        }<br>
+<br>
+    }<br>
+<br>
+    bool YuvHistogram::computeLumaEdgeHistogram(x265_picture &frame) {<br>
+<br>
+        pixel pixel_val = 0;<br>
+<br>
+        memset(edge_hist[0].frequency_distribution, 0, HISTOGRAM_SIZE * sizeof(int32_t));<br>
+<br>
+        int size = frame.height*(frame.stride[0] >> SHIFT);<br>
+<br>
+        for (int i = 0; i < size; i++) {<br>
+            pixel_val = edgePic[0][i];<br>
+            edge_hist[0].frequency_distribution[pixel_val]++;<br>
+        }<br>
+        return true;<br>
+    }<br>
+<br>
+    bool YuvHistogram::computeChromaHistogram(x265_picture &frame) {<br>
+        /*u hist calculation*/<br>
+        pixel pixel_val = 0;<br>
+        int32_t pixel_ucount = 0, pixel_vcount = 0;<br>
+<br>
+        int u_height = (frame.height >> x265_cli_csps[frame.colorSpace].height[1]);<br>
+        int size = u_height * (frame.stride[1] >> SHIFT);<br>
+        memset(yuv_hist[1].frequency_distribution, 0, HISTOGRAM_SIZE * sizeof(int32_t));<br>
+<br>
+        for (int i = 0; i < size; i++) {<br>
+            pixel_val = *((pixel *)frame.planes[1] + i);<br>
+            yuv_hist[1].frequency_distribution[pixel_val]++;<br>
+            pixel_ucount++;<br>
+        }<br>
+<br>
+        /*v hist calculation for independent uv planes */<br>
+<br>
+        if (plane_count == 3) {<br>
+            pixel_val = 0;<br>
+            int v_height = (frame.height >> x265_cli_csps[frame.colorSpace].height[2]);<br>
+            size = v_height * (frame.stride[2] >> SHIFT);<br>
+            memset(yuv_hist[2].frequency_distribution, 0, HISTOGRAM_SIZE * sizeof(int32_t));<br>
+ <br>
+            for (int i = 0; i < size; i++) {<br>
+                pixel_val = *((pixel *)frame.planes[2] + i);<br>
+                yuv_hist[2].frequency_distribution[pixel_val]++;<br>
+                pixel_vcount++;<br>
+            }<br>
+<br>
+            for (int i = 0; i < HISTOGRAM_SIZE; i++) {<br>
+                maxuv_hist.frequency_distribution[i] = max(yuv_hist[1].frequency_distribution[i], yuv_hist[2].frequency_distribution[i]);<br>
+            }<br>
+<br>
+        }<br>
+        else {<br>
+            maxuv_hist = yuv_hist[1]; //for two planes scenario<br>
+        }<br>
+<br>
+        return true;<br>
+    }<br>
+<br>
+    bool YuvHistogram::isUpdated() {<br>
+        return bisUpdated;<br>
+    }<br>
+<br>
+    void YuvHistogram::setUpdateFlag(bool flag) {<br>
+        bisUpdated = flag;<br>
+    }<br>
+<br>
+    bool YuvHistogram::getUpdateFlag() {<br>
+        return bisUpdated;<br>
+    }<br>
+<br>
+    SadYuv::SadYuv() { }<br>
+<br>
+    void SadYuv::initSadYuv(int planecount) {<br>
+        this->plane_count = planecount;<br>
+        sad_yuv = NULL;<br>
+        psad_yuv = NULL;<br>
+        sad_yuv = X265_MALLOC(int32_t, plane_count);<br>
+        psad_yuv = X265_MALLOC(double, plane_count);<br>
+        if (sad_yuv && psad_yuv) {<br>
+            memset(sad_yuv, 0, plane_count * sizeof(int32_t));<br>
+            memset(psad_yuv, 0, sizeof(double) * plane_count);<br>
+        }<br>
+    }<br>
+<br>
+    SadYuv & SadYuv::operator=(SadYuv const& sad_val) {<br>
+        this->plane_count = sad_val.plane_count;<br>
+        if (!sad_yuv && !psad_yuv) {<br>
+            sad_yuv = NULL;<br>
+            psad_yuv = NULL;<br>
+            sad_yuv = X265_MALLOC(int32_t, plane_count);<br>
+            psad_yuv = X265_MALLOC(double, plane_count);<br>
+            if (sad_yuv && psad_yuv) {<br>
+                memcpy(sad_yuv, sad_val.sad_yuv, plane_count * sizeof(int32_t));<br>
+                memcpy(psad_yuv, sad_val.psad_yuv, sizeof(double) * plane_count);<br>
+            }<br>
+        }<br>
+        else {<br>
+            if (sad_yuv)<br>
+                memcpy(sad_yuv, sad_val.sad_yuv, plane_count * sizeof(int32_t));<br>
+            if (psad_yuv)<br>
+                memcpy(psad_yuv, sad_val.psad_yuv, sizeof(double) * plane_count);<br>
+        }<br>
+        return *this;<br>
+    }<br>
+<br>
+    SadYuv::~SadYuv() {<br>
+        if (sad_yuv && psad_yuv) {<br>
+            X265_FREE(sad_yuv);<br>
+            X265_FREE(psad_yuv);<br>
+        }<br>
+    }<br>
+<br>
+    int sad_stats::frames_scanned=0;<br>
+    int sad_stats::line_number=0;<br>
+<br>
+    sad_stats::sad_stats(int planecount, double threshold) {<br>
+        this->plane_count = planecount;<br>
+        calculateThresholds(threshold);<br>
+        allocateBuffers();<br>
+    }<br>
+<br>
+    void sad_stats::calculateThresholds(double threshold) {<br>
+        edge_hist_threshold = threshold;<br>
+        strength_factor = 2.0;<br>
+        chroma_hist_threshold = threshold * 10.0;<br>
+        scaled_edge_threshold = edge_hist_threshold * strength_factor;<br>
+        scaled_chroma_threshold = chroma_hist_threshold * strength_factor;<br>
+    }<br>
+<br>
+    void sad_stats::init() {<br>
+        bscene_cut = NULL;<br>
+        bdrop_frame = NULL;<br>
+        sad_vals = NULL;<br>
+        maxuv_sad_vals = NULL;<br>
+        edge_sad_vals = NULL;<br>
+        prev_hist = NULL;<br>
+    }<br>
+<br>
+    sad_stats::~sad_stats() {<br>
+        releaseBuffers();<br>
+    }<br>
+<br>
+    void sad_stats::allocateBuffers() {<br>
+<br>
+        init();<br>
+        sad_vals = new SadYuv[DUP_BUFFER]();<br>
+        maxuv_sad_vals = new SadYuv[DUP_BUFFER]();<br>
+        edge_sad_vals = new SadYuv[DUP_BUFFER]();<br>
+        prev_hist = new YuvHistogram();<br>
+        prev_hist->initHistograms(plane_count);<br>
+<br>
+        for (int i = 0; i < DUP_BUFFER; i++) {<br>
+            sad_vals[i].initSadYuv(plane_count);<br>
+            maxuv_sad_vals[i].initSadYuv(plane_count);<br>
+            edge_sad_vals[i].initSadYuv(plane_count);<br>
+        }<br>
+<br>
+        bscene_cut = new bool[DUP_BUFFER];<br>
+        bdrop_frame = new bool[DUP_BUFFER];<br>
+<br>
+        if (!sad_vals || !maxuv_sad_vals || !edge_sad_vals || !bscene_cut || !bdrop_frame) {<br>
+            x265_log(NULL, X265_LOG_ERROR, "Heap Error !");<br>
+            exit(101);<br>
+        }<br>
+        else {<br>
+            memset(bscene_cut, false, 2 * sizeof(bool));<br>
+            memset(bdrop_frame, false, 2 * sizeof(bool));<br>
+        }<br>
+<br>
+    }<br>
+<br>
+    void sad_stats::releaseBuffers() {<br>
+        if (sad_vals && maxuv_sad_vals && edge_sad_vals && bscene_cut && bdrop_frame && prev_hist) {<br>
+            delete[] sad_vals;<br>
+            delete[] maxuv_sad_vals;<br>
+            delete[] edge_sad_vals;<br>
+            delete[] bscene_cut;<br>
+            delete[] bdrop_frame;<br>
+            delete prev_hist;<br>
+        }<br>
+    }<br>
+<br>
+    bool sad_stats::computeSadValue(YuvHistogram *input_frames, int32_t* plane_sizes) {<br>
+<br>
+        int32_t   *yuv_sad_val = NULL, *edge_sad_val = NULL, *maxuv_sad_val = NULL;<br>
+<br>
+        double *maxuv_normalized_sad = NULL, *yuv_norm_sad = NULL, *edge_normalized_sads = NULL;<br>
+<br>
+        YuvHistogram * ref_hist = NULL, *cur_hist = NULL;<br>
+<br>
+        /*inorder to process frames as per poc's updated by frame duplication */<br>
+        if (frames_scanned > 0) {<br>
+           <br>
+            if (!input_frames[0].isUpdated() && input_frames[1].isUpdated()) {<br>
+                ref_hist = prev_hist;<br>
+                cur_hist = input_frames + 1;<br>
+<br>
+                yuv_sad_val = sad_vals[1].sad_yuv,<br>
+                edge_sad_val = edge_sad_vals[1].sad_yuv,<br>
+                maxuv_sad_val = maxuv_sad_vals[1].sad_yuv;<br>
+                maxuv_normalized_sad = maxuv_sad_vals[1].psad_yuv,<br>
+                yuv_norm_sad = sad_vals[1].psad_yuv,<br>
+                edge_normalized_sads = edge_sad_vals[1].psad_yuv;<br>
+                input_frames[1].setUpdateFlag(false);<br>
+<br>
+            }<br>
+            else if (input_frames[0].isUpdated() && input_frames[1].isUpdated()) {<br>
+                ref_hist = prev_hist;<br>
+                cur_hist = input_frames;<br>
+<br>
+                yuv_sad_val = sad_vals[0].sad_yuv,<br>
+                edge_sad_val = edge_sad_vals[0].sad_yuv,<br>
+                maxuv_sad_val = maxuv_sad_vals[0].sad_yuv;<br>
+                maxuv_normalized_sad = maxuv_sad_vals[0].psad_yuv,<br>
+                yuv_norm_sad = sad_vals[0].psad_yuv,<br>
+                edge_normalized_sads = edge_sad_vals[0].psad_yuv;<br>
+                input_frames[0].setUpdateFlag(false);<br>
+<br>
+            }<br>
+            else if (input_frames[0].isUpdated() && !input_frames[1].isUpdated()) {<br>
+                ref_hist = prev_hist;<br>
+                cur_hist = input_frames;<br>
+<br>
+                yuv_sad_val = sad_vals[0].sad_yuv,<br>
+                edge_sad_val = edge_sad_vals[0].sad_yuv,<br>
+                maxuv_sad_val = maxuv_sad_vals[0].sad_yuv;<br>
+                maxuv_normalized_sad = maxuv_sad_vals[0].psad_yuv,<br>
+                yuv_norm_sad = sad_vals[0].psad_yuv,<br>
+                edge_normalized_sads = edge_sad_vals[0].psad_yuv;<br>
+                input_frames[0].setUpdateFlag(false);<br>
+            }<br>
+            else {<br>
+                return true;<br>
+            }<br>
+        }<br>
+        else {<br>
+            cur_hist = input_frames;<br>
+ <br>
+            yuv_sad_val = sad_vals[0].sad_yuv,<br>
+            edge_sad_val = edge_sad_vals[0].sad_yuv,<br>
+            maxuv_sad_val = maxuv_sad_vals[0].sad_yuv;<br>
+<br>
+            maxuv_normalized_sad = maxuv_sad_vals[0].psad_yuv,<br>
+            yuv_norm_sad = sad_vals[0].psad_yuv,<br>
+            edge_normalized_sads = edge_sad_vals[0].psad_yuv;<br>
+            input_frames[0].setUpdateFlag(false);<br>
+        }<br>
+<br>
+        if (frames_scanned == 0) { //first frame is scenecut by default no sad computation for the same.<br>
+<br>
+            maxuv_sad_val[0] = 0;<br>
+            maxuv_normalized_sad[0] = 0.0;<br>
+            memset(yuv_sad_val, 0 , plane_count * sizeof(int32_t));<br>
+            memset(edge_sad_val, 0, plane_count * sizeof(int32_t));<br>
+            memset(edge_normalized_sads, 0, plane_count * sizeof(double));<br>
+            memset(yuv_norm_sad, 0, plane_count * sizeof(double));<br>
+<br>
+        }<br>
+        else {<br>
+            int32_t freq_diff[3];<br>
+            int32_t maxuv_freq_diff[1];<br>
+            int32_t edge_freq_diff[3];<br>
+            double color_probability_diff[3], edge_probability_diff[3];<br>
+<br>
+            memset(yuv_sad_val, 0, plane_count*sizeof(int32_t));<br>
+            memset(edge_sad_val, 0, plane_count*sizeof(int32_t));<br>
+<br>
+            memset(yuv_norm_sad, 0, plane_count * sizeof(double));<br>
+            memset(edge_normalized_sads, 0, plane_count * sizeof(double));<br>
+            memset(color_probability_diff, 0, plane_count * sizeof(double));<br>
+            memset(edge_probability_diff, 0, plane_count * sizeof(double));<br>
+<br>
+            maxuv_normalized_sad[0] = 0.0;<br>
+            maxuv_sad_val[0] = 0;<br>
+<br>
+            memset(freq_diff, 0, 3 * sizeof(int32_t));<br>
+            memset(maxuv_freq_diff, 0, sizeof(int32_t));<br>
+            memset(edge_freq_diff, 0, 3 * sizeof(int32_t));<br>
+<br>
+            for (int i = 0; i < plane_count; i++) {<br>
+                {<br>
+                    for (int j = 0; j < HISTOGRAM_SIZE; j++) {<br>
+<br>
+                        if (i == 0 && plane_count >= 1) {<br>
+                            maxuv_freq_diff[i] = (abs(cur_hist->maxuv_hist.frequency_distribution[j] - ref_hist->maxuv_hist.frequency_distribution[j]));<br>
+                            maxuv_sad_val[i] += maxuv_freq_diff[i];<br>
+                            maxuv_normalized_sad[i] += (double)maxuv_freq_diff[i] / plane_sizes[i];<br>
+                            edge_freq_diff[i] = abs(cur_hist->edge_hist[i].frequency_distribution[j] - ref_hist->edge_hist[i].frequency_distribution[j]);<br>
+                            edge_probability_diff[i] = double(edge_freq_diff[i]) / plane_sizes[i];<br>
+                            edge_sad_val[i] += edge_freq_diff[i];<br>
+                            edge_normalized_sads[i] += edge_probability_diff[i];<br>
+                        }<br>
+                        else {<br>
+                            freq_diff[i] = abs(cur_hist->yuv_hist[i].frequency_distribution[j] - ref_hist->yuv_hist[i].frequency_distribution[j]);<br>
+                            color_probability_diff[i] = (double)freq_diff[i] / plane_sizes[i];<br>
+                            yuv_sad_val[i] += freq_diff[i];<br>
+                            yuv_norm_sad[i] += color_probability_diff[i];<br>
+                        }<br>
+<br>
+                    }<br>
+<br>
+                }<br>
+            }<br>
+<br>
+        }<br>
+<br>
+        *prev_hist = *cur_hist;<br>
+<br>
+        frames_scanned++;<br>
+<br>
+        return  true;<br>
+    }<br>
+<br>
+    void sad_stats::findSceneCuts(x265_picture * picList, bool& bdup) { <br>
+<br>
+            if (frames_scanned == 1) {<br>
+                //for first frame<br>
+                bscene_cut[0] = true;<br>
+                bdrop_frame[0] = false;<br>
+                picList->analysisData.bScenecut = (int)getSceneCutflag(0);<br>
+                bdup = getDropflag(0);<br>
+                picList->analysisData.edgeSadValue = edge_sad_vals[0].psad_yuv[0];<br>
+                picList->analysisData.chromaSadValue = maxuv_sad_vals[0].psad_yuv[0];<br>
+            }<br>
+            else {<br>
+                 bscene_cut[1] = bdrop_frame[1] = false;<br>
+                if (edge_sad_vals[1].psad_yuv[0] == 0) {<br>
+                    bdrop_frame[1] = true;<br>
+                }<br>
+                else if (edge_sad_vals[1].psad_yuv[0] > edge_hist_threshold || maxuv_sad_vals[1].psad_yuv[0] >= chroma_hist_threshold) {<br>
+                    bscene_cut[1] = true;<br>
+                    bdrop_frame[1] = false;<br>
+                }<br>
+                else if (edge_sad_vals[1].psad_yuv[0] >  scaled_edge_threshold || maxuv_sad_vals[1].psad_yuv[0] >= scaled_chroma_threshold) {<br>
+                    bscene_cut[1] = true;<br>
+                    bdrop_frame[1] = false;<br>
+                }<br>
+                picList->analysisData.bScenecut = (int)getSceneCutflag(1);<br>
+                bdup = getDropflag(1);<br>
+                picList->analysisData.edgeSadValue = edge_sad_vals[1].psad_yuv[0];<br>
+                picList->analysisData.chromaSadValue = maxuv_sad_vals[1].psad_yuv[0];<br>
+            }<br>
+     }<br>
+<br>
+    bool sad_stats::getDropflag(int i) {<br>
+        return bdrop_frame[i];<br>
+    }<br>
+<br>
+    bool sad_stats::getSceneCutflag(int i) {<br>
+        return bscene_cut[i];<br>
+    }<br>
+<br>
+}<br>
\ No newline at end of file<br>
diff -r 37648fca915b -r deaecadc4306 source/common/scenecut.h<br>
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000<br>
+++ b/source/common/scenecut.h  Tue Oct 15 12:16:17 2019 +0530<br>
@@ -0,0 +1,147 @@<br>
+#ifndef SCENECUT_H<br>
+#define SCENECUT_H<br>
+<br>
+#include <string><br>
+#include <iostream><br>
+#include <sstream><br>
+#include <vector><br>
+#include <algorithm><br>
+#include <math.h><br>
+<br>
+#include "yuv.h"<br>
+#include "common.h"<br>
+<br>
+#ifdef HIGH_BIT_DEPTH<br>
+#define edge_threshold 1023.0<br>
+#define whitePixel 1023.0<br>
+#else<br>
+#define edge_threshold 255.0<br>
+#define pixel whitePixel 255.0<br>
+#endif<br>
+<br>
+using namespace std;<br>
+<br>
+namespace X265_NS {<br>
+<br>
+    class Histogram {<br>
+<br>
+    public:<br>
+        int32_t frequency_distribution[HISTOGRAM_SIZE];<br>
+<br>
+        Histogram();<br>
+<br>
+        Histogram(Histogram const& hist);<br>
+<br>
+        Histogram & operator=(Histogram const& hist);<br>
+<br>
+        ~Histogram();<br>
+<br>
+    };<br>
+<br>
+    class YuvHistogram {<br>
+    public:<br>
+        Histogram *yuv_hist;<br>
+        Histogram *edge_hist;<br>
+        int32_t *plane_sizes;<br>
+        int32_t *plane_heights;<br>
+        int32_t *plane_widths;<br>
+<br>
+        Histogram maxuv_hist;<br>
+        int32_t plane_count;<br>
+        bool bisUpdated;<br>
+<br>
+        pixel** edgePic;<br>
+        pixel** edgeThetaPic;<br>
+<br>
+        x265_param * param; /*for handling various color spaces*/<br>
+        bool m_isalloc;<br>
+<br>
+        YuvHistogram();<br>
+<br>
+        void initHistograms(int32_t plane_count);<br>
+<br>
+        void initHistograms(x265_param *p);<br>
+<br>
+        bool allocHistogramBuffers();<br>
+<br>
+        YuvHistogram(YuvHistogram const& hist);<br>
+<br>
+        YuvHistogram & operator=(const YuvHistogram & copy_hist);<br>
+<br>
+        ~YuvHistogram();<br>
+<br>
+        void initFrameDimensions(x265_picture & pic);<br>
+<br>
+        void freeHistogramBuffers();<br>
+<br>
+        bool edgeFilter(x265_picture *frame);<br>
+<br>
+        bool computeHistograms(x265_picture &cur_frame);<br>
+<br>
+        bool computeLumaEdgeHistogram(x265_picture &frame);<br>
+<br>
+        bool computeChromaHistogram(x265_picture &frame);<br>
+<br>
+        bool isUpdated();<br>
+<br>
+        void setUpdateFlag(bool flag);<br>
+<br>
+        bool getUpdateFlag();<br>
+<br>
+    };<br>
+<br>
+ struct SadYuv {<br>
+        int32_t *sad_yuv;<br>
+        double *psad_yuv;<br>
+        int plane_count;<br>
+        ~SadYuv();<br>
+        SadYuv();<br>
+        void initSadYuv(int plane_count);<br>
+        SadYuv & operator=(SadYuv const& sad_val);<br>
+};<br>
+<br>
+    class sad_stats {<br>
+<br>
+        bool *bscene_cut;<br>
+        bool *bdrop_frame;<br>
+        SadYuv * sad_vals;<br>
+        SadYuv * maxuv_sad_vals;<br>
+        SadYuv * edge_sad_vals;<br>
+        int plane_count;<br>
+        static int line_number;<br>
+        static int frames_scanned;<br>
+        YuvHistogram *prev_hist;<br>
+        double edge_hist_threshold;<br>
+        double chroma_hist_threshold;<br>
+        double scaled_chroma_threshold;<br>
+        double scaled_edge_threshold;<br>
+        double strength_factor;<br>
+<br>
+    public:<br>
+        sad_stats(int plane_count, double threshold);<br>
+<br>
+        ~sad_stats();<br>
+        <br>
+        void init();<br>
+        <br>
+        void allocateBuffers();<br>
+        <br>
+        void releaseBuffers();<br>
+        <br>
+        void calculateThresholds(double threshold);<br>
+        <br>
+        bool computeSadValue(YuvHistogram *frames, int32_t* plane_sizes);<br>
+        <br>
+        void findSceneCuts(x265_picture * piclist,bool & bdup);<br>
+        <br>
+        bool getDropflag(int i);<br>
+        <br>
+        bool getSceneCutflag(int i);<br>
+<br>
+    };<br>
+<br>
+void computeEdge(pixel * edgePic, pixel *refPic, pixel * edgeTheta, intptr_t stride, int height, int width);<br>
+<br>
+}<br>
+<br>
+#endif<br>
diff -r 37648fca915b -r deaecadc4306 source/encoder/api.cpp<br>
--- a/source/encoder/api.cpp    Fri Oct 11 12:45:52 2019 +0530<br>
+++ b/source/encoder/api.cpp    Tue Oct 15 12:16:17 2019 +0530<br>
@@ -31,6 +31,7 @@<br>
 #include "nal.h"<br>
 #include "bitcost.h"<br>
 #include "svt.h"<br>
+#include "scenecut.h"<br>
<br>
 #if ENABLE_LIBVMAF<br>
 #include "libvmaf.h"<br>
@@ -117,7 +118,10 @@<br>
     x265_log(param, X265_LOG_INFO, "build info %s\n", PFX(build_info_str));<br>
<br>
     encoder = new Encoder;<br>
-<br>
+    encoder->m_sad_stats = new sad_stats(x265_cli_csps[p->internalCsp].planes,param->edgeTransitionThreshold);<br>
+    encoder->m_hist_of_adj_frames = new YuvHistogram[2];<br>
+    encoder->m_hist_of_adj_frames[0].initHistograms(p);<br>
+    encoder->m_hist_of_adj_frames[1].initHistograms(p);<br>
 #ifdef SVT_HEVC<br>
<br>
     if (param->bEnableSvtHevc)<br>
@@ -809,6 +813,7 @@<br>
             CHECKED_MALLOC_ZERO(interData->ref, int32_t, analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU * numDir);<br>
     }<br>
     analysis->interData = interData;<br>
+    analysis->bScenecut = false;<br>
<br>
     return;<br>
<br>
@@ -924,6 +929,7 @@<br>
     pic->rpu.payloadSize = 0;<br>
     pic->rpu.payload = NULL;<br>
     pic->picStruct = 0;<br>
+    pic->bufUpdated = false;<br>
<br>
     if ((param->analysisSave || param->analysisLoad) || (param->bAnalysisType == AVC_INFO))<br>
     {<br>
@@ -933,7 +939,9 @@<br>
         uint32_t numCUsInFrame   = widthInCU * heightInCU;<br>
         pic->analysisData.numCUsInFrame = numCUsInFrame;<br>
         pic->analysisData.numPartitions = param->num4x4Partitions;<br>
+        pic->analysisData.bScenecut = false;<br>
     }<br>
+<br>
 }<br>
<br>
 void x265_picture_free(x265_picture *p)<br>
@@ -955,7 +963,8 @@<br>
 {<br>
     if (param && param->rc.zonefileCount) {<br>
         for (int i = 0; i < param->rc.zonefileCount; i++)<br>
-            x265_free(param->rc.zones[i].zoneParam);<br>
+            if(param->rc.zones[i].zoneParam)<br>
+              x265_free(param->rc.zones[i].zoneParam);<br>
     }<br>
     if (param && (param->rc.zoneCount || param->rc.zonefileCount))<br>
         x265_free(param->rc.zones);<br>
diff -r 37648fca915b -r deaecadc4306 source/encoder/encoder.cpp<br>
--- a/source/encoder/encoder.cpp        Fri Oct 11 12:45:52 2019 +0530<br>
+++ b/source/encoder/encoder.cpp        Tue Oct 15 12:16:17 2019 +0530<br>
@@ -119,6 +119,9 @@<br>
         m_frameEncoder[i] = NULL;<br>
     for (uint32_t i = 0; i < DUP_BUFFER; i++)<br>
         m_dupBuffer[i] = NULL;<br>
+    <br>
+    m_hist_of_adj_frames = NULL;<br>
+    m_sad_stats = NULL;<br>
     MotionEstimate::initScales();<br>
<br>
 #if ENABLE_HDR10_PLUS<br>
@@ -162,7 +165,9 @@<br>
     int rows = (p->sourceHeight + p->maxCUSize - 1) >> g_log2Size[p->maxCUSize];<br>
     int cols = (p->sourceWidth  + p->maxCUSize - 1) >> g_log2Size[p->maxCUSize];<br>
<br>
-    if (m_param->bEnableFrameDuplication)<br>
+<br>
+<br>
+    if (m_param->bEnableFrameDuplication || m_param->bHistbasedScenecut)<br>
     {<br>
         size_t framesize = 0;<br>
         int pixelbytes = p->sourceBitDepth > 8 ? 2 : 1;<br>
@@ -184,6 +189,7 @@<br>
             m_dupBuffer[i]->dupPlane = NULL;<br>
             m_dupBuffer[i]->dupPlane = X265_MALLOC(char, framesize);<br>
             m_dupBuffer[i]->dupPic->planes[0] = m_dupBuffer[i]->dupPlane;<br>
+                       m_dupBuffer[i]->bufUpdated = false;<br>
             m_dupBuffer[i]->bOccupied = false;<br>
             m_dupBuffer[i]->bDup = false;<br>
         }<br>
@@ -820,7 +826,7 @@<br>
         m_exportedPic = NULL;<br>
     }<br>
<br>
-    if (m_param->bEnableFrameDuplication)<br>
+    if (m_param->bEnableFrameDuplication || m_param->bHistbasedScenecut)<br>
     {<br>
         for (uint32_t i = 0; i < DUP_BUFFER; i++)<br>
         {<br>
@@ -1280,6 +1286,33 @@<br>
     return psnrWeight = (psnrY * 6 + psnrU + psnrV) / 8;<br>
 }<br>
<br>
+void Encoder::updateSceneCutAndFrameDuplicateFlags() {<br>
+    /* SCD computation and drop flag*/<br>
+    for (int i = 0; i < DUP_BUFFER; i++) {<br>
+        if (m_dupBuffer[i]->bufUpdated) {<br>
+            m_hist_of_adj_frames[i].setUpdateFlag(true);<br>
+            m_hist_of_adj_frames[i].edgeFilter(m_dupBuffer[i]->dupPic);<br>
+            m_hist_of_adj_frames[i].computeHistograms(*m_dupBuffer[i]->dupPic);<br>
+            m_sad_stats->computeSadValue(m_hist_of_adj_frames, m_hist_of_adj_frames->plane_sizes);<br>
+            m_sad_stats->findSceneCuts(m_dupBuffer[i]->dupPic, m_dupBuffer[i]->bDup);<br>
+<br>
+            if (m_dupBuffer[i]->dupPic->analysisData.bScenecut) {<br>
+                x265_log(m_param, X265_LOG_DEBUG, "scene cut at %d edge hist sad: %0.4lf maxuv hist sad: %0.4lf\n",<br>
+                   m_dupBuffer[i]->dupPic->poc,m_dupBuffer[i]->dupPic->analysisData.edgeSadValue,m_dupBuffer[i]->dupPic->analysisData.chromaSadValue);<br>
+            }<br>
+<br>
+            if (m_dupBuffer[1]->bufUpdated)<br>
+                m_hist_of_adj_frames[0] = m_hist_of_adj_frames[1];<br>
+        }<br>
+    }<br>
+<br>
+ }<br>
+<br>
+/* TBD <br>
+- to be updated for missing parameters in case of re-use else where and improvised to copy constructor / assignment operator of x265 picture data structure.<br>
+- benefits avoid function and use language features appropriately.<br>
+*/<br>
+<br>
 void Encoder::copyPicture(x265_picture *dest, const x265_picture *src)<br>
 {<br>
     dest->poc = src->poc;<br>
@@ -1299,6 +1332,25 @@<br>
     memcpy(dest->planes[0], src->planes[0], src->framesize * sizeof(char));<br>
     dest->planes[1] = (char*)dest->planes[0] + src->stride[0] * src->height;<br>
     dest->planes[2] = (char*)dest->planes[1] + src->stride[1] * (src->height >> x265_cli_csps[src->colorSpace].height[1]);<br>
+    memcpy(&dest->analysisData, &src->analysisData, sizeof(src->analysisData));<br>
+ <br>
+}<br>
+<br>
+void Encoder::setPictureFlags(int idx) {<br>
+        m_dupBuffer[idx]->bOccupied = true;<br>
+        m_dupBuffer[idx]->bufUpdated = true;<br>
+        m_dupBuffer[idx]->bDup = false;<br>
+}<br>
+<br>
+void Encoder::unsetPictureFlags(int idx) {<br>
+    if (idx == 1) {<br>
+        m_dupBuffer[idx]->bOccupied = false;<br>
+        m_dupBuffer[idx]->bufUpdated = false;<br>
+        m_dupBuffer[idx]->bDup = false;<br>
+    }<br>
+    else if (idx == 0) {<br>
+        m_dupBuffer[idx]->bufUpdated = false;<br>
+    }<br>
 }<br>
<br>
 /**<br>
@@ -1327,7 +1379,9 @@<br>
     const x265_picture* inputPic = NULL;<br>
     static int written = 0, read = 0;<br>
     bool dontRead = false;<br>
-<br>
+    bool isScenecutEnabled = m_param->bHistbasedScenecut;<br>
+    bool dropflag = false;<br>
+ <br>
     if (m_exportedPic)<br>
     {<br>
         if (!m_param->bUseAnalysisFile && m_param->analysisSave)<br>
@@ -1338,7 +1392,7 @@<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->bEnableFrameDuplication && !pic_in && (read < written)))<br>
+        if ((m_param->bEnableFrameDuplication && !pic_in && (read < written)) || (isScenecutEnabled && !pic_in && (read < written)))<br>
             dontRead = true;<br>
         else<br>
         {<br>
@@ -1361,7 +1415,7 @@<br>
             }<br>
         }<br>
<br>
-        if (m_param->bEnableFrameDuplication)<br>
+        if (m_param->bEnableFrameDuplication || isScenecutEnabled )<br>
         {<br>
             double psnrWeight = 0;<br>
<br>
@@ -1372,6 +1426,11 @@<br>
                     copyPicture(m_dupBuffer[0]->dupPic, pic_in);<br>
                     m_dupBuffer[0]->bOccupied = true;<br>
                     written++;<br>
+                    if (m_param->bHistbasedScenecut) {<br>
+                        setPictureFlags(0);<br>
+                        updateSceneCutAndFrameDuplicateFlags();<br>
+                        unsetPictureFlags(0);<br>
+                    }<br>
                     return 0;<br>
                 }<br>
                 else if (!m_dupBuffer[1]->bOccupied)<br>
@@ -1379,31 +1438,54 @@<br>
                     copyPicture(m_dupBuffer[1]->dupPic, pic_in);<br>
                     m_dupBuffer[1]->bOccupied = true;<br>
                     written++;<br>
+                    if (m_param->bHistbasedScenecut) {<br>
+                        setPictureFlags(1);<br>
+                        updateSceneCutAndFrameDuplicateFlags();<br>
+                        unsetPictureFlags(1);<br>
+                    }<br>
                 }<br>
<br>
-                psnrWeight = ComputePSNR(m_dupBuffer[0]->dupPic, m_dupBuffer[1]->dupPic, m_param);<br>
-<br>
-                if (psnrWeight >= m_param->dupThreshold)<br>
-                {<br>
-                    if (m_dupBuffer[0]->bDup)<br>
-                    {<br>
-                        m_dupBuffer[0]->dupPic->picStruct = tripling;<br>
-                        m_dupBuffer[0]->bDup = false;<br>
-                        read++;<br>
+                if (m_param->bEnableFrameDuplication && m_param->bHistbasedScenecut) {<br>
+                    if (m_dupBuffer[1]->bDup == false && m_dupBuffer[1]->dupPic->analysisData.bScenecut == false) {<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>
-                        m_dupBuffer[0]->dupPic->picStruct = doubling;<br>
-                        m_dupBuffer[0]->bDup = true;<br>
-                        m_dupBuffer[1]->bOccupied = false;<br>
-                        read++;<br>
-                        return 0;<br>
+                    else {<br>
+                        dropflag = true;<br>
                     }<br>
                 }<br>
-                else if (m_dupBuffer[0]->bDup)<br>
+                else if (m_param->bEnableFrameDuplication) {<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 (m_param->bEnableFrameDuplication)<br>
+                {<br>
+                    if (dropflag)<br>
+                    {<br>
+                        if (m_dupBuffer[0]->bDup)<br>
+                        {<br>
+                            m_dupBuffer[0]->dupPic->picStruct = tripling;<br>
+                            m_dupBuffer[0]->bDup = false;<br>
+                            read++;<br>
+                        }<br>
+                        else<br>
+                        {<br>
+                            m_dupBuffer[0]->dupPic->picStruct = doubling;<br>
+                            m_dupBuffer[0]->bDup = true;<br>
+                            m_dupBuffer[1]->bOccupied = false;<br>
+                            read++;<br>
+                            return 0;<br>
+                        }<br>
+                    }<br>
+                    else if (m_dupBuffer[0]->bDup)<br>
                     m_dupBuffer[0]->bDup = false;<br>
-                else<br>
-                    m_dupBuffer[0]->dupPic->picStruct = 0;<br>
+                    else<br>
+                        m_dupBuffer[0]->dupPic->picStruct = 0;<br>
+                }<br>
+<br>
             }<br>
<br>
             if (read < written)<br>
@@ -1485,7 +1567,10 @@<br>
<br>
         inFrame->m_poc       = ++m_pocLast;<br>
         inFrame->m_userData  = inputPic->userData;<br>
-        inFrame->m_pts       = inputPic->pts;<br>
+        inFrame->m_pts = inputPic->pts;<br>
+        if (m_param->bHistbasedScenecut) {<br>
+           inFrame->m_lowres.bScenecut = inputPic->analysisData.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>
@@ -1613,7 +1698,7 @@<br>
             m_param->bUseRcStats = 0;<br>
         }<br>
<br>
-        if (m_param->bEnableFrameDuplication && ((read < written) || (m_dupBuffer[0]->dupPic->picStruct == tripling && (read <= written))))<br>
+        if ( (m_param->bEnableFrameDuplication || isScenecutEnabled) && ((read < written) || (m_dupBuffer[0]->dupPic->picStruct == tripling && (read <= written))))<br>
         {<br>
             if (m_dupBuffer[0]->dupPic->picStruct == tripling)<br>
                 m_dupBuffer[0]->bOccupied = m_dupBuffer[1]->bOccupied = false;<br>
@@ -3162,6 +3247,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>
@@ -3175,6 +3261,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>
@@ -3828,6 +3915,20 @@<br>
             m_param->searchMethod = m_param->hmeSearchMethod[2];<br>
         }<br>
     }<br>
+<br>
+    if (p->bHistbasedScenecut && p->scenecutThreshold) {<br>
+        p->scenecutThreshold = 0;<br>
+        p->bHistbasedScenecut = false;<br>
+        x265_log(p, X265_LOG_WARNING, "Amibigious choice. disabling scene cut detection \n");<br>
+    }<br>
+    else if (p->scenecutThreshold && p->edgeTransitionThreshold != 0.01) {<br>
+        x265_log(p, X265_LOG_WARNING, "using  scenecut-bias %d for scene cut detection\n",p->scenecutBias);<br>
+    }<br>
+    else if (p->bHistbasedScenecut && p->edgeTransitionThreshold == 0.0) {<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>
 }<br>
<br>
 void Encoder::readAnalysisFile(x265_analysis_data* analysis, int curPoc, const x265_picture* picIn, int paramBytes)<br>
diff -r 37648fca915b -r deaecadc4306 source/encoder/encoder.h<br>
--- a/source/encoder/encoder.h  Fri Oct 11 12:45:52 2019 +0530<br>
+++ b/source/encoder/encoder.h  Tue Oct 15 12:16:17 2019 +0530<br>
@@ -32,6 +32,8 @@<br>
 #include "nal.h"<br>
 #include "framedata.h"<br>
 #include "svt.h"<br>
+#include "scenecut.h"<br>
+<br>
 #ifdef ENABLE_HDR10_PLUS<br>
     #include "dynamicHDR10/hdr10plus.h"<br>
 #endif<br>
@@ -154,6 +156,9 @@<br>
<br>
     //Flag to check whether the picture has duplicated.<br>
     bool bDup;<br>
+<br>
+    bool bufUpdated;<br>
+<br>
 };<br>
<br>
<br>
@@ -195,6 +200,9 @@<br>
<br>
     ThreadPool*        m_threadPool;<br>
     FrameEncoder*      m_frameEncoder[X265_MAX_FRAME_THREADS];<br>
+<br>
+    YuvHistogram*      m_hist_of_adj_frames;<br>
+    sad_stats*         m_sad_stats;<br>
     DPB*               m_dpb;<br>
     Frame*             m_exportedPic;<br>
     FILE*              m_analysisFileIn;<br>
@@ -279,6 +287,10 @@<br>
         if (m_prevTonemapPayload.payload != NULL)<br>
             X265_FREE(m_prevTonemapPayload.payload);<br>
 #endif<br>
+        delete m_sad_stats;<br>
+        m_sad_stats = NULL;<br>
+        delete[] m_hist_of_adj_frames;<br>
+        m_hist_of_adj_frames = NULL;<br>
     };<br>
<br>
     void create();<br>
@@ -349,6 +361,12 @@<br>
<br>
     void copyPicture(x265_picture *dest, const x265_picture *src);<br>
<br>
+    void unsetPictureFlags(int index);<br>
+<br>
+    void setPictureFlags(int index);<br>
+<br>
+    void updateSceneCutAndFrameDuplicateFlags();<br>
+<br>
     void initRefIdx();<br>
     void analyseRefIdx(int *numRefIdx);<br>
     void updateRefIdx();<br>
@@ -364,6 +382,7 @@<br>
     void initSPS(SPS *sps);<br>
     void initPPS(PPS *pps);<br>
 };<br>
+<br>
 }<br>
<br>
 #endif // ifndef X265_ENCODER_H<br>
diff -r 37648fca915b -r deaecadc4306 source/encoder/ratecontrol.cpp<br>
--- a/source/encoder/ratecontrol.cpp    Fri Oct 11 12:45:52 2019 +0530<br>
+++ b/source/encoder/ratecontrol.cpp    Tue Oct 15 12:16:17 2019 +0530<br>
@@ -493,6 +493,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>
@@ -1183,6 +1184,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>
@@ -2173,7 +2175,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 37648fca915b -r deaecadc4306 source/encoder/slicetype.cpp<br>
--- a/source/encoder/slicetype.cpp      Fri Oct 11 12:45:52 2019 +0530<br>
+++ b/source/encoder/slicetype.cpp      Tue Oct 15 12:16:17 2019 +0530<br>
@@ -30,6 +30,7 @@<br>
 #include "primitives.h"<br>
 #include "lowres.h"<br>
 #include "mv.h"<br>
+#include "scenecut.h"<br>
<br>
 #include "slicetype.h"<br>
 #include "motion.h"<br>
@@ -114,8 +115,8 @@<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 = pic1 + 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>
     {<br>
         for (int colNum = 0; colNum < width; colNum++)<br>
@@ -127,7 +128,8 @@<br>
                  1  [4   9   12  9   4]<br>
                 --- [5   12  15  12  5]<br>
                 159 [4   9   12  9   4]<br>
-                    [2   4   5   4   2]*/<br>
+                    [2   4   5   4   2]<br>
+                           */<br>
<br>
                 const intptr_t rowOne = (rowNum - 2)*stride, colOne = colNum - 2;<br>
                 const intptr_t rowTwo = (rowNum - 1)*stride, colTwo = colNum - 1;<br>
@@ -145,52 +147,7 @@<br>
             }<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>
+    computeEdge(edgePic, refPic, edgeTheta, stride, height, width);<br>
 }<br>
<br>
 //Find the angle of a block by averaging the pixel angles <br>
@@ -1471,7 +1428,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>
@@ -1962,10 +1919,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>
@@ -1976,14 +1938,24 @@<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)<br>
+                    {<br>
+                        if (frames[j]->bScenecut && scenecutInternal(frames, j - 1, j, true))<br>
+                        {<br>
+                               m_extendGopBoundary = true;<br>
+                               break;<br>
+                        }<br>
+                    }<br>
+                    else if(m_param->bHistbasedScenecut && frames[j]->bScenecut)<br>
+                    {<br>
+                            m_extendGopBoundary = true;<br>
+                            break;<br>
+                    }<br>
             }<br>
             if (m_extendGopBoundary)<br>
                 break;<br>
@@ -2088,13 +2060,23 @@<br>
         {<br>
             for (int j = 1; j < numBFrames + 1; j++)<br>
             {<br>
-                if (scenecut(frames, j, j + 1, false, origNumFrames) || <br>
-                    (bForceRADL && (frames[j]->frameNum == preRADL)))<br>
-                {<br>
-                    frames[j]->sliceType = X265_TYPE_P;<br>
-                    numAnalyzed = j;<br>
-                    break;<br>
+                if (m_param->bHistbasedScenecut) {<br>
+                    if (frames[j]->bScenecut || (bForceRADL && (frames[j]->frameNum == preRADL)))<br>
+                    {<br>
+                        frames[j]->sliceType = X265_TYPE_P;<br>
+                        numAnalyzed = j;<br>
+                        break;<br>
+                    }<br>
                 }<br>
+                else if (m_param->scenecutThreshold){<br>
+                    if ( scenecut(frames, j, j + 1, false, origNumFrames) || (bForceRADL && (frames[j]->frameNum == preRADL)) )<br>
+                    {<br>
+                        frames[j]->sliceType = X265_TYPE_P;<br>
+                        numAnalyzed = j;<br>
+                        break;<br>
+                    }<br>
+                }<br>
+<br>
             }<br>
         }<br>
         resetStart = bKeyframe ? 1 : X265_MIN(numBFrames + 2, numAnalyzed + 1);<br>
diff -r 37648fca915b -r deaecadc4306 source/encoder/slicetype.h<br>
--- a/source/encoder/slicetype.h        Fri Oct 11 12:45:52 2019 +0530<br>
+++ b/source/encoder/slicetype.h        Tue Oct 15 12:16:17 2019 +0530<br>
@@ -43,6 +43,14 @@<br>
 #define AQ_EDGE_BIAS 0.5<br>
 #define EDGE_INCLINATION 45<br>
<br>
+#ifdef HIGH_BIT_DEPTH<br>
+#define edge_threshold 1023.0<br>
+#define whitePixel 1023.0<br>
+#else<br>
+#define edge_threshold 255.0<br>
+#define pixel whitePixel 255.0<br>
+#endif<br>
+<br>
 /* Thread local data for lookahead tasks */<br>
 struct LookaheadTLD<br>
 {<br>
diff -r 37648fca915b -r deaecadc4306 source/test/regression-tests.txt<br>
--- a/source/test/regression-tests.txt  Fri Oct 11 12:45:52 2019 +0530<br>
+++ b/source/test/regression-tests.txt  Tue Oct 15 12:16:17 2019 +0530<br>
@@ -157,6 +157,9 @@<br>
 ducks_take_off_420_720p50.y4m,--preset medium --aq-mode 4 --crf 22 --no-cutree<br>
 ducks_take_off_420_1_720p50.y4m,--preset medium --selective-sao 4 --sao --crf 20<br>
 Traffic_4096x2048_30p.y4m, --preset medium --frame-dup --dup-threshold 60 --hrd --bitrate 10000 --vbv-bufsize 15000 --vbv-maxrate 12000<br>
+sintel_trailer_2k_1920x1080_24.yuv, --preset medium --hist-scenecut --hist-threshold 0.01<br>
+Traffic_4096x2048_30p.y4m, --preset medium --frame-dup --dup-threshold 60 --hrd --bitrate 10000 --vbv-bufsize 15000 --vbv-maxrate 12000 --hist-scenecut --hist-threshold 0.01<br>
+sintel_trailer_2k_1920x1080_24.yuv, --preset medium --scenecut 40 --scenecut-bias 20<br>
<br>
 # Main12 intraCost overflow bug test<br>
 720p50_parkrun_ter.y4m,--preset medium<br>
diff -r 37648fca915b -r deaecadc4306 source/x265.h<br>
--- a/source/x265.h     Fri Oct 11 12:45:52 2019 +0530<br>
+++ b/source/x265.h     Tue Oct 15 12:16:17 2019 +0530<br>
@@ -210,7 +210,9 @@<br>
     uint32_t                          numCUsInFrame;<br>
     uint32_t                          numPartitions;<br>
     uint32_t                          depthBytes;<br>
-    int                               bScenecut;<br>
+    bool                               bScenecut;<br>
+    double                             edgeSadValue;<br>
+    double                             chromaSadValue;<br>
     x265_weight_param*                wt;<br>
     x265_analysis_inter_data*         interData;<br>
     x265_analysis_intra_data*         intraData;<br>
@@ -291,6 +293,9 @@<br>
     char             sliceType;<br>
     int              bScenecut;<br>
     double           ipCostRatio;<br>
+    double           yedgeSadValue;<br>
+    double           chromaSadValue;<br>
+<br>
     int              frameLatency;<br>
     x265_cu_stats    cuStats;<br>
     x265_pu_stats    puStats;<br>
@@ -465,6 +470,9 @@<br>
     //Dolby Vision RPU metadata<br>
     x265_dolby_vision_rpu rpu;<br>
<br>
+    //Flag to determine the latest frame in the buffer<br>
+    bool bufUpdated;<br>
+<br>
     int fieldNum;<br>
<br>
     //SEI picture structure message<br>
@@ -1017,8 +1025,9 @@<br>
      * decisions. Default is 0 - disabled. 1 is the same as 0. Max 16 */<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>
+    /*  An arbitrary threshold which determines how aggressively the lookahead<br>
+     * should detect scene cuts. The default (40) is recommended.<br>
+     * Used for encoding cost based scenecut detection */<br>
     int       scenecutThreshold;<br>
<br>
     /* Replace keyframes by using a column of intra blocks that move across the video<br>
@@ -1803,6 +1812,7 @@<br>
<br>
     /*Emit content light level info SEI*/<br>
     int         bEmitCLL;<br>
+       <br>
<br>
     /*<br>
     * Signals picture structure SEI timing message for every frame<br>
@@ -1819,6 +1829,17 @@<br>
<br>
     /*Input sequence bit depth. It can be either 8bit, 10bit or 12bit.*/<br>
     int       sourceBitDepth;<br>
+       <br>
+     /* A genuine threshold which determines whether a frame is a scenecut or not<br>
+      * when compared against edge and color sad values of a frames histograms.Default 0.01<br>
+      * Range:real number in range (0,2)<br>
+      * Used for histogram based scene cut detection */<br>
+      double    edgeTransitionThreshold;<br>
+<br>
+    /*enables improved scenecut detection algorithm to detect scenecuts for slice type<br>
+      decision and rate control */<br>
+      bool      bHistbasedScenecut;<br>
+<br>
 } x265_param;<br>
 /* x265_param_alloc:<br>
  *  Allocates an x265_param instance. The returned param structure is not<br>
diff -r 37648fca915b -r deaecadc4306 source/x265cli.h<br>
--- a/source/x265cli.h  Fri Oct 11 12:45:52 2019 +0530<br>
+++ b/source/x265cli.h  Tue Oct 15 12:16:17 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>
     { "radl",           required_argument, NULL, 0 },<br>
@@ -485,7 +488,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>
+    H0("   --hist-scenecut .....         Enables improved scene-cut detection using histogram based algorithm.");<br>
+    H0("   --no-hist-scenecut            Disables improved scene-cut detection using histogram based algorithm. ");<br>
+    H0("   --scenecut-bias <0..100.0>    Bias for scenecut detection. Default %.2f\n", param->scenecutBias); <br>
+    H0("   --hist-threshold <0.0..2.0>   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>
     H0("   --radl <integer>              Number of RADL pictures allowed in front of IDR. Default %d\n", param->radl);<br>
     H0("   --intra-refresh               Use Periodic Intra Refresh instead of IDR frames\n");<br>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org" target="_blank">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="gmail_signature"><div dir="ltr"><font face="georgia, serif">Regards,</font><div><font face="georgia, serif">Aruna</font></div></div></div>