<div dir="ltr"># HG changeset patch<br># User Srikanth Kurapati <<a href="mailto:srikanth.kurapati@multicorewareinc.com">srikanth.kurapati@multicorewareinc.com</a>><br># Date 1573649311 -19800<br>#      Wed Nov 13 18:18:31 2019 +0530<br># Node ID 36d20a880ddc3df6089bb83ff4fb494f1113a03a<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 36d20a880ddc 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>+  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>+     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 36d20a880ddc 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">x265.def.in</a>"<br>                "${PROJECT_BINARY_DIR}/x265.def")<br> configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265_config.h.in">x265_config.h.in</a>"<br>diff -r 04db2bfee5d6 -r 36d20a880ddc 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 36d20a880ddc 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>     char nameBuf[64];<br>     static int count;<br> <br>@@ -920,11 +924,17 @@<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>+                x265_log(p, X265_LOG_INFO, "I/P cost based scenecut method enabled\n");<br>+                scenecutChoice = 0;<br>+            }<br>         }<br>     }<br>     OPT("temporal-layers") p->bEnableTemporalSubLayers = atobool(value);<br>@@ -1191,6 +1201,47 @@<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>+                    x265_log(p, X265_LOG_INFO, "Histogram based scenecut method enabled \n");<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>+            {<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 +1682,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 +1851,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 +2024,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 +2173,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>@@ -2261,6 +2328,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 +2488,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 36d20a880ddc 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>+        double strengthFactor = 2.0;<br>+        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>+<br>+    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)<br>+    {<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>+        }<br>+    }<br>+    else<br>+    {   /* in case of bi planar color space */<br>+        memcpy(m_curMaxUVHist,m_curUVHist[0],HISTOGRAM_BINS*sizeof(int32_t));<br>+    }<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>+            {<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>+<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>+}<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>+                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>+        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>+    {<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 36d20a880ddc 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 36d20a880ddc 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 36d20a880ddc 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,13 +2011,16 @@<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>+                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>+                     m_extendGopBoundary = true;<br>+                     break;<br>                 }<br>             }<br>             if (m_extendGopBoundary)<br>@@ -2097,12 +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>+                        frames[j]->sliceType = X265_TYPE_P;<br>+                        numAnalyzed = j;<br>+                        break;<br>+<br>                 }<br>             }<br>         }<br>@@ -3289,3 +3320,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 36d20a880ddc 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 36d20a880ddc 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> <br> # Main12 intraCost overflow bug test<br> 720p50_parkrun_ter.y4m,--preset medium<br>diff -r 04db2bfee5d6 -r 36d20a880ddc 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>     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>     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> } x265_param;<br> /* x265_param_alloc:<br>  *  Allocates an x265_param instance. The returned param structure is not<br>diff -r 04db2bfee5d6 -r 36d20a880ddc 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" class="gmail_signature" data-smartmail="gmail_signature"><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>