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