[x265] [PATCH] Improved scenecut detection
Aruna Matheswaran
aruna at multicorewareinc.com
Tue Oct 15 20:34:02 CEST 2019
This patch fails to build on the latest default; Please fix that and resend
the patch.
On Tue, Oct 15, 2019 at 12:25 PM <gopi.satykrishna at multicorewareinc.com>
wrote:
> # HG changeset patch
> # User gopi Satykrishna Akisetty
> # Date 1571121977 -19800
> # Tue Oct 15 12:16:17 2019 +0530
> # Node ID deaecadc43060ba37a85d9724a1a306a86433432
> # Parent 37648fca915b389bafe923d8443818359e80ebf2
> Improved scenecut detection
>
> This patch does the following.
> 1. identifies scenecuts using sad of edge and chroma histogram based
> thresholding.
> 2. Add option "--hist-scenecut" and "--hist-threshold' to enable improved
> scenecut method for slice type decisions,rate control and a threshold for
> determining scene-cuts.
> 3. Removed duplicate edgefilter code and created a global function for use
> in scene cut detection and aq in Lookahead.
>
> diff -r 37648fca915b -r deaecadc4306 doc/reST/cli.rst
> --- a/doc/reST/cli.rst Fri Oct 11 12:45:52 2019 +0530
> +++ b/doc/reST/cli.rst Tue Oct 15 12:16:17 2019 +0530
> @@ -1427,6 +1427,18 @@
> 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.
> +
> +.. option:: --hist-scenecut, --no-hist-scenecut
> +
> + indicates that I-frames need to be inserted using edge and color
> histogram based scenecut algorithm.
> + option: `--hist-scencut` 1 enables adaptive I frame placement
> using this method and disables the default scene cut algorithm.
> + option:`--no-hist-scenecut` adaptive I frame placement.
> +
> +.. option:: --hist-threshold <0.0..2.0>
> +
> + This value represents the threshold for SAD for 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 SAD value
> greater than 0.2 against the previous frame as scenecut.
> + Values between 0.0 and 2.0 are recommended. Default 0.1.
>
> .. option:: --radl <integer>
>
> diff -r 37648fca915b -r deaecadc4306 source/CMakeLists.txt
> --- a/source/CMakeLists.txt Fri Oct 11 12:45:52 2019 +0530
> +++ b/source/CMakeLists.txt Tue Oct 15 12:16:17 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 180)
> +set(X265_BUILD 181)
> configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
> "${PROJECT_BINARY_DIR}/x265.def")
> configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
> diff -r 37648fca915b -r deaecadc4306 source/common/CMakeLists.txt
> --- a/source/common/CMakeLists.txt Fri Oct 11 12:45:52 2019 +0530
> +++ b/source/common/CMakeLists.txt Tue Oct 15 12:16:17 2019 +0530
> @@ -151,4 +151,5 @@
> predict.cpp predict.h
> scalinglist.cpp scalinglist.h
> quant.cpp quant.h contexts.h
> - deblock.cpp deblock.h)
> + deblock.cpp deblock.h
> + scenecut.h scenecut.cpp)
> diff -r 37648fca915b -r deaecadc4306 source/common/common.h
> --- a/source/common/common.h Fri Oct 11 12:45:52 2019 +0530
> +++ b/source/common/common.h Tue Oct 15 12:16:17 2019 +0530
> @@ -129,14 +129,20 @@
> typedef uint64_t sum2_t;
> typedef uint64_t pixel4;
> typedef int64_t ssum2_t;
> +#define HISTOGRAM_SIZE 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_SIZE 256
> +#define SHIFT 0
> #endif // if HIGH_BIT_DEPTH
>
> +#define PI 3.14159265
> +
> #if X265_DEPTH < 10
> typedef uint32_t sse_t;
> #else
> diff -r 37648fca915b -r deaecadc4306 source/common/param.cpp
> --- a/source/common/param.cpp Fri Oct 11 12:45:52 2019 +0530
> +++ b/source/common/param.cpp Tue Oct 15 12:16:17 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;
> @@ -567,6 +569,7 @@
> param->bframes = 0;
> param->lookaheadDepth = 0;
> param->scenecutThreshold = 0;
> + param->bHistbasedScenecut = false;
> param->rc.cuTree = 0;
> param->frameNumThreads = 1;
> }
> @@ -609,7 +612,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") ||
> @@ -920,6 +923,7 @@
> {
> bError = false;
> p->scenecutThreshold = atoi(value);
> + p->bHistbasedScenecut = false;
> }
> }
> OPT("temporal-layers") p->bEnableTemporalSubLayers = atobool(value);
> @@ -1186,6 +1190,31 @@
> 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")
> + {
> + p->bHistbasedScenecut = atobool(value);
> +
> + if (bError)
> + {
> + bError = false;
> + p->bHistbasedScenecut = false;
> + }
> +
> + if (p->bHistbasedScenecut) {
> + bError = false;
> + p->scenecutThreshold = 0;
> + }
> +
> + }
> + OPT("hist-threshold") {
> + 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);
> + }
> + }
> 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);
> @@ -1623,8 +1652,14 @@
> "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,
> @@ -1780,10 +1815,20 @@
> 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);
> + if (param->scenecutThreshold && param->keyframeMax != INT_MAX)
> + param->edgeTransitionThreshold = 0.0;
> + else if (param->bHistbasedScenecut && param->keyframeMax != INT_MAX)
> + param->scenecutBias = 0.0;
> + else if (param->keyframeMax != INT_MAX) {
> + param->edgeTransitionThreshold = 0.0;
> + param->scenecutBias = 0.0;
> + }
> +
> + if (param->keyframeMax == INT_MAX)
> + x265_log(param, X265_LOG_INFO, "Keyframe min / max / scenecut
> : disabled\n");
> else
> - x265_log(param, X265_LOG_INFO, "Keyframe min / max / scenecut
> : disabled\n");
> + x265_log(param, X265_LOG_INFO, "Keyframe min / max / scenecut /
> bias / threshold : %d / %d / %d / %.2lf / %.2lf\n", param->keyframeMin,
> param->keyframeMax, ( param->bHistbasedScenecut || param->scenecutThreshold
> ), param->scenecutBias * 100, param->edgeTransitionThreshold);
> +
>
> if (param->cbQpOffset || param->crQpOffset)
> x265_log(param, X265_LOG_INFO, "Cb/Cr QP Offset
> : %d / %d\n", param->cbQpOffset, param->crQpOffset);
> @@ -1949,6 +1994,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");
> @@ -2096,6 +2143,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);
> +
> BOOL(p->bOptCUDeltaQP, "opt-cu-delta-qp");
> BOOL(p->bAQMotion, "aq-motion");
> BOOL(p->bEmitHDRSEI, "hdr");
> @@ -2246,6 +2295,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;
> @@ -2403,6 +2453,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 37648fca915b -r deaecadc4306 source/common/scenecut.cpp
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/source/common/scenecut.cpp Tue Oct 15 12:16:17 2019 +0530
> @@ -0,0 +1,674 @@
> +#include <iostream>
> +#include <sstream>
> +#include <vector>
> +#include <algorithm>
> +#include <math.h>
> +#include "encoder.h"
> +#include "scenecut.h"
> +#include "slicetype.h"
> +
> +using namespace std;
> +using namespace X265_NS;
> +
> +#define EDGE_PLANE_COUNT 1
> +
> +namespace X265_NS {
> +
> +void computeEdge(pixel * edgePic, pixel *refPic, pixel * edgeTheta,
> intptr_t stride, int height, int width)
> + {
> + float gradientH = 0, gradientV = 0, radians = 0, theta = 0;
> + float gradientMagnitude = 0;
> + pixel blackPixel = 0;
> +
> + //Applying Sobel filter
> + 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] = (pixel)(gradientMagnitude >=
> edge_threshold ? whitePixel : blackPixel);
> + }
> + }
> + }
> + }
> +
> + Histogram::Histogram()
> + {
> + memset(frequency_distribution, 0, HISTOGRAM_SIZE *
> sizeof(int32_t));
> + }
> +
> + Histogram::Histogram(Histogram const& hist) {
> + memset(frequency_distribution, 0, HISTOGRAM_SIZE *
> sizeof(int32_t));
> + for (int i = 0; i < HISTOGRAM_SIZE; i++) {
> + frequency_distribution[i] = hist.frequency_distribution[i];
> + }
> + }
> +
> + Histogram & Histogram::operator=(Histogram const& hist)
> + {
> + memset(frequency_distribution, 0, HISTOGRAM_SIZE *
> sizeof(int32_t));
> + memcpy(frequency_distribution, hist.frequency_distribution,
> sizeof(int32_t)*HISTOGRAM_SIZE);
> + return *this;
> + }
> +
> + Histogram::~Histogram() {}
> +
> + YuvHistogram::YuvHistogram() {}
> +
> + void YuvHistogram::initHistograms(int32_t planecount) {
> + this->plane_count = planecount;
> + m_isalloc = false;
> + bisUpdated = false;
> + param = NULL;
> +
> + yuv_hist = edge_hist = NULL;
> + plane_sizes = plane_heights = plane_widths = NULL;
> + edgePic = edgeThetaPic = NULL;
> +
> + plane_sizes = X265_MALLOC(int32_t, plane_count);
> + plane_heights = X265_MALLOC(int32_t, plane_count);
> + plane_widths = X265_MALLOC(int32_t, plane_count);
> +
> + if (!plane_sizes || !plane_heights || !plane_widths) {
> + x265_log(param, X265_LOG_ERROR, "unable to allocate memory
> for plane dimensions\n");
> + m_isalloc &= false;
> + }
> + else {
> + memset(plane_sizes, 0, plane_count * sizeof(int32_t));
> + memset(plane_heights, 0, plane_count * sizeof(int32_t));
> + memset(plane_widths, 0, plane_count * sizeof(int32_t));
> + m_isalloc &= true;
> + }
> +
> + yuv_hist = X265_MALLOC(Histogram, plane_count);
> + edge_hist = X265_MALLOC(Histogram, plane_count);
> +
> + if (!yuv_hist || !edge_hist) {
> + m_isalloc &= false;
> + x265_log(param, X265_LOG_ERROR, "unable to allocate memory
> for histograms\n");
> + }
> +
> + }
> +
> + void YuvHistogram::initHistograms(x265_param *p) {
> + param = p;
> + plane_count = x265_cli_csps[param->internalCsp].planes;
> + bisUpdated = false;
> + m_isalloc = false;
> +
> + yuv_hist = edge_hist = NULL;
> + plane_sizes = plane_heights = plane_widths = NULL;
> + edgePic = edgeThetaPic = NULL;
> +
> + plane_sizes = X265_MALLOC(int32_t, plane_count);
> + plane_heights = X265_MALLOC(int32_t, plane_count);
> + plane_widths = X265_MALLOC(int32_t, plane_count);
> +
> + if (!plane_sizes || !plane_heights || !plane_widths) {
> + x265_log(param, X265_LOG_ERROR, "unable to allocate memory
> for plane dimensions\n");
> + m_isalloc &= false;
> + }
> + else {
> + memset(plane_sizes, 0, plane_count * sizeof(int32_t));
> + memset(plane_heights, 0, plane_count * sizeof(int32_t));
> + memset(plane_widths, 0, plane_count * sizeof(int32_t));
> + m_isalloc &= true;
> + }
> +
> + yuv_hist = X265_MALLOC(Histogram, plane_count);
> + edge_hist = X265_MALLOC(Histogram, plane_count);
> +
> + if (!yuv_hist || !edge_hist) {
> + m_isalloc &= false;
> + x265_log(param, X265_LOG_ERROR, "unable to allocate memory
> for histograms\n");
> + }
> +
> + }
> +
> + bool YuvHistogram::allocHistogramBuffers() {
> + //allocate memory for edge filter output and histograms
> + bool isalloc = true;
> +
> + edgePic = X265_MALLOC(pixel*, plane_count);
> + edgeThetaPic = X265_MALLOC(pixel*, plane_count);
> +
> + if (!edgePic || !edgeThetaPic) {
> + isalloc &= false;
> + x265_log(param, X265_LOG_ERROR, "unable to allocate memory
> for edge buffers\n");
> + return isalloc;
> + }
> +
> + for (int i = 0; i < plane_count; i++) {
> +
> + edgePic[i] = edgeThetaPic[i] = NULL;
> + edgePic[i] = X265_MALLOC(pixel, plane_sizes[i]);
> + edgeThetaPic[i] = X265_MALLOC(pixel, plane_sizes[i]);
> +
> + if (edgePic[i] && edgeThetaPic[i]) {
> + memset(edgePic[i], 0, plane_sizes[i] * sizeof(pixel));
> + memset(edgeThetaPic[i], 0, plane_sizes[i] *
> sizeof(pixel));
> + isalloc &= true;
> + }
> + else
> + isalloc &= false;
> + }
> + return isalloc;
> + }
> +
> + YuvHistogram::~YuvHistogram()
> + {
> + freeHistogramBuffers(); //change implementation based on
> allocation changes
> + }
> +
> + YuvHistogram::YuvHistogram(YuvHistogram const& hist) {
> +
> + maxuv_hist = hist.maxuv_hist;
> + plane_count = hist.plane_count;
> + bisUpdated = hist.bisUpdated;
> + param = hist.param;
> + memcpy(plane_sizes, hist.plane_sizes, plane_count *
> sizeof(int32_t));
> + memcpy(plane_heights, hist.plane_heights, plane_count *
> sizeof(int32_t));
> + memcpy(plane_widths, hist.plane_widths, plane_count *
> sizeof(int32_t));
> + memcpy(yuv_hist, hist.yuv_hist, plane_count * sizeof(Histogram));
> + memcpy(edge_hist, hist.edge_hist, plane_count *
> sizeof(Histogram));
> +
> + if (!m_isalloc) {
> + m_isalloc = false;
> + m_isalloc = allocHistogramBuffers();
> + }
> +
> + if (m_isalloc) {
> + for (int i = 0; i < plane_count; i++) {
> + if (edgePic[i] && edgeThetaPic[i]) {
> + memcpy(edgePic[i], hist.edgePic[i], plane_sizes[i] *
> sizeof(pixel));
> + memcpy(edgeThetaPic[i], hist.edgeThetaPic[i],
> plane_sizes[i] * sizeof(pixel));
> + }
> + }
> + }
> +
> + }
> +
> + YuvHistogram & YuvHistogram ::operator=(const YuvHistogram &
> copy_hist)
> + {
> + maxuv_hist = copy_hist.maxuv_hist;
> + plane_count = copy_hist.plane_count;
> + bisUpdated = copy_hist.bisUpdated;
> + param = copy_hist.param;
> + memcpy(plane_sizes, copy_hist.plane_sizes, plane_count *
> sizeof(int32_t));
> + memcpy(plane_heights, copy_hist.plane_heights, plane_count *
> sizeof(int32_t));
> + memcpy(plane_widths, copy_hist.plane_widths, plane_count *
> sizeof(int32_t));
> + memcpy(yuv_hist, copy_hist.yuv_hist, plane_count *
> sizeof(Histogram));
> + memcpy(edge_hist, copy_hist.edge_hist, plane_count *
> sizeof(Histogram));
> +
> + if (!m_isalloc) {
> + m_isalloc = false;
> + m_isalloc = allocHistogramBuffers();
> + }
> +
> + if (m_isalloc) {
> + for (int i = 0; i < plane_count; i++) {
> + if (edgePic[i] && edgeThetaPic[i]) {
> + memcpy(edgePic[i], copy_hist.edgePic[i],
> plane_sizes[i] * sizeof(pixel));
> + memcpy(edgeThetaPic[i], copy_hist.edgeThetaPic[i],
> plane_sizes[i] * sizeof(pixel));
> + }
> + }
> + }
> +
> + return *this;
> + }
> +
> + void YuvHistogram::initFrameDimensions(x265_picture & pic) {
> +
> + for (int i = 0; i < plane_count; i++) {
> + plane_widths[i] = pic.width;
> + plane_heights[i] = pic.height >>
> x265_cli_csps[pic.colorSpace].height[i];
> + plane_sizes[i] = plane_widths[i] * plane_heights[i];
> + }
> + }
> +
> + void YuvHistogram::freeHistogramBuffers() {
> + //de allocate memory for histograms and edge filtered output
> + if (edgePic && edgeThetaPic) {
> + for (int i = 0; i < plane_count; i++) {
> + if (edgePic[i] && edgeThetaPic[i]) {
> + X265_FREE_ZERO(edgePic[i]);
> + X265_FREE_ZERO(edgeThetaPic[i]);
> + }
> + }
> + X265_FREE_ZERO(edgePic);
> + X265_FREE_ZERO(edgeThetaPic);
> + }
> +
> + if (plane_sizes && plane_heights && plane_widths) {
> + X265_FREE_ZERO(plane_sizes);
> + X265_FREE_ZERO(plane_heights);
> + X265_FREE_ZERO(plane_widths);
> + }
> +
> + if (yuv_hist && edge_hist) {
> + X265_FREE_ZERO(yuv_hist);
> + X265_FREE_ZERO(edge_hist);
> + }
> + }
> +
> + bool YuvHistogram::edgeFilter(x265_picture *frame) {
> +
> + if (!m_isalloc) {
> + initFrameDimensions(*frame);
> + m_isalloc = allocHistogramBuffers();
> + }
> +
> + if (m_isalloc) {
> + for (int idx = 0; idx < EDGE_PLANE_COUNT; idx++) {
> +
> + memset(edgePic[idx], 0, sizeof(pixel) * plane_sizes[idx]);
> + memset(edgeThetaPic[idx], 0, sizeof(pixel) *
> plane_sizes[idx]);
> +
> + pixel *src = (pixel*)frame->planes[idx];
> + pixel *edge_pic = edgePic[idx];
> + pixel *ref_pic = src;
> + pixel *edge_theta = edgeThetaPic[idx];
> +
> + assert(edge_pic != NULL);
> + assert(ref_pic != NULL);
> + memcpy(edge_pic, src, plane_sizes[idx] * sizeof(pixel));
> + memcpy(ref_pic, src, plane_sizes[idx] * sizeof(pixel));
> +
> + computeEdge(edge_pic, ref_pic,
> edge_theta,plane_widths[idx], plane_heights[idx], plane_widths[idx]);
> + }
> + return true;
> + }
> + else {
> + return false;
> + }
> + }
> +
> + bool YuvHistogram::computeHistograms(x265_picture &cur_frame) {
> +
> + bool bsuccess = false;
> + bsuccess = computeLumaEdgeHistogram(cur_frame);
> + if (bsuccess) {
> + if (plane_count > 1) {
> + bsuccess &= computeChromaHistogram(cur_frame);
> + }
> + return bsuccess;
> + }
> + else {
> + return bsuccess;
> + }
> +
> + }
> +
> + bool YuvHistogram::computeLumaEdgeHistogram(x265_picture &frame) {
> +
> + pixel pixel_val = 0;
> +
> + memset(edge_hist[0].frequency_distribution, 0, HISTOGRAM_SIZE *
> sizeof(int32_t));
> +
> + int size = frame.height*(frame.stride[0] >> SHIFT);
> +
> + for (int i = 0; i < size; i++) {
> + pixel_val = edgePic[0][i];
> + edge_hist[0].frequency_distribution[pixel_val]++;
> + }
> + return true;
> + }
> +
> + bool YuvHistogram::computeChromaHistogram(x265_picture &frame) {
> + /*u hist calculation*/
> + pixel pixel_val = 0;
> + int32_t pixel_ucount = 0, pixel_vcount = 0;
> +
> + int u_height = (frame.height >>
> x265_cli_csps[frame.colorSpace].height[1]);
> + int size = u_height * (frame.stride[1] >> SHIFT);
> + memset(yuv_hist[1].frequency_distribution, 0, HISTOGRAM_SIZE *
> sizeof(int32_t));
> +
> + for (int i = 0; i < size; i++) {
> + pixel_val = *((pixel *)frame.planes[1] + i);
> + yuv_hist[1].frequency_distribution[pixel_val]++;
> + pixel_ucount++;
> + }
> +
> + /*v hist calculation for independent uv planes */
> +
> + if (plane_count == 3) {
> + pixel_val = 0;
> + int v_height = (frame.height >>
> x265_cli_csps[frame.colorSpace].height[2]);
> + size = v_height * (frame.stride[2] >> SHIFT);
> + memset(yuv_hist[2].frequency_distribution, 0, HISTOGRAM_SIZE
> * sizeof(int32_t));
> +
> + for (int i = 0; i < size; i++) {
> + pixel_val = *((pixel *)frame.planes[2] + i);
> + yuv_hist[2].frequency_distribution[pixel_val]++;
> + pixel_vcount++;
> + }
> +
> + for (int i = 0; i < HISTOGRAM_SIZE; i++) {
> + maxuv_hist.frequency_distribution[i] =
> max(yuv_hist[1].frequency_distribution[i],
> yuv_hist[2].frequency_distribution[i]);
> + }
> +
> + }
> + else {
> + maxuv_hist = yuv_hist[1]; //for two planes scenario
> + }
> +
> + return true;
> + }
> +
> + bool YuvHistogram::isUpdated() {
> + return bisUpdated;
> + }
> +
> + void YuvHistogram::setUpdateFlag(bool flag) {
> + bisUpdated = flag;
> + }
> +
> + bool YuvHistogram::getUpdateFlag() {
> + return bisUpdated;
> + }
> +
> + SadYuv::SadYuv() { }
> +
> + void SadYuv::initSadYuv(int planecount) {
> + this->plane_count = planecount;
> + sad_yuv = NULL;
> + psad_yuv = NULL;
> + sad_yuv = X265_MALLOC(int32_t, plane_count);
> + psad_yuv = X265_MALLOC(double, plane_count);
> + if (sad_yuv && psad_yuv) {
> + memset(sad_yuv, 0, plane_count * sizeof(int32_t));
> + memset(psad_yuv, 0, sizeof(double) * plane_count);
> + }
> + }
> +
> + SadYuv & SadYuv::operator=(SadYuv const& sad_val) {
> + this->plane_count = sad_val.plane_count;
> + if (!sad_yuv && !psad_yuv) {
> + sad_yuv = NULL;
> + psad_yuv = NULL;
> + sad_yuv = X265_MALLOC(int32_t, plane_count);
> + psad_yuv = X265_MALLOC(double, plane_count);
> + if (sad_yuv && psad_yuv) {
> + memcpy(sad_yuv, sad_val.sad_yuv, plane_count *
> sizeof(int32_t));
> + memcpy(psad_yuv, sad_val.psad_yuv, sizeof(double) *
> plane_count);
> + }
> + }
> + else {
> + if (sad_yuv)
> + memcpy(sad_yuv, sad_val.sad_yuv, plane_count *
> sizeof(int32_t));
> + if (psad_yuv)
> + memcpy(psad_yuv, sad_val.psad_yuv, sizeof(double) *
> plane_count);
> + }
> + return *this;
> + }
> +
> + SadYuv::~SadYuv() {
> + if (sad_yuv && psad_yuv) {
> + X265_FREE(sad_yuv);
> + X265_FREE(psad_yuv);
> + }
> + }
> +
> + int sad_stats::frames_scanned=0;
> + int sad_stats::line_number=0;
> +
> + sad_stats::sad_stats(int planecount, double threshold) {
> + this->plane_count = planecount;
> + calculateThresholds(threshold);
> + allocateBuffers();
> + }
> +
> + void sad_stats::calculateThresholds(double threshold) {
> + edge_hist_threshold = threshold;
> + strength_factor = 2.0;
> + chroma_hist_threshold = threshold * 10.0;
> + scaled_edge_threshold = edge_hist_threshold * strength_factor;
> + scaled_chroma_threshold = chroma_hist_threshold * strength_factor;
> + }
> +
> + void sad_stats::init() {
> + bscene_cut = NULL;
> + bdrop_frame = NULL;
> + sad_vals = NULL;
> + maxuv_sad_vals = NULL;
> + edge_sad_vals = NULL;
> + prev_hist = NULL;
> + }
> +
> + sad_stats::~sad_stats() {
> + releaseBuffers();
> + }
> +
> + void sad_stats::allocateBuffers() {
> +
> + init();
> + sad_vals = new SadYuv[DUP_BUFFER]();
> + maxuv_sad_vals = new SadYuv[DUP_BUFFER]();
> + edge_sad_vals = new SadYuv[DUP_BUFFER]();
> + prev_hist = new YuvHistogram();
> + prev_hist->initHistograms(plane_count);
> +
> + for (int i = 0; i < DUP_BUFFER; i++) {
> + sad_vals[i].initSadYuv(plane_count);
> + maxuv_sad_vals[i].initSadYuv(plane_count);
> + edge_sad_vals[i].initSadYuv(plane_count);
> + }
> +
> + bscene_cut = new bool[DUP_BUFFER];
> + bdrop_frame = new bool[DUP_BUFFER];
> +
> + if (!sad_vals || !maxuv_sad_vals || !edge_sad_vals || !bscene_cut
> || !bdrop_frame) {
> + x265_log(NULL, X265_LOG_ERROR, "Heap Error !");
> + exit(101);
> + }
> + else {
> + memset(bscene_cut, false, 2 * sizeof(bool));
> + memset(bdrop_frame, false, 2 * sizeof(bool));
> + }
> +
> + }
> +
> + void sad_stats::releaseBuffers() {
> + if (sad_vals && maxuv_sad_vals && edge_sad_vals && bscene_cut &&
> bdrop_frame && prev_hist) {
> + delete[] sad_vals;
> + delete[] maxuv_sad_vals;
> + delete[] edge_sad_vals;
> + delete[] bscene_cut;
> + delete[] bdrop_frame;
> + delete prev_hist;
> + }
> + }
> +
> + bool sad_stats::computeSadValue(YuvHistogram *input_frames, int32_t*
> plane_sizes) {
> +
> + int32_t *yuv_sad_val = NULL, *edge_sad_val = NULL,
> *maxuv_sad_val = NULL;
> +
> + double *maxuv_normalized_sad = NULL, *yuv_norm_sad = NULL,
> *edge_normalized_sads = NULL;
> +
> + YuvHistogram * ref_hist = NULL, *cur_hist = NULL;
> +
> + /*inorder to process frames as per poc's updated by frame
> duplication */
> + if (frames_scanned > 0) {
> +
> + if (!input_frames[0].isUpdated() &&
> input_frames[1].isUpdated()) {
> + ref_hist = prev_hist;
> + cur_hist = input_frames + 1;
> +
> + yuv_sad_val = sad_vals[1].sad_yuv,
> + edge_sad_val = edge_sad_vals[1].sad_yuv,
> + maxuv_sad_val = maxuv_sad_vals[1].sad_yuv;
> + maxuv_normalized_sad = maxuv_sad_vals[1].psad_yuv,
> + yuv_norm_sad = sad_vals[1].psad_yuv,
> + edge_normalized_sads = edge_sad_vals[1].psad_yuv;
> + input_frames[1].setUpdateFlag(false);
> +
> + }
> + else if (input_frames[0].isUpdated() &&
> input_frames[1].isUpdated()) {
> + ref_hist = prev_hist;
> + cur_hist = input_frames;
> +
> + yuv_sad_val = sad_vals[0].sad_yuv,
> + edge_sad_val = edge_sad_vals[0].sad_yuv,
> + maxuv_sad_val = maxuv_sad_vals[0].sad_yuv;
> + maxuv_normalized_sad = maxuv_sad_vals[0].psad_yuv,
> + yuv_norm_sad = sad_vals[0].psad_yuv,
> + edge_normalized_sads = edge_sad_vals[0].psad_yuv;
> + input_frames[0].setUpdateFlag(false);
> +
> + }
> + else if (input_frames[0].isUpdated() &&
> !input_frames[1].isUpdated()) {
> + ref_hist = prev_hist;
> + cur_hist = input_frames;
> +
> + yuv_sad_val = sad_vals[0].sad_yuv,
> + edge_sad_val = edge_sad_vals[0].sad_yuv,
> + maxuv_sad_val = maxuv_sad_vals[0].sad_yuv;
> + maxuv_normalized_sad = maxuv_sad_vals[0].psad_yuv,
> + yuv_norm_sad = sad_vals[0].psad_yuv,
> + edge_normalized_sads = edge_sad_vals[0].psad_yuv;
> + input_frames[0].setUpdateFlag(false);
> + }
> + else {
> + return true;
> + }
> + }
> + else {
> + cur_hist = input_frames;
> +
> + yuv_sad_val = sad_vals[0].sad_yuv,
> + edge_sad_val = edge_sad_vals[0].sad_yuv,
> + maxuv_sad_val = maxuv_sad_vals[0].sad_yuv;
> +
> + maxuv_normalized_sad = maxuv_sad_vals[0].psad_yuv,
> + yuv_norm_sad = sad_vals[0].psad_yuv,
> + edge_normalized_sads = edge_sad_vals[0].psad_yuv;
> + input_frames[0].setUpdateFlag(false);
> + }
> +
> + if (frames_scanned == 0) { //first frame is scenecut by default
> no sad computation for the same.
> +
> + maxuv_sad_val[0] = 0;
> + maxuv_normalized_sad[0] = 0.0;
> + memset(yuv_sad_val, 0 , plane_count * sizeof(int32_t));
> + memset(edge_sad_val, 0, plane_count * sizeof(int32_t));
> + memset(edge_normalized_sads, 0, plane_count * sizeof(double));
> + memset(yuv_norm_sad, 0, plane_count * sizeof(double));
> +
> + }
> + else {
> + int32_t freq_diff[3];
> + int32_t maxuv_freq_diff[1];
> + int32_t edge_freq_diff[3];
> + double color_probability_diff[3], edge_probability_diff[3];
> +
> + memset(yuv_sad_val, 0, plane_count*sizeof(int32_t));
> + memset(edge_sad_val, 0, plane_count*sizeof(int32_t));
> +
> + memset(yuv_norm_sad, 0, plane_count * sizeof(double));
> + memset(edge_normalized_sads, 0, plane_count * sizeof(double));
> + memset(color_probability_diff, 0, plane_count *
> sizeof(double));
> + memset(edge_probability_diff, 0, plane_count *
> sizeof(double));
> +
> + maxuv_normalized_sad[0] = 0.0;
> + maxuv_sad_val[0] = 0;
> +
> + memset(freq_diff, 0, 3 * sizeof(int32_t));
> + memset(maxuv_freq_diff, 0, sizeof(int32_t));
> + memset(edge_freq_diff, 0, 3 * sizeof(int32_t));
> +
> + for (int i = 0; i < plane_count; i++) {
> + {
> + for (int j = 0; j < HISTOGRAM_SIZE; j++) {
> +
> + if (i == 0 && plane_count >= 1) {
> + maxuv_freq_diff[i] =
> (abs(cur_hist->maxuv_hist.frequency_distribution[j] -
> ref_hist->maxuv_hist.frequency_distribution[j]));
> + maxuv_sad_val[i] += maxuv_freq_diff[i];
> + maxuv_normalized_sad[i] +=
> (double)maxuv_freq_diff[i] / plane_sizes[i];
> + edge_freq_diff[i] =
> abs(cur_hist->edge_hist[i].frequency_distribution[j] -
> ref_hist->edge_hist[i].frequency_distribution[j]);
> + edge_probability_diff[i] =
> double(edge_freq_diff[i]) / plane_sizes[i];
> + edge_sad_val[i] += edge_freq_diff[i];
> + edge_normalized_sads[i] +=
> edge_probability_diff[i];
> + }
> + else {
> + freq_diff[i] =
> abs(cur_hist->yuv_hist[i].frequency_distribution[j] -
> ref_hist->yuv_hist[i].frequency_distribution[j]);
> + color_probability_diff[i] =
> (double)freq_diff[i] / plane_sizes[i];
> + yuv_sad_val[i] += freq_diff[i];
> + yuv_norm_sad[i] += color_probability_diff[i];
> + }
> +
> + }
> +
> + }
> + }
> +
> + }
> +
> + *prev_hist = *cur_hist;
> +
> + frames_scanned++;
> +
> + return true;
> + }
> +
> + void sad_stats::findSceneCuts(x265_picture * picList, bool& bdup) {
> +
> + if (frames_scanned == 1) {
> + //for first frame
> + bscene_cut[0] = true;
> + bdrop_frame[0] = false;
> + picList->analysisData.bScenecut = (int)getSceneCutflag(0);
> + bdup = getDropflag(0);
> + picList->analysisData.edgeSadValue =
> edge_sad_vals[0].psad_yuv[0];
> + picList->analysisData.chromaSadValue =
> maxuv_sad_vals[0].psad_yuv[0];
> + }
> + else {
> + bscene_cut[1] = bdrop_frame[1] = false;
> + if (edge_sad_vals[1].psad_yuv[0] == 0) {
> + bdrop_frame[1] = true;
> + }
> + else if (edge_sad_vals[1].psad_yuv[0] >
> edge_hist_threshold || maxuv_sad_vals[1].psad_yuv[0] >=
> chroma_hist_threshold) {
> + bscene_cut[1] = true;
> + bdrop_frame[1] = false;
> + }
> + else if (edge_sad_vals[1].psad_yuv[0] >
> scaled_edge_threshold || maxuv_sad_vals[1].psad_yuv[0] >=
> scaled_chroma_threshold) {
> + bscene_cut[1] = true;
> + bdrop_frame[1] = false;
> + }
> + picList->analysisData.bScenecut = (int)getSceneCutflag(1);
> + bdup = getDropflag(1);
> + picList->analysisData.edgeSadValue =
> edge_sad_vals[1].psad_yuv[0];
> + picList->analysisData.chromaSadValue =
> maxuv_sad_vals[1].psad_yuv[0];
> + }
> + }
> +
> + bool sad_stats::getDropflag(int i) {
> + return bdrop_frame[i];
> + }
> +
> + bool sad_stats::getSceneCutflag(int i) {
> + return bscene_cut[i];
> + }
> +
> +}
> \ No newline at end of file
> diff -r 37648fca915b -r deaecadc4306 source/common/scenecut.h
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/source/common/scenecut.h Tue Oct 15 12:16:17 2019 +0530
> @@ -0,0 +1,147 @@
> +#ifndef SCENECUT_H
> +#define SCENECUT_H
> +
> +#include <string>
> +#include <iostream>
> +#include <sstream>
> +#include <vector>
> +#include <algorithm>
> +#include <math.h>
> +
> +#include "yuv.h"
> +#include "common.h"
> +
> +#ifdef HIGH_BIT_DEPTH
> +#define edge_threshold 1023.0
> +#define whitePixel 1023.0
> +#else
> +#define edge_threshold 255.0
> +#define pixel whitePixel 255.0
> +#endif
> +
> +using namespace std;
> +
> +namespace X265_NS {
> +
> + class Histogram {
> +
> + public:
> + int32_t frequency_distribution[HISTOGRAM_SIZE];
> +
> + Histogram();
> +
> + Histogram(Histogram const& hist);
> +
> + Histogram & operator=(Histogram const& hist);
> +
> + ~Histogram();
> +
> + };
> +
> + class YuvHistogram {
> + public:
> + Histogram *yuv_hist;
> + Histogram *edge_hist;
> + int32_t *plane_sizes;
> + int32_t *plane_heights;
> + int32_t *plane_widths;
> +
> + Histogram maxuv_hist;
> + int32_t plane_count;
> + bool bisUpdated;
> +
> + pixel** edgePic;
> + pixel** edgeThetaPic;
> +
> + x265_param * param; /*for handling various color spaces*/
> + bool m_isalloc;
> +
> + YuvHistogram();
> +
> + void initHistograms(int32_t plane_count);
> +
> + void initHistograms(x265_param *p);
> +
> + bool allocHistogramBuffers();
> +
> + YuvHistogram(YuvHistogram const& hist);
> +
> + YuvHistogram & operator=(const YuvHistogram & copy_hist);
> +
> + ~YuvHistogram();
> +
> + void initFrameDimensions(x265_picture & pic);
> +
> + void freeHistogramBuffers();
> +
> + bool edgeFilter(x265_picture *frame);
> +
> + bool computeHistograms(x265_picture &cur_frame);
> +
> + bool computeLumaEdgeHistogram(x265_picture &frame);
> +
> + bool computeChromaHistogram(x265_picture &frame);
> +
> + bool isUpdated();
> +
> + void setUpdateFlag(bool flag);
> +
> + bool getUpdateFlag();
> +
> + };
> +
> + struct SadYuv {
> + int32_t *sad_yuv;
> + double *psad_yuv;
> + int plane_count;
> + ~SadYuv();
> + SadYuv();
> + void initSadYuv(int plane_count);
> + SadYuv & operator=(SadYuv const& sad_val);
> +};
> +
> + class sad_stats {
> +
> + bool *bscene_cut;
> + bool *bdrop_frame;
> + SadYuv * sad_vals;
> + SadYuv * maxuv_sad_vals;
> + SadYuv * edge_sad_vals;
> + int plane_count;
> + static int line_number;
> + static int frames_scanned;
> + YuvHistogram *prev_hist;
> + double edge_hist_threshold;
> + double chroma_hist_threshold;
> + double scaled_chroma_threshold;
> + double scaled_edge_threshold;
> + double strength_factor;
> +
> + public:
> + sad_stats(int plane_count, double threshold);
> +
> + ~sad_stats();
> +
> + void init();
> +
> + void allocateBuffers();
> +
> + void releaseBuffers();
> +
> + void calculateThresholds(double threshold);
> +
> + bool computeSadValue(YuvHistogram *frames, int32_t* plane_sizes);
> +
> + void findSceneCuts(x265_picture * piclist,bool & bdup);
> +
> + bool getDropflag(int i);
> +
> + bool getSceneCutflag(int i);
> +
> + };
> +
> +void computeEdge(pixel * edgePic, pixel *refPic, pixel * edgeTheta,
> intptr_t stride, int height, int width);
> +
> +}
> +
> +#endif
> diff -r 37648fca915b -r deaecadc4306 source/encoder/api.cpp
> --- a/source/encoder/api.cpp Fri Oct 11 12:45:52 2019 +0530
> +++ b/source/encoder/api.cpp Tue Oct 15 12:16:17 2019 +0530
> @@ -31,6 +31,7 @@
> #include "nal.h"
> #include "bitcost.h"
> #include "svt.h"
> +#include "scenecut.h"
>
> #if ENABLE_LIBVMAF
> #include "libvmaf.h"
> @@ -117,7 +118,10 @@
> x265_log(param, X265_LOG_INFO, "build info %s\n",
> PFX(build_info_str));
>
> encoder = new Encoder;
> -
> + encoder->m_sad_stats = new
> sad_stats(x265_cli_csps[p->internalCsp].planes,param->edgeTransitionThreshold);
> + encoder->m_hist_of_adj_frames = new YuvHistogram[2];
> + encoder->m_hist_of_adj_frames[0].initHistograms(p);
> + encoder->m_hist_of_adj_frames[1].initHistograms(p);
> #ifdef SVT_HEVC
>
> if (param->bEnableSvtHevc)
> @@ -809,6 +813,7 @@
> CHECKED_MALLOC_ZERO(interData->ref, int32_t,
> analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU * numDir);
> }
> analysis->interData = interData;
> + analysis->bScenecut = false;
>
> return;
>
> @@ -924,6 +929,7 @@
> pic->rpu.payloadSize = 0;
> pic->rpu.payload = NULL;
> pic->picStruct = 0;
> + pic->bufUpdated = false;
>
> if ((param->analysisSave || param->analysisLoad) ||
> (param->bAnalysisType == AVC_INFO))
> {
> @@ -933,7 +939,9 @@
> uint32_t numCUsInFrame = widthInCU * heightInCU;
> pic->analysisData.numCUsInFrame = numCUsInFrame;
> pic->analysisData.numPartitions = param->num4x4Partitions;
> + pic->analysisData.bScenecut = false;
> }
> +
> }
>
> void x265_picture_free(x265_picture *p)
> @@ -955,7 +963,8 @@
> {
> if (param && param->rc.zonefileCount) {
> for (int i = 0; i < param->rc.zonefileCount; i++)
> - x265_free(param->rc.zones[i].zoneParam);
> + if(param->rc.zones[i].zoneParam)
> + x265_free(param->rc.zones[i].zoneParam);
> }
> if (param && (param->rc.zoneCount || param->rc.zonefileCount))
> x265_free(param->rc.zones);
> diff -r 37648fca915b -r deaecadc4306 source/encoder/encoder.cpp
> --- a/source/encoder/encoder.cpp Fri Oct 11 12:45:52 2019 +0530
> +++ b/source/encoder/encoder.cpp Tue Oct 15 12:16:17 2019 +0530
> @@ -119,6 +119,9 @@
> m_frameEncoder[i] = NULL;
> for (uint32_t i = 0; i < DUP_BUFFER; i++)
> m_dupBuffer[i] = NULL;
> +
> + m_hist_of_adj_frames = NULL;
> + m_sad_stats = NULL;
> MotionEstimate::initScales();
>
> #if ENABLE_HDR10_PLUS
> @@ -162,7 +165,9 @@
> int rows = (p->sourceHeight + p->maxCUSize - 1) >>
> g_log2Size[p->maxCUSize];
> int cols = (p->sourceWidth + p->maxCUSize - 1) >>
> g_log2Size[p->maxCUSize];
>
> - if (m_param->bEnableFrameDuplication)
> +
> +
> + if (m_param->bEnableFrameDuplication || m_param->bHistbasedScenecut)
> {
> size_t framesize = 0;
> int pixelbytes = p->sourceBitDepth > 8 ? 2 : 1;
> @@ -184,6 +189,7 @@
> m_dupBuffer[i]->dupPlane = NULL;
> m_dupBuffer[i]->dupPlane = X265_MALLOC(char, framesize);
> m_dupBuffer[i]->dupPic->planes[0] = m_dupBuffer[i]->dupPlane;
> + m_dupBuffer[i]->bufUpdated = false;
> m_dupBuffer[i]->bOccupied = false;
> m_dupBuffer[i]->bDup = false;
> }
> @@ -820,7 +826,7 @@
> m_exportedPic = NULL;
> }
>
> - if (m_param->bEnableFrameDuplication)
> + if (m_param->bEnableFrameDuplication || m_param->bHistbasedScenecut)
> {
> for (uint32_t i = 0; i < DUP_BUFFER; i++)
> {
> @@ -1280,6 +1286,33 @@
> return psnrWeight = (psnrY * 6 + psnrU + psnrV) / 8;
> }
>
> +void Encoder::updateSceneCutAndFrameDuplicateFlags() {
> + /* SCD computation and drop flag*/
> + for (int i = 0; i < DUP_BUFFER; i++) {
> + if (m_dupBuffer[i]->bufUpdated) {
> + m_hist_of_adj_frames[i].setUpdateFlag(true);
> + m_hist_of_adj_frames[i].edgeFilter(m_dupBuffer[i]->dupPic);
> +
> m_hist_of_adj_frames[i].computeHistograms(*m_dupBuffer[i]->dupPic);
> + m_sad_stats->computeSadValue(m_hist_of_adj_frames,
> m_hist_of_adj_frames->plane_sizes);
> + m_sad_stats->findSceneCuts(m_dupBuffer[i]->dupPic,
> m_dupBuffer[i]->bDup);
> +
> + if (m_dupBuffer[i]->dupPic->analysisData.bScenecut) {
> + x265_log(m_param, X265_LOG_DEBUG, "scene cut at %d edge
> hist sad: %0.4lf maxuv hist sad: %0.4lf\n",
> +
> m_dupBuffer[i]->dupPic->poc,m_dupBuffer[i]->dupPic->analysisData.edgeSadValue,m_dupBuffer[i]->dupPic->analysisData.chromaSadValue);
> + }
> +
> + if (m_dupBuffer[1]->bufUpdated)
> + m_hist_of_adj_frames[0] = m_hist_of_adj_frames[1];
> + }
> + }
> +
> + }
> +
> +/* TBD
> +- to be updated for missing parameters in case of re-use else where and
> improvised to copy constructor / assignment operator of x265 picture data
> structure.
> +- benefits avoid function and use language features appropriately.
> +*/
> +
> void Encoder::copyPicture(x265_picture *dest, const x265_picture *src)
> {
> dest->poc = src->poc;
> @@ -1299,6 +1332,25 @@
> memcpy(dest->planes[0], src->planes[0], src->framesize *
> sizeof(char));
> dest->planes[1] = (char*)dest->planes[0] + src->stride[0] *
> src->height;
> dest->planes[2] = (char*)dest->planes[1] + src->stride[1] *
> (src->height >> x265_cli_csps[src->colorSpace].height[1]);
> + memcpy(&dest->analysisData, &src->analysisData,
> sizeof(src->analysisData));
> +
> +}
> +
> +void Encoder::setPictureFlags(int idx) {
> + m_dupBuffer[idx]->bOccupied = true;
> + m_dupBuffer[idx]->bufUpdated = true;
> + m_dupBuffer[idx]->bDup = false;
> +}
> +
> +void Encoder::unsetPictureFlags(int idx) {
> + if (idx == 1) {
> + m_dupBuffer[idx]->bOccupied = false;
> + m_dupBuffer[idx]->bufUpdated = false;
> + m_dupBuffer[idx]->bDup = false;
> + }
> + else if (idx == 0) {
> + m_dupBuffer[idx]->bufUpdated = false;
> + }
> }
>
> /**
> @@ -1327,7 +1379,9 @@
> const x265_picture* inputPic = NULL;
> static int written = 0, read = 0;
> bool dontRead = false;
> -
> + bool isScenecutEnabled = m_param->bHistbasedScenecut;
> + bool dropflag = false;
> +
> if (m_exportedPic)
> {
> if (!m_param->bUseAnalysisFile && m_param->analysisSave)
> @@ -1338,7 +1392,7 @@
> }
> if ((pic_in && (!m_param->chunkEnd || (m_encodedFrameNum <
> m_param->chunkEnd))) || (m_param->bEnableFrameDuplication && !pic_in &&
> (read < written)))
> {
> - if ((m_param->bEnableFrameDuplication && !pic_in && (read <
> written)))
> + if ((m_param->bEnableFrameDuplication && !pic_in && (read <
> written)) || (isScenecutEnabled && !pic_in && (read < written)))
> dontRead = true;
> else
> {
> @@ -1361,7 +1415,7 @@
> }
> }
>
> - if (m_param->bEnableFrameDuplication)
> + if (m_param->bEnableFrameDuplication || isScenecutEnabled )
> {
> double psnrWeight = 0;
>
> @@ -1372,6 +1426,11 @@
> copyPicture(m_dupBuffer[0]->dupPic, pic_in);
> m_dupBuffer[0]->bOccupied = true;
> written++;
> + if (m_param->bHistbasedScenecut) {
> + setPictureFlags(0);
> + updateSceneCutAndFrameDuplicateFlags();
> + unsetPictureFlags(0);
> + }
> return 0;
> }
> else if (!m_dupBuffer[1]->bOccupied)
> @@ -1379,31 +1438,54 @@
> copyPicture(m_dupBuffer[1]->dupPic, pic_in);
> m_dupBuffer[1]->bOccupied = true;
> written++;
> + if (m_param->bHistbasedScenecut) {
> + setPictureFlags(1);
> + updateSceneCutAndFrameDuplicateFlags();
> + unsetPictureFlags(1);
> + }
> }
>
> - psnrWeight = ComputePSNR(m_dupBuffer[0]->dupPic,
> m_dupBuffer[1]->dupPic, m_param);
> -
> - if (psnrWeight >= m_param->dupThreshold)
> - {
> - if (m_dupBuffer[0]->bDup)
> - {
> - m_dupBuffer[0]->dupPic->picStruct = tripling;
> - m_dupBuffer[0]->bDup = false;
> - read++;
> + if (m_param->bEnableFrameDuplication &&
> m_param->bHistbasedScenecut) {
> + if (m_dupBuffer[1]->bDup == false &&
> m_dupBuffer[1]->dupPic->analysisData.bScenecut == false) {
> + psnrWeight = ComputePSNR(m_dupBuffer[0]->dupPic,
> m_dupBuffer[1]->dupPic, m_param);
> + if (psnrWeight >= m_param->dupThreshold)
> + dropflag = true;
> }
> - else
> - {
> - m_dupBuffer[0]->dupPic->picStruct = doubling;
> - m_dupBuffer[0]->bDup = true;
> - m_dupBuffer[1]->bOccupied = false;
> - read++;
> - return 0;
> + else {
> + dropflag = true;
> }
> }
> - else if (m_dupBuffer[0]->bDup)
> + 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 (m_param->bEnableFrameDuplication)
> + {
> + if (dropflag)
> + {
> + if (m_dupBuffer[0]->bDup)
> + {
> + m_dupBuffer[0]->dupPic->picStruct = tripling;
> + m_dupBuffer[0]->bDup = false;
> + read++;
> + }
> + else
> + {
> + m_dupBuffer[0]->dupPic->picStruct = doubling;
> + m_dupBuffer[0]->bDup = true;
> + m_dupBuffer[1]->bOccupied = false;
> + read++;
> + return 0;
> + }
> + }
> + else if (m_dupBuffer[0]->bDup)
> m_dupBuffer[0]->bDup = false;
> - else
> - m_dupBuffer[0]->dupPic->picStruct = 0;
> + else
> + m_dupBuffer[0]->dupPic->picStruct = 0;
> + }
> +
> }
>
> if (read < written)
> @@ -1485,7 +1567,10 @@
>
> inFrame->m_poc = ++m_pocLast;
> inFrame->m_userData = inputPic->userData;
> - inFrame->m_pts = inputPic->pts;
> + inFrame->m_pts = inputPic->pts;
> + if (m_param->bHistbasedScenecut) {
> + inFrame->m_lowres.bScenecut = inputPic->analysisData.bScenecut;
> + }
> inFrame->m_forceqp = inputPic->forceqp;
> inFrame->m_param = (m_reconfigure || m_reconfigureRc) ?
> m_latestParam : m_param;
> inFrame->m_picStruct = inputPic->picStruct;
> @@ -1613,7 +1698,7 @@
> m_param->bUseRcStats = 0;
> }
>
> - if (m_param->bEnableFrameDuplication && ((read < written) ||
> (m_dupBuffer[0]->dupPic->picStruct == tripling && (read <= written))))
> + if ( (m_param->bEnableFrameDuplication || isScenecutEnabled) &&
> ((read < written) || (m_dupBuffer[0]->dupPic->picStruct == tripling &&
> (read <= written))))
> {
> if (m_dupBuffer[0]->dupPic->picStruct == tripling)
> m_dupBuffer[0]->bOccupied = m_dupBuffer[1]->bOccupied =
> false;
> @@ -3162,6 +3247,7 @@
> * adaptive I frame placement */
> p->keyframeMax = INT_MAX;
> p->scenecutThreshold = 0;
> + p->bHistbasedScenecut = 0;
> }
> else if (p->keyframeMax <= 1)
> {
> @@ -3175,6 +3261,7 @@
> p->lookaheadDepth = 0;
> p->bframes = 0;
> p->scenecutThreshold = 0;
> + p->bHistbasedScenecut = 0;
> p->bFrameAdaptive = 0;
> p->rc.cuTree = 0;
> p->bEnableWeightedPred = 0;
> @@ -3828,6 +3915,20 @@
> m_param->searchMethod = m_param->hmeSearchMethod[2];
> }
> }
> +
> + if (p->bHistbasedScenecut && p->scenecutThreshold) {
> + p->scenecutThreshold = 0;
> + p->bHistbasedScenecut = false;
> + x265_log(p, X265_LOG_WARNING, "Amibigious choice. disabling scene
> cut detection \n");
> + }
> + else if (p->scenecutThreshold && p->edgeTransitionThreshold != 0.01) {
> + x265_log(p, X265_LOG_WARNING, "using scenecut-bias %d for scene
> cut detection\n",p->scenecutBias);
> + }
> + else if (p->bHistbasedScenecut && p->edgeTransitionThreshold == 0.0) {
> + p->edgeTransitionThreshold = 0.01;
> + x265_log(p, X265_LOG_INFO, "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 37648fca915b -r deaecadc4306 source/encoder/encoder.h
> --- a/source/encoder/encoder.h Fri Oct 11 12:45:52 2019 +0530
> +++ b/source/encoder/encoder.h Tue Oct 15 12:16:17 2019 +0530
> @@ -32,6 +32,8 @@
> #include "nal.h"
> #include "framedata.h"
> #include "svt.h"
> +#include "scenecut.h"
> +
> #ifdef ENABLE_HDR10_PLUS
> #include "dynamicHDR10/hdr10plus.h"
> #endif
> @@ -154,6 +156,9 @@
>
> //Flag to check whether the picture has duplicated.
> bool bDup;
> +
> + bool bufUpdated;
> +
> };
>
>
> @@ -195,6 +200,9 @@
>
> ThreadPool* m_threadPool;
> FrameEncoder* m_frameEncoder[X265_MAX_FRAME_THREADS];
> +
> + YuvHistogram* m_hist_of_adj_frames;
> + sad_stats* m_sad_stats;
> DPB* m_dpb;
> Frame* m_exportedPic;
> FILE* m_analysisFileIn;
> @@ -279,6 +287,10 @@
> if (m_prevTonemapPayload.payload != NULL)
> X265_FREE(m_prevTonemapPayload.payload);
> #endif
> + delete m_sad_stats;
> + m_sad_stats = NULL;
> + delete[] m_hist_of_adj_frames;
> + m_hist_of_adj_frames = NULL;
> };
>
> void create();
> @@ -349,6 +361,12 @@
>
> void copyPicture(x265_picture *dest, const x265_picture *src);
>
> + void unsetPictureFlags(int index);
> +
> + void setPictureFlags(int index);
> +
> + void updateSceneCutAndFrameDuplicateFlags();
> +
> void initRefIdx();
> void analyseRefIdx(int *numRefIdx);
> void updateRefIdx();
> @@ -364,6 +382,7 @@
> void initSPS(SPS *sps);
> void initPPS(PPS *pps);
> };
> +
> }
>
> #endif // ifndef X265_ENCODER_H
> diff -r 37648fca915b -r deaecadc4306 source/encoder/ratecontrol.cpp
> --- a/source/encoder/ratecontrol.cpp Fri Oct 11 12:45:52 2019 +0530
> +++ b/source/encoder/ratecontrol.cpp Tue Oct 15 12:16:17 2019 +0530
> @@ -493,6 +493,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)
> {
> @@ -1183,6 +1184,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;
> @@ -2173,7 +2175,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 37648fca915b -r deaecadc4306 source/encoder/slicetype.cpp
> --- a/source/encoder/slicetype.cpp Fri Oct 11 12:45:52 2019 +0530
> +++ b/source/encoder/slicetype.cpp Tue Oct 15 12:16:17 2019 +0530
> @@ -30,6 +30,7 @@
> #include "primitives.h"
> #include "lowres.h"
> #include "mv.h"
> +#include "scenecut.h"
>
> #include "slicetype.h"
> #include "motion.h"
> @@ -114,8 +115,8 @@
> //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 = pic1 + curFrame->m_fencPic->m_lumaMarginY * stride +
> curFrame->m_fencPic->m_lumaMarginX;
> pixel pixelValue = 0;
> -
> for (int rowNum = 0; rowNum < height; rowNum++)
> {
> for (int colNum = 0; colNum < width; colNum++)
> @@ -127,7 +128,8 @@
> 1 [4 9 12 9 4]
> --- [5 12 15 12 5]
> 159 [4 9 12 9 4]
> - [2 4 5 4 2]*/
> + [2 4 5 4 2]
> + */
>
> const intptr_t rowOne = (rowNum - 2)*stride, colOne =
> colNum - 2;
> const intptr_t rowTwo = (rowNum - 1)*stride, colTwo =
> colNum - 1;
> @@ -145,52 +147,7 @@
> }
> }
> }
> -
> -#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;
> - }
> - }
> - }
> + computeEdge(edgePic, refPic, edgeTheta, stride, height, width);
> }
>
> //Find the angle of a block by averaging the pixel angles
> @@ -1471,7 +1428,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);
> @@ -1962,10 +1919,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;
> @@ -1976,14 +1938,24 @@
> 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)
> + {
> + if (frames[j]->bScenecut &&
> scenecutInternal(frames, j - 1, j, true))
> + {
> + m_extendGopBoundary = true;
> + break;
> + }
> + }
> + else if(m_param->bHistbasedScenecut &&
> frames[j]->bScenecut)
> + {
> + m_extendGopBoundary = true;
> + break;
> + }
> }
> if (m_extendGopBoundary)
> break;
> @@ -2088,13 +2060,23 @@
> {
> for (int j = 1; j < numBFrames + 1; j++)
> {
> - if (scenecut(frames, j, j + 1, false, origNumFrames) ||
> - (bForceRADL && (frames[j]->frameNum == preRADL)))
> - {
> - frames[j]->sliceType = X265_TYPE_P;
> - numAnalyzed = j;
> - break;
> + if (m_param->bHistbasedScenecut) {
> + if (frames[j]->bScenecut || (bForceRADL &&
> (frames[j]->frameNum == preRADL)))
> + {
> + frames[j]->sliceType = X265_TYPE_P;
> + numAnalyzed = j;
> + break;
> + }
> }
> + else if (m_param->scenecutThreshold){
> + if ( scenecut(frames, j, j + 1, false, origNumFrames)
> || (bForceRADL && (frames[j]->frameNum == preRADL)) )
> + {
> + frames[j]->sliceType = X265_TYPE_P;
> + numAnalyzed = j;
> + break;
> + }
> + }
> +
> }
> }
> resetStart = bKeyframe ? 1 : X265_MIN(numBFrames + 2, numAnalyzed
> + 1);
> diff -r 37648fca915b -r deaecadc4306 source/encoder/slicetype.h
> --- a/source/encoder/slicetype.h Fri Oct 11 12:45:52 2019 +0530
> +++ b/source/encoder/slicetype.h Tue Oct 15 12:16:17 2019 +0530
> @@ -43,6 +43,14 @@
> #define AQ_EDGE_BIAS 0.5
> #define EDGE_INCLINATION 45
>
> +#ifdef HIGH_BIT_DEPTH
> +#define edge_threshold 1023.0
> +#define whitePixel 1023.0
> +#else
> +#define edge_threshold 255.0
> +#define pixel whitePixel 255.0
> +#endif
> +
> /* Thread local data for lookahead tasks */
> struct LookaheadTLD
> {
> diff -r 37648fca915b -r deaecadc4306 source/test/regression-tests.txt
> --- a/source/test/regression-tests.txt Fri Oct 11 12:45:52 2019 +0530
> +++ b/source/test/regression-tests.txt Tue Oct 15 12:16:17 2019 +0530
> @@ -157,6 +157,9 @@
> ducks_take_off_420_720p50.y4m,--preset medium --aq-mode 4 --crf 22
> --no-cutree
> ducks_take_off_420_1_720p50.y4m,--preset medium --selective-sao 4 --sao
> --crf 20
> Traffic_4096x2048_30p.y4m, --preset medium --frame-dup --dup-threshold 60
> --hrd --bitrate 10000 --vbv-bufsize 15000 --vbv-maxrate 12000
> +sintel_trailer_2k_1920x1080_24.yuv, --preset medium --hist-scenecut
> --hist-threshold 0.01
> +Traffic_4096x2048_30p.y4m, --preset medium --frame-dup --dup-threshold 60
> --hrd --bitrate 10000 --vbv-bufsize 15000 --vbv-maxrate 12000
> --hist-scenecut --hist-threshold 0.01
> +sintel_trailer_2k_1920x1080_24.yuv, --preset medium --scenecut 40
> --scenecut-bias 20
>
> # Main12 intraCost overflow bug test
> 720p50_parkrun_ter.y4m,--preset medium
> diff -r 37648fca915b -r deaecadc4306 source/x265.h
> --- a/source/x265.h Fri Oct 11 12:45:52 2019 +0530
> +++ b/source/x265.h Tue Oct 15 12:16:17 2019 +0530
> @@ -210,7 +210,9 @@
> uint32_t numCUsInFrame;
> uint32_t numPartitions;
> uint32_t depthBytes;
> - int bScenecut;
> + bool bScenecut;
> + double edgeSadValue;
> + double chromaSadValue;
> x265_weight_param* wt;
> x265_analysis_inter_data* interData;
> x265_analysis_intra_data* intraData;
> @@ -291,6 +293,9 @@
> char sliceType;
> int bScenecut;
> double ipCostRatio;
> + double yedgeSadValue;
> + double chromaSadValue;
> +
> int frameLatency;
> x265_cu_stats cuStats;
> x265_pu_stats puStats;
> @@ -465,6 +470,9 @@
> //Dolby Vision RPU metadata
> x265_dolby_vision_rpu rpu;
>
> + //Flag to determine the latest frame in the buffer
> + bool bufUpdated;
> +
> int fieldNum;
>
> //SEI picture structure message
> @@ -1017,8 +1025,9 @@
> * decisions. Default is 0 - disabled. 1 is the same as 0. Max 16 */
> int lookaheadSlices;
>
> - /* An arbitrary threshold which determines how aggressively the
> lookahead
> - * should detect scene cuts. The default (40) is recommended. */
> + /* An arbitrary threshold which determines how aggressively the
> lookahead
> + * should detect scene cuts. The default (40) is recommended.
> + * Used for encoding cost based scenecut detection */
> int scenecutThreshold;
>
> /* Replace keyframes by using a column of intra blocks that move
> across the video
> @@ -1803,6 +1812,7 @@
>
> /*Emit content light level info SEI*/
> int bEmitCLL;
> +
>
> /*
> * Signals picture structure SEI timing message for every frame
> @@ -1819,6 +1829,17 @@
>
> /*Input sequence bit depth. It can be either 8bit, 10bit or 12bit.*/
> int sourceBitDepth;
> +
> + /* A genuine threshold which determines whether a frame is a
> scenecut or not
> + * when compared against edge and color sad values of a frames
> histograms.Default 0.01
> + * Range:real number in range (0,2)
> + * Used for histogram based scene cut detection */
> + double edgeTransitionThreshold;
> +
> + /*enables improved scenecut detection algorithm to detect scenecuts
> for slice type
> + decision and rate control */
> + bool bHistbasedScenecut;
> +
> } x265_param;
> /* x265_param_alloc:
> * Allocates an x265_param instance. The returned param structure is not
> diff -r 37648fca915b -r deaecadc4306 source/x265cli.h
> --- a/source/x265cli.h Fri Oct 11 12:45:52 2019 +0530
> +++ b/source/x265cli.h Tue Oct 15 12:16:17 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 },
> { "radl", required_argument, NULL, 0 },
> @@ -485,7 +488,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);
> + H0(" --hist-scenecut ..... Enables improved scene-cut
> detection using histogram based algorithm.");
> + H0(" --no-hist-scenecut Disables improved scene-cut
> detection using histogram based algorithm. ");
> + H0(" --scenecut-bias <0..100.0> Bias for scenecut detection.
> Default %.2f\n", param->scenecutBias);
> + H0(" --hist-threshold <0.0..2.0> 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));
> H0(" --radl <integer> Number of RADL pictures allowed
> in front of IDR. Default %d\n", param->radl);
> H0(" --intra-refresh Use Periodic Intra Refresh
> instead of IDR frames\n");
> _______________________________________________
> x265-devel mailing list
> x265-devel at videolan.org
> https://mailman.videolan.org/listinfo/x265-devel
>
--
Regards,
Aruna
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20191016/3bf6e0e9/attachment-0001.html>
More information about the x265-devel
mailing list