<div dir="ltr"><div dir="ltr"><div>From 4716fe4dcbb4f552d1951db281cd2622fb4cc703 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 13:07:35 +0530</div><div>Subject: [PATCH] Add function for histogram based scene change</div><div><br></div><div>---</div><div> source/encoder/slicetype.cpp | 166 ++++++++++++++++++++++++++++++++++-</div><div> source/encoder/slicetype.h   |   3 +</div><div> 2 files changed, 168 insertions(+), 1 deletion(-)</div><div><br></div><div>diff --git a/source/encoder/slicetype.cpp b/source/encoder/slicetype.cpp</div><div>index 9343593cc..79541e5cb 100644</div><div>--- a/source/encoder/slicetype.cpp</div><div>+++ b/source/encoder/slicetype.cpp</div><div>@@ -2398,7 +2398,10 @@ void Lookahead::slicetypeAnalyse(Lowres **frames, bool bKeyframe)</div><div>     int numAnalyzed = numFrames;</div><div>     bool isScenecut = false;</div><div> </div><div>-    isScenecut = scenecut(frames, 0, 1, true, origNumFrames);</div><div>+    if (m_param->bHistBasedSceneCut)</div><div>+        isScenecut = histBasedScenecut(frames, 0, 1, origNumFrames);</div><div>+    else</div><div>+        isScenecut = scenecut(frames, 0, 1, true, origNumFrames);</div><div> </div><div>     /* When scenecut threshold is set, use scenecut detection for I frame placements */</div><div>     if (m_param->scenecutThreshold && isScenecut)</div><div>@@ -2710,6 +2713,167 @@ bool Lookahead::scenecutInternal(Lowres **frames, int p0, int p1, bool bRealScen</div><div>     return res;</div><div> }</div><div> </div><div>+bool Lookahead::detectHistBasedSceneChange(Lowres **frames, int p0, int p1, int p2)</div><div>+{</div><div>+    bool isAbruptChange;</div><div>+    bool isSceneChange;</div><div>+</div><div>+    Lowres  *previousFrame = frames[p0];</div><div>+    Lowres  *currentFrame = frames[p1];</div><div>+    Lowres  *futureFrame = frames[p2];</div><div>+</div><div>+    currentFrame->bHistScenecutAnalyzed = true;</div><div>+</div><div>+    uint32_t **accHistDiffRunningAvgCb = m_accHistDiffRunningAvgCb;</div><div>+    uint32_t **accHistDiffRunningAvgCr = m_accHistDiffRunningAvgCr;</div><div>+    uint32_t **accHistDiffRunningAvg = m_accHistDiffRunningAvg;</div><div>+</div><div>+    uint8_t absIntDiffFuturePast = 0;</div><div>+    uint8_t absIntDiffFuturePresent = 0;</div><div>+    uint8_t absIntDiffPresentPast = 0;</div><div>+</div><div>+    uint32_t abruptChangeCount = 0;</div><div>+    uint32_t sceneChangeCount = 0;</div><div>+</div><div>+    uint32_t segmentWidth = frames[1]->widthFullRes / NUMBER_OF_SEGMENTS_IN_WIDTH;</div><div>+    uint32_t segmentHeight = frames[1]->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>+            isAbruptChange = false;</div><div>+            isSceneChange = false;</div><div>+</div><div>+            // accumulative absolute histogram differences between the past and current frame</div><div>+            uint32_t accHistDiff = 0;</div><div>+            uint32_t accHistDiffCb = 0;</div><div>+            uint32_t accHistDiffCr = 0;</div><div>+</div><div>+            uint32_t segmentWidthOffset = (segmentInFrameWidthIndex == NUMBER_OF_SEGMENTS_IN_WIDTH - 1) ?</div><div>+                frames[1]->widthFullRes - (NUMBER_OF_SEGMENTS_IN_WIDTH * segmentWidth) : 0;</div><div>+</div><div>+            uint32_t segmentHeightOffset = (segmentInFrameHeightIndex == NUMBER_OF_SEGMENTS_IN_HEIGHT - 1) ?</div><div>+                frames[1]->heightFullRes - (NUMBER_OF_SEGMENTS_IN_HEIGHT * segmentHeight) : 0;</div><div>+</div><div>+            segmentWidth += segmentWidthOffset;</div><div>+            segmentHeight += segmentHeightOffset;</div><div>+</div><div>+            uint32_t segmentThreshHold = (</div><div>+                ((X265_ABS((int64_t)currentFrame->picAvgVariance - (int64_t)previousFrame->picAvgVariance)) > PICTURE_DIFF_VARIANCE_TH) &&</div><div>+                (currentFrame->picAvgVariance > PICTURE_VARIANCE_TH || previousFrame->picAvgVariance > PICTURE_VARIANCE_TH)) ?</div><div>+                HIGH_VAR_SCENE_CHANGE_TH * NUM64x64INPIC(segmentWidth, segmentHeight) : LOW_VAR_SCENE_CHANGE_TH * NUM64x64INPIC(segmentWidth, segmentHeight);</div><div>+</div><div>+            uint32_t segmentThreshHoldCb = (</div><div>+                ((X265_ABS((int64_t)currentFrame->picAvgVarianceCb - (int64_t)previousFrame->picAvgVarianceCb)) > PICTURE_DIFF_VARIANCE_CHROMA_TH) &&</div><div>+                (currentFrame->picAvgVarianceCb > PICTURE_VARIANCE_CHROMA_TH || previousFrame->picAvgVarianceCb > PICTURE_VARIANCE_CHROMA_TH)) ?</div><div>+                HIGH_VAR_SCENE_CHANGE_CHROMA_TH * NUM64x64INPIC(segmentWidth, segmentHeight) : LOW_VAR_SCENE_CHANGE_CHROMA_TH * NUM64x64INPIC(segmentWidth, segmentHeight);</div><div>+</div><div>+            uint32_t segmentThreshHoldCr = (</div><div>+                ((X265_ABS((int64_t)currentFrame->picAvgVarianceCr - (int64_t)previousFrame->picAvgVarianceCr)) > PICTURE_DIFF_VARIANCE_CHROMA_TH) &&</div><div>+                (currentFrame->picAvgVarianceCr > PICTURE_VARIANCE_CHROMA_TH || previousFrame->picAvgVarianceCr > PICTURE_VARIANCE_CHROMA_TH)) ?</div><div>+                HIGH_VAR_SCENE_CHANGE_CHROMA_TH * NUM64x64INPIC(segmentWidth, segmentHeight) : LOW_VAR_SCENE_CHANGE_CHROMA_TH * NUM64x64INPIC(segmentWidth, segmentHeight);</div><div>+</div><div>+            for (uint32_t bin = 0; bin < HISTOGRAM_NUMBER_OF_BINS; ++bin) {</div><div>+                accHistDiff += X265_ABS((int32_t)currentFrame->picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0][bin] - (int32_t)previousFrame->picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0][bin]);</div><div>+                accHistDiffCb += X265_ABS((int32_t)currentFrame->picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][1][bin] - (int32_t)previousFrame->picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][1][bin]);</div><div>+                accHistDiffCr += X265_ABS((int32_t)currentFrame->picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][2][bin] - (int32_t)previousFrame->picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][2][bin]);</div><div>+            }</div><div>+</div><div>+            if (m_resetRunningAvg) {</div><div>+                accHistDiffRunningAvg[segmentInFrameWidthIndex][segmentInFrameHeightIndex] = accHistDiff;</div><div>+                accHistDiffRunningAvgCb[segmentInFrameWidthIndex][segmentInFrameHeightIndex] = accHistDiffCb;</div><div>+                accHistDiffRunningAvgCr[segmentInFrameWidthIndex][segmentInFrameHeightIndex] = accHistDiffCr;</div><div>+            }</div><div>+</div><div>+            // difference between accumulative absolute histogram differences and the running average at the current frame.</div><div>+            uint32_t accHistDiffError = X265_ABS((int32_t)accHistDiffRunningAvg[segmentInFrameWidthIndex][segmentInFrameHeightIndex] - (int32_t)accHistDiff);</div><div>+            uint32_t accHistDiffErrorCb = X265_ABS((int32_t)accHistDiffRunningAvgCb[segmentInFrameWidthIndex][segmentInFrameHeightIndex] - (int32_t)accHistDiffCb);</div><div>+            uint32_t accHistDiffErrorCr = X265_ABS((int32_t)accHistDiffRunningAvgCr[segmentInFrameWidthIndex][segmentInFrameHeightIndex] - (int32_t)accHistDiffCr);</div><div>+</div><div>+            if ((accHistDiffError > segmentThreshHold     && accHistDiff >= accHistDiffError) ||</div><div>+                (accHistDiffErrorCb > segmentThreshHoldCb && accHistDiffCb >= accHistDiffErrorCb) ||</div><div>+                (accHistDiffErrorCr > segmentThreshHoldCr && accHistDiffCr >= accHistDiffErrorCr)) {</div><div>+</div><div>+                isAbruptChange = true;</div><div>+            }</div><div>+</div><div>+            if (isAbruptChange)</div><div>+            {</div><div>+                absIntDiffFuturePast = (uint8_t)X265_ABS((int16_t)futureFrame->averageIntensityPerSegment[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0] - (int16_t)previousFrame->averageIntensityPerSegment[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0]);</div><div>+                absIntDiffFuturePresent = (uint8_t)X265_ABS((int16_t)futureFrame->averageIntensityPerSegment[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0] - (int16_t)currentFrame->averageIntensityPerSegment[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0]);</div><div>+                absIntDiffPresentPast = (uint8_t)X265_ABS((int16_t)currentFrame->averageIntensityPerSegment[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0] - (int16_t)previousFrame->averageIntensityPerSegment[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0]);</div><div>+</div><div>+                if (absIntDiffFuturePresent >= FLASH_TH * absIntDiffFuturePast && absIntDiffPresentPast >= FLASH_TH * absIntDiffFuturePast) {</div><div>+                    x265_log(m_param, X265_LOG_DEBUG, "Flash in frame# %i , %i, %i, %i\n", currentFrame->frameNum, absIntDiffFuturePast, absIntDiffFuturePresent, absIntDiffPresentPast);</div><div>+                }</div><div>+                else if (absIntDiffFuturePresent < FADE_TH && absIntDiffPresentPast < FADE_TH) {</div><div>+                    x265_log(m_param, X265_LOG_DEBUG, "Fade in frame# %i , %i, %i, %i\n", currentFrame->frameNum, absIntDiffFuturePast, absIntDiffFuturePresent, absIntDiffPresentPast);</div><div>+                }</div><div>+                else if (X265_ABS(absIntDiffFuturePresent - absIntDiffPresentPast) < INTENSITY_CHANGE_TH && absIntDiffFuturePresent + absIntDiffPresentPast >= absIntDiffFuturePast) {</div><div>+                    x265_log(m_param, X265_LOG_DEBUG, "Intensity Change in frame# %i , %i, %i, %i\n", currentFrame->frameNum, absIntDiffFuturePast, absIntDiffFuturePresent, absIntDiffPresentPast);</div><div>+                }</div><div>+                else {</div><div>+                    isSceneChange = true;</div><div>+                    x265_log(m_param, X265_LOG_DEBUG, "Scene change in frame# %i , %i, %i, %i\n", currentFrame->frameNum, absIntDiffFuturePast, absIntDiffFuturePresent, absIntDiffPresentPast);</div><div>+                }</div><div>+</div><div>+            }</div><div>+            else {</div><div>+                accHistDiffRunningAvg[segmentInFrameWidthIndex][segmentInFrameHeightIndex] = (3 * accHistDiffRunningAvg[segmentInFrameWidthIndex][segmentInFrameHeightIndex] + accHistDiff) / 4;</div><div>+            }</div><div>+</div><div>+            abruptChangeCount += isAbruptChange;</div><div>+            sceneChangeCount += isSceneChange;</div><div>+        }</div><div>+    }</div><div>+</div><div>+    if (abruptChangeCount >= m_segmentCountThreshold) {</div><div>+        m_resetRunningAvg = true;</div><div>+    }</div><div>+    else {</div><div>+        m_resetRunningAvg = false;</div><div>+    }</div><div>+</div><div>+    if ((sceneChangeCount >= m_segmentCountThreshold)) {</div><div>+        x265_log(m_param, X265_LOG_DEBUG, "Scene Change in Pic Number# %i\n", currentFrame->frameNum);</div><div>+</div><div>+        return true;</div><div>+    }</div><div>+    else {</div><div>+        return false;</div><div>+    }</div><div>+</div><div>+}</div><div>+</div><div>+bool Lookahead::histBasedScenecut(Lowres **frames, int p0, int p1, int numFrames)</div><div>+{</div><div>+    /* Only do analysis during a normal scenecut check. */</div><div>+    if (m_param->bframes)</div><div>+    {</div><div>+        int origmaxp1 = p0 + 1;</div><div>+        /* Look ahead to avoid coding short flashes as scenecuts. */</div><div>+        origmaxp1 += m_param->bframes;</div><div>+        int maxp1 = X265_MIN(origmaxp1, numFrames);</div><div>+</div><div>+        for (int cp1 = p0; cp1 < maxp1; cp1++)</div><div>+        {</div><div>+            if (frames[cp1 + 1]->bHistScenecutAnalyzed == true)</div><div>+                continue;</div><div>+</div><div>+            if (detectHistBasedSceneChange(frames, cp1, cp1 + 1, cp1 + 2))</div><div>+            {</div><div>+                /* If current frame is a Scenecut from p0 frame as well as Scenecut from</div><div>+                 * preceeding frame, mark it as a Scenecut */</div><div>+                frames[cp1+1]->bScenecut = true;</div><div>+            }</div><div>+        }</div><div>+</div><div>+    }</div><div>+</div><div>+    return frames[p1]->bScenecut;</div><div>+}</div><div>+</div><div> void Lookahead::slicetypePath(Lowres **frames, int length, char(*best_paths)[X265_LOOKAHEAD_MAX + 1])</div><div> {</div><div>     char paths[2][X265_LOOKAHEAD_MAX + 1];</div><div>diff --git a/source/encoder/slicetype.h b/source/encoder/slicetype.h</div><div>index 442063cf4..d0a39506a 100644</div><div>--- a/source/encoder/slicetype.h</div><div>+++ b/source/encoder/slicetype.h</div><div>@@ -232,6 +232,9 @@ protected:</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>+    bool    histBasedScenecut(Lowres **frames, int p0, int p1, int numFrames);</div><div>+    bool    detectHistBasedSceneChange(Lowres **frames, int p0, int p1, int p2);</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>