Hi Srikanth, Why would there be any relationship between scene cut detection method and frame duplication? Functionality-wise, they should be independent irrespective of the underlying implementation. Best, Alex.
On Tue, Nov 19, 2019 at 3:13 AM Srikanth Kurapati < srikanth.kurap...@multicorewareinc.com> wrote: > 1. Is this necessary? Can you make the latest option set to take effect? > Ans: Thats the normal behavior and how the cli is parsed. We had a > discussion on this. > 1. to enable default method when user chooses both. > 2. or enable latest - user's last choice. > 3. to process only the users first choice. > We choose the last option. > That was how it was initially designed. > 2. Will this work if --hist-scenecut is set after --hist-threshold in the > CLI? > No. It's mentioned in the documentation how to use the new cli options > that the method needs to be enabled before the threshold being set. > else in the case when only threshold is set and method is not enabled its > unnecessarily being processed again and again though its nor used in the > library. > Incase the user threshold is not read the default value will always be > used for processing. > 3. float point comparison; might result in rounding errors. > - at the end of a high precision which is not the case for typical > thresholds set by user upto to 2 to 3 decimal places. > 4. Also, why are you checking p->edgeTransitionThreshold when naive > scenecut algorithm is enabled? > - to handle the case when user has configured the wrong threshold but > since its unnecessary I will remove the same. > 5. Please add one more CLI to test the functionality of hist-scenecut in > the absence of frame duplication. > - It has been discussed and decided to add only one for the full > feature. Should I still add the same. > 6. This will affect backward compatibility. May I know how ? > Everywhere in the code we are setting the flags to true or false it > should be of type bool. > > Will address the rest of the valid comments. > > On Mon, Nov 18, 2019 at 11:06 PM Aruna Matheswaran < > ar...@multicorewareinc.com> wrote: > >> >> >> On Mon, Nov 18, 2019 at 12:20 PM Srikanth Kurapati < >> srikanth.kurap...@multicorewareinc.com> wrote: >> >>> # HG changeset patch >>> # User Srikanth Kurapati <srikanth.kurap...@multicorewareinc.com> >>> # Date 1573649311 -19800 >>> # Wed Nov 13 18:18:31 2019 +0530 >>> # Node ID 40beab295ca274bf62cb2fd2e732da722d10eea3 >>> # Parent 04db2bfee5d628d931d1407355b909ac8ff1c898 >>> Histogram based scenecut detection >>> >>> This patch does the following. >>> 1.Identifies scenecuts by thresholding against sad of edge and chroma >>> histograms. >>> 2.Add option "--hist-scenecut" to enable histogram based scenecut method. >>> 3.Add option "--hist-threshold" to provide threshold for determining >>> scene-cuts. >>> 3.Optimizes frame duplication through reuse of sad for marking duplicate >>> frames. >>> >>> diff -r 04db2bfee5d6 -r 40beab295ca2 doc/reST/cli.rst >>> --- a/doc/reST/cli.rst Thu Oct 31 16:23:27 2019 +0530 >>> +++ b/doc/reST/cli.rst Wed Nov 13 18:18:31 2019 +0530 >>> @@ -1426,7 +1426,23 @@ >>> This value represents the percentage difference between the inter cost >>> and >>> intra cost of a frame used in scenecut detection. For example, a value >>> of 5 indicates, >>> if the inter cost of a frame is greater than or equal to 95 percent of >>> the intra cost of the frame, >>> - then detect this frame as scenecut. Values between 5 and 15 are >>> recommended. Default 5. >>> + then detect this frame as scenecut. Values between 5 and 15 are >>> recommended. >>> + This value is evaluated only when --scenecut is enabled else it is >>> ignored. Default 5. >>> + >>> +.. option:: --hist-scenecut, --no-hist-scenecut >>> + >>> + indicates that scenecuts need to be detected using luma edge and >>> chroma histograms. >>> >> Case issue in "indicates". >> >>> + option: `--hist-scenecut` enables scenecut detection using the >>> histograms and disables the default scene cut algorithm. >>> + option: `--no-hist-scenecut` disables histogram based scenecut >>> algorithm. >>> + >>> + Note that if --hist-scenecut and --scenecut are enabled together the >>> first choice of user is considered for processing. >>> + >>> +.. option:: --hist-threshold <0.0..2.0> >>> + >>> + This value represents the threshold for normalized SAD of edge >>> histograms used in scenecut detection. >>> + This requires hist-scenecut to be enabled. For example, a value of 0.2 >>> indicates that a frame with normalized SAD value >>> >> Add a link to hist-scenecut (option: `--hist-scenecut` ) >> >>> + greater than 0.2 against the previous frame as scenecut. >>> + Default 0.01. >>> >>> .. option:: --radl <integer> >>> >>> diff -r 04db2bfee5d6 -r 40beab295ca2 source/CMakeLists.txt >>> --- a/source/CMakeLists.txt Thu Oct 31 16:23:27 2019 +0530 >>> +++ b/source/CMakeLists.txt Wed Nov 13 18:18:31 2019 +0530 >>> @@ -29,7 +29,7 @@ >>> option(STATIC_LINK_CRT "Statically link C runtime for release builds" >>> OFF) >>> mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD) >>> # X265_BUILD must be incremented each time the public API is changed >>> -set(X265_BUILD 182) >>> +set(X265_BUILD 183) >>> configure_file("${PROJECT_SOURCE_DIR}/x265.def.in" >>> "${PROJECT_BINARY_DIR}/x265.def") >>> configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in" >>> diff -r 04db2bfee5d6 -r 40beab295ca2 source/common/common.h >>> --- a/source/common/common.h Thu Oct 31 16:23:27 2019 +0530 >>> +++ b/source/common/common.h Wed Nov 13 18:18:31 2019 +0530 >>> @@ -129,12 +129,16 @@ >>> typedef uint64_t sum2_t; >>> typedef uint64_t pixel4; >>> typedef int64_t ssum2_t; >>> +#define HISTOGRAM_BINS 1024 >>> +#define SHIFT 1 >>> #else >>> typedef uint8_t pixel; >>> typedef uint16_t sum_t; >>> typedef uint32_t sum2_t; >>> typedef uint32_t pixel4; >>> typedef int32_t ssum2_t; // Signed sum >>> +#define HISTOGRAM_BINS 256 >>> +#define SHIFT 0 >>> #endif // if HIGH_BIT_DEPTH >>> >>> #if X265_DEPTH < 10 >>> diff -r 04db2bfee5d6 -r 40beab295ca2 source/common/param.cpp >>> --- a/source/common/param.cpp Thu Oct 31 16:23:27 2019 +0530 >>> +++ b/source/common/param.cpp Wed Nov 13 18:18:31 2019 +0530 >>> @@ -167,6 +167,8 @@ >>> param->bFrameAdaptive = X265_B_ADAPT_TRELLIS; >>> param->bBPyramid = 1; >>> param->scenecutThreshold = 40; /* Magic number pulled in from x264 >>> */ >>> + param->edgeTransitionThreshold = 0.01; >>> + param->bHistBasedSceneCut = false; >>> param->lookaheadSlices = 8; >>> param->lookaheadThreads = 0; >>> param->scenecutBias = 5.0; >>> @@ -572,6 +574,7 @@ >>> param->bframes = 0; >>> param->lookaheadDepth = 0; >>> param->scenecutThreshold = 0; >>> + param->bHistBasedSceneCut = false; >>> param->rc.cuTree = 0; >>> param->frameNumThreads = 1; >>> } >>> @@ -614,7 +617,7 @@ >>> return 0; >>> } >>> >>> -static int x265_atobool(const char* str, bool& bError) >>> +static bool x265_atobool(const char* str, bool& bError) >>> { >>> if (!strcmp(str, "1") || >>> !strcmp(str, "true") || >>> @@ -764,6 +767,7 @@ >>> bool bNameWasBool = false; >>> bool bValueWasNull = !value; >>> bool bExtraParams = false; >>> + static int scenecutChoice = -1; >>> >> Is this necessary? Can you make the latest option set to take effect? >> >>> char nameBuf[64]; >>> static int count; >>> >>> @@ -920,11 +924,16 @@ >>> OPT("lookahead-slices") p->lookaheadSlices = atoi(value); >>> OPT("scenecut") >>> { >>> - p->scenecutThreshold = atobool(value); >>> - if (bError || p->scenecutThreshold) >>> + if (scenecutChoice == -1) >>> { >>> - bError = false; >>> - p->scenecutThreshold = atoi(value); >>> + p->scenecutThreshold = atobool(value); >>> + if (bError || p->scenecutThreshold) >>> + { >>> + bError = false; >>> + p->scenecutThreshold = atoi(value); >>> + p->bHistBasedSceneCut = false; >>> + scenecutChoice = 0; >>> + } >>> } >>> } >>> OPT("temporal-layers") p->bEnableTemporalSubLayers = atobool(value); >>> @@ -1191,6 +1200,46 @@ >>> OPT("opt-ref-list-length-pps") p->bOptRefListLengthPPS = >>> atobool(value); >>> OPT("multi-pass-opt-rps") p->bMultiPassOptRPS = atobool(value); >>> OPT("scenecut-bias") p->scenecutBias = atof(value); >>> + OPT("hist-scenecut") >>> + { >>> + if (scenecutChoice == -1) >>> + { >>> + p->bHistBasedSceneCut = atobool(value); >>> + if (bError) >>> + { >>> + bError = false; >>> + p->bHistBasedSceneCut = false; >>> + } >>> + if (p->bHistBasedSceneCut) >>> + { >>> + bError = false; >>> + p->scenecutThreshold = 0; >>> + scenecutChoice = 1; >>> + } >>> + } >>> + else >>> + { >>> + p->bHistBasedSceneCut = atobool(value); >>> + p->bHistBasedSceneCut = false; >>> + } >>> + } >>> + OPT("hist-threshold") >>> + { >>> + if (p->bHistBasedSceneCut) >>> >> Will this work if --hist-scenecut is set after --hist-threshold in the >> CLI? >> >>> + { >>> + p->edgeTransitionThreshold = atof(value); >>> + if (bError) >>> + { >>> + bError = false; >>> + p->edgeTransitionThreshold = 0.01; >>> + x265_log(p, X265_LOG_INFO, "Using default >>> threshold %.2lf for scene cut detection\n", p->edgeTransitionThreshold); >>> + } >>> + } >>> + else >>> + { >>> + x265_log(p, X265_LOG_WARNING, "Histogram based scene >>> cut detection not enabled\n", p->edgeTransitionThreshold); >>> + } >>> + } >>> OPT("lookahead-threads") p->lookaheadThreads = atoi(value); >>> OPT("opt-cu-delta-qp") p->bOptCUDeltaQP = atobool(value); >>> OPT("multi-pass-opt-analysis") p->analysisMultiPassRefine = >>> atobool(value); >>> @@ -1631,8 +1680,16 @@ >>> "Valid Logging level -1:none 0:error 1:warning 2:info 3:debug >>> 4:full"); >>> CHECK(param->scenecutThreshold < 0, >>> "scenecutThreshold must be greater than 0"); >>> - CHECK(param->scenecutBias < 0 || 100 < param->scenecutBias, >>> - "scenecut-bias must be between 0 and 100"); >>> + if (param->scenecutThreshold) >>> + { >>> + CHECK(param->scenecutBias < 0 || 100 < param->scenecutBias, >>> + "scenecut-bias must be between 0 and 100"); >>> + } >>> + else if (param->bHistBasedSceneCut) >>> + { >>> + CHECK(param->edgeTransitionThreshold < 0.0 || 2.0 < >>> param->edgeTransitionThreshold, >>> + "hist-threshold must be between 0.0 and 2.0"); >>> + } >>> CHECK(param->radl < 0 || param->radl > param->bframes, >>> "radl must be between 0 and bframes"); >>> CHECK(param->rdPenalty < 0 || param->rdPenalty > 2, >>> @@ -1792,9 +1849,13 @@ >>> x265_log(param, X265_LOG_INFO, "ME / range / subpel / merge >>> : %s / %d / %d / %d\n", >>> x265_motion_est_names[param->searchMethod], >>> param->searchRange, param->subpelRefine, param->maxNumMergeCand); >>> >>> - if (param->keyframeMax != INT_MAX || param->scenecutThreshold) >>> - x265_log(param, X265_LOG_INFO, "Keyframe min / max / scenecut / >>> bias: %d / %d / %d / %.2lf\n", param->keyframeMin, param->keyframeMax, >>> param->scenecutThreshold, param->scenecutBias * 100); >>> - else >>> + if (param->scenecutThreshold && param->keyframeMax != INT_MAX) >>> + x265_log(param, X265_LOG_INFO, "Keyframe min / max / scenecut / >>> bias : %d / %d / %d / %.2lf \n", >>> + param->keyframeMin, param->keyframeMax, >>> param->scenecutThreshold, param->scenecutBias * 100); >>> + else if (param->bHistBasedSceneCut && param->keyframeMax != >>> INT_MAX) >>> + x265_log(param, X265_LOG_INFO, "Keyframe min / max / scenecut / >>> edge threshold : %d / %d / %d / %.2lf\n", >>> + param->keyframeMin, param->keyframeMax, >>> param->bHistBasedSceneCut, param->edgeTransitionThreshold); >>> + else if (param->keyframeMax == INT_MAX) >>> x265_log(param, X265_LOG_INFO, "Keyframe min / max / scenecut >>> : disabled\n"); >>> >>> if (param->cbQpOffset || param->crQpOffset) >>> @@ -1961,6 +2022,8 @@ >>> s += sprintf(s, " rc-lookahead=%d", p->lookaheadDepth); >>> s += sprintf(s, " lookahead-slices=%d", p->lookaheadSlices); >>> s += sprintf(s, " scenecut=%d", p->scenecutThreshold); >>> + s += sprintf(s, " hist-scenecut=%d", p->bHistBasedSceneCut); >>> + s += sprintf(s, " hist-threshold=%.2f", p->edgeTransitionThreshold); >>> s += sprintf(s, " radl=%d", p->radl); >>> BOOL(p->bEnableHRDConcatFlag, "splice"); >>> BOOL(p->bIntraRefresh, "intra-refresh"); >>> @@ -2108,6 +2171,8 @@ >>> BOOL(p->bOptRefListLengthPPS, "opt-ref-list-length-pps"); >>> BOOL(p->bMultiPassOptRPS, "multi-pass-opt-rps"); >>> s += sprintf(s, " scenecut-bias=%.2f", p->scenecutBias); >>> + s += sprintf(s, " hist-threshold=%.2f", p->edgeTransitionThreshold); >>> + >>> >> >> Added twice; Please remove one. >>> >> BOOL(p->bOptCUDeltaQP, "opt-cu-delta-qp"); >>> BOOL(p->bAQMotion, "aq-motion"); >>> BOOL(p->bEmitHDRSEI, "hdr"); >>> @@ -2261,6 +2326,7 @@ >>> dst->lookaheadSlices = src->lookaheadSlices; >>> dst->lookaheadThreads = src->lookaheadThreads; >>> dst->scenecutThreshold = src->scenecutThreshold; >>> + dst->bHistBasedSceneCut = src->bHistBasedSceneCut; >>> dst->bIntraRefresh = src->bIntraRefresh; >>> dst->maxCUSize = src->maxCUSize; >>> dst->minCUSize = src->minCUSize; >>> @@ -2420,6 +2486,7 @@ >>> dst->bOptRefListLengthPPS = src->bOptRefListLengthPPS; >>> dst->bMultiPassOptRPS = src->bMultiPassOptRPS; >>> dst->scenecutBias = src->scenecutBias; >>> + dst->edgeTransitionThreshold = src->edgeTransitionThreshold; >>> dst->gopLookahead = src->lookaheadDepth; >>> dst->bOptCUDeltaQP = src->bOptCUDeltaQP; >>> dst->analysisMultiPassDistortion = src->analysisMultiPassDistortion; >>> diff -r 04db2bfee5d6 -r 40beab295ca2 source/encoder/encoder.cpp >>> --- a/source/encoder/encoder.cpp Thu Oct 31 16:23:27 2019 +0530 >>> +++ b/source/encoder/encoder.cpp Wed Nov 13 18:18:31 2019 +0530 >>> @@ -130,12 +130,17 @@ >>> #if SVT_HEVC >>> m_svtAppData = NULL; >>> #endif >>> - >>> m_prevTonemapPayload.payload = NULL; >>> m_startPoint = 0; >>> m_saveCTUSize = 0; >>> + m_edgePic = NULL; >>> + m_edgeHistThreshold = 0; >>> + m_chromaHistThreshold = 0.0; >>> + m_scaledEdgeThreshold = 0.0; >>> + m_scaledChromaThreshold = 0.0; >>> m_zoneIndex = 0; >>> } >>> + >>> inline char *strcatFilename(const char *input, const char *suffix) >>> { >>> char *output = X265_MALLOC(char, strlen(input) + strlen(suffix) + >>> 1); >>> @@ -210,6 +215,24 @@ >>> } >>> } >>> >>> + if (m_param->bHistBasedSceneCut) >>> + { >>> + for (int i = 0; i < x265_cli_csps[m_param->internalCsp].planes; >>> i++) >>> + { >>> + m_planeSizes[i] = m_param->sourceWidth * >>> m_param->sourceHeight >> x265_cli_csps[m_param->internalCsp].height[i]; >>> + } >>> + uint32_t pixelbytes = m_param->sourceBitDepth > 8 ? 2 : 1; >>> + m_edgePic = X265_MALLOC(pixel, m_planeSizes[0]*pixelbytes); >>> >> Indentation issue // m_planeSizes[0]*pixelbytes >> >>> + double strengthFactor = 2.0; >>> >> Replace the constant with a macro >> >>> + m_edgeHistThreshold = m_param->edgeTransitionThreshold; >>> + m_chromaHistThreshold = m_edgeHistThreshold * 10.0; >>> + m_chromaHistThreshold = x265_min(m_chromaHistThreshold, >>> MAX_SCENECUT_THRESHOLD); >>> + m_scaledEdgeThreshold = m_edgeHistThreshold * strengthFactor; >>> + m_scaledEdgeThreshold = x265_min(m_scaledEdgeThreshold, >>> MAX_SCENECUT_THRESHOLD); >>> + m_scaledChromaThreshold = m_chromaHistThreshold * >>> strengthFactor; >>> + m_scaledChromaThreshold = x265_min(m_scaledChromaThreshold, >>> MAX_SCENECUT_THRESHOLD); >>> + } >>> + >>> // Do not allow WPP if only one row or fewer than 3 columns, it is >>> pointless and unstable >>> if (rows == 1 || cols < 3) >>> { >>> @@ -854,6 +877,12 @@ >>> } >>> } >>> >>> + if (m_param->bHistBasedSceneCut) >>> + { >>> + if(m_edgePic != NULL) >>> + X265_FREE_ZERO(m_edgePic); >>> + } >>> + >>> for (int i = 0; i < m_param->frameNumThreads; i++) >>> { >>> if (m_frameEncoder[i]) >>> @@ -1313,6 +1342,141 @@ >>> dest->planes[2] = (char*)dest->planes[1] + src->stride[1] * >>> (src->height >> x265_cli_csps[src->colorSpace].height[1]); >>> } >>> >>> +bool Encoder::computeHistograms(x265_picture *pic) >>> +{ >>> + pixel *src = (pixel*)pic->planes[0]; >>> + size_t bufSize = sizeof(pixel) * m_planeSizes[0]; >>> + int32_t planeCount = x265_cli_csps[m_param->internalCsp].planes; >>> + int32_t numBytes = m_param->sourceBitDepth > 8 ? 2 : 1; >>> + memset(m_edgePic, 0, bufSize*numBytes); >>> + >>> + if (!computeEdge(m_edgePic, src, NULL, pic->width, pic->height, >>> pic->width, false)) >>> + { >>> + x265_log(m_param, X265_LOG_ERROR, "Failed edge computation!"); >>> + return false; >>> + } >>> + >>> + pixel pixelVal; >>> + int64_t size = pic->height * (pic->stride[0] >> SHIFT); >>> + int32_t *edgeHist = m_curEdgeHist; >>> + memset(edgeHist, 0, 2 * sizeof(int32_t)); >>> + for (int64_t i = 0; i < size; i++) >>> + { >>> + if (!m_edgePic[i]) >>> + edgeHist[0]++; >>> + else >>> + edgeHist[1]++; >>> + } >>> + >>> + /*U Histogram Calculation*/ >>> + int32_t HeightL = (pic->height >> >>> x265_cli_csps[pic->colorSpace].height[1]); >>> + size = HeightL * (pic->stride[1] >> SHIFT); >>> + int32_t *uHist = m_curUVHist[0]; >>> + pixel *chromaPlane = (pixel *)pic->planes[1]; >>> >> Encoder crashes with X265_CSP_I400 input; You need to check the CSP type >> before accessing the UV planes. >> >>> + >>> >> + memset(uHist, 0, HISTOGRAM_BINS * sizeof(int32_t)); >>> + >>> + for (int64_t i = 0; i < size; i++) >>> + { >>> + pixelVal = chromaPlane[i]; >>> + uHist[pixelVal]++; >>> + } >>> + >>> + /*V Histogram Calculation */ >>> + if (planeCount == 3) >>> >> + { >>> + pixelVal = 0; >>> + int32_t heightV = (pic->height >> >>> x265_cli_csps[pic->colorSpace].height[2]); >>> + size = heightV * (pic->stride[2] >> SHIFT); >>> + int32_t *vHist = m_curUVHist[1]; >>> + chromaPlane = (pixel *)pic->planes[2]; >>> + >>> + memset(vHist, 0, HISTOGRAM_BINS * sizeof(int32_t)); >>> + for (int64_t i = 0; i < size; i++) >>> + { >>> + pixelVal = chromaPlane[i]; >>> + vHist[pixelVal]++; >>> + } >>> + for (int i = 0; i < HISTOGRAM_BINS; i++) >>> + { >>> + m_curMaxUVHist[i] = x265_max(uHist[i],vHist[i]); >>> >> Intendation issue >> >>> + } >>> + } >>> + else >>> + { /* in case of bi planar color space */ >>> + >>> memcpy(m_curMaxUVHist,m_curUVHist[0],HISTOGRAM_BINS*sizeof(int32_t)); >>> >> Intendation issue >> >>> + } >>> + >>> + return true; >>> +} >>> + >>> +void Encoder::computeHistogramSAD(double *maxUVNormalizedSad, double >>> *edgeNormalizedSad, int curPoc) >>> +{ >>> + >>> + if (curPoc == 0) >>> + { /* first frame is scenecut by default no sad computation for the >>> same. */ >>> + *maxUVNormalizedSad = 0.0; >>> + *edgeNormalizedSad = 0.0; >>> + } >>> + else >>> + { >>> + /* compute sum of absolute difference of normalized histogram >>> bins for maxUV and edge histograms. */ >>> + int32_t edgefreqDiff = 0; >>> + int32_t maxUVfreqDiff = 0; >>> + double edgeProbabilityDiff = 0; >>> + >>> + for (int j = 0; j < HISTOGRAM_BINS; j++) >>> + { >>> + if (j < 2 ) >>> >> indentation issue >> >>> + { >>> + edgefreqDiff = abs(m_curEdgeHist[j] - m_prevEdgeHist[j]); >>> + edgeProbabilityDiff = (double) edgefreqDiff / >>> m_planeSizes[0]; >>> + *edgeNormalizedSad += edgeProbabilityDiff; >>> + } >>> + maxUVfreqDiff = abs(m_curMaxUVHist[j] - m_prevMaxUVHist[j]); >>> + *maxUVNormalizedSad += (double)maxUVfreqDiff / >>> m_planeSizes[2]; >>> + } >>> + } >>> + >>> + /* store histograms of previous frame for reference */ >>> + size_t bufsize = HISTOGRAM_BINS * sizeof(int32_t); >>> + memcpy(m_prevMaxUVHist, m_curMaxUVHist, bufsize); >>> + memcpy(m_prevEdgeHist, m_curEdgeHist, 2*sizeof(int32_t)); >>> >> indentation issue >> >>> + >>> +} >>> + >>> +void Encoder::findSceneCuts(x265_picture * pic, bool& bDup, double >>> maxUVSad, double edgeSad) >>> +{ >>> + pic->frameData.bScenecut = false; >>> + >>> + if (pic->poc == 0) >>> + { >>> + /* for first frame */ >>> + pic->frameData.bScenecut = false; >>> + bDup = false; >>> + } >>> + else >>> + { >>> + if (edgeSad == 0.0 && maxUVSad == 0.0) >>> + { >>> + bDup = true; >>> + } >>> + else if (edgeSad > m_edgeHistThreshold && maxUVSad >= >>> m_chromaHistThreshold) >>> + { >>> + pic->frameData.bScenecut = true; >>> + bDup = false; >>> + } >>> + else if (edgeSad > m_scaledEdgeThreshold || maxUVSad >= >>> m_scaledChromaThreshold) >>> + { >>> + pic->frameData.bScenecut = true; >>> + bDup = false; >>> + } >>> + } >>> + >>> + if (pic->frameData.bScenecut) >>> + x265_log(m_param, X265_LOG_DEBUG, "scene cut at %d \n",pic->poc); >>> >> indentation issue >> >>> +} >>> + >>> /** >>> * Feed one new input frame into the encoder, get one frame out. If >>> pic_in is >>> * NULL, a flush condition is implied and pic_in must be NULL for all >>> subsequent >>> @@ -1339,6 +1503,8 @@ >>> const x265_picture* inputPic = NULL; >>> static int written = 0, read = 0; >>> bool dontRead = false; >>> + bool bdropFrame = false; >>> + bool dropflag = false; >>> >>> if (m_exportedPic) >>> { >>> @@ -1350,6 +1516,17 @@ >>> } >>> if ((pic_in && (!m_param->chunkEnd || (m_encodedFrameNum < >>> m_param->chunkEnd))) || (m_param->bEnableFrameDuplication && !pic_in && >>> (read < written))) >>> { >>> + if (m_param->bHistBasedSceneCut && pic_in) >>> + { >>> + x265_picture *pic = (x265_picture *) pic_in; >>> + if (computeHistograms(pic)) >>> + { >>> + double maxUVSad = 0.0, edgeSad = 0.0; >>> + computeHistogramSAD(&maxUVSad, &edgeSad,pic_in->poc); >>> >> indentation issue. >> >>> + findSceneCuts(pic, bdropFrame, maxUVSad, edgeSad); >>> + } >>> + } >>> + >>> if ((m_param->bEnableFrameDuplication && !pic_in && (read < >>> written))) >>> dontRead = true; >>> else >>> @@ -1393,9 +1570,27 @@ >>> written++; >>> } >>> >>> - psnrWeight = ComputePSNR(m_dupBuffer[0]->dupPic, >>> m_dupBuffer[1]->dupPic, m_param); >>> - >>> - if (psnrWeight >= m_param->dupThreshold) >>> + if (m_param->bEnableFrameDuplication && >>> m_param->bHistBasedSceneCut) >>> + { >>> + if (!bdropFrame && >>> m_dupBuffer[1]->dupPic->frameData.bScenecut == false) >>> + { >>> + psnrWeight = ComputePSNR(m_dupBuffer[0]->dupPic, >>> m_dupBuffer[1]->dupPic, m_param); >>> + if (psnrWeight >= m_param->dupThreshold) >>> + dropflag = true; >>> + } >>> + else >>> + { >>> + dropflag = true; >>> + } >>> + } >>> + else if (m_param->bEnableFrameDuplication) >>> + { >>> + psnrWeight = ComputePSNR(m_dupBuffer[0]->dupPic, >>> m_dupBuffer[1]->dupPic, m_param); >>> + if (psnrWeight >= m_param->dupThreshold) >>> + dropflag = true; >>> + } >>> + >>> + if (dropflag) >>> { >>> if (m_dupBuffer[0]->bDup) >>> { >>> @@ -1498,6 +1693,10 @@ >>> inFrame->m_poc = ++m_pocLast; >>> inFrame->m_userData = inputPic->userData; >>> inFrame->m_pts = inputPic->pts; >>> + if (m_param->bHistBasedSceneCut) >>> + { >>> + inFrame->m_lowres.bScenecut = inputPic->frameData.bScenecut; >>> + } >>> inFrame->m_forceqp = inputPic->forceqp; >>> inFrame->m_param = (m_reconfigure || m_reconfigureRc) ? >>> m_latestParam : m_param; >>> inFrame->m_picStruct = inputPic->picStruct; >>> @@ -3209,6 +3408,7 @@ >>> * adaptive I frame placement */ >>> p->keyframeMax = INT_MAX; >>> p->scenecutThreshold = 0; >>> + p->bHistBasedSceneCut = 0; >>> } >>> else if (p->keyframeMax <= 1) >>> { >>> @@ -3222,6 +3422,7 @@ >>> p->lookaheadDepth = 0; >>> p->bframes = 0; >>> p->scenecutThreshold = 0; >>> + p->bHistBasedSceneCut = 0; >>> p->bFrameAdaptive = 0; >>> p->rc.cuTree = 0; >>> p->bEnableWeightedPred = 0; >>> @@ -3881,6 +4082,17 @@ >>> m_param->searchMethod = m_param->hmeSearchMethod[2]; >>> } >>> } >>> + >>> + if (p->scenecutThreshold && p->edgeTransitionThreshold != 0.01) >>> + { >>> >> float point comparison; might result in rounding errors. >> Also, why are you checking p->edgeTransitionThreshold when naive >> scenecut algorithm is enabled? >> >>> + x265_log(p, X265_LOG_WARNING, "using default scenecut-bias %.2lf >>> for scene cut detection\n",p->scenecutBias); >>> + } >>> + else if (p->bHistBasedSceneCut && p->edgeTransitionThreshold == 0.0) >>> >> float point comparison; might result in rounding errors. >> >>> + { >>> + p->edgeTransitionThreshold = 0.01; >>> + x265_log(p, X265_LOG_WARNING, "using default threshold %.2lf >>> for scene cut detection\n", p->edgeTransitionThreshold); >>> + } >>> + >>> } >>> >>> void Encoder::readAnalysisFile(x265_analysis_data* analysis, int >>> curPoc, const x265_picture* picIn, int paramBytes) >>> diff -r 04db2bfee5d6 -r 40beab295ca2 source/encoder/encoder.h >>> --- a/source/encoder/encoder.h Thu Oct 31 16:23:27 2019 +0530 >>> +++ b/source/encoder/encoder.h Wed Nov 13 18:18:31 2019 +0530 >>> @@ -156,7 +156,6 @@ >>> bool bDup; >>> }; >>> >>> - >>> class FrameEncoder; >>> class DPB; >>> class Lookahead; >>> @@ -164,6 +163,8 @@ >>> class ThreadPool; >>> class FrameData; >>> >>> +#define MAX_SCENECUT_THRESHOLD 2.0 >>> + >>> class Encoder : public x265_encoder >>> { >>> public: >>> @@ -228,7 +229,7 @@ >>> bool m_reconfigureRc; >>> bool m_reconfigureZone; >>> >>> - int m_saveCtuDistortionLevel; >>> + int m_saveCtuDistortionLevel; >>> >>> /* Begin intra refresh when one not in progress or else begin one >>> as soon as the current >>> * one is done. Requires bIntraRefresh to be set.*/ >>> @@ -245,11 +246,24 @@ >>> Lock m_rpsInSpsLock; >>> int m_rpsInSpsCount; >>> /* For HDR*/ >>> - double m_cB; >>> - double m_cR; >>> + double m_cB; >>> + double m_cR; >>> + >>> + int m_bToneMap; // Enables tone-mapping >>> + int m_enableNal; >>> >>> - int m_bToneMap; // Enables tone-mapping >>> - int m_enableNal; >>> + /* For histogram based scene-cut detection */ >>> + pixel* m_edgePic; >>> + int32_t m_curUVHist[2][HISTOGRAM_BINS]; >>> + int32_t m_curMaxUVHist[HISTOGRAM_BINS]; >>> + int32_t m_prevMaxUVHist[HISTOGRAM_BINS]; >>> + int32_t m_curEdgeHist[2]; >>> + int32_t m_prevEdgeHist[2]; >>> + uint32_t m_planeSizes[3]; >>> + double m_edgeHistThreshold; >>> + double m_chromaHistThreshold; >>> + double m_scaledEdgeThreshold; >>> + double m_scaledChromaThreshold; >>> >>> #ifdef ENABLE_HDR10_PLUS >>> const hdr10plus_api *m_hdr10plus_api; >>> @@ -355,6 +369,10 @@ >>> >>> void copyPicture(x265_picture *dest, const x265_picture *src); >>> >>> + bool computeHistograms(x265_picture *pic); >>> + void computeHistogramSAD(double *maxUVNormalizedSAD, double >>> *edgeNormalizedSAD, int curPoc); >>> + void findSceneCuts(x265_picture * pic, bool& bDup, double >>> m_maxUVSADVal, double m_edgeSADVal); >>> + >>> void initRefIdx(); >>> void analyseRefIdx(int *numRefIdx); >>> void updateRefIdx(); >>> diff -r 04db2bfee5d6 -r 40beab295ca2 source/encoder/ratecontrol.cpp >>> --- a/source/encoder/ratecontrol.cpp Thu Oct 31 16:23:27 2019 +0530 >>> +++ b/source/encoder/ratecontrol.cpp Wed Nov 13 18:18:31 2019 +0530 >>> @@ -508,6 +508,7 @@ >>> CMP_OPT_FIRST_PASS("open-gop", m_param->bOpenGOP); >>> CMP_OPT_FIRST_PASS(" keyint", m_param->keyframeMax); >>> CMP_OPT_FIRST_PASS("scenecut", >>> m_param->scenecutThreshold); >>> + CMP_OPT_FIRST_PASS("hist-threshold", >>> m_param->edgeTransitionThreshold); >>> CMP_OPT_FIRST_PASS("intra-refresh", >>> m_param->bIntraRefresh); >>> if (m_param->bMultiPassOptRPS) >>> { >>> @@ -1200,6 +1201,7 @@ >>> m_param->rc.bStatRead = 0; >>> m_param->bFrameAdaptive = 0; >>> m_param->scenecutThreshold = 0; >>> + m_param->bHistBasedSceneCut = false; >>> m_param->rc.cuTree = 0; >>> if (m_param->bframes > 1) >>> m_param->bframes = 1; >>> @@ -2284,7 +2286,7 @@ >>> if (m_isVbv && m_currentSatd > 0 && curFrame) >>> { >>> if (m_param->lookaheadDepth || m_param->rc.cuTree || >>> - m_param->scenecutThreshold || >>> + (m_param->scenecutThreshold || m_param->bHistBasedSceneCut) >>> || >>> (m_param->bFrameAdaptive && m_param->bframes)) >>> { >>> /* Lookahead VBV: If lookahead is done, raise the quantizer >>> as necessary >>> diff -r 04db2bfee5d6 -r 40beab295ca2 source/encoder/slicetype.cpp >>> --- a/source/encoder/slicetype.cpp Thu Oct 31 16:23:27 2019 +0530 >>> +++ b/source/encoder/slicetype.cpp Wed Nov 13 18:18:31 2019 +0530 >>> @@ -85,6 +85,69 @@ >>> >>> } // end anonymous namespace >>> >>> +namespace X265_NS { >>> + >>> +bool computeEdge(pixel *edgePic, pixel *refPic, pixel *edgeTheta, >>> intptr_t stride, int height, int width, bool bcalcTheta) >>> +{ >>> + intptr_t rowOne = 0, rowTwo = 0, rowThree = 0, colOne = 0, colTwo = >>> 0, colThree = 0; >>> + intptr_t middle = 0, topLeft = 0, topRight = 0, bottomLeft = 0, >>> bottomRight = 0; >>> + >>> + const int startIndex = 1; >>> + >>> + if (!edgePic || !refPic || (!edgeTheta && bcalcTheta)) >>> + { >>> + return false; >>> + } >>> + else >>> + { >>> + float gradientH = 0, gradientV = 0, radians = 0, theta = 0; >>> + float gradientMagnitude = 0; >>> + pixel blackPixel = 0; >>> + >>> + //Applying Sobel filter expect for border pixels >>> + height = height - startIndex; >>> + width = width - startIndex; >>> + for (int rowNum = startIndex; rowNum < height; rowNum++) >>> + { >>> + rowTwo = rowNum * stride; >>> + rowOne = rowTwo - stride; >>> + rowThree = rowTwo + stride; >>> + >>> + for (int colNum = startIndex; colNum < width; colNum++) >>> + { >>> + >>> + /* Horizontal and vertical gradients >>> + [ -3 0 3 ] [-3 -10 -3 ] >>> + gH =[ -10 0 10] gV = [ 0 0 0 ] >>> + [ -3 0 3 ] [ 3 10 3 ] */ >>> + >>> + colTwo = colNum; >>> + colOne = colTwo - startIndex; >>> + colThree = colTwo + startIndex; >>> + middle = rowTwo + colTwo; >>> + topLeft = rowOne + colOne; >>> + topRight = rowOne + colThree; >>> + bottomLeft = rowThree + colOne; >>> + bottomRight = rowThree + colThree; >>> + gradientH = (float)(-3 * refPic[topLeft] + 3 * >>> refPic[topRight] - 10 * refPic[rowTwo + colOne] + 10 * refPic[rowTwo + >>> colThree] - 3 * refPic[bottomLeft] + 3 * refPic[bottomRight]); >>> + gradientV = (float)(-3 * refPic[topLeft] - 10 * >>> refPic[rowOne + colTwo] - 3 * refPic[topRight] + 3 * refPic[bottomLeft] + >>> 10 * refPic[rowThree + colTwo] + 3 * refPic[bottomRight]); >>> + gradientMagnitude = sqrtf(gradientH * gradientH + >>> gradientV * gradientV); >>> + if(bcalcTheta) >>> + { >>> + edgeTheta[middle] = 0; >>> + radians = atan2(gradientV, gradientH); >>> + theta = (float)((radians * 180) / PI); >>> + if (theta < 0) >>> + theta = 180 + theta; >>> + edgeTheta[middle] = (pixel)theta; >>> + } >>> + edgePic[middle] = (pixel)(gradientMagnitude >= >>> edgeThreshold ? edgeThreshold : blackPixel); >>> + } >>> + } >>> + return true; >>> + } >>> +} >>> + >>> void edgeFilter(Frame *curFrame, x265_param* param) >>> { >>> int height = curFrame->m_fencPic->m_picHeight; >>> @@ -114,6 +177,7 @@ >>> //Applying Gaussian filter on the picture >>> src = (pixel*)curFrame->m_fencPic->m_picOrg[0]; >>> refPic = curFrame->m_gaussianPic + >>> curFrame->m_fencPic->m_lumaMarginY * stride + >>> curFrame->m_fencPic->m_lumaMarginX; >>> + edgePic = curFrame->m_edgePic + curFrame->m_fencPic->m_lumaMarginY >>> * stride + curFrame->m_fencPic->m_lumaMarginX; >>> pixel pixelValue = 0; >>> >>> for (int rowNum = 0; rowNum < height; rowNum++) >>> @@ -146,51 +210,8 @@ >>> } >>> } >>> >>> -#if HIGH_BIT_DEPTH //10-bit build >>> - float threshold = 1023; >>> - pixel whitePixel = 1023; >>> -#else >>> - float threshold = 255; >>> - pixel whitePixel = 255; >>> -#endif >>> -#define PI 3.14159265 >>> - >>> - float gradientH = 0, gradientV = 0, radians = 0, theta = 0; >>> - float gradientMagnitude = 0; >>> - pixel blackPixel = 0; >>> - edgePic = curFrame->m_edgePic + curFrame->m_fencPic->m_lumaMarginY >>> * stride + curFrame->m_fencPic->m_lumaMarginX; >>> - //Applying Sobel filter on the gaussian filtered picture >>> - for (int rowNum = 0; rowNum < height; rowNum++) >>> - { >>> - for (int colNum = 0; colNum < width; colNum++) >>> - { >>> - edgeTheta[(rowNum*stride) + colNum] = 0; >>> - if ((rowNum != 0) && (colNum != 0) && (rowNum != height - >>> 1) && (colNum != width - 1)) //Ignoring the border pixels of the picture >>> - { >>> - /*Horizontal and vertical gradients >>> - [ -3 0 3 ] [-3 -10 -3 ] >>> - gH = [ -10 0 10] gV = [ 0 0 0 ] >>> - [ -3 0 3 ] [ 3 10 3 ]*/ >>> - >>> - const intptr_t rowOne = (rowNum - 1)*stride, colOne = >>> colNum -1; >>> - const intptr_t rowTwo = rowNum * stride, colTwo = >>> colNum; >>> - const intptr_t rowThree = (rowNum + 1)*stride, colThree >>> = colNum + 1; >>> - const intptr_t index = (rowNum*stride) + colNum; >>> - >>> - 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]); >>> - 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]); >>> - >>> - gradientMagnitude = sqrtf(gradientH * gradientH + >>> gradientV * gradientV); >>> - radians = atan2(gradientV, gradientH); >>> - theta = (float)((radians * 180) / PI); >>> - if (theta < 0) >>> - theta = 180 + theta; >>> - edgeTheta[(rowNum*stride) + colNum] = (pixel)theta; >>> - >>> - edgePic[index] = gradientMagnitude >= threshold ? >>> whitePixel : blackPixel; >>> - } >>> - } >>> - } >>> + if(!computeEdge(edgePic, refPic, edgeTheta, stride, height, width, >>> true)) >>> + x265_log(NULL, X265_LOG_ERROR, "Failed edge computation!"); >>> } >>> >>> //Find the angle of a block by averaging the pixel angles >>> @@ -1471,7 +1492,7 @@ >>> >>> if (m_lastNonB && !m_param->rc.bStatRead && >>> ((m_param->bFrameAdaptive && m_param->bframes) || >>> - m_param->rc.cuTree || m_param->scenecutThreshold || >>> + m_param->rc.cuTree || m_param->scenecutThreshold || >>> m_param->bHistBasedSceneCut || >>> (m_param->lookaheadDepth && m_param->rc.vbvBufferSize))) >>> { >>> slicetypeAnalyse(frames, false); >>> @@ -1971,10 +1992,15 @@ >>> >>> int numBFrames = 0; >>> int numAnalyzed = numFrames; >>> - bool isScenecut = scenecut(frames, 0, 1, true, origNumFrames); >>> + bool isScenecut = false; >>> >>> /* When scenecut threshold is set, use scenecut detection for I >>> frame placements */ >>> - if (m_param->scenecutThreshold && isScenecut) >>> + if (m_param->scenecutThreshold) >>> + isScenecut = scenecut(frames, 0, 1, true, origNumFrames); >>> + else if (m_param->bHistBasedSceneCut) >>> + isScenecut = frames[1]->bScenecut; >>> + >>> + if (isScenecut) >>> { >>> frames[1]->sliceType = X265_TYPE_I; >>> return; >>> @@ -1985,14 +2011,17 @@ >>> m_extendGopBoundary = false; >>> for (int i = m_param->bframes + 1; i < origNumFrames; i += >>> m_param->bframes + 1) >>> { >>> - scenecut(frames, i, i + 1, true, origNumFrames); >>> + if (m_param->scenecutThreshold) >>> + scenecut(frames, i, i + 1, true, origNumFrames); >>> + >>> for (int j = i + 1; j <= X265_MIN(i + m_param->bframes + 1, >>> origNumFrames); j++) >>> { >>> - if (frames[j]->bScenecut && scenecutInternal(frames, j >>> - 1, j, true) ) >>> - { >>> - m_extendGopBoundary = true; >>> - break; >>> - } >>> + if (( m_param->scenecutThreshold && >>> frames[j]->bScenecut && scenecutInternal(frames, j - 1, j, true)) || >>> + (m_param->bHistBasedSceneCut && >>> frames[j]->bScenecut)) >>> + { >>> + m_extendGopBoundary = true; >>> + break; >>> + } >>> } >>> if (m_extendGopBoundary) >>> break; >>> @@ -2097,13 +2126,14 @@ >>> { >>> for (int j = 1; j < numBFrames + 1; j++) >>> { >>> - if (scenecut(frames, j, j + 1, false, origNumFrames) || >>> + if ((m_param->scenecutThreshold && scenecut(frames, j, >>> j + 1, false, origNumFrames)) || >>> + (m_param->bHistBasedSceneCut && frames[j + >>> 1]->bScenecut) || >>> (bForceRADL && (frames[j]->frameNum == preRADL))) >>> - { >>> - frames[j]->sliceType = X265_TYPE_P; >>> - numAnalyzed = j; >>> - break; >>> - } >>> + { >>> + frames[j]->sliceType = X265_TYPE_P; >>> + numAnalyzed = j; >>> + break; >>> + } >>> } >>> } >>> resetStart = bKeyframe ? 1 : X265_MIN(numBFrames + 2, >>> numAnalyzed + 1); >>> @@ -3289,3 +3319,5 @@ >>> fenc->rowSatds[b - p0][p1 - b][cuY] += bcostAq; >>> fenc->lowresCosts[b - p0][p1 - b][cuXY] = >>> (uint16_t)(X265_MIN(bcost, LOWRES_COST_MASK) | (listused << >>> LOWRES_COST_SHIFT)); >>> } >>> + >>> +} >>> diff -r 04db2bfee5d6 -r 40beab295ca2 source/encoder/slicetype.h >>> --- a/source/encoder/slicetype.h Thu Oct 31 16:23:27 2019 +0530 >>> +++ b/source/encoder/slicetype.h Wed Nov 13 18:18:31 2019 +0530 >>> @@ -43,6 +43,13 @@ >>> #define AQ_EDGE_BIAS 0.5 >>> #define EDGE_INCLINATION 45 >>> >>> +#ifdef HIGH_BIT_DEPTH >>> +#define edgeThreshold 1023.0 >>> +#else >>> +#define edgeThreshold 255.0 >>> +#endif >>> +#define PI 3.14159265 >>> + >>> /* Thread local data for lookahead tasks */ >>> struct LookaheadTLD >>> { >>> @@ -258,6 +265,7 @@ >>> CostEstimateGroup& operator=(const CostEstimateGroup&); >>> }; >>> >>> -} >>> +bool computeEdge(pixel *edgePic, pixel *refPic, pixel *edgeTheta, >>> intptr_t stride, int height, int width, bool bcalcTheta); >>> >>> +} >>> #endif // ifndef X265_SLICETYPE_H >>> diff -r 04db2bfee5d6 -r 40beab295ca2 source/test/regression-tests.txt >>> --- a/source/test/regression-tests.txt Thu Oct 31 16:23:27 2019 +0530 >>> +++ b/source/test/regression-tests.txt Wed Nov 13 18:18:31 2019 +0530 >>> @@ -159,6 +159,7 @@ >>> Traffic_4096x2048_30p.y4m, --preset medium --frame-dup --dup-threshold >>> 60 --hrd --bitrate 10000 --vbv-bufsize 15000 --vbv-maxrate 12000 >>> Kimono1_1920x1080_24_400.yuv,--preset superfast --qp 28 --zones >>> 0,139,q=32 >>> Island_960x540_420p_8bit_24fps.yuv,--no-cutree --aq-mode 0 --bitrate >>> 6000 --scenecut-aware-qp >>> +sintel_trailer_2k_1920x1080_24.yuv, --preset medium --hist-scenecut >>> --hist-threshold 0.02 --frame-dup --dup-threshold 60 --hrd --bitrate 10000 >>> --vbv-bufsize 15000 --vbv-maxrate 12000 >>> >> Please add one more CLI to test the functionality of hist-scenecut in the >> absence of frame duplication. >> >>> >>> # Main12 intraCost overflow bug test >>> 720p50_parkrun_ter.y4m,--preset medium >>> diff -r 04db2bfee5d6 -r 40beab295ca2 source/x265.h >>> --- a/source/x265.h Thu Oct 31 16:23:27 2019 +0530 >>> +++ b/source/x265.h Wed Nov 13 18:18:31 2019 +0530 >>> @@ -211,7 +211,7 @@ >>> uint32_t numCUsInFrame; >>> uint32_t numPartitions; >>> uint32_t depthBytes; >>> - int bScenecut; >>> + bool bScenecut; >>> >> This will affect backward compatibility. >> >>> x265_weight_param* wt; >>> x265_analysis_inter_data* interData; >>> x265_analysis_intra_data* intraData; >>> @@ -294,7 +294,7 @@ >>> double avgChromaVLevel; >>> >>> char sliceType; >>> - int bScenecut; >>> + bool bScenecut; >>> >> Affects backward compatibility. >> >>> double ipCostRatio; >>> int frameLatency; >>> x265_cu_stats cuStats; >>> @@ -1024,7 +1024,8 @@ >>> int lookaheadSlices; >>> >>> /* An arbitrary threshold which determines how aggressively the >>> lookahead >>> - * should detect scene cuts. The default (40) is recommended. */ >>> + * should detect scene cuts for cost based scenecut detection. >>> + * The default (40) is recommended. */ >>> int scenecutThreshold; >>> >>> /* Replace keyframes by using a column of intra blocks that move >>> across the video >>> @@ -1846,6 +1847,16 @@ >>> /* The offset by which QP is incremented for inter-frames when >>> bEnableSceneCutAwareQp is set. >>> * Default is +5. */ >>> int maxQpDelta; >>> + >>> + /* A genuine threshold used for histogram based scene cut detection. >>> + * This threshold determines whether a frame is a scenecut or not >>> + * when compared against the edge and chroma histogram sad values. >>> + * Default 0.01. Range: Real number in the interval (0,2). */ >>> + double edgeTransitionThreshold; >>> + >>> + /* Enables histogram based scenecut detection algorithm to detect >>> scenecuts. */ >>> + bool bHistBasedSceneCut; >>> + >>> >> Indentation issue >> >>> } x265_param; >>> /* x265_param_alloc: >>> * Allocates an x265_param instance. The returned param structure is >>> not >>> diff -r 04db2bfee5d6 -r 40beab295ca2 source/x265cli.h >>> --- a/source/x265cli.h Thu Oct 31 16:23:27 2019 +0530 >>> +++ b/source/x265cli.h Wed Nov 13 18:18:31 2019 +0530 >>> @@ -129,6 +129,9 @@ >>> { "scenecut", required_argument, NULL, 0 }, >>> { "no-scenecut", no_argument, NULL, 0 }, >>> { "scenecut-bias", required_argument, NULL, 0 }, >>> + { "hist-scenecut", no_argument, NULL, 0}, >>> + { "no-hist-scenecut", no_argument, NULL, 0}, >>> + { "hist-threshold", required_argument, NULL, 0}, >>> { "fades", no_argument, NULL, 0 }, >>> { "no-fades", no_argument, NULL, 0 }, >>> { "scenecut-aware-qp", no_argument, NULL, 0 }, >>> @@ -489,7 +492,10 @@ >>> H0(" --gop-lookahead <integer> Extends gop boundary if a >>> scenecut is found within this from keyint boundary. Default 0\n"); >>> H0(" --no-scenecut Disable adaptive I-frame >>> decision\n"); >>> H0(" --scenecut <integer> How aggressively to insert >>> extra I-frames. Default %d\n", param->scenecutThreshold); >>> - H1(" --scenecut-bias <0..100.0> Bias for scenecut detection. >>> Default %.2f\n", param->scenecutBias); >>> + H1(" --scenecut-bias <0..100.0> Bias for scenecut detection. >>> Default %.2f\n", param->scenecutBias); >>> + H0(" --hist-scenecut Enables histogram based >>> scene-cut detection using histogram based algorithm.\n"); >>> + H0(" --no-hist-scenecut Disables histogram based >>> scene-cut detection using histogram based algorithm.\n"); >>> + H1(" --hist-threshold <0.0..2.0> Luma Edge histogram's >>> Normalized SAD threshold for histogram based scenecut detection Default >>> %.2f\n", param->edgeTransitionThreshold); >>> H0(" --[no-]fades Enable detection and handling >>> of fade-in regions. Default %s\n", OPT(param->bEnableFades)); >>> H1(" --[no-]scenecut-aware-qp Enable increasing QP for >>> frames inside the scenecut window after scenecut. Default %s\n", >>> OPT(param->bEnableSceneCutAwareQp)); >>> H1(" --scenecut-window <0..1000> QP incremental duration(in >>> milliseconds) when scenecut-aware-qp is enabled. Default %d\n", >>> param->scenecutWindow); >>> >>> -- >>> *With Regards,* >>> *Srikanth Kurapati.* >>> _______________________________________________ >>> x265-devel mailing list >>> x265-devel@videolan.org >>> https://mailman.videolan.org/listinfo/x265-devel >>> >> >> >> -- >> Regards, >> *Aruna Matheswaran,* >> Video Codec Engineer, >> Media & AI analytics BU, >> >> >> >> _______________________________________________ >> x265-devel mailing list >> x265-devel@videolan.org >> https://mailman.videolan.org/listinfo/x265-devel >> > > > -- > *With Regards,* > *Srikanth Kurapati.* > _______________________________________________ > x265-devel mailing list > x265-devel@videolan.org > https://mailman.videolan.org/listinfo/x265-devel >
_______________________________________________ x265-devel mailing list x265-devel@videolan.org https://mailman.videolan.org/listinfo/x265-devel