[x265] [PATCH 4 of 5] zone: tune base QP to achieve zone target
Aruna Matheswaran
aruna at multicorewareinc.com
Wed Nov 13 07:52:15 CET 2019
# HG changeset patch
# User Aruna Matheswaran <aruna at multicorewareinc.com>
# Date 1571647307 -19800
# Mon Oct 21 14:11:47 2019 +0530
# Node ID 5297824e605c5eed543c2f99c41335d466d17b4b
# Parent 858a6b6267e025776b18eafc3279dc5addf891e4
zone: tune base QP to achieve zone target
diff -r 858a6b6267e0 -r 5297824e605c source/encoder/api.cpp
--- a/source/encoder/api.cpp Wed Aug 28 15:08:18 2019 +0530
+++ b/source/encoder/api.cpp Mon Oct 21 14:11:47 2019 +0530
@@ -199,6 +199,7 @@
{
param->rc.zones[i].zoneParam = X265_MALLOC(x265_param, 1);
memcpy(param->rc.zones[i].zoneParam, param, sizeof(x265_param));
+ param->rc.zones[i].relativeComplexity = X265_MALLOC(double, param->reconfigWindowSize);
}
}
@@ -379,17 +380,28 @@
{
if (!enc || !zone_in)
return -1;
+
Encoder* encoder = static_cast<Encoder*>(enc);
+ int read = encoder->zoneReadCount[encoder->m_zoneIndex].get();
+ int write = encoder->zoneWriteCount[encoder->m_zoneIndex].get();
+
x265_zone* zone = &(encoder->m_param->rc).zones[encoder->m_zoneIndex];
x265_param* zoneParam = zone->zoneParam;
+
+ if (write && (read < write))
+ {
+ read = encoder->zoneReadCount[encoder->m_zoneIndex].waitForChange(read);
+ }
+
+ zone->startFrame = zone_in->startFrame;
+ zoneParam->rc.bitrate = zone_in->zoneParam->rc.bitrate;
+ zoneParam->rc.vbvMaxBitrate = zone_in->zoneParam->rc.vbvMaxBitrate;
+ memcpy(zone->relativeComplexity, zone_in->relativeComplexity, sizeof(double) * encoder->m_param->reconfigWindowSize);
- int ret = encoder->reconfigureParam(zoneParam, zone_in->zoneParam);
- if (ret)
- return -1;
- memcpy(zone, zone_in, sizeof(x265_zone));
-
+ encoder->zoneWriteCount[encoder->m_zoneIndex].incr();
encoder->m_zoneIndex++;
encoder->m_zoneIndex %= encoder->m_param->rc.zonefileCount;
+
return 0;
}
diff -r 858a6b6267e0 -r 5297824e605c source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp Wed Aug 28 15:08:18 2019 +0530
+++ b/source/encoder/encoder.cpp Mon Oct 21 14:11:47 2019 +0530
@@ -323,7 +323,13 @@
lookAheadThreadPool[i].start();
m_lookahead->m_numPools = pools;
m_dpb = new DPB(m_param);
- m_rateControl = new RateControl(*m_param);
+ m_rateControl = new RateControl(*m_param, this);
+ if (!m_param->bResetZoneConfig)
+ {
+ zoneReadCount = new ThreadSafeInteger[m_param->rc.zonefileCount];
+ zoneWriteCount = new ThreadSafeInteger[m_param->rc.zonefileCount];
+ }
+
initVPS(&m_vps);
initSPS(&m_sps);
initPPS(&m_pps);
@@ -868,6 +874,11 @@
}
delete m_dpb;
+ if (!m_param->bResetZoneConfig && m_param->rc.zonefileCount)
+ {
+ delete[] zoneReadCount;
+ delete[] zoneWriteCount;
+ }
if (m_rateControl)
{
m_rateControl->destroy();
diff -r 858a6b6267e0 -r 5297824e605c source/encoder/encoder.h
--- a/source/encoder/encoder.h Wed Aug 28 15:08:18 2019 +0530
+++ b/source/encoder/encoder.h Mon Oct 21 14:11:47 2019 +0530
@@ -274,6 +274,10 @@
bool m_saveCTUSize;
+
+ ThreadSafeInteger* zoneReadCount;
+ ThreadSafeInteger* zoneWriteCount;
+
Encoder();
~Encoder()
{
diff -r 858a6b6267e0 -r 5297824e605c source/encoder/ratecontrol.cpp
--- a/source/encoder/ratecontrol.cpp Wed Aug 28 15:08:18 2019 +0530
+++ b/source/encoder/ratecontrol.cpp Mon Oct 21 14:11:47 2019 +0530
@@ -146,9 +146,10 @@
return NULL;
}
-RateControl::RateControl(x265_param& p)
+RateControl::RateControl(x265_param& p, Encoder *top)
{
m_param = &p;
+ m_top = top;
int lowresCuWidth = ((m_param->sourceWidth / 2) + X265_LOWRES_CU_SIZE - 1) >> X265_LOWRES_CU_BITS;
int lowresCuHeight = ((m_param->sourceHeight / 2) + X265_LOWRES_CU_SIZE - 1) >> X265_LOWRES_CU_BITS;
m_ncu = lowresCuWidth * lowresCuHeight;
@@ -156,6 +157,7 @@
m_qCompress = (m_param->rc.cuTree && !m_param->rc.hevcAq) ? 1 : m_param->rc.qCompress;
// validate for param->rc, maybe it is need to add a function like x265_parameters_valiate()
+ m_zoneBufferIdx = 0;
m_residualFrames = 0;
m_partialResidualFrames = 0;
m_residualCost = 0;
@@ -210,6 +212,7 @@
m_lastBsliceSatdCost = 0;
m_movingAvgSum = 0.0;
m_isNextGop = false;
+ m_relativeComplexity = NULL;
// vbv initialization
m_param->rc.vbvBufferSize = x265_clip3(0, 2000000, m_param->rc.vbvBufferSize);
@@ -354,6 +357,16 @@
m_initVbv = true;
}
+ if (!m_param->bResetZoneConfig && (m_relativeComplexity == NULL))
+ {
+ m_relativeComplexity = X265_MALLOC(double, m_param->reconfigWindowSize);
+ if (m_relativeComplexity == NULL)
+ {
+ x265_log(m_param, X265_LOG_ERROR, "Failed to allocate memory for m_relativeComplexity\n");
+ return false;
+ }
+ }
+
m_totalBits = 0;
m_encodedBits = 0;
m_framesDone = 0;
@@ -699,6 +712,8 @@
{
m_param->rc.vbvBufferSize = x265_clip3(0, 2000000, m_param->rc.vbvBufferSize);
m_param->rc.vbvMaxBitrate = x265_clip3(0, 2000000, m_param->rc.vbvMaxBitrate);
+ if (m_param->reconfigWindowSize)
+ m_param->rc.vbvMaxBitrate = (int)(m_param->rc.vbvMaxBitrate * (double)(m_fps / m_param->reconfigWindowSize));
if (m_param->rc.vbvMaxBitrate < m_param->rc.bitrate &&
m_param->rc.rateControlMode == X265_RC_ABR)
{
@@ -753,7 +768,7 @@
m_qpConstant[P_SLICE] = m_qpConstant[I_SLICE] = m_qpConstant[B_SLICE] = m_qp;
}
}
- m_bitrate = m_param->rc.bitrate * 1000;
+ m_bitrate = (double)m_param->rc.bitrate * 1000;
}
void RateControl::initHRD(SPS& sps)
@@ -1244,17 +1259,43 @@
m_predType = getPredictorType(curFrame->m_lowres.sliceType, m_sliceType);
rce->poc = m_curSlice->m_poc;
- /* change ratecontrol stats for next zone if specified */
- for (int i = 0; i < m_param->rc.zonefileCount; i++)
+ if (!m_param->bResetZoneConfig && (rce->encodeOrder % m_param->reconfigWindowSize == 0))
{
- if (m_param->rc.zones[i].startFrame == curFrame->m_encodeOrder)
+ int index = m_zoneBufferIdx % m_param->rc.zonefileCount;
+ int read = m_top->zoneReadCount[index].get();
+ int write = m_top->zoneWriteCount[index].get();
+ if (write <= read)
+ write = m_top->zoneWriteCount[index].waitForChange(write);
+ m_zoneBufferIdx++;
+
+ for (int i = 0; i < m_param->rc.zonefileCount; i++)
{
- m_param = m_param->rc.zones[i].zoneParam;
- reconfigureRC();
- if (m_param->bResetZoneConfig)
- init(*m_curSlice->m_sps);
+ if (m_param->rc.zones[i].startFrame == rce->encodeOrder)
+ {
+ m_param->rc.bitrate = m_param->rc.zones[i].zoneParam->rc.bitrate;
+ m_param->rc.vbvMaxBitrate = m_param->rc.zones[i].zoneParam->rc.vbvMaxBitrate;
+ memcpy(m_relativeComplexity, m_param->rc.zones[i].relativeComplexity, sizeof(double) * m_param->reconfigWindowSize);
+ reconfigureRC();
+ m_top->zoneReadCount[i].incr();
+ }
}
}
+
+
+ if (m_param->bResetZoneConfig)
+ {
+ /* change ratecontrol stats for next zone if specified */
+ for (int i = 0; i < m_param->rc.zonefileCount; i++)
+ {
+ if (m_param->rc.zones[i].startFrame == curFrame->m_encodeOrder)
+ {
+ m_param = m_param->rc.zones[i].zoneParam;
+ reconfigureRC();
+ init(*m_curSlice->m_sps);
+ }
+ }
+ }
+
if (m_param->rc.bStatRead)
{
X265_CHECK(rce->poc >= 0 && rce->poc < m_numEntries, "bad encode ordinal\n");
@@ -1649,6 +1690,31 @@
return qScale;
}
+double RateControl::tuneQScaleForZone(RateControlEntry *rce, double qScale)
+{
+ rce->frameSizePlanned = predictSize(&m_pred[m_predType], qScale, (double)m_currentSatd);
+ int loop = 0;
+
+ double availableBits = (double)m_param->rc.bitrate * 1000 * m_relativeComplexity[rce->encodeOrder % m_param->reconfigWindowSize];
+
+ // Tune qScale to adhere to the available frame bits.
+ for (int i = 0; i < 1000 && loop != 3; i++)
+ {
+ if (rce->frameSizePlanned < availableBits)
+ {
+ qScale = qScale / 1.01;
+ loop = loop | 1;
+ }
+ else if (rce->frameSizePlanned > availableBits)
+ {
+ qScale = qScale * 1.01;
+ loop = loop | 2;
+ }
+ rce->frameSizePlanned = predictSize(&m_pred[m_predType], qScale, (double)m_currentSatd);
+ }
+ return qScale;
+}
+
double RateControl::tuneQScaleForGrain(double rcOverflow)
{
double qpstep = rcOverflow > 1.1 ? rcOverflow : m_lstep;
@@ -1789,11 +1855,21 @@
qScale = x265_clip3(lmin, lmax, qScale);
q = x265_qScale2qp(qScale);
}
+
+ if (!m_param->bResetZoneConfig)
+ {
+ double lqmin = m_lmin[m_sliceType];
+ double lqmax = m_lmax[m_sliceType];
+ qScale = tuneQScaleForZone(rce, qScale);
+ qScale = x265_clip3(lqmin, lqmax, qScale);
+ }
+
if (!m_2pass)
{
- qScale = clipQscale(curFrame, rce, qScale);
/* clip qp to permissible range after vbv-lookahead estimation to avoid possible
* mispredictions by initial frame size predictors */
+ qScale = clipQscale(curFrame, rce, qScale);
+
if (m_pred[m_predType].count == 1)
qScale = x265_clip3(lmin, lmax, qScale);
m_lastQScaleFor[m_sliceType] = qScale;
@@ -2015,7 +2091,20 @@
m_avgPFrameQp = m_avgPFrameQp == 0 ? rce->qpNoVbv : m_avgPFrameQp;
m_avgPFrameQp = (m_avgPFrameQp + rce->qpNoVbv) / 2;
}
+
+ if (!m_param->bResetZoneConfig)
+ {
+ q = tuneQScaleForZone(rce, q);
+ q = x265_clip3(lqmin, lqmax, q);
+ }
q = clipQscale(curFrame, rce, q);
+
+
+ if (m_2pass)
+ rce->frameSizePlanned = qScale2bits(rce, q);
+ else
+ rce->frameSizePlanned = predictSize(&m_pred[m_predType], q, (double)m_currentSatd);
+
/* clip qp to permissible range after vbv-lookahead estimation to avoid possible
* mispredictions by initial frame size predictors, after each scenecut */
bool isFrameAfterScenecut = m_sliceType!= I_SLICE && m_curSlice->m_refFrameList[0][0]->m_lowres.bScenecut;
@@ -2194,7 +2283,8 @@
frameQ[B_SLICE] = frameQ[P_SLICE] * m_param->rc.pbFactor;
frameQ[I_SLICE] = frameQ[P_SLICE] / m_param->rc.ipFactor;
/* Loop over the planned future frames. */
- for (int j = 0; bufferFillCur >= 0; j++)
+ bool iter = true;
+ for (int j = 0; bufferFillCur >= 0 && iter ; j++)
{
int type = curFrame->m_lowres.plannedType[j];
if (type == X265_TYPE_AUTO || totalDuration >= 1.0)
@@ -2208,6 +2298,8 @@
int predType = getPredictorType(curFrame->m_lowres.plannedType[j], type);
curBits = predictSize(&m_pred[predType], frameQ[type], (double)satd);
bufferFillCur -= curBits;
+ if (!m_param->bResetZoneConfig && ((uint64_t)j == (m_param->reconfigWindowSize - 1)))
+ iter = false;
}
if (rce->vbvEndAdj)
{
@@ -2977,6 +3069,9 @@
X265_FREE(m_encOrder);
for (int i = 0; i < 2; i++)
X265_FREE(m_cuTreeStats.qpBuffer[i]);
+
+ if (m_relativeComplexity)
+ X265_FREE(m_relativeComplexity);
}
diff -r 858a6b6267e0 -r 5297824e605c source/encoder/ratecontrol.h
--- a/source/encoder/ratecontrol.h Wed Aug 28 15:08:18 2019 +0530
+++ b/source/encoder/ratecontrol.h Mon Oct 21 14:11:47 2019 +0530
@@ -128,6 +128,10 @@
int m_ncu; /* number of CUs in a frame */
int m_qp; /* updated qp for current frame */
+ /*Zone reconfiguration*/
+ double* m_relativeComplexity;
+ int m_zoneBufferIdx;
+
bool m_isAbr;
bool m_isVbv;
bool m_isCbr;
@@ -228,6 +232,8 @@
int64_t m_predictedBits;
int *m_encOrder;
RateControlEntry* m_rce2Pass;
+ Encoder* m_top;
+
struct
{
uint16_t *qpBuffer[2]; /* Global buffers for converting MB-tree quantizer data. */
@@ -235,7 +241,7 @@
* This value is the current position (0 or 1). */
} m_cuTreeStats;
- RateControl(x265_param& p);
+ RateControl(x265_param& p, Encoder *enc);
bool init(const SPS& sps);
void initHRD(SPS& sps);
void reconfigureRC();
@@ -271,6 +277,7 @@
double getQScale(RateControlEntry *rce, double rateFactor);
double rateEstimateQscale(Frame* pic, RateControlEntry *rce); // main logic for calculating QP based on ABR
double tuneAbrQScaleFromFeedback(double qScale);
+ double tuneQScaleForZone(RateControlEntry *rce, double qScale); // Tune qScale to adhere to zone budget
void accumPQpUpdate();
int getPredictorType(int lowresSliceType, int sliceType);
diff -r 858a6b6267e0 -r 5297824e605c source/x265.h
--- a/source/x265.h Wed Aug 28 15:08:18 2019 +0530
+++ b/source/x265.h Mon Oct 21 14:11:47 2019 +0530
@@ -683,6 +683,7 @@
int qp;
float bitrateFactor;
struct x265_param* zoneParam;
+ double* relativeComplexity;
} x265_zone;
/* data to calculate aggregate VMAF score */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: x265_push-4.patch
Type: text/x-patch
Size: 13857 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20191113/07000943/attachment-0001.bin>
More information about the x265-devel
mailing list