[x265] [PATCH 3/3] Add function for histogram based scene change

Mahesh Pittala mahesh at multicorewareinc.com
Fri Nov 4 07:34:33 UTC 2022


Pushed 3 patches to the master branch.

On Wed, Nov 2, 2022 at 4:25 PM Snehaa Giridharan <
snehaa at multicorewareinc.com> wrote:

> From b203e94ffc619a32ead6937a61471efa584afa71 Mon Sep 17 00:00:00 2001
> From: ashok2022 <ashok at multicorewareinc.com>
> Date: Wed, 26 Oct 2022 13:07:35 +0530
> Subject: [PATCH] Add function for histogram based scene change
>
> Signed-off-by: Snehaa Giridharan <snehaa at multicorewareinc.com>
> ---
>  source/encoder/slicetype.cpp | 166 ++++++++++++++++++++++++++++++++++-
>  source/encoder/slicetype.h   |   3 +
>  2 files changed, 168 insertions(+), 1 deletion(-)
>
> diff --git a/source/encoder/slicetype.cpp b/source/encoder/slicetype.cpp
> index 9343593cc..79541e5cb 100644
> --- a/source/encoder/slicetype.cpp
> +++ b/source/encoder/slicetype.cpp
> @@ -2398,7 +2398,10 @@ void Lookahead::slicetypeAnalyse(Lowres **frames,
> bool bKeyframe)
>      int numAnalyzed = numFrames;
>      bool isScenecut = false;
>
> -    isScenecut = scenecut(frames, 0, 1, true, origNumFrames);
> +    if (m_param->bHistBasedSceneCut)
> +        isScenecut = histBasedScenecut(frames, 0, 1, origNumFrames);
> +    else
> +        isScenecut = scenecut(frames, 0, 1, true, origNumFrames);
>
>      /* When scenecut threshold is set, use scenecut detection for I frame
> placements */
>      if (m_param->scenecutThreshold && isScenecut)
> @@ -2710,6 +2713,167 @@ bool Lookahead::scenecutInternal(Lowres **frames,
> int p0, int p1, bool bRealScen
>      return res;
>  }
>
> +bool Lookahead::detectHistBasedSceneChange(Lowres **frames, int p0, int
> p1, int p2)
> +{
> +    bool isAbruptChange;
> +    bool isSceneChange;
> +
> +    Lowres  *previousFrame = frames[p0];
> +    Lowres  *currentFrame = frames[p1];
> +    Lowres  *futureFrame = frames[p2];
> +
> +    currentFrame->bHistScenecutAnalyzed = true;
> +
> +    uint32_t **accHistDiffRunningAvgCb = m_accHistDiffRunningAvgCb;
> +    uint32_t **accHistDiffRunningAvgCr = m_accHistDiffRunningAvgCr;
> +    uint32_t **accHistDiffRunningAvg = m_accHistDiffRunningAvg;
> +
> +    uint8_t absIntDiffFuturePast = 0;
> +    uint8_t absIntDiffFuturePresent = 0;
> +    uint8_t absIntDiffPresentPast = 0;
> +
> +    uint32_t abruptChangeCount = 0;
> +    uint32_t sceneChangeCount = 0;
> +
> +    uint32_t segmentWidth = frames[1]->widthFullRes /
> NUMBER_OF_SEGMENTS_IN_WIDTH;
> +    uint32_t segmentHeight = frames[1]->heightFullRes /
> NUMBER_OF_SEGMENTS_IN_HEIGHT;
> +
> +    for (uint32_t segmentInFrameWidthIndex = 0; segmentInFrameWidthIndex
> < NUMBER_OF_SEGMENTS_IN_WIDTH; segmentInFrameWidthIndex++)
> +    {
> +        for (uint32_t segmentInFrameHeightIndex = 0;
> segmentInFrameHeightIndex < NUMBER_OF_SEGMENTS_IN_HEIGHT;
> segmentInFrameHeightIndex++)
> +        {
> +            isAbruptChange = false;
> +            isSceneChange = false;
> +
> +            // accumulative absolute histogram differences between the
> past and current frame
> +            uint32_t accHistDiff = 0;
> +            uint32_t accHistDiffCb = 0;
> +            uint32_t accHistDiffCr = 0;
> +
> +            uint32_t segmentWidthOffset = (segmentInFrameWidthIndex ==
> NUMBER_OF_SEGMENTS_IN_WIDTH - 1) ?
> +                frames[1]->widthFullRes - (NUMBER_OF_SEGMENTS_IN_WIDTH *
> segmentWidth) : 0;
> +
> +            uint32_t segmentHeightOffset = (segmentInFrameHeightIndex ==
> NUMBER_OF_SEGMENTS_IN_HEIGHT - 1) ?
> +                frames[1]->heightFullRes - (NUMBER_OF_SEGMENTS_IN_HEIGHT
> * segmentHeight) : 0;
> +
> +            segmentWidth += segmentWidthOffset;
> +            segmentHeight += segmentHeightOffset;
> +
> +            uint32_t segmentThreshHold = (
> +                ((X265_ABS((int64_t)currentFrame->picAvgVariance -
> (int64_t)previousFrame->picAvgVariance)) > PICTURE_DIFF_VARIANCE_TH) &&
> +                (currentFrame->picAvgVariance > PICTURE_VARIANCE_TH ||
> previousFrame->picAvgVariance > PICTURE_VARIANCE_TH)) ?
> +                HIGH_VAR_SCENE_CHANGE_TH * NUM64x64INPIC(segmentWidth,
> segmentHeight) : LOW_VAR_SCENE_CHANGE_TH * NUM64x64INPIC(segmentWidth,
> segmentHeight);
> +
> +            uint32_t segmentThreshHoldCb = (
> +                ((X265_ABS((int64_t)currentFrame->picAvgVarianceCb -
> (int64_t)previousFrame->picAvgVarianceCb)) >
> PICTURE_DIFF_VARIANCE_CHROMA_TH) &&
> +                (currentFrame->picAvgVarianceCb >
> PICTURE_VARIANCE_CHROMA_TH || previousFrame->picAvgVarianceCb >
> PICTURE_VARIANCE_CHROMA_TH)) ?
> +                HIGH_VAR_SCENE_CHANGE_CHROMA_TH *
> NUM64x64INPIC(segmentWidth, segmentHeight) : LOW_VAR_SCENE_CHANGE_CHROMA_TH
> * NUM64x64INPIC(segmentWidth, segmentHeight);
> +
> +            uint32_t segmentThreshHoldCr = (
> +                ((X265_ABS((int64_t)currentFrame->picAvgVarianceCr -
> (int64_t)previousFrame->picAvgVarianceCr)) >
> PICTURE_DIFF_VARIANCE_CHROMA_TH) &&
> +                (currentFrame->picAvgVarianceCr >
> PICTURE_VARIANCE_CHROMA_TH || previousFrame->picAvgVarianceCr >
> PICTURE_VARIANCE_CHROMA_TH)) ?
> +                HIGH_VAR_SCENE_CHANGE_CHROMA_TH *
> NUM64x64INPIC(segmentWidth, segmentHeight) : LOW_VAR_SCENE_CHANGE_CHROMA_TH
> * NUM64x64INPIC(segmentWidth, segmentHeight);
> +
> +            for (uint32_t bin = 0; bin < HISTOGRAM_NUMBER_OF_BINS; ++bin)
> {
> +                accHistDiff +=
> X265_ABS((int32_t)currentFrame->picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0][bin]
> -
> (int32_t)previousFrame->picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0][bin]);
> +                accHistDiffCb +=
> X265_ABS((int32_t)currentFrame->picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][1][bin]
> -
> (int32_t)previousFrame->picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][1][bin]);
> +                accHistDiffCr +=
> X265_ABS((int32_t)currentFrame->picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][2][bin]
> -
> (int32_t)previousFrame->picHistogram[segmentInFrameWidthIndex][segmentInFrameHeightIndex][2][bin]);
> +            }
> +
> +            if (m_resetRunningAvg) {
> +
> accHistDiffRunningAvg[segmentInFrameWidthIndex][segmentInFrameHeightIndex]
> = accHistDiff;
> +
> accHistDiffRunningAvgCb[segmentInFrameWidthIndex][segmentInFrameHeightIndex]
> = accHistDiffCb;
> +
> accHistDiffRunningAvgCr[segmentInFrameWidthIndex][segmentInFrameHeightIndex]
> = accHistDiffCr;
> +            }
> +
> +            // difference between accumulative absolute histogram
> differences and the running average at the current frame.
> +            uint32_t accHistDiffError =
> X265_ABS((int32_t)accHistDiffRunningAvg[segmentInFrameWidthIndex][segmentInFrameHeightIndex]
> - (int32_t)accHistDiff);
> +            uint32_t accHistDiffErrorCb =
> X265_ABS((int32_t)accHistDiffRunningAvgCb[segmentInFrameWidthIndex][segmentInFrameHeightIndex]
> - (int32_t)accHistDiffCb);
> +            uint32_t accHistDiffErrorCr =
> X265_ABS((int32_t)accHistDiffRunningAvgCr[segmentInFrameWidthIndex][segmentInFrameHeightIndex]
> - (int32_t)accHistDiffCr);
> +
> +            if ((accHistDiffError > segmentThreshHold     && accHistDiff
> >= accHistDiffError) ||
> +                (accHistDiffErrorCb > segmentThreshHoldCb &&
> accHistDiffCb >= accHistDiffErrorCb) ||
> +                (accHistDiffErrorCr > segmentThreshHoldCr &&
> accHistDiffCr >= accHistDiffErrorCr)) {
> +
> +                isAbruptChange = true;
> +            }
> +
> +            if (isAbruptChange)
> +            {
> +                absIntDiffFuturePast =
> (uint8_t)X265_ABS((int16_t)futureFrame->averageIntensityPerSegment[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0]
> -
> (int16_t)previousFrame->averageIntensityPerSegment[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0]);
> +                absIntDiffFuturePresent =
> (uint8_t)X265_ABS((int16_t)futureFrame->averageIntensityPerSegment[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0]
> -
> (int16_t)currentFrame->averageIntensityPerSegment[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0]);
> +                absIntDiffPresentPast =
> (uint8_t)X265_ABS((int16_t)currentFrame->averageIntensityPerSegment[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0]
> -
> (int16_t)previousFrame->averageIntensityPerSegment[segmentInFrameWidthIndex][segmentInFrameHeightIndex][0]);
> +
> +                if (absIntDiffFuturePresent >= FLASH_TH *
> absIntDiffFuturePast && absIntDiffPresentPast >= FLASH_TH *
> absIntDiffFuturePast) {
> +                    x265_log(m_param, X265_LOG_DEBUG, "Flash in frame# %i
> , %i, %i, %i\n", currentFrame->frameNum, absIntDiffFuturePast,
> absIntDiffFuturePresent, absIntDiffPresentPast);
> +                }
> +                else if (absIntDiffFuturePresent < FADE_TH &&
> absIntDiffPresentPast < FADE_TH) {
> +                    x265_log(m_param, X265_LOG_DEBUG, "Fade in frame# %i
> , %i, %i, %i\n", currentFrame->frameNum, absIntDiffFuturePast,
> absIntDiffFuturePresent, absIntDiffPresentPast);
> +                }
> +                else if (X265_ABS(absIntDiffFuturePresent -
> absIntDiffPresentPast) < INTENSITY_CHANGE_TH && absIntDiffFuturePresent +
> absIntDiffPresentPast >= absIntDiffFuturePast) {
> +                    x265_log(m_param, X265_LOG_DEBUG, "Intensity Change
> in frame# %i , %i, %i, %i\n", currentFrame->frameNum, absIntDiffFuturePast,
> absIntDiffFuturePresent, absIntDiffPresentPast);
> +                }
> +                else {
> +                    isSceneChange = true;
> +                    x265_log(m_param, X265_LOG_DEBUG, "Scene change in
> frame# %i , %i, %i, %i\n", currentFrame->frameNum, absIntDiffFuturePast,
> absIntDiffFuturePresent, absIntDiffPresentPast);
> +                }
> +
> +            }
> +            else {
> +
> accHistDiffRunningAvg[segmentInFrameWidthIndex][segmentInFrameHeightIndex]
> = (3 *
> accHistDiffRunningAvg[segmentInFrameWidthIndex][segmentInFrameHeightIndex]
> + accHistDiff) / 4;
> +            }
> +
> +            abruptChangeCount += isAbruptChange;
> +            sceneChangeCount += isSceneChange;
> +        }
> +    }
> +
> +    if (abruptChangeCount >= m_segmentCountThreshold) {
> +        m_resetRunningAvg = true;
> +    }
> +    else {
> +        m_resetRunningAvg = false;
> +    }
> +
> +    if ((sceneChangeCount >= m_segmentCountThreshold)) {
> +        x265_log(m_param, X265_LOG_DEBUG, "Scene Change in Pic Number#
> %i\n", currentFrame->frameNum);
> +
> +        return true;
> +    }
> +    else {
> +        return false;
> +    }
> +
> +}
> +
> +bool Lookahead::histBasedScenecut(Lowres **frames, int p0, int p1, int
> numFrames)
> +{
> +    /* Only do analysis during a normal scenecut check. */
> +    if (m_param->bframes)
> +    {
> +        int origmaxp1 = p0 + 1;
> +        /* Look ahead to avoid coding short flashes as scenecuts. */
> +        origmaxp1 += m_param->bframes;
> +        int maxp1 = X265_MIN(origmaxp1, numFrames);
> +
> +        for (int cp1 = p0; cp1 < maxp1; cp1++)
> +        {
> +            if (frames[cp1 + 1]->bHistScenecutAnalyzed == true)
> +                continue;
> +
> +            if (detectHistBasedSceneChange(frames, cp1, cp1 + 1, cp1 + 2))
> +            {
> +                /* If current frame is a Scenecut from p0 frame as well
> as Scenecut from
> +                 * preceeding frame, mark it as a Scenecut */
> +                frames[cp1+1]->bScenecut = true;
> +            }
> +        }
> +
> +    }
> +
> +    return frames[p1]->bScenecut;
> +}
> +
>  void Lookahead::slicetypePath(Lowres **frames, int length,
> char(*best_paths)[X265_LOOKAHEAD_MAX + 1])
>  {
>      char paths[2][X265_LOOKAHEAD_MAX + 1];
> diff --git a/source/encoder/slicetype.h b/source/encoder/slicetype.h
> index 442063cf4..d0a39506a 100644
> --- a/source/encoder/slicetype.h
> +++ b/source/encoder/slicetype.h
> @@ -232,6 +232,9 @@ protected:
>      bool    scenecut(Lowres **frames, int p0, int p1, bool bRealScenecut,
> int numFrames);
>      bool    scenecutInternal(Lowres **frames, int p0, int p1, bool
> bRealScenecut);
>
> +    bool    histBasedScenecut(Lowres **frames, int p0, int p1, int
> numFrames);
> +    bool    detectHistBasedSceneChange(Lowres **frames, int p0, int p1,
> int p2);
> +
>      void    slicetypePath(Lowres **frames, int length,
> char(*best_paths)[X265_LOOKAHEAD_MAX + 1]);
>      int64_t slicetypePathCost(Lowres **frames, char *path, int64_t
> threshold);
>      int64_t vbvFrameCost(Lowres **frames, int p0, int p1, int b);
> --
> 2.37.2.windows.2
>
> *Thanks and Regards,*
>
>
>
>
>
> *Snehaa.GVideo Codec Engineer,Media & AI analytics
> <https://multicorewareinc.com/>*
> _______________________________________________
> x265-devel mailing list
> x265-devel at videolan.org
> https://mailman.videolan.org/listinfo/x265-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20221104/c5835891/attachment-0001.htm>


More information about the x265-devel mailing list