Pushed 3 patches to the master branch. On Wed, Nov 2, 2022 at 4:25 PM Snehaa Giridharan < [email protected]> wrote:
> From b203e94ffc619a32ead6937a61471efa584afa71 Mon Sep 17 00:00:00 2001 > From: ashok2022 <[email protected]> > Date: Wed, 26 Oct 2022 13:07:35 +0530 > Subject: [PATCH] Add function for histogram based scene change > > Signed-off-by: Snehaa Giridharan <[email protected]> > --- > 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 > [email protected] > https://mailman.videolan.org/listinfo/x265-devel >
_______________________________________________ x265-devel mailing list [email protected] https://mailman.videolan.org/listinfo/x265-devel
