<div dir="ltr">  # HG changeset patch<br># User Srikanth Kurapati <<a href="mailto:srikanth.kurapati@multicorewareinc.com" target="_blank">srikanth.kurapati@multicorewareinc.com</a>><br># Date 1571317991 -19800<br>#      Thu Oct 17 18:43:11 2019 +0530<br># Node ID 978a57943c8f622de41ddb1931504d6df4ebafc1<br># Parent  7fc1f6ef2b96aa7c85bbae06c649a02efc44e940<br>Histogram Based Scenecut Detection<br>1. Adds infrastructure to identify scenecuts using sad of edge and chroma histogram based thresholding.<br><br>diff -r 7fc1f6ef2b96 -r 978a57943c8f source/common/CMakeLists.txt<br>--- a/source/common/CMakeLists.txt Mon Oct 14 14:33:16 2019 +0530<br>+++ b/source/common/CMakeLists.txt Thu Oct 17 18:43:11 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>+    histscenecut.h histscenecut.cpp)<br>diff -r 7fc1f6ef2b96 -r 978a57943c8f source/common/common.h<br>--- a/source/common/common.h Mon Oct 14 14:33:16 2019 +0530<br>+++ b/source/common/common.h Thu Oct 17 18:43:11 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 7fc1f6ef2b96 -r 978a57943c8f source/common/histscenecut.cpp<br>--- /dev/null Thu Jan 01 00:00:00 1970 +0000<br>+++ b/source/common/histscenecut.cpp Thu Oct 17 18:43:11 2019 +0530<br>@@ -0,0 +1,637 @@<br>+#include "encoder.h"<br>+#include "histscenecut.h"<br>+#include "slicetype.h"<br>+<br>+using namespace std;<br>+using namespace X265_NS;<br>+<br>+namespace X265_NS {<br>+<br>+bool computeEdge(pixel * edgePic, pixel *refPic, pixel * edgeTheta, intptr_t stride, int height, int width)<br>+{<br>+    if (!edgePic || !refPic || !edgeTheta)<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>+        //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>+                    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>+                    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>+                    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>+                    edgePic[index] = (pixel)(gradientMagnitude >= edgeThreshold ? whitePixel : blackPixel);<br>+                }<br>+            }<br>+        }<br>+        return true;<br>+    }<br>+}<br>+<br>+Histogram::Histogram()<br>+{<br>+    memset(m_frequencyDistribution, 0, HISTOGRAM_SIZE * sizeof(int32_t));<br>+}<br>+<br>+void Histogram::copyHistogram(Histogram const& hist)<br>+{<br>+    memset(m_frequencyDistribution, 0, HISTOGRAM_SIZE * sizeof(int32_t));<br>+    memcpy(m_frequencyDistribution, hist.m_frequencyDistribution, sizeof(int32_t)*HISTOGRAM_SIZE);<br>+}<br>+<br>+Histogram::Histogram(Histogram const& hist)<br>+{<br>+    copyHistogram(hist);<br>+}<br>+<br>+Histogram & Histogram::operator=(Histogram const& hist)<br>+{<br>+    copyHistogram(hist);<br>+    return *this;<br>+}<br>+<br>+Histogram::~Histogram() {}<br>+<br>+YuvHistogram::YuvHistogram() {}<br>+<br>+void YuvHistogram::initHists()<br>+{<br>+    bAlloc = false;<br>+    bisUpdated = false;<br>+    m_param = NULL;<br>+    m_yuvHist = m_edgeHist = NULL;<br>+    m_planeSizes = m_planeHeights = m_planeWidths = NULL;<br>+    m_edgePic = m_edgeThetaPic = NULL;<br>+    m_planeSizes = X265_MALLOC(int32_t, m_planeCount);<br>+    m_planeHeights = X265_MALLOC(int32_t, m_planeCount);<br>+    m_planeWidths = X265_MALLOC(int32_t, m_planeCount);<br>+    if (!m_planeSizes || !m_planeHeights || !m_planeWidths)<br>+    {<br>+        x265_log(m_param, X265_LOG_ERROR, "unable to allocate memory for plane dimensions\n");<br>+        bAlloc &= false;<br>+    }<br>+    else<br>+    {<br>+        memset(m_planeSizes, 0, m_planeCount * sizeof(int32_t));<br>+        memset(m_planeHeights, 0, m_planeCount * sizeof(int32_t));<br>+        memset(m_planeWidths, 0, m_planeCount * sizeof(int32_t));<br>+        bAlloc &= true;<br>+    }<br>+<br>+    m_yuvHist = X265_MALLOC(Histogram, m_planeCount);<br>+    m_edgeHist = X265_MALLOC(Histogram, m_planeCount);<br>+    if (!m_yuvHist || !m_edgeHist)<br>+    {<br>+        bAlloc &= false;<br>+        x265_log(m_param, X265_LOG_ERROR, "unable to allocate memory for histograms\n");<br>+    }<br>+}<br>+<br>+void YuvHistogram::initHistograms(int32_t planeCount)<br>+{<br>+    this->m_planeCount = planeCount;<br>+    initHists();<br>+}<br>+<br>+void YuvHistogram::initHistograms(x265_param *p)<br>+{<br>+    m_param = p;<br>+    m_planeCount = x265_cli_csps[m_param->internalCsp].planes;<br>+    initHists();<br>+}<br>+<br>+bool YuvHistogram::allocEdgeBuffers()<br>+{<br>+    //allocate memory for edge filter output and histograms<br>+    bool isalloc = true;<br>+    m_edgePic = X265_MALLOC(pixel*, m_planeCount);<br>+    m_edgeThetaPic = X265_MALLOC(pixel*, m_planeCount);<br>+    if (!m_edgePic || !m_edgeThetaPic)<br>+    {<br>+        isalloc &= false;<br>+        x265_log(m_param, X265_LOG_ERROR, "unable to allocate memory for edge buffers\n");<br>+        return isalloc;<br>+    }<br>+    for (int i = 0; i < m_planeCount; i++) {<br>+        m_edgePic[i] = m_edgeThetaPic[i] = NULL;<br>+        m_edgePic[i] = X265_MALLOC(pixel, m_planeSizes[i]);<br>+        m_edgeThetaPic[i] = X265_MALLOC(pixel, m_planeSizes[i]);<br>+        if (m_edgePic[i] && m_edgeThetaPic[i])<br>+        {<br>+          memset(m_edgePic[i], 0, m_planeSizes[i] * sizeof(pixel));<br>+          memset(m_edgeThetaPic[i], 0, m_planeSizes[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>+void YuvHistogram::copyHist(YuvHistogram const& hist)<br>+{<br>+    m_maxuvHist = hist.m_maxuvHist;<br>+    m_planeCount = hist.m_planeCount;<br>+    bisUpdated = hist.bisUpdated;<br>+    m_param = hist.m_param;<br>+    memcpy(m_planeSizes, hist.m_planeSizes, m_planeCount * sizeof(int32_t));<br>+    memcpy(m_planeHeights, hist.m_planeHeights, m_planeCount * sizeof(int32_t));<br>+    memcpy(m_planeWidths, hist.m_planeWidths, m_planeCount * sizeof(int32_t));<br>+    memcpy(m_yuvHist, hist.m_yuvHist, m_planeCount * sizeof(Histogram));<br>+    memcpy(m_edgeHist, hist.m_edgeHist, m_planeCount * sizeof(Histogram));<br>+    if (!bAlloc)<br>+    {<br>+        bAlloc = false;<br>+        bAlloc = allocEdgeBuffers();<br>+    }<br>+    if (bAlloc)<br>+    {<br>+        for (int i = 0; i < m_planeCount; i++)<br>+        {<br>+            if (m_edgePic[i] && m_edgeThetaPic[i]) {<br>+                memcpy(m_edgePic[i], hist.m_edgePic[i], m_planeSizes[i] * sizeof(pixel));<br>+                memcpy(m_edgeThetaPic[i], hist.m_edgeThetaPic[i], m_planeSizes[i] * sizeof(pixel));<br>+            }<br>+        }<br>+    }<br>+}<br>+<br>+YuvHistogram::YuvHistogram(YuvHistogram const& hist)<br>+{<br>+    copyHist(hist);<br>+}<br>+<br>+YuvHistogram & YuvHistogram ::operator=(const YuvHistogram & refHist)<br>+{<br>+    copyHist(refHist);<br>+    return *this;<br>+}<br>+<br>+void YuvHistogram::freeHistogramBuffers()<br>+{<br>+    //de allocate memory for histograms and edge filtered output<br>+    if (m_edgePic && m_edgeThetaPic)<br>+    {<br>+        for (int i = 0; i < m_planeCount; i++)<br>+        {<br>+            if (m_edgePic[i] && m_edgeThetaPic[i])<br>+            {<br>+                X265_FREE_ZERO(m_edgePic[i]);<br>+                X265_FREE_ZERO(m_edgeThetaPic[i]);<br>+            }<br>+        }<br>+        X265_FREE_ZERO(m_edgePic);<br>+        X265_FREE_ZERO(m_edgeThetaPic);<br>+    }<br>+<br>+    if (m_planeSizes && m_planeHeights && m_planeWidths)<br>+    {<br>+        X265_FREE_ZERO(m_planeSizes);<br>+        X265_FREE_ZERO(m_planeHeights);<br>+        X265_FREE_ZERO(m_planeWidths);<br>+    }<br>+<br>+    if (m_yuvHist && m_edgeHist)<br>+    {<br>+        X265_FREE_ZERO(m_yuvHist);<br>+        X265_FREE_ZERO(m_edgeHist);<br>+    }<br>+}<br>+<br>+bool YuvHistogram::edgeFilter(x265_picture *pic)<br>+{<br>+<br>+    if (!bAlloc)<br>+    {<br>+        for (int i = 0; i < m_planeCount; i++)<br>+        {<br>+            m_planeWidths[i] = pic->width;<br>+            m_planeHeights[i] = pic->height >> x265_cli_csps[pic->colorSpace].height[i];<br>+            m_planeSizes[i] = m_planeWidths[i] * m_planeHeights[i];<br>+        }<br>+        bAlloc = allocEdgeBuffers();<br>+    }<br>+    if (bAlloc)<br>+    {<br>+        memset(m_edgePic[0], 0, sizeof(pixel) * m_planeSizes[0]);<br>+        memset(m_edgeThetaPic[0], 0, sizeof(pixel) * m_planeSizes[0]);<br>+        pixel *src = (pixel*)pic->planes[0];<br>+        pixel *edge_pic = m_edgePic[0];<br>+        pixel *ref_pic = src;<br>+        pixel *edge_theta = m_edgeThetaPic[0];<br>+        assert(edge_pic != NULL);<br>+        assert(ref_pic != NULL);<br>+        memcpy(edge_pic, src, m_planeSizes[0] * sizeof(pixel));<br>+        memcpy(ref_pic, src, m_planeSizes[0] * sizeof(pixel));<br>+<br>+        if (!computeEdge(edge_pic, ref_pic, edge_theta, m_planeWidths[0], m_planeHeights[0], m_planeWidths[0]))<br>+           {<br>+            x265_log(m_param, X265_LOG_ERROR, "Failed edge computation!");<br>+            return false;<br>+           }<br>+    }<br>+    else<br>+    {<br>+        return false;<br>+    }<br>+    return true;<br>+}<br>+<br>+bool YuvHistogram::computeHistograms(x265_picture &curFrame)<br>+{<br>+    bool bSuccess = false;<br>+    bSuccess = computeLumaEdgeHistogram(curFrame);<br>+    if (bSuccess)<br>+    {<br>+        if (m_planeCount > 1)<br>+        {<br>+            bSuccess &= computeChromaHistograms(curFrame);<br>+        }<br>+        return bSuccess;<br>+    }<br>+    else<br>+    {<br>+        return bSuccess;<br>+    }<br>+}<br>+<br>+bool YuvHistogram::computeLumaEdgeHistogram(x265_picture &frame)<br>+{<br>+    pixel pixelVal = 0;<br>+    memset(m_edgeHist[0].m_frequencyDistribution, 0, HISTOGRAM_SIZE * sizeof(int32_t));<br>+    int size = frame.height*(frame.stride[0] >> SHIFT);<br>+    for (int i = 0; i < size; i++)<br>+    {<br>+        pixelVal = m_edgePic[0][i];<br>+        m_edgeHist[0].m_frequencyDistribution[pixelVal]++;<br>+    }<br>+    return true;<br>+}<br>+<br>+bool YuvHistogram::computeChromaHistograms(x265_picture &frame)<br>+{<br>+    /*u hist calculation*/<br>+    pixel pixelVal = 0;<br>+    int HeightL = (frame.height >> x265_cli_csps[frame.colorSpace].height[1]);<br>+    int size = HeightL * (frame.stride[1] >> SHIFT);<br>+    memset(m_yuvHist[1].m_frequencyDistribution, 0, HISTOGRAM_SIZE * sizeof(int32_t));<br>+<br>+    for (int i = 0; i < size; i++)<br>+    {<br>+        pixelVal = *((pixel *)frame.planes[1] + i);<br>+        m_yuvHist[1].m_frequencyDistribution[pixelVal]++;<br>+    }<br>+<br>+    /*v hist calculation for independent uv planes */<br>+    if (m_planeCount == 3)<br>+    {<br>+        pixelVal = 0;<br>+        int heightV = (frame.height >> x265_cli_csps[frame.colorSpace].height[2]);<br>+        size = heightV * (frame.stride[2] >> SHIFT);<br>+        memset(m_yuvHist[2].m_frequencyDistribution, 0, HISTOGRAM_SIZE * sizeof(int32_t));<br>+        for (int i = 0; i < size; i++)<br>+        {<br>+            pixelVal = *((pixel *)frame.planes[2] + i);<br>+            m_yuvHist[2].m_frequencyDistribution[pixelVal]++;<br>+        }<br>+        for (int i = 0; i < HISTOGRAM_SIZE; i++)<br>+        {<br>+            m_maxuvHist.m_frequencyDistribution[i] = max(m_yuvHist[1].m_frequencyDistribution[i], m_yuvHist[2].m_frequencyDistribution[i]);<br>+        }<br>+    }<br>+    else<br>+    {<br>+        m_maxuvHist = m_yuvHist[1]; //for two planes scenario<br>+    }<br>+    return true;<br>+}<br>+<br>+ bool YuvHistogram::isUpdated()<br>+{<br>+    return bisUpdated;<br>+}<br>+<br>+ void YuvHistogram::setUpdateFlag(bool flag)<br>+{<br>+    bisUpdated = flag;<br>+}<br>+<br>+ bool YuvHistogram::getUpdateFlag()<br>+{<br>+    return bisUpdated;<br>+}<br>+<br>+SadYuv::SadYuv() { }<br>+<br>+void SadYuv::initSadYuv(int planecount)<br>+{<br>+    this->planeCount = planecount;<br>+    sadYuv = NULL;<br>+    psadYuv = NULL;<br>+    sadYuv = X265_MALLOC(int32_t, planeCount);<br>+    psadYuv = X265_MALLOC(double, planeCount);<br>+    if (sadYuv && psadYuv)<br>+    {<br>+        memset(sadYuv, 0, planeCount * sizeof(int32_t));<br>+        memset(psadYuv, 0, sizeof(double) * planeCount);<br>+    }<br>+}<br>+<br>+SadYuv & SadYuv::operator=(SadYuv const& sadVal)<br>+{<br>+    this->planeCount = sadVal.planeCount;<br>+    if (!sadYuv && !psadYuv)<br>+    {<br>+        sadYuv = NULL;<br>+        psadYuv = NULL;<br>+        sadYuv = X265_MALLOC(int32_t, planeCount);<br>+        psadYuv = X265_MALLOC(double, planeCount);<br>+        if (sadYuv && psadYuv)<br>+        {<br>+            memcpy(sadYuv, sadVal.sadYuv, planeCount * sizeof(int32_t));<br>+            memcpy(psadYuv, sadVal.psadYuv, sizeof(double) * planeCount);<br>+        }<br>+    }<br>+    else<br>+    {<br>+        if (sadYuv)<br>+            memcpy(sadYuv, sadVal.sadYuv, planeCount * sizeof(int32_t));<br>+        if (psadYuv)<br>+            memcpy(psadYuv, sadVal.psadYuv, sizeof(double) * planeCount);<br>+    }<br>+    return *this;<br>+}<br>+<br>+SadYuv::~SadYuv()<br>+{<br>+    if (sadYuv && psadYuv)<br>+    {<br>+        X265_FREE(sadYuv);<br>+        X265_FREE(psadYuv);<br>+    }<br>+}<br>+<br>+int sad_stats::m_framesRead=0;<br>+<br>+sad_stats::sad_stats(int planeCount, double threshold)<br>+{<br>+    this->m_planeCount = planeCount;<br>+    calculateThresholds(threshold);<br>+    allocateBuffers();<br>+}<br>+<br>+void sad_stats::calculateThresholds(double threshold)<br>+{<br>+    m_edgeHistThreshold = threshold;<br>+    m_strengthFactor = 2.0;<br>+    m_chromaHistThreshold = threshold * 10.0;<br>+    m_scaledEdgeThreshold = m_edgeHistThreshold * m_strengthFactor;<br>+    m_scaledChromaThreshold = m_chromaHistThreshold * m_strengthFactor;<br>+}<br>+<br>+void sad_stats::init()<br>+{<br>+    bSceneCut = NULL;<br>+    bDropFrame = NULL;<br>+    m_SadVals = NULL;<br>+    m_maxuvSadVals = NULL;<br>+    m_edgeSadVals = NULL;<br>+    m_prevHist = NULL;<br>+}<br>+<br>+sad_stats::~sad_stats()<br>+{<br>+    releaseBuffers();<br>+}<br>+<br>+void sad_stats::allocateBuffers()<br>+{<br>+    init();<br>+    m_SadVals = new SadYuv[DUP_BUFFER]();<br>+    m_maxuvSadVals = new SadYuv[DUP_BUFFER]();<br>+    m_edgeSadVals = new SadYuv[DUP_BUFFER]();<br>+    m_prevHist = new YuvHistogram();<br>+    m_prevHist->initHistograms(m_planeCount);<br>+    bSceneCut = new bool[DUP_BUFFER];<br>+    bDropFrame = new bool[DUP_BUFFER];<br>+<br>+    for (int i = 0; i < DUP_BUFFER; i++)<br>+    {<br>+        m_SadVals[i].initSadYuv(m_planeCount);<br>+        m_maxuvSadVals[i].initSadYuv(m_planeCount);<br>+        m_edgeSadVals[i].initSadYuv(m_planeCount);<br>+    }<br>+    if (!m_SadVals || !m_maxuvSadVals || !m_edgeSadVals || !bSceneCut || !bDropFrame)<br>+    {<br>+        x265_log(NULL, X265_LOG_ERROR, "Heap Error !");<br>+        exit(101);<br>+    }<br>+    else<br>+    {<br>+        memset(bSceneCut, false, 2 * sizeof(bool));<br>+        memset(bDropFrame, false, 2 * sizeof(bool));<br>+    }<br>+}<br>+<br>+void sad_stats::releaseBuffers()<br>+{<br>+    if (m_SadVals && m_maxuvSadVals && m_edgeSadVals && bSceneCut && bDropFrame && m_prevHist)<br>+    {<br>+        delete[] m_SadVals;<br>+        delete[] m_maxuvSadVals;<br>+        delete[] m_edgeSadVals;<br>+        delete[] bSceneCut;<br>+        delete[] bDropFrame;<br>+        delete   m_prevHist;<br>+    }<br>+}<br>+<br>+void sad_stats::updateSadVals(int32_t **yuvSadVal, int32_t **edgeSadVal, int32_t** maxuvSadVal,<br>+    double** maxuvNormalizedSad, double** yuvNormalizedSad, double ** edgeNormalizedSad)<br>+{<br>+    *yuvSadVal = m_SadVals[0].sadYuv,<br>+    *edgeSadVal = m_edgeSadVals[0].sadYuv,<br>+    *maxuvSadVal = m_maxuvSadVals[0].sadYuv;<br>+    *maxuvNormalizedSad = m_maxuvSadVals[0].psadYuv,<br>+    *yuvNormalizedSad = m_SadVals[0].psadYuv,<br>+    *edgeNormalizedSad = m_edgeSadVals[0].psadYuv;<br>+}<br>+<br>+void sad_stats::resetSadVals(int32_t *yuvSadVal, int32_t *edgeSadVal, int32_t* maxuvSadVal,<br>+    double* maxuvNormalizedSad, double* yuvNormalizedSad, double * edgeNormalizedSad)<br>+{<br>+    maxuvSadVal[0] = 0;<br>+    maxuvNormalizedSad[0] = 0.0;<br>+    memset(yuvSadVal, 0, m_planeCount * sizeof(int32_t));<br>+    memset(edgeSadVal, 0, m_planeCount * sizeof(int32_t));<br>+    memset(edgeNormalizedSad, 0, m_planeCount * sizeof(double));<br>+    memset(yuvNormalizedSad, 0, m_planeCount * sizeof(double));<br>+}<br>+<br>+bool sad_stats::computeSadValue(YuvHistogram *frameHists, int32_t* planeSizes)<br>+{<br>+    int32_t   *yuvSadVal = NULL, *edgeSadVal = NULL, *maxuvSadVal = NULL;<br>+    double *maxuvNormalizedSad = NULL, *yuvNormalizedSad = NULL, *edgeNormalizedSad = NULL;<br>+    YuvHistogram * refHist = NULL, *curHist = NULL;<br>+<br>+    /*inorder to process frames as per poc's updated by frame duplication */<br>+    if (m_framesRead > 0)<br>+    {<br>+        if (!frameHists[0].isUpdated() && frameHists[1].isUpdated())<br>+        {<br>+            refHist = m_prevHist;<br>+            curHist = frameHists + 1;<br>+            yuvSadVal = m_SadVals[1].sadYuv,<br>+            edgeSadVal = m_edgeSadVals[1].sadYuv,<br>+            maxuvSadVal = m_maxuvSadVals[1].sadYuv;<br>+            maxuvNormalizedSad = m_maxuvSadVals[1].psadYuv,<br>+            yuvNormalizedSad = m_SadVals[1].psadYuv,<br>+            edgeNormalizedSad = m_edgeSadVals[1].psadYuv;<br>+            frameHists[1].setUpdateFlag(false);<br>+        }<br>+        else if (frameHists[0].isUpdated() && frameHists[1].isUpdated())<br>+        {<br>+            refHist = m_prevHist;<br>+            curHist = frameHists;<br>+            frameHists[0].setUpdateFlag(false);<br>+            updateSadVals(&yuvSadVal, &edgeSadVal, &maxuvSadVal,&maxuvNormalizedSad,&yuvNormalizedSad,&edgeNormalizedSad);<br>+        }<br>+        else if (frameHists[0].isUpdated() && !frameHists[1].isUpdated())<br>+        {<br>+            refHist = m_prevHist;<br>+            curHist = frameHists;<br>+            frameHists[0].setUpdateFlag(false);<br>+            updateSadVals(&yuvSadVal, &edgeSadVal, &maxuvSadVal, &maxuvNormalizedSad, &yuvNormalizedSad, &edgeNormalizedSad);<br>+        }<br>+        else<br>+        {<br>+            return true;<br>+        }<br>+    }<br>+    else<br>+    {<br>+        curHist = frameHists;<br>+        updateSadVals(&yuvSadVal, &edgeSadVal, &maxuvSadVal, &maxuvNormalizedSad, &yuvNormalizedSad, &edgeNormalizedSad);<br>+        frameHists[0].setUpdateFlag(false);<br>+    }<br>+<br>+    if (m_framesRead == 0)<br>+    { //first frame is scenecut by default no sad computation for the same.<br>+        resetSadVals(yuvSadVal, edgeSadVal, maxuvSadVal, maxuvNormalizedSad, yuvNormalizedSad, edgeNormalizedSad);<br>+    }<br>+    else<br>+    {<br>+        int32_t freqDiff[3];<br>+        int32_t edgefreqDiff[3];<br>+        int32_t maxuvfreqDiff;<br>+        double chromaProbabilityDiff[3], edgeProbabilityDiff[3];<br>+        memset(chromaProbabilityDiff, 0, m_planeCount * sizeof(double));<br>+        memset(edgeProbabilityDiff, 0, m_planeCount * sizeof(double));<br>+        memset(freqDiff, 0, 3 * sizeof(int32_t));<br>+        maxuvfreqDiff = 0;<br>+        memset(edgefreqDiff, 0, 3 * sizeof(int32_t));<br>+        resetSadVals(yuvSadVal, edgeSadVal, maxuvSadVal, maxuvNormalizedSad, yuvNormalizedSad, edgeNormalizedSad);<br>+        for (int i = 0; i < m_planeCount; i++)<br>+        {<br>+            for (int j = 0; j < HISTOGRAM_SIZE; j++)<br>+            {<br>+                if (i == 0 && m_planeCount >= 1)<br>+                {<br>+                    maxuvfreqDiff = (abs(curHist->m_maxuvHist.m_frequencyDistribution[j] - refHist->m_maxuvHist.m_frequencyDistribution[j]));<br>+                    maxuvSadVal[i] += maxuvfreqDiff;<br>+                    maxuvNormalizedSad[i] += (double)maxuvfreqDiff / planeSizes[i];<br>+                    edgefreqDiff[i] = abs(curHist->m_edgeHist[i].m_frequencyDistribution[j] - refHist->m_edgeHist[i].m_frequencyDistribution[j]);<br>+                    edgeProbabilityDiff[i] = double(edgefreqDiff[i]) / planeSizes[i];<br>+                    edgeSadVal[i] += edgefreqDiff[i];<br>+                    edgeNormalizedSad[i] += edgeProbabilityDiff[i];<br>+                }<br>+                else<br>+                {<br>+                    freqDiff[i] = abs(curHist->m_yuvHist[i].m_frequencyDistribution[j] - refHist->m_yuvHist[i].m_frequencyDistribution[j]);<br>+                    chromaProbabilityDiff[i] = (double)freqDiff[i] / planeSizes[i];<br>+                    yuvSadVal[i] += freqDiff[i];<br>+                    yuvNormalizedSad[i] += chromaProbabilityDiff[i];<br>+                }<br>+            }<br>+        }<br>+    }<br>+    *m_prevHist = *curHist;<br>+    m_framesRead++;<br>+    return  true;<br>+}<br>+<br>+void sad_stats::findSceneCuts(x265_picture * picList, bool& bDup)<br>+{<br>+        if (m_framesRead == 1)<br>+        {<br>+            //for first frame<br>+            bSceneCut[0] = true;<br>+            bDropFrame[0] = false;<br>+            picList->analysisData.bScenecut = (int)getSceneCutflag(0);<br>+            bDup = getDropflag(0);<br>+            picList->analysisData.edgeSadValue = m_edgeSadVals[0].psadYuv[0];<br>+            picList->analysisData.chromaSadValue = m_maxuvSadVals[0].psadYuv[0];<br>+        }<br>+        else<br>+        {<br>+            bSceneCut[1] = bDropFrame[1] = false;<br>+            if (m_edgeSadVals[1].psadYuv[0] == 0)<br>+            {<br>+                bDropFrame[1] = true;<br>+            }<br>+            else if (m_edgeSadVals[1].psadYuv[0] > m_edgeHistThreshold || m_maxuvSadVals[1].psadYuv[0] >= m_chromaHistThreshold)<br>+            {<br>+                bSceneCut[1] = true;<br>+                bDropFrame[1] = false;<br>+            }<br>+            else if (m_edgeSadVals[1].psadYuv[0] >  m_scaledEdgeThreshold || m_maxuvSadVals[1].psadYuv[0] >= m_scaledChromaThreshold)<br>+            {<br>+                bSceneCut[1] = true;<br>+                bDropFrame[1] = false;<br>+            }<br>+            picList->analysisData.bScenecut = (int)getSceneCutflag(1);<br>+            bDup = getDropflag(1);<br>+            bDup = getDropflag(1);<br>+            picList->analysisData.edgeSadValue = m_edgeSadVals[1].psadYuv[0];<br>+            picList->analysisData.chromaSadValue = m_maxuvSadVals[1].psadYuv[0];<br>+        }<br>+    }<br>+<br>+bool sad_stats::getDropflag(int idx)<br>+{<br>+    return bDropFrame[idx];<br>+}<br>+<br>+bool sad_stats::getSceneCutflag(int idx)<br>+{<br>+    return bSceneCut[idx];<br>+}<br>+<br>+}<br>diff -r 7fc1f6ef2b96 -r 978a57943c8f source/common/histscenecut.h<br>--- /dev/null Thu Jan 01 00:00:00 1970 +0000<br>+++ b/source/common/histscenecut.h Thu Oct 17 18:43:11 2019 +0530<br>@@ -0,0 +1,106 @@<br>+#ifndef SCENECUT_H<br>+#define SCENECUT_H<br>+<br>+#include "yuv.h"<br>+#include "common.h"<br>+<br>+#ifdef HIGH_BIT_DEPTH<br>+#define edgeThreshold 1023.0<br>+#define whitePixel 1023.0<br>+#else<br>+#define edgeThreshold 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 m_frequencyDistribution[HISTOGRAM_SIZE];<br>+    Histogram();<br>+    void copyHistogram(Histogram const& hist);<br>+    Histogram(Histogram const& hist);<br>+    Histogram & operator=(Histogram const& hist);<br>+    ~Histogram();<br>+};<br>+<br>+class YuvHistogram {<br>+public:<br>+    pixel     **m_edgePic;<br>+    pixel     **m_edgeThetaPic;<br>+    Histogram  *m_yuvHist;<br>+    Histogram  *m_edgeHist;<br>+    Histogram   m_maxuvHist;<br>+    int32_t    *m_planeSizes;<br>+    int32_t    *m_planeHeights;<br>+    int32_t    *m_planeWidths;<br>+    int32_t     m_planeCount;<br>+    x265_param *m_param; /*for handling various color spaces*/<br>+    bool bisUpdated;<br>+    bool bAlloc;<br>+    YuvHistogram();<br>+    ~YuvHistogram();<br>+    void initHists();<br>+    void initHistograms(int32_t planeCount);<br>+    void initHistograms(x265_param *p);<br>+    bool allocEdgeBuffers();<br>+    void copyHist(YuvHistogram const & hist);<br>+    YuvHistogram(YuvHistogram const& hist);<br>+    YuvHistogram & operator=(const YuvHistogram & refHist);<br>+    void freeHistogramBuffers();<br>+    bool edgeFilter(x265_picture *frame);<br>+    bool computeHistograms(x265_picture &curFrame);<br>+    bool computeLumaEdgeHistogram(x265_picture &frame);<br>+    bool computeChromaHistograms(x265_picture &frame);<br>+    bool isUpdated();<br>+    void setUpdateFlag(bool flag);<br>+    bool getUpdateFlag();<br>+};<br>+<br>+struct SadYuv {<br>+    int32_t *sadYuv;<br>+    double  *psadYuv;<br>+    int      planeCount;<br>+    SadYuv();<br>+    ~SadYuv();<br>+    void initSadYuv(int planeCount);<br>+    SadYuv & operator=(SadYuv const& sadVal);<br>+};<br>+<br>+class sad_stats {<br>+    bool            *bSceneCut;<br>+    bool            *bDropFrame;<br>+    SadYuv          *m_SadVals;<br>+    SadYuv          *m_maxuvSadVals;<br>+    SadYuv          *m_edgeSadVals;<br>+    int              m_planeCount;<br>+    YuvHistogram    *m_prevHist;<br>+    static int       m_framesRead;<br>+    double           m_edgeHistThreshold;<br>+    double           m_chromaHistThreshold;<br>+    double           m_scaledChromaThreshold;<br>+    double           m_scaledEdgeThreshold;<br>+    double           m_strengthFactor;<br>+public:<br>+    sad_stats(int planeCount, double threshold);<br>+    ~sad_stats();<br>+    void init();<br>+    void allocateBuffers();<br>+    void releaseBuffers();<br>+    void updateSadVals(int32_t **yuvSadVal, int32_t **edgeSadVal, int32_t** maxuvSadVal, double** maxuvNormalizedSad, double** yuvNormalizedSad, double ** edgeNormalizedSad);<br>+    void resetSadVals(int32_t *yuvSadVal, int32_t *edgeSadVal, int32_t *maxuvSadVal, double *maxuvNormalizedSad, double *yuvNormalizedSad, double *edgeNormalizedSad);<br>+    void calculateThresholds(double threshold);<br>+    bool computeSadValue(YuvHistogram *frames, int32_t* planeSizes);<br>+    void findSceneCuts(x265_picture * picList, bool & bDup);<br>+    bool getDropflag(int idx);<br>+    bool getSceneCutflag(int idx);<br>+};<br>+<br>+bool computeEdge(pixel *edgePic, pixel *refPic, pixel *edgeTheta, intptr_t stride, int height, int width);<br>+<br>+}<br>+<br>+#endif<br>diff -r 7fc1f6ef2b96 -r 978a57943c8f source/x265.h<br>--- a/source/x265.h Mon Oct 14 14:33:16 2019 +0530<br>+++ b/source/x265.h Thu Oct 17 18:43:11 2019 +0530<br>@@ -210,7 +210,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>@@ -219,6 +219,8 @@<br>     uint8_t*                          modeFlag[2];<br>     x265_analysis_validate            saveParam;<br>     x265_analysis_distortion_data*    distortionData;<br>+    double                             edgeSadValue;<br>+    double                             chromaSadValue;<br> } x265_analysis_data;<br> <br> /* cu statistics */<br>@@ -291,12 +293,15 @@<br>     char             sliceType;<br>     int              bScenecut;<br>     double           ipCostRatio;<br>+<br>     int              frameLatency;<br>     x265_cu_stats    cuStats;<br>     x265_pu_stats    puStats;<br>     double           totalFrameTime;<br>     double           vmafFrameScore;<br>     double           bufferFillFinal;<br>+    double           yedgeSadValue;<br>+    double           chromaSadValue;<br> } x265_frame_stats;<br> <br> typedef struct x265_ctu_info_t<br>@@ -471,6 +476,9 @@<br>     uint32_t picStruct;<br> <br>     int    width;<br>+<br>+    //Flag to determine the latest frame in the buffer<br>+    bool bufUpdated;<br> } x265_picture;<br> <br> typedef enum<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<font color="#888888"><br><div><br></div></font><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>