<div dir="ltr"><div dir="ltr"><div>From 4684e9ce76391341f6781a5291ab33fe9097324f Mon Sep 17 00:00:00 2001</div><div>From: ashok2022 <<a href="mailto:ashok@multicorewareinc.com">ashok@multicorewareinc.com</a>></div><div>Date: Wed, 26 Oct 2022 12:25:21 +0530</div><div>Subject: [PATCH] Compute picture variance, pixel intensity for histogram based</div><div> scene change</div><div><br></div><div>---</div><div> source/common/frame.cpp      |   3 +-</div><div> source/common/lowres.cpp     |  94 +++++++++-</div><div> source/common/lowres.h       |  25 ++-</div><div> source/encoder/slicetype.cpp | 320 +++++++++++++++++++++++++++++++++++</div><div> source/encoder/slicetype.h   |  48 ++++++</div><div> 5 files changed, 485 insertions(+), 5 deletions(-)</div><div><br></div><div>diff --git a/source/common/frame.cpp b/source/common/frame.cpp</div><div>index f51270bf0..d7f8ce2a8 100644</div><div>--- a/source/common/frame.cpp</div><div>+++ b/source/common/frame.cpp</div><div>@@ -330,7 +330,8 @@ void Frame::destroy()</div><div>         X265_FREE(m_addOnPrevChange);</div><div>         m_addOnPrevChange = NULL;</div><div>     }</div><div>-    m_lowres.destroy();</div><div>+</div><div>+    m_lowres.destroy(m_param);</div><div>     X265_FREE(m_rcData);</div><div> </div><div>     if (m_param->bDynamicRefine)</div><div>diff --git a/source/common/lowres.cpp b/source/common/lowres.cpp</div><div>index 56b98b364..16ff02509 100644</div><div>--- a/source/common/lowres.cpp</div><div>+++ b/source/common/lowres.cpp</div><div>@@ -28,6 +28,28 @@</div><div> </div><div> using namespace X265_NS;</div><div> </div><div>+/*</div><div>+ * Down Sample input picture</div><div>+ */</div><div>+static</div><div>+void frame_lowres_core(const pixel* src0, pixel* dst0,</div><div>+    intptr_t src_stride, intptr_t dst_stride, int width, int height)</div><div>+{</div><div>+    for (int y = 0; y < height; y++)</div><div>+    {</div><div>+        const pixel* src1 = src0 + src_stride;</div><div>+        for (int x = 0; x < width; x++)</div><div>+        {</div><div>+            // slower than naive bilinear, but matches asm</div><div>+#define FILTER(a, b, c, d) ((((a + b + 1) >> 1) + ((c + d + 1) >> 1) + 1) >> 1)</div><div>+            dst0[x] = FILTER(src0[2 * x], src1[2 * x], src0[2 * x + 1], src1[2 * x + 1]);</div><div>+#undef FILTER</div><div>+        }</div><div>+        src0 += src_stride * 2;</div><div>+        dst0 += dst_stride;</div><div>+    }</div><div>+}</div><div>+</div><div> bool PicQPAdaptationLayer::create(uint32_t width, uint32_t height, uint32_t partWidth, uint32_t partHeight, uint32_t numAQPartInWidthExt, uint32_t numAQPartInHeightExt)</div><div> {</div><div>     aqPartWidth = partWidth;</div><div>@@ -193,13 +215,45 @@ bool Lowres::create(x265_param* param, PicYuv *origPic, uint32_t qgSize)</div><div>     if (param->rc.frameSegment)</div><div>         lowresEdgePlane = X265_MALLOC(pixel, lumaStride * (lines + (origPic->m_lumaMarginY * 2)));</div><div> </div><div>+    if (param->bHistBasedSceneCut)</div><div>+    {</div><div>+        quarterSampleLowResWidth = widthFullRes / 4;</div><div>+        quarterSampleLowResHeight = heightFullRes / 4;</div><div>+        quarterSampleLowResOriginX = 16;</div><div>+        quarterSampleLowResOriginY = 16;</div><div>+        quarterSampleLowResStrideY = quarterSampleLowResWidth + 2 * quarterSampleLowResOriginY;</div><div>+</div><div>+        size_t quarterSampleLowResPlanesize = quarterSampleLowResStrideY * (quarterSampleLowResHeight + 2 * quarterSampleLowResOriginX);</div><div>+        /* allocate quarter sampled lowres buffers */</div><div>+        CHECKED_MALLOC_ZERO(quarterSampleLowResBuffer, pixel, quarterSampleLowResPlanesize);</div><div>+</div><div>+        // Allocate memory for Histograms</div><div>+        picHistogram = X265_MALLOC(uint32_t***, NUMBER_OF_SEGMENTS_IN_WIDTH * sizeof(uint32_t***));</div><div>+        picHistogram[0] = X265_MALLOC(uint32_t**, NUMBER_OF_SEGMENTS_IN_WIDTH * NUMBER_OF_SEGMENTS_IN_HEIGHT);</div><div>+        for (uint32_t wd = 1; wd < NUMBER_OF_SEGMENTS_IN_WIDTH; wd++) {</div><div>+            picHistogram[wd] = picHistogram[0] + wd * NUMBER_OF_SEGMENTS_IN_HEIGHT;</div><div>+        }</div><div>+</div><div>+        for (uint32_t regionInPictureWidthIndex = 0; regionInPictureWidthIndex < NUMBER_OF_SEGMENTS_IN_WIDTH; regionInPictureWidthIndex++)</div><div>+        {</div><div>+            for (uint32_t regionInPictureHeightIndex = 0; regionInPictureHeightIndex < NUMBER_OF_SEGMENTS_IN_HEIGHT; regionInPictureHeightIndex++)</div><div>+            {</div><div>+                picHistogram[regionInPictureWidthIndex][regionInPictureHeightIndex] = X265_MALLOC(uint32_t*, NUMBER_OF_SEGMENTS_IN_WIDTH *sizeof(uint32_t*));</div><div>+                picHistogram[regionInPictureWidthIndex][regionInPictureHeightIndex][0] = X265_MALLOC(uint32_t, 3 * HISTOGRAM_NUMBER_OF_BINS * sizeof(uint32_t));</div><div>+                for (uint32_t wd = 1; wd < 3; wd++) {</div><div>+                    picHistogram[regionInPictureWidthIndex][regionInPictureHeightIndex][wd] = picHistogram[regionInPictureWidthIndex][regionInPictureHeightIndex][0] + wd * HISTOGRAM_NUMBER_OF_BINS;</div><div>+                }</div><div>+            }</div><div>+        }</div><div>+    }</div><div>+</div><div>     return true;</div><div> </div><div> fail:</div><div>     return false;</div><div> }</div><div> </div><div>-void Lowres::destroy()</div><div>+void Lowres::destroy(x265_param* param)</div><div> {</div><div>     X265_FREE(buffer[0]);</div><div>     if(bEnableHME)</div><div>@@ -237,7 +291,8 @@ void Lowres::destroy()</div><div>     X265_FREE(invQscaleFactor8x8);</div><div>     X265_FREE(edgeInclined);</div><div>     X265_FREE(qpAqMotionOffset);</div><div>-    X265_FREE(blockVariance);</div><div>+    if (param->bDynamicRefine || param->bEnableFades)</div><div>+        X265_FREE(blockVariance);</div><div> </div><div>     if (maxAQDepth > 0)</div><div>     {</div><div>@@ -258,6 +313,29 @@ void Lowres::destroy()</div><div> </div><div>         delete[] pAQLayer;</div><div>     }</div><div>+</div><div>+    // Histograms</div><div>+    if (param->bHistBasedSceneCut)</div><div>+    {</div><div>+        for (uint32_t segmentInFrameWidthIdx = 0; segmentInFrameWidthIdx < NUMBER_OF_SEGMENTS_IN_WIDTH; segmentInFrameWidthIdx++)</div><div>+        {</div><div>+            if (picHistogram[segmentInFrameWidthIdx])</div><div>+            {</div><div>+                for (uint32_t segmentInFrameHeightIdx = 0; segmentInFrameHeightIdx < NUMBER_OF_SEGMENTS_IN_HEIGHT; segmentInFrameHeightIdx++)</div><div>+                {</div><div>+                    if (picHistogram[segmentInFrameWidthIdx][segmentInFrameHeightIdx])</div><div>+                        X265_FREE(picHistogram[segmentInFrameWidthIdx][segmentInFrameHeightIdx][0]);</div><div>+                    X265_FREE(picHistogram[segmentInFrameWidthIdx][segmentInFrameHeightIdx]);</div><div>+                }</div><div>+            }</div><div>+        }</div><div>+        if (picHistogram)</div><div>+            X265_FREE(picHistogram[0]);</div><div>+        X265_FREE(picHistogram);</div><div>+</div><div>+        X265_FREE(quarterSampleLowResBuffer);</div><div>+</div><div>+    }</div><div> }</div><div> // (re) initialize lowres state</div><div> void Lowres::init(PicYuv *origPic, int poc)</div><div>@@ -314,4 +392,16 @@ void Lowres::init(PicYuv *origPic, int poc)</div><div>     }</div><div> </div><div>     fpelPlane[0] = lowresPlane[0];</div><div>+</div><div>+    if (origPic->m_param->bHistBasedSceneCut)</div><div>+    {</div><div>+        // Quarter Sampled Input Picture Formation</div><div>+        // TO DO: Replace with ASM function</div><div>+        frame_lowres_core(</div><div>+            lowresPlane[0],</div><div>+            quarterSampleLowResBuffer + quarterSampleLowResOriginX + quarterSampleLowResOriginY * quarterSampleLowResStrideY,</div><div>+            lumaStride,</div><div>+            quarterSampleLowResStrideY,</div><div>+            widthFullRes / 4, heightFullRes / 4);</div><div>+    }</div><div> }</div><div>diff --git a/source/common/lowres.h b/source/common/lowres.h</div><div>index 8adb93a81..c2ae270e3 100644</div><div>--- a/source/common/lowres.h</div><div>+++ b/source/common/lowres.h</div><div>@@ -32,6 +32,10 @@</div><div> namespace X265_NS {</div><div> // private namespace</div><div> </div><div>+#define HISTOGRAM_NUMBER_OF_BINS         256</div><div>+#define NUMBER_OF_SEGMENTS_IN_WIDTH      4</div><div>+#define NUMBER_OF_SEGMENTS_IN_HEIGHT     4</div><div>+</div><div> struct ReferencePlanes</div><div> {</div><div>     ReferencePlanes() { memset(this, 0, sizeof(ReferencePlanes)); }</div><div>@@ -233,13 +237,30 @@ struct Lowres : public ReferencePlanes</div><div>     uint32_t heightFullRes;</div><div>     uint32_t m_maxCUSize;</div><div>     uint32_t m_qgSize;</div><div>-    </div><div>+</div><div>     uint16_t* propagateCost;</div><div>     double    weightedCostDelta[X265_BFRAME_MAX + 2];</div><div>     ReferencePlanes weightedRef[X265_BFRAME_MAX + 2];</div><div> </div><div>+    /* For hist-based scenecut */</div><div>+    int          quarterSampleLowResWidth;     // width of 1/4 lowres frame in pixels</div><div>+    int          quarterSampleLowResHeight;    // height of 1/4 lowres frame in pixels</div><div>+    int          quarterSampleLowResStrideY;</div><div>+    int          quarterSampleLowResOriginX;</div><div>+    int          quarterSampleLowResOriginY;</div><div>+    pixel       *quarterSampleLowResBuffer;</div><div>+    bool         bHistScenecutAnalyzed;</div><div>+</div><div>+    uint16_t     picAvgVariance;</div><div>+    uint16_t     picAvgVarianceCb;</div><div>+    uint16_t     picAvgVarianceCr;</div><div>+</div><div>+    uint32_t ****picHistogram;</div><div>+    uint64_t     averageIntensityPerSegment[NUMBER_OF_SEGMENTS_IN_WIDTH][NUMBER_OF_SEGMENTS_IN_HEIGHT][3];</div><div>+    uint8_t      averageIntensity[3];</div><div>+</div><div>     bool create(x265_param* param, PicYuv *origPic, uint32_t qgSize);</div><div>-    void destroy();</div><div>+    void destroy(x265_param* param);</div><div>     void init(PicYuv *origPic, int poc);</div><div> };</div><div> }</div><div>diff --git a/source/encoder/slicetype.cpp b/source/encoder/slicetype.cpp</div><div>index 1ff5abcc8..9343593cc 100644</div><div>--- a/source/encoder/slicetype.cpp</div><div>+++ b/source/encoder/slicetype.cpp</div><div>@@ -45,6 +45,14 @@ using namespace X265_NS;</div><div> </div><div> namespace {</div><div> </div><div>+uint32_t acEnergyVarHist(uint64_t sum_ssd, int shift)</div><div>+{</div><div>+    uint32_t sum = (uint32_t)sum_ssd;</div><div>+    uint32_t ssd = (uint32_t)(sum_ssd >> 32);</div><div>+</div><div>+    return ssd - ((uint64_t)sum * sum >> shift);</div><div>+}</div><div>+</div><div> /* Compute variance to derive AC energy of each block */</div><div> inline uint32_t acEnergyVar(Frame *curFrame, uint64_t sum_ssd, int shift, int plane)</div><div> {</div><div>@@ -1050,6 +1058,30 @@ Lookahead::Lookahead(x265_param *param, ThreadPool* pool)</div><div>     m_countPreLookahead = 0;</div><div> #endif</div><div> </div><div>+    m_accHistDiffRunningAvgCb = X265_MALLOC(uint32_t*, NUMBER_OF_SEGMENTS_IN_WIDTH * sizeof(uint32_t*));</div><div>+    m_accHistDiffRunningAvgCb[0] = X265_MALLOC(uint32_t, NUMBER_OF_SEGMENTS_IN_WIDTH * NUMBER_OF_SEGMENTS_IN_HEIGHT);</div><div>+    memset(m_accHistDiffRunningAvgCb[0], 0, sizeof(uint32_t) * NUMBER_OF_SEGMENTS_IN_WIDTH * NUMBER_OF_SEGMENTS_IN_HEIGHT);</div><div>+    for (uint32_t w = 1; w < NUMBER_OF_SEGMENTS_IN_WIDTH; w++) {</div><div>+        m_accHistDiffRunningAvgCb[w] = m_accHistDiffRunningAvgCb[0] + w * NUMBER_OF_SEGMENTS_IN_HEIGHT;</div><div>+    }</div><div>+</div><div>+    m_accHistDiffRunningAvgCr = X265_MALLOC(uint32_t*, NUMBER_OF_SEGMENTS_IN_WIDTH * sizeof(uint32_t*));</div><div>+    m_accHistDiffRunningAvgCr[0] = X265_MALLOC(uint32_t, NUMBER_OF_SEGMENTS_IN_WIDTH * NUMBER_OF_SEGMENTS_IN_HEIGHT);</div><div>+    memset(m_accHistDiffRunningAvgCr[0], 0, sizeof(uint32_t) * NUMBER_OF_SEGMENTS_IN_WIDTH * NUMBER_OF_SEGMENTS_IN_HEIGHT);</div><div>+    for (uint32_t w = 1; w < NUMBER_OF_SEGMENTS_IN_WIDTH; w++) {</div><div>+        m_accHistDiffRunningAvgCr[w] = m_accHistDiffRunningAvgCr[0] + w * NUMBER_OF_SEGMENTS_IN_HEIGHT;</div><div>+    }</div><div>+</div><div>+    m_accHistDiffRunningAvg = X265_MALLOC(uint32_t*, NUMBER_OF_SEGMENTS_IN_WIDTH * sizeof(uint32_t*));</div><div>+    m_accHistDiffRunningAvg[0] = X265_MALLOC(uint32_t, NUMBER_OF_SEGMENTS_IN_WIDTH * NUMBER_OF_SEGMENTS_IN_HEIGHT);</div><div>+    memset(m_accHistDiffRunningAvg[0], 0, sizeof(uint32_t) * NUMBER_OF_SEGMENTS_IN_WIDTH * NUMBER_OF_SEGMENTS_IN_HEIGHT);</div><div>+    for (uint32_t w = 1; w < NUMBER_OF_SEGMENTS_IN_WIDTH; w++) {</div><div>+        m_accHistDiffRunningAvg[w] = m_accHistDiffRunningAvg[0] + w * NUMBER_OF_SEGMENTS_IN_HEIGHT;</div><div>+    }</div><div>+</div><div>+    m_resetRunningAvg = true;</div><div>+</div><div>+    m_segmentCountThreshold = (uint32_t)(((float)((NUMBER_OF_SEGMENTS_IN_WIDTH * NUMBER_OF_SEGMENTS_IN_HEIGHT) * 50) / 100) + 0.5);</div><div> }</div><div> </div><div> #if DETAILED_CU_STATS</div><div>@@ -1415,6 +1447,290 @@ double computeEdgeIntensity(pixel *inPlane, int width, int height, intptr_t stri</div><div>     return (count / (width * height)) * 100;</div><div> }</div><div> </div><div>+uint32_t LookaheadTLD::calcVariance(pixel* inpSrc, intptr_t stride, intptr_t blockOffset, uint32_t plane)</div><div>+{</div><div>+    pixel* src = inpSrc + blockOffset;</div><div>+</div><div>+    uint32_t var;</div><div>+    if (!plane)</div><div>+        var = acEnergyVarHist(<a href="http://primitives.cu">primitives.cu</a>[BLOCK_8x8].var(src, stride), 6);</div><div>+    else</div><div>+        var = acEnergyVarHist(<a href="http://primitives.cu">primitives.cu</a>[BLOCK_4x4].var(src, stride), 4);</div><div>+</div><div>+    x265_emms();</div><div>+    return var;</div><div>+}</div><div>+</div><div>+/*</div><div>+** Compute Block and Picture Variance, Block Mean for all blocks in the picture</div><div>+*/</div><div>+void LookaheadTLD::computePictureStatistics(Frame *curFrame)</div><div>+{</div><div>+    int maxCol = curFrame->m_fencPic->m_picWidth;</div><div>+    int maxRow = curFrame->m_fencPic->m_picHeight;</div><div>+    intptr_t inpStride = curFrame->m_fencPic->m_stride;</div><div>+</div><div>+    // Variance</div><div>+    uint64_t picTotVariance = 0;</div><div>+    uint32_t variance;</div><div>+</div><div>+    uint64_t blockXY = 0;</div><div>+    pixel* src = curFrame->m_fencPic->m_picOrg[0];</div><div>+</div><div>+    for (int blockY = 0; blockY < maxRow; blockY += 8)</div><div>+    {</div><div>+        uint64_t rowVariance = 0;</div><div>+        for (int blockX = 0; blockX < maxCol; blockX += 8)</div><div>+        {</div><div>+            intptr_t blockOffsetLuma = blockX + (blockY * inpStride);</div><div>+</div><div>+            variance = calcVariance(</div><div>+                src,</div><div>+                inpStride,</div><div>+                blockOffsetLuma, 0);</div><div>+</div><div>+            rowVariance += variance;</div><div>+            blockXY++;</div><div>+        }</div><div>+        picTotVariance += (uint16_t)(rowVariance / maxCol);</div><div>+    }</div><div>+</div><div>+    curFrame->m_lowres.picAvgVariance = (uint16_t)(picTotVariance / maxRow);</div><div>+</div><div>+    // Collect chroma variance</div><div>+    int hShift = curFrame->m_fencPic->m_hChromaShift;</div><div>+    int vShift = curFrame->m_fencPic->m_vChromaShift;</div><div>+</div><div>+    int maxColChroma = curFrame->m_fencPic->m_picWidth >> hShift;</div><div>+    int maxRowChroma = curFrame->m_fencPic->m_picHeight >> vShift;</div><div>+    intptr_t cStride = curFrame->m_fencPic->m_strideC;</div><div>+</div><div>+    pixel* srcCb = curFrame->m_fencPic->m_picOrg[1];</div><div>+</div><div>+    picTotVariance = 0;</div><div>+    for (int blockY = 0; blockY < maxRowChroma; blockY += 4)</div><div>+    {</div><div>+        uint64_t rowVariance = 0;</div><div>+        for (int blockX = 0; blockX < maxColChroma; blockX += 4)</div><div>+        {</div><div>+            intptr_t blockOffsetChroma = blockX + blockY * cStride;</div><div>+</div><div>+            variance = calcVariance(</div><div>+                srcCb,</div><div>+                cStride,</div><div>+                blockOffsetChroma, 1);</div><div>+</div><div>+            rowVariance += variance;</div><div>+            blockXY++;</div><div>+        }</div><div>+        picTotVariance += (uint16_t)(rowVariance / maxColChroma);</div><div>+    }</div><div>+</div><div>+    curFrame->m_lowres.picAvgVarianceCb = (uint16_t)(picTotVariance / maxRowChroma);</div><div>+</div><div>+</div><div>+    pixel* srcCr = curFrame->m_fencPic->m_picOrg[2];</div><div>+</div><div>+    picTotVariance = 0;</div><div>+    for (int blockY = 0; blockY < maxRowChroma; blockY += 4)</div><div>+    {</div><div>+        uint64_t rowVariance = 0;</div><div>+        for (int blockX = 0; blockX < maxColChroma; blockX += 4)</div><div>+        {</div><div>+            intptr_t blockOffsetChroma = blockX + blockY * cStride;</div><div>+</div><div>+            variance = calcVariance(</div><div>+                srcCr,</div><div>+                cStride,</div><div>+                blockOffsetChroma, 2);</div><div>+</div><div>+            rowVariance += variance;</div><div>+            blockXY++;</div><div>+        }</div><div>+        picTotVariance += (uint16_t)(rowVariance / maxColChroma);</div><div>+    }</div><div>+</div><div>+    curFrame->m_lowres.picAvgVarianceCr = (uint16_t)(picTotVariance / maxRowChroma);</div><div>+}</div><div>+</div><div>+/*</div><div>+* Compute histogram of n-bins for the input</div><div>+*/</div><div>+void LookaheadTLD::calculateHistogram(</div><div>+    pixel     *inputSrc,</div><div>+    uint32_t   inputWidth,</div><div>+    uint32_t   inputHeight,</div><div>+    intptr_t   stride,</div><div>+    uint8_t    dsFactor,</div><div>+    uint32_t  *histogram,</div><div>+    uint64_t  *sum)</div><div>+</div><div>+{</div><div>+    *sum = 0;</div><div>+</div><div>+    for (uint32_t verticalIdx = 0; verticalIdx < inputHeight; verticalIdx += dsFactor)</div><div>+    {</div><div>+        for (uint32_t horizontalIdx = 0; horizontalIdx < inputWidth; horizontalIdx += dsFactor)</div><div>+        {</div><div>+            ++(histogram[inputSrc[horizontalIdx]]);</div><div>+            *sum += inputSrc[horizontalIdx];</div><div>+        }</div><div>+        inputSrc += (stride << (dsFactor >> 1));</div><div>+    }</div><div>+</div><div>+    return;</div><div>+}</div><div>+</div><div>+/*</div><div>+* Compute histogram bins and chroma pixel intensity *</div><div>+*/</div><div>+void LookaheadTLD::computeIntensityHistogramBinsChroma(</div><div>+    Frame    *curFrame,</div><div>+    uint64_t *sumAverageIntensityCb,</div><div>+    uint64_t *sumAverageIntensityCr)</div><div>+{</div><div>+    uint64_t    sum;</div><div>+    uint8_t     dsFactor = 4;</div><div>+</div><div>+    uint32_t segmentWidth = curFrame->m_lowres.widthFullRes / NUMBER_OF_SEGMENTS_IN_WIDTH;</div><div>+    uint32_t segmentHeight = curFrame->m_lowres.heightFullRes / NUMBER_OF_SEGMENTS_IN_HEIGHT;</div><div>+</div><div>+    for (uint32_t segmentInFrameWidthIndex = 0; segmentInFrameWidthIndex < NUMBER_OF_SEGMENTS_IN_WIDTH; segmentInFrameWidthIndex++)</div><div>+    {</div><div>+        for (uint32_t segmentInFrameHeightIndex = 0; segmentInFrameHeightIndex < NUMBER_OF_SEGMENTS_IN_HEIGHT; segmentInFrameHeightIndex++)</div><div>+        {</div><div>+            // Initialize bins to 1</div><div>+            for (uint32_t cuIndex = 0; cuIndex < 256; cuIndex++) {</div><div>+                curFrame->m_lowres.picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][1][cuIndex] = 1;</div><div>+                curFrame->m_lowres.picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][2][cuIndex] = 1;</div><div>+            }</div><div>+</div><div>+            uint32_t segmentWidthOffset = (segmentInFrameWidthIndex == NUMBER_OF_SEGMENTS_IN_WIDTH - 1) ?</div><div>+                curFrame->m_lowres.widthFullRes - (NUMBER_OF_SEGMENTS_IN_WIDTH * segmentWidth) : 0;</div><div>+</div><div>+            uint32_t segmentHeightOffset = (segmentInFrameHeightIndex == NUMBER_OF_SEGMENTS_IN_HEIGHT - 1) ?</div><div>+                curFrame->m_lowres.heightFullRes - (NUMBER_OF_SEGMENTS_IN_HEIGHT * segmentHeight) : 0;</div><div>+</div><div>+</div><div>+            // U Histogram</div><div>+            calculateHistogram(</div><div>+                curFrame->m_fencPic->m_picOrg[1] + ((segmentInFrameWidthIndex * segmentWidth) >> 1) + (((segmentInFrameHeightIndex * segmentHeight) >> 1) * curFrame->m_fencPic->m_strideC),</div><div>+                (segmentWidth + segmentWidthOffset) >> 1,</div><div>+                (segmentHeight + segmentHeightOffset) >> 1,</div><div>+                curFrame->m_fencPic->m_strideC,</div><div>+                dsFactor,</div><div>+                curFrame->m_lowres.picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][1],</div><div>+                &sum);</div><div>+</div><div>+            sum = (sum << dsFactor);</div><div>+            *sumAverageIntensityCb += sum;</div><div>+            curFrame->m_lowres.averageIntensityPerSegment[segmentInFrameWidthIndex][segmentInFrameHeightIndex][1] =</div><div>+                (uint8_t)((sum + (((segmentWidth + segmentWidthOffset) * (segmentHeight + segmentHeightOffset)) >> 3)) / (((segmentWidth + segmentWidthOffset) * (segmentHeight + segmentHeightOffset)) >> 2));</div><div>+</div><div>+            for (uint16_t histogramBin = 0; histogramBin < HISTOGRAM_NUMBER_OF_BINS; histogramBin++) {</div><div>+                curFrame->m_lowres.picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][1][histogramBin] =</div><div>+                    curFrame->m_lowres.picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][1][histogramBin] << dsFactor;</div><div>+            }</div><div>+</div><div>+            // V Histogram</div><div>+            calculateHistogram(</div><div>+                curFrame->m_fencPic->m_picOrg[2] + ((segmentInFrameWidthIndex * segmentWidth) >> 1) + (((segmentInFrameHeightIndex * segmentHeight) >> 1) * curFrame->m_fencPic->m_strideC),</div><div>+                (segmentWidth + segmentWidthOffset) >> 1,</div><div>+                (segmentHeight + segmentHeightOffset) >> 1,</div><div>+                curFrame->m_fencPic->m_strideC,</div><div>+                dsFactor,</div><div>+                curFrame->m_lowres.picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][2],</div><div>+                &sum);</div><div>+</div><div>+            sum = (sum << dsFactor);</div><div>+            *sumAverageIntensityCr += sum;</div><div>+            curFrame->m_lowres.averageIntensityPerSegment[segmentInFrameWidthIndex][segmentInFrameHeightIndex][2] =</div><div>+                (uint8_t)((sum + (((segmentWidth + segmentWidthOffset) * (segmentHeight + segmentHeightOffset)) >> 3)) / (((segmentWidth + segmentHeightOffset) * (segmentHeight + segmentHeightOffset)) >> 2));</div><div>+</div><div>+            for (uint16_t histogramBin = 0; histogramBin < HISTOGRAM_NUMBER_OF_BINS; histogramBin++) {</div><div>+                curFrame->m_lowres.picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][2][histogramBin] =</div><div>+                    curFrame->m_lowres.picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][2][histogramBin] << dsFactor;</div><div>+            }</div><div>+        }</div><div>+    }</div><div>+    return;</div><div>+</div><div>+}</div><div>+</div><div>+/*</div><div>+* Compute histogram bins and luma pixel intensity *</div><div>+*/</div><div>+void LookaheadTLD::computeIntensityHistogramBinsLuma(</div><div>+    Frame    *curFrame,</div><div>+    uint64_t *sumAvgIntensityTotalSegmentsLuma)</div><div>+{</div><div>+    uint64_t sum;</div><div>+</div><div>+    uint32_t segmentWidth = curFrame->m_lowres.quarterSampleLowResWidth / NUMBER_OF_SEGMENTS_IN_WIDTH;</div><div>+    uint32_t segmentHeight = curFrame->m_lowres.quarterSampleLowResHeight / NUMBER_OF_SEGMENTS_IN_HEIGHT;</div><div>+</div><div>+    for (uint32_t segmentInFrameWidthIndex = 0; segmentInFrameWidthIndex < NUMBER_OF_SEGMENTS_IN_WIDTH; segmentInFrameWidthIndex++)</div><div>+    {</div><div>+        for (uint32_t segmentInFrameHeightIndex = 0; segmentInFrameHeightIndex < NUMBER_OF_SEGMENTS_IN_HEIGHT; segmentInFrameHeightIndex++)</div><div>+        {</div><div>+            // Initialize bins to 1</div><div>+            for (uint32_t cuIndex = 0; cuIndex < 256; cuIndex++) {</div><div>+                curFrame->m_lowres.picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0][cuIndex] = 1;</div><div>+            }</div><div>+</div><div>+            uint32_t segmentWidthOffset = (segmentInFrameWidthIndex == NUMBER_OF_SEGMENTS_IN_WIDTH - 1) ?</div><div>+                curFrame->m_lowres.quarterSampleLowResWidth - (NUMBER_OF_SEGMENTS_IN_WIDTH * segmentWidth) : 0;</div><div>+</div><div>+            uint32_t segmentHeightOffset = (segmentInFrameHeightIndex == NUMBER_OF_SEGMENTS_IN_HEIGHT - 1) ?</div><div>+                curFrame->m_lowres.quarterSampleLowResHeight - (NUMBER_OF_SEGMENTS_IN_HEIGHT * segmentHeight) : 0;</div><div>+</div><div>+            // Y Histogram</div><div>+            calculateHistogram(</div><div>+                curFrame->m_lowres.quarterSampleLowResBuffer + (curFrame->m_lowres.quarterSampleLowResOriginX + segmentInFrameWidthIndex * segmentWidth) + ((curFrame->m_lowres.quarterSampleLowResOriginY + segmentInFrameHeightIndex * segmentHeight) * curFrame->m_lowres.quarterSampleLowResStrideY),</div><div>+                segmentWidth + segmentWidthOffset,</div><div>+                segmentHeight + segmentHeightOffset,</div><div>+                curFrame->m_lowres.quarterSampleLowResStrideY,</div><div>+                1,</div><div>+                curFrame->m_lowres.picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0],</div><div>+                &sum);</div><div>+</div><div>+            curFrame->m_lowres.averageIntensityPerSegment[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0] = (uint8_t)((sum + (((segmentWidth + segmentWidthOffset)*(segmentWidth + segmentHeightOffset)) >> 1)) / ((segmentWidth + segmentWidthOffset)*(segmentHeight + segmentHeightOffset)));</div><div>+            (*sumAvgIntensityTotalSegmentsLuma) += (sum << 4);</div><div>+            for (uint32_t histogramBin = 0; histogramBin < HISTOGRAM_NUMBER_OF_BINS; histogramBin++)</div><div>+            {</div><div>+                curFrame->m_lowres.picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0][histogramBin] =</div><div>+                    curFrame->m_lowres.picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0][histogramBin] << 4;</div><div>+            }</div><div>+        }</div><div>+    }</div><div>+}</div><div>+</div><div>+void LookaheadTLD::collectPictureStatistics(Frame *curFrame)</div><div>+{</div><div>+</div><div>+    uint64_t sumAverageIntensityCb = 0;</div><div>+    uint64_t sumAverageIntensityCr = 0;</div><div>+    uint64_t sumAverageIntensity = 0;</div><div>+</div><div>+    // Histogram bins for Luma</div><div>+    computeIntensityHistogramBinsLuma(</div><div>+        curFrame,</div><div>+        &sumAverageIntensity);</div><div>+</div><div>+    // Histogram bins for Chroma</div><div>+    computeIntensityHistogramBinsChroma(</div><div>+        curFrame,</div><div>+        &sumAverageIntensityCb,</div><div>+        &sumAverageIntensityCr);</div><div>+</div><div>+    curFrame->m_lowres.averageIntensity[0] = (uint8_t)((sumAverageIntensity + ((curFrame->m_lowres.widthFullRes * curFrame->m_lowres.heightFullRes) >> 1)) / (curFrame->m_lowres.widthFullRes * curFrame->m_lowres.heightFullRes));</div><div>+    curFrame->m_lowres.averageIntensity[1] = (uint8_t)((sumAverageIntensityCb + ((curFrame->m_lowres.widthFullRes * curFrame->m_lowres.heightFullRes) >> 3)) / ((curFrame->m_lowres.widthFullRes * curFrame->m_lowres.heightFullRes) >> 2));</div><div>+    curFrame->m_lowres.averageIntensity[2] = (uint8_t)((sumAverageIntensityCr + ((curFrame->m_lowres.widthFullRes * curFrame->m_lowres.heightFullRes) >> 3)) / ((curFrame->m_lowres.widthFullRes * curFrame->m_lowres.heightFullRes) >> 2));</div><div>+</div><div>+    computePictureStatistics(curFrame);</div><div>+</div><div>+    curFrame->m_lowres.bHistScenecutAnalyzed = false;</div><div>+}</div><div> </div><div> void PreLookaheadGroup::processTasks(int workerThreadID)</div><div> {</div><div>@@ -1462,6 +1778,10 @@ void PreLookaheadGroup::processTasks(int workerThreadID)</div><div> </div><div>         if (m_lookahead.m_bAdaptiveQuant)</div><div>             tld.calcAdaptiveQuantFrame(preFrame, m_lookahead.m_param);</div><div>+</div><div>+        if (m_lookahead.m_param->bHistBasedSceneCut)</div><div>+            tld.collectPictureStatistics(preFrame);</div><div>+</div><div>         tld.lowresIntraEstimate(preFrame->m_lowres, m_lookahead.m_param->rc.qgSize);</div><div>         preFrame->m_lowresInit = true;</div><div> </div><div>diff --git a/source/encoder/slicetype.h b/source/encoder/slicetype.h</div><div>index 490e7ba1a..442063cf4 100644</div><div>--- a/source/encoder/slicetype.h</div><div>+++ b/source/encoder/slicetype.h</div><div>@@ -44,6 +44,24 @@ class Lookahead;</div><div> #define EDGE_INCLINATION 45</div><div> #define TEMPORAL_SCENECUT_THRESHOLD 50</div><div> </div><div>+#define X265_ABS(a)                        (((a) < 0) ? (-(a)) : (a))</div><div>+</div><div>+#define PICTURE_DIFF_VARIANCE_TH            390</div><div>+#define PICTURE_VARIANCE_TH                 1500</div><div>+#define LOW_VAR_SCENE_CHANGE_TH             2250</div><div>+#define HIGH_VAR_SCENE_CHANGE_TH            3500</div><div>+</div><div>+#define PICTURE_DIFF_VARIANCE_CHROMA_TH     10</div><div>+#define PICTURE_VARIANCE_CHROMA_TH          20</div><div>+#define LOW_VAR_SCENE_CHANGE_CHROMA_TH      2250/4</div><div>+#define HIGH_VAR_SCENE_CHANGE_CHROMA_TH     3500/4</div><div>+</div><div>+#define FLASH_TH                            1.5</div><div>+#define FADE_TH                             4</div><div>+#define INTENSITY_CHANGE_TH                 4</div><div>+</div><div>+#define NUM64x64INPIC(w,h)                  ((w*h)>> (MAX_LOG2_CU_SIZE<<1))</div><div>+</div><div> #if HIGH_BIT_DEPTH</div><div> #define EDGE_THRESHOLD 1023.0</div><div> #else</div><div>@@ -93,6 +111,27 @@ struct LookaheadTLD</div><div> </div><div>     ~LookaheadTLD() { X265_FREE(wbuffer[0]); }</div><div> </div><div>+    void collectPictureStatistics(Frame *curFrame);</div><div>+    void computeIntensityHistogramBinsLuma(Frame *curFrame, uint64_t *sumAvgIntensityTotalSegmentsLuma);</div><div>+</div><div>+    void computeIntensityHistogramBinsChroma(</div><div>+        Frame    *curFrame,</div><div>+        uint64_t *sumAverageIntensityCb,</div><div>+        uint64_t *sumAverageIntensityCr);</div><div>+</div><div>+    void calculateHistogram(</div><div>+        pixel    *inputSrc,</div><div>+        uint32_t  inputWidth,</div><div>+        uint32_t  inputHeight,</div><div>+        intptr_t  stride,</div><div>+        uint8_t   dsFactor,</div><div>+        uint32_t *histogram,</div><div>+        uint64_t *sum);</div><div>+</div><div>+    void computePictureStatistics(Frame *curFrame);</div><div>+</div><div>+    uint32_t calcVariance(pixel* src, intptr_t stride, intptr_t blockOffset, uint32_t plane);</div><div>+</div><div>     void calcAdaptiveQuantFrame(Frame *curFrame, x265_param* param);</div><div>     void lowresIntraEstimate(Lowres& fenc, uint32_t qgSize);</div><div> </div><div>@@ -152,6 +191,14 @@ public:</div><div>     bool          m_isFadeIn;</div><div>     uint64_t      m_fadeCount;</div><div>     int           m_fadeStart;</div><div>+</div><div>+    uint32_t    **m_accHistDiffRunningAvgCb;</div><div>+    uint32_t    **m_accHistDiffRunningAvgCr;</div><div>+    uint32_t    **m_accHistDiffRunningAvg;</div><div>+</div><div>+    bool          m_resetRunningAvg;</div><div>+    uint32_t      m_segmentCountThreshold;</div><div>+</div><div>     Lookahead(x265_param *param, ThreadPool *pool);</div><div> #if DETAILED_CU_STATS</div><div>     int64_t       m_slicetypeDecideElapsedTime;</div><div>@@ -184,6 +231,7 @@ protected:</div><div>     /* called by slicetypeAnalyse() to make slice decisions */</div><div>     bool    scenecut(Lowres **frames, int p0, int p1, bool bRealScenecut, int numFrames);</div><div>     bool    scenecutInternal(Lowres **frames, int p0, int p1, bool bRealScenecut);</div><div>+</div><div>     void    slicetypePath(Lowres **frames, int length, char(*best_paths)[X265_LOOKAHEAD_MAX + 1]);</div><div>     int64_t slicetypePathCost(Lowres **frames, char *path, int64_t threshold);</div><div>     int64_t vbvFrameCost(Lowres **frames, int p0, int p1, int b);</div><div>-- </div><div>2.34.1.windows.1</div><div><br></div><div><div dir="ltr" class="gmail_signature"><div dir="ltr"><div><i><font face="georgia, serif">Thanks and Regards,</font></i></div><div><i><font face="georgia, serif"><b>Snehaa.G</b><br>Video Codec Engineer,<br>Media & AI analytics<br><a href="https://multicorewareinc.com/" target="_blank"><img src="https://ci3.googleusercontent.com/mail-sig/AIorK4yEumXeQ2mgcFAR2us9INa7z3rCbl8ordut3fbdeIbuPv0n3EA75Or1rHs0neGaI0WM8mFPz1g"></a><br><span></span><span></span><br></font></i></div></div></div></div></div></div>