[x265] x265 patch (Store commonly-used RPS in SPS)
Zheng Wang
zheng at multicorewareinc.com
Fri Oct 21 05:56:52 CEST 2016
# HG changeset patch
# User ZhengWang <zheng at multicorewareinc.com>
# Date 1476863434 -28800
# Wed Oct 19 15:50:34 2016 +0800
# Node ID b1662beb64862095079cc1600ee2ecc8c05d8227
# Parent 0e9e5264054606a38a3fe6c87272a1737b340b1a
Store commonly-used RPS in SPS in 2 pass mode.
Add new param --[no]-multi-pass-opt-rps to control it, default disabled.
diff -r 0e9e52640546 -r b1662beb6486 doc/reST/cli.rst
--- a/doc/reST/cli.rst Wed Oct 12 17:58:49 2016 +0530
+++ b/doc/reST/cli.rst Wed Oct 19 15:50:34 2016 +0800
@@ -1389,6 +1389,10 @@
Specify file name of of the multi-pass stats file. If unspecified
the encoder will use x265_2pass.log
+.. option:: --[no]-multi-pass-opt-rps
+
+ Enable storing commonly RPS in SPS in multi pass mode. Default disabled.
+
.. option:: --slow-firstpass, --no-slow-firstpass
Enable first pass encode with the exact settings specified.
diff -r 0e9e52640546 -r b1662beb6486 source/CMakeLists.txt
--- a/source/CMakeLists.txt Wed Oct 12 17:58:49 2016 +0530
+++ b/source/CMakeLists.txt Wed Oct 19 15:50:34 2016 +0800
@@ -30,7 +30,7 @@
mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)
# X265_BUILD must be incremented each time the public API is changed
-set(X265_BUILD 98)
+set(X265_BUILD 99)
configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
"${PROJECT_BINARY_DIR}/x265.def")
configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
diff -r 0e9e52640546 -r b1662beb6486 source/common/common.h
--- a/source/common/common.h Wed Oct 12 17:58:49 2016 +0530
+++ b/source/common/common.h Wed Oct 19 15:50:34 2016 +0800
@@ -312,6 +312,7 @@
#define MAX_NUM_REF_PICS 16 // max. number of pictures used for
reference
#define MAX_NUM_REF 16 // max. number of entries in
picture reference list
+#define MAX_NUM_SHORT_TERM_RPS 64 // max. number of short term
reference picture set in SPS
#define REF_NOT_VALID -1
diff -r 0e9e52640546 -r b1662beb6486 source/common/framedata.cpp
--- a/source/common/framedata.cpp Wed Oct 12 17:58:49 2016 +0530
+++ b/source/common/framedata.cpp Wed Oct 19 15:50:34 2016 +0800
@@ -37,6 +37,9 @@
m_slice = new Slice;
m_picCTU = new CUData[sps.numCUsInFrame];
m_picCsp = csp;
+ m_spsrpsIdx = -1;
+ if (param.rc.bStatWrite)
+ m_spsrps = const_cast<RPS*>(sps.spsrps);
m_cuMemPool.create(0, param.internalCsp, sps.numCUsInFrame);
for (uint32_t ctuAddr = 0; ctuAddr < sps.numCUsInFrame; ctuAddr++)
diff -r 0e9e52640546 -r b1662beb6486 source/common/framedata.h
--- a/source/common/framedata.h Wed Oct 12 17:58:49 2016 +0530
+++ b/source/common/framedata.h Wed Oct 19 15:50:34 2016 +0800
@@ -106,6 +106,9 @@
CUDataMemPool m_cuMemPool;
CUData* m_picCTU;
+ RPS* m_spsrps;
+ int m_spsrpsIdx;
+
/* Rate control data used during encode and by references */
struct RCStatCU
{
diff -r 0e9e52640546 -r b1662beb6486 source/common/param.cpp
--- a/source/common/param.cpp Wed Oct 12 17:58:49 2016 +0530
+++ b/source/common/param.cpp Wed Oct 19 15:50:34 2016 +0800
@@ -198,6 +198,7 @@
param->bCULossless = 0;
param->bEnableTemporalSubLayers = 0;
param->bEnableRdRefine = 0;
+ param->bMultiPassOptRPS = 0;
/* Rate control options */
param->rc.vbvMaxBitrate = 0;
@@ -915,6 +916,8 @@
OPT("limit-tu") p->limitTU = atoi(value);
OPT("opt-qp-pps") p->bOptQpPPS = atobool(value);
OPT("opt-ref-list-length-pps") p->bOptRefListLengthPPS =
atobool(value);
+ OPT("multi-pass-opt-rps") p->bMultiPassOptRPS = atobool(value);
+
else
return X265_PARAM_BAD_NAME;
}
diff -r 0e9e52640546 -r b1662beb6486 source/common/slice.h
--- a/source/common/slice.h Wed Oct 12 17:58:49 2016 +0530
+++ b/source/common/slice.h Wed Oct 19 15:50:34 2016 +0800
@@ -239,6 +239,10 @@
uint32_t maxLatencyIncrease;
int numReorderPics;
+ RPS spsrps[MAX_NUM_SHORT_TERM_RPS];
+ int spsrpsNum;
+ int numGOPBegin;
+
bool bUseSAO; // use param
bool bUseAMP; // use param
bool bUseStrongIntraSmoothing; // use param
@@ -337,6 +341,7 @@
int m_sliceQp;
int m_poc;
int m_lastIDR;
+ int m_rpsIdx;
uint32_t m_colRefIdx; // never modified
@@ -352,6 +357,7 @@
int m_iPPSQpMinus26;
int numRefIdxDefault[2];
+ int m_iNumRPSInSPS;
Slice()
{
@@ -365,6 +371,7 @@
m_iPPSQpMinus26 = 0;
numRefIdxDefault[0] = 1;
numRefIdxDefault[1] = 1;
+ m_rpsIdx = -1;
}
void disableWeights();
diff -r 0e9e52640546 -r b1662beb6486 source/encoder/api.cpp
--- a/source/encoder/api.cpp Wed Oct 12 17:58:49 2016 +0530
+++ b/source/encoder/api.cpp Wed Oct 19 15:50:34 2016 +0800
@@ -141,6 +141,11 @@
Encoder *encoder = static_cast<Encoder*>(enc);
Entropy sbacCoder;
Bitstream bs;
+ if (encoder->m_param->rc.bStatRead &&
encoder->m_param->bMultiPassOptRPS)
+ {
+ if (!encoder->computeSPSRPSIndex())
+ return -1;
+ }
encoder->getStreamHeaders(encoder->m_nalList, sbacCoder, bs);
*pp_nal = &encoder->m_nalList.m_nal[0];
if (pi_nal) *pi_nal = encoder->m_nalList.m_numNal;
diff -r 0e9e52640546 -r b1662beb6486 source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp Wed Oct 12 17:58:49 2016 +0530
+++ b/source/encoder/encoder.cpp Wed Oct 19 15:50:34 2016 +0800
@@ -77,6 +77,7 @@
m_iFrameNum = 0;
m_iPPSQpMinus26 = 0;
m_iLastSliceQp = 0;
+ m_rpsInSpsCount = 0;
for (int i = 0; i < X265_MAX_FRAME_THREADS; i++)
m_frameEncoder[i] = NULL;
@@ -905,6 +906,7 @@
frameEnc->m_encData->m_slice->m_iPPSQpMinus26 =
m_iPPSQpMinus26;
frameEnc->m_encData->m_slice->numRefIdxDefault[0] =
m_pps.numRefIdxDefault[0];
frameEnc->m_encData->m_slice->numRefIdxDefault[1] =
m_pps.numRefIdxDefault[1];
+ frameEnc->m_encData->m_slice->m_iNumRPSInSPS = m_sps.spsrpsNum;
curEncoder->m_rce.encodeOrder = frameEnc->m_encodeOrder =
m_encodedFrameNum++;
if (m_bframeDelay)
@@ -1068,6 +1070,13 @@
x265_log(m_param, X265_LOG_INFO, "lossless compression ratio
%.2f::1\n", uncompressed / m_analyzeAll.m_accBits);
}
+ if (m_param->bMultiPassOptRPS && m_param->rc.bStatRead)
+ {
+ x265_log(m_param, X265_LOG_INFO, "RPS in SPS: %d frames (%.2f%%),
RPS not in SPS: %d frames (%.2f%%)\n",
+ m_rpsInSpsCount, (float)100.0 * m_rpsInSpsCount /
m_rateControl->m_numEntries,
+ m_rateControl->m_numEntries - m_rpsInSpsCount,
+ (float)100.0 * (m_rateControl->m_numEntries - m_rpsInSpsCount)
/ m_rateControl->m_numEntries);
+ }
if (m_analyzeAll.m_numPics)
{
@@ -2433,3 +2442,203 @@
TOOLCMP(oldParam->maxNumMergeCand, newParam->maxNumMergeCand,
"max-merge=%d to %d\n");
TOOLCMP(oldParam->bIntraInBFrames, newParam->bIntraInBFrames,
"b-intra=%d to %d\n");
}
+
+bool Encoder::computeSPSRPSIndex()
+{
+ RPS* rpsInSPS = m_sps.spsrps;
+ int* rpsNumInPSP = &m_sps.spsrpsNum;
+ int beginNum = m_sps.numGOPBegin;
+ int endNum;
+ RPS* rpsInRec;
+ RPS* rpsInIdxList;
+ RPS* thisRpsInSPS;
+ RPS* thisRpsInList;
+ RPSListNode* headRpsIdxList = NULL;
+ RPSListNode* tailRpsIdxList = NULL;
+ RPSListNode* rpsIdxListIter = NULL;
+ RateControlEntry *rce2Pass = m_rateControl->m_rce2Pass;
+ int numEntries = m_rateControl->m_numEntries;
+ RateControlEntry *rce;
+ int idx = 0;
+ int pos = 0;
+ int resultIdx[64];
+ memset(rpsInSPS, 0, sizeof(RPS) * MAX_NUM_SHORT_TERM_RPS);
+
+ // find out all RPS date in current GOP
+ beginNum++;
+ endNum = beginNum;
+ if (!m_param->bRepeatHeaders)
+ {
+ endNum = numEntries;
+ }
+ else
+ {
+ while (endNum < numEntries)
+ {
+ rce = &rce2Pass[endNum];
+ if (rce->sliceType == I_SLICE)
+ {
+ break;
+ }
+ endNum++;
+ }
+ }
+ m_sps.numGOPBegin = endNum;
+
+ // find out all kinds of RPS
+ for (int i = beginNum; i < endNum; i++)
+ {
+ rce = &rce2Pass[i];
+ rpsInRec = &rce->rpsData;
+ rpsIdxListIter = headRpsIdxList;
+ // i frame don't recode RPS info
+ if (rce->sliceType != I_SLICE)
+ {
+ while (rpsIdxListIter)
+ {
+ rpsInIdxList = rpsIdxListIter->rps;
+ if (rpsInRec->numberOfPictures ==
rpsInIdxList->numberOfPictures
+ && rpsInRec->numberOfNegativePictures ==
rpsInIdxList->numberOfNegativePictures
+ && rpsInRec->numberOfPositivePictures ==
rpsInIdxList->numberOfPositivePictures)
+ {
+ for (pos = 0; pos < rpsInRec->numberOfPictures; pos++)
+ {
+ if (rpsInRec->deltaPOC[pos] !=
rpsInIdxList->deltaPOC[pos]
+ || rpsInRec->bUsed[pos] !=
rpsInIdxList->bUsed[pos])
+ break;
+ }
+ if (pos == rpsInRec->numberOfPictures) // if this
type of RPS has exist
+ {
+ rce->rpsIdx = rpsIdxListIter->idx;
+ rpsIdxListIter->count++;
+ // sort RPS type link after reset RPS type count.
+ RPSListNode* next = rpsIdxListIter->next;
+ RPSListNode* prior = rpsIdxListIter->prior;
+ RPSListNode* iter = prior;
+ if (iter)
+ {
+ while (iter)
+ {
+ if (iter->count > rpsIdxListIter->count)
+ break;
+ iter = iter->prior;
+ }
+ if (iter)
+ {
+ prior->next = next;
+ if (next)
+ next->prior = prior;
+ else
+ tailRpsIdxList = prior;
+ rpsIdxListIter->next = iter->next;
+ rpsIdxListIter->prior = iter;
+ iter->next->prior = rpsIdxListIter;
+ iter->next = rpsIdxListIter;
+ }
+ else
+ {
+ prior->next = next;
+ if (next)
+ next->prior = prior;
+ else
+ tailRpsIdxList = prior;
+ headRpsIdxList->prior = rpsIdxListIter;
+ rpsIdxListIter->next = headRpsIdxList;
+ rpsIdxListIter->prior = NULL;
+ headRpsIdxList = rpsIdxListIter;
+ }
+ }
+ break;
+ }
+ }
+ rpsIdxListIter = rpsIdxListIter->next;
+ }
+ if (!rpsIdxListIter) // add new type of RPS
+ {
+ RPSListNode* newIdxNode = new RPSListNode();
+ if (newIdxNode == NULL)
+ goto fail;
+ newIdxNode->rps = rpsInRec;
+ newIdxNode->idx = idx++;
+ newIdxNode->count = 1;
+ newIdxNode->next = NULL;
+ newIdxNode->prior = NULL;
+ if (!tailRpsIdxList)
+ tailRpsIdxList = headRpsIdxList = newIdxNode;
+ else
+ {
+ tailRpsIdxList->next = newIdxNode;
+ newIdxNode->prior = tailRpsIdxList;
+ tailRpsIdxList = newIdxNode;
+ }
+ rce->rpsIdx = newIdxNode->idx;
+ }
+ }
+ else
+ {
+ rce->rpsIdx = -1;
+ }
+ }
+
+ // get commonly RPS set
+ memset(resultIdx, 0, sizeof(resultIdx));
+ if (idx > MAX_NUM_SHORT_TERM_RPS)
+ idx = MAX_NUM_SHORT_TERM_RPS;
+
+ *rpsNumInPSP = idx;
+ rpsIdxListIter = headRpsIdxList;
+ for (int i = 0; i < idx; i++)
+ {
+ resultIdx[i] = rpsIdxListIter->idx;
+ m_rpsInSpsCount += rpsIdxListIter->count;
+ thisRpsInSPS = rpsInSPS + i;
+ thisRpsInList = rpsIdxListIter->rps;
+ thisRpsInSPS->numberOfPictures = thisRpsInList->numberOfPictures;
+ thisRpsInSPS->numberOfNegativePictures =
thisRpsInList->numberOfNegativePictures;
+ thisRpsInSPS->numberOfPositivePictures =
thisRpsInList->numberOfPositivePictures;
+ for (pos = 0; pos < thisRpsInList->numberOfPictures; pos++)
+ {
+ thisRpsInSPS->deltaPOC[pos] = thisRpsInList->deltaPOC[pos];
+ thisRpsInSPS->bUsed[pos] = thisRpsInList->bUsed[pos];
+ }
+ rpsIdxListIter = rpsIdxListIter->next;
+ }
+
+ //reset every frame's RPS index
+ for (int i = beginNum; i < endNum; i++)
+ {
+ int j;
+ rce = &rce2Pass[i];
+ for (j = 0; j < idx; j++)
+ {
+ if (rce->rpsIdx == resultIdx[j])
+ {
+ rce->rpsIdx = j;
+ break;
+ }
+ }
+
+ if (j == idx)
+ rce->rpsIdx = -1;
+ }
+
+ rpsIdxListIter = headRpsIdxList;
+ while (rpsIdxListIter)
+ {
+ RPSListNode* freeIndex = rpsIdxListIter;
+ rpsIdxListIter = rpsIdxListIter->next;
+ delete freeIndex;
+ }
+ return true;
+
+fail:
+ rpsIdxListIter = headRpsIdxList;
+ while (rpsIdxListIter)
+ {
+ RPSListNode* freeIndex = rpsIdxListIter;
+ rpsIdxListIter = rpsIdxListIter->next;
+ delete freeIndex;
+ }
+ return false;
+}
+
diff -r 0e9e52640546 -r b1662beb6486 source/encoder/encoder.h
--- a/source/encoder/encoder.h Wed Oct 12 17:58:49 2016 +0530
+++ b/source/encoder/encoder.h Wed Oct 19 15:50:34 2016 +0800
@@ -79,6 +79,15 @@
int numRefIdxl1[MAX_NUM_REF_IDX];
};
+struct RPSListNode
+{
+ int idx;
+ int count;
+ RPS* rps;
+ RPSListNode* next;
+ RPSListNode* prior;
+};
+
class FrameEncoder;
class DPB;
class Lookahead;
@@ -156,6 +165,9 @@
Lock m_sliceRefIdxLock;
RefIdxLastGOP m_refIdxLastGOP;
+ Lock m_rpsInSpsLock;
+ int m_rpsInSpsCount;
+
Encoder();
~Encoder() {}
@@ -196,6 +208,7 @@
void initRefIdx();
void analyseRefIdx(int *numRefIdx);
void updateRefIdx();
+ bool computeSPSRPSIndex();
protected:
diff -r 0e9e52640546 -r b1662beb6486 source/encoder/entropy.cpp
--- a/source/encoder/entropy.cpp Wed Oct 12 17:58:49 2016 +0530
+++ b/source/encoder/entropy.cpp Wed Oct 19 15:50:34 2016 +0800
@@ -312,7 +312,9 @@
WRITE_FLAG(sps.bUseSAO, "sample_adaptive_offset_enabled_flag");
WRITE_FLAG(0, "pcm_enabled_flag");
- WRITE_UVLC(0, "num_short_term_ref_pic_sets");
+ WRITE_UVLC(sps.spsrpsNum, "num_short_term_ref_pic_sets");
+ for (int i = 0; i < sps.spsrpsNum; i++)
+ codeShortTermRefPicSet(sps.spsrps[i], i);
WRITE_FLAG(0, "long_term_ref_pics_present_flag");
WRITE_FLAG(sps.bTemporalMVPEnabled, "sps_temporal_mvp_enable_flag");
@@ -614,8 +616,21 @@
}
#endif
- WRITE_FLAG(0, "short_term_ref_pic_set_sps_flag");
- codeShortTermRefPicSet(slice.m_rps);
+ if (slice.m_rpsIdx < 0)
+ {
+ WRITE_FLAG(0, "short_term_ref_pic_set_sps_flag");
+ codeShortTermRefPicSet(slice.m_rps, slice.m_sps->spsrpsNum);
+ }
+ else
+ {
+ WRITE_FLAG(1, "short_term_ref_pic_set_sps_flag");
+ int numBits = 0;
+ while ((1 << numBits) < slice.m_iNumRPSInSPS)
+ numBits++;
+
+ if (numBits > 0)
+ WRITE_CODE(slice.m_rpsIdx, numBits,
"short_term_ref_pic_set_idx");
+ }
if (slice.m_sps->bTemporalMVPEnabled)
WRITE_FLAG(1, "slice_temporal_mvp_enable_flag");
@@ -707,8 +722,11 @@
WRITE_CODE(substreamSizes[i] - 1, offsetLen,
"entry_point_offset_minus1");
}
-void Entropy::codeShortTermRefPicSet(const RPS& rps)
+void Entropy::codeShortTermRefPicSet(const RPS& rps, int idx)
{
+ if (idx > 0)
+ WRITE_FLAG(0, "inter_ref_pic_set_prediction_flag");
+
WRITE_UVLC(rps.numberOfNegativePictures, "num_negative_pics");
WRITE_UVLC(rps.numberOfPositivePictures, "num_positive_pics");
int prev = 0;
diff -r 0e9e52640546 -r b1662beb6486 source/encoder/entropy.h
--- a/source/encoder/entropy.h Wed Oct 12 17:58:49 2016 +0530
+++ b/source/encoder/entropy.h Wed Oct 19 15:50:34 2016 +0800
@@ -149,7 +149,7 @@
void codeSliceHeader(const Slice& slice, FrameData& encData, uint32_t
slice_addr, uint32_t slice_addr_bits, int sliceQp);
void codeSliceHeaderWPPEntryPoints(const uint32_t *substreamSizes,
uint32_t numSubStreams, uint32_t maxOffset);
- void codeShortTermRefPicSet(const RPS& rps);
+ void codeShortTermRefPicSet(const RPS& rps, int idx);
void finishSlice() { encodeBinTrm(1); finish();
dynamic_cast<Bitstream*>(m_bitIf)->writeByteAlignment(); }
void encodeCTU(const CUData& cu, const CUGeom& cuGeom);
diff -r 0e9e52640546 -r b1662beb6486 source/encoder/frameencoder.cpp
--- a/source/encoder/frameencoder.cpp Wed Oct 12 17:58:49 2016 +0530
+++ b/source/encoder/frameencoder.cpp Wed Oct 19 15:50:34 2016 +0800
@@ -359,9 +359,23 @@
ScopedLock refIdxLock(m_top->m_sliceRefIdxLock);
m_top->updateRefIdx();
}
- m_top->getStreamHeaders(m_nalList, m_entropyCoder, m_bs);
+ if (m_top->m_param->rc.bStatRead && m_top->m_param->bMultiPassOptR
PS)
+ {
+ ScopedLock refIdxLock(m_top->m_rpsInSpsLock);
+ if (!m_top->computeSPSRPSIndex())
+ {
+ x265_log(m_param, X265_LOG_ERROR, "compute commonly RPS
failed!\n");
+ m_top->m_aborted = true;
+ }
+ m_top->getStreamHeaders(m_nalList, m_entropyCoder, m_bs);
+ }
+ else
+ m_top->getStreamHeaders(m_nalList, m_entropyCoder, m_bs);
}
+ if (m_top->m_param->rc.bStatRead && m_top->m_param->bMultiPassOptRPS)
+ m_frame->m_encData->m_slice->m_rpsIdx =
(m_top->m_rateControl->m_rce2Pass + m_frame->m_encodeOrder)->rpsIdx;
+
// Weighted Prediction parameters estimation.
bool bUseWeightP = slice->m_sliceType == P_SLICE &&
slice->m_pps->bUseWeightPred;
bool bUseWeightB = slice->m_sliceType == B_SLICE &&
slice->m_pps->bUseWeightedBiPred;
diff -r 0e9e52640546 -r b1662beb6486 source/encoder/ratecontrol.cpp
--- a/source/encoder/ratecontrol.cpp Wed Oct 12 17:58:49 2016 +0530
+++ b/source/encoder/ratecontrol.cpp Wed Oct 19 15:50:34 2016 +0800
@@ -544,10 +544,27 @@
}
rce = &m_rce2Pass[encodeOrder];
m_encOrder[frameNumber] = encodeOrder;
- e += sscanf(p, " in:%*d out:%*d type:%c q:%lf q-aq:%lf
q-noVbv:%lf q-Rceq:%lf tex:%d mv:%d misc:%d icu:%lf pcu:%lf scu:%lf",
- &picType, &qpRc, &qpAq, &qNoVbv, &qRceq,
&rce->coeffBits,
- &rce->mvBits, &rce->miscBits, &rce->iCuCount,
&rce->pCuCount,
- &rce->skipCuCount);
+ if (!m_param->bMultiPassOptRPS)
+ {
+ e += sscanf(p, " in:%*d out:%*d type:%c q:%lf q-aq:%lf
q-noVbv:%lf q-Rceq:%lf tex:%d mv:%d misc:%d icu:%lf pcu:%lf scu:%lf",
+ &picType, &qpRc, &qpAq, &qNoVbv, &qRceq,
&rce->coeffBits,
+ &rce->mvBits, &rce->miscBits, &rce->iCuCount,
&rce->pCuCount,
+ &rce->skipCuCount);
+ }
+ else
+ {
+ char deltaPOC[1024];
+ char bUsed[1024];
+ memset(deltaPOC, 0, sizeof(deltaPOC));
+ memset(bUsed, 0, sizeof(bUsed));
+ e += sscanf(p, " in:%*d out:%*d type:%c q:%lf q-aq:%lf
q-noVbv:%lf q-Rceq:%lf tex:%d mv:%d misc:%d icu:%lf pcu:%lf scu:%lf nump:%d
numnegp:%d numposp:%d deltapoc:%s bused:%s",
+ &picType, &qpRc, &qpAq, &qNoVbv, &qRceq,
&rce->coeffBits,
+ &rce->mvBits, &rce->miscBits, &rce->iCuCount,
&rce->pCuCount,
+ &rce->skipCuCount, &rce->rpsData.numberOfPictures,
&rce->rpsData.numberOfNegativePictures, &rce->rpsData.numberOfPositivePictures,
&deltaPOC, &bUsed);
+ splitdeltaPOC(deltaPOC, rce);
+ splitbUsed(bUsed, rce);
+ rce->rpsIdx = -1;
+ }
rce->keptAsRef = true;
rce->isIdr = false;
if (picType == 'b' || picType == 'p')
@@ -2632,18 +2649,55 @@
char cType = rce->sliceType == I_SLICE ? (curFrame->m_lowres.sliceType
== X265_TYPE_IDR ? 'I' : 'i')
: rce->sliceType == P_SLICE ? 'P'
: IS_REFERENCED(curFrame) ? 'B' : 'b';
- if (fprintf(m_statFileOut,
- "in:%d out:%d type:%c q:%.2f q-aq:%.2f q-noVbv:%.2f
q-Rceq:%.2f tex:%d mv:%d misc:%d icu:%.2f pcu:%.2f scu:%.2f ;\n",
- rce->poc, rce->encodeOrder,
- cType, curEncData.m_avgQpRc, curEncData.m_avgQpAq,
- rce->qpNoVbv, rce->qRceq,
- curFrame->m_encData->m_frameStats.coeffBits,
- curFrame->m_encData->m_frameStats.mvBits,
- curFrame->m_encData->m_frameStats.miscBits,
- curFrame->m_encData->m_frameStats.percent8x8Intra * m_ncu,
- curFrame->m_encData->m_frameStats.percent8x8Inter * m_ncu,
- curFrame->m_encData->m_frameStats.percent8x8Skip * m_ncu)
< 0)
- goto writeFailure;
+
+ if (!curEncData.m_param->bMultiPassOptRPS)
+ {
+ if (fprintf(m_statFileOut,
+ "in:%d out:%d type:%c q:%.2f q-aq:%.2f q-noVbv:%.2f
q-Rceq:%.2f tex:%d mv:%d misc:%d icu:%.2f pcu:%.2f scu:%.2f ;\n",
+ rce->poc, rce->encodeOrder,
+ cType, curEncData.m_avgQpRc, curEncData.m_avgQpAq,
+ rce->qpNoVbv, rce->qRceq,
+ curFrame->m_encData->m_frameStats.coeffBits,
+ curFrame->m_encData->m_frameStats.mvBits,
+ curFrame->m_encData->m_frameStats.miscBits,
+ curFrame->m_encData->m_frameStats.percent8x8Intra * m_ncu,
+ curFrame->m_encData->m_frameStats.percent8x8Inter * m_ncu,
+ curFrame->m_encData->m_frameStats.percent8x8Skip * m_ncu) < 0)
+ goto writeFailure;
+ }
+ else{
+ RPS* rpsWriter = &curFrame->m_encData->m_slice->m_rps;
+ int i, num = rpsWriter->numberOfPictures;
+ char deltaPOC[128];
+ char bUsed[40];
+ memset(deltaPOC, 0, sizeof(deltaPOC));
+ memset(bUsed, 0, sizeof(bUsed));
+ sprintf(deltaPOC, "deltapoc:~");
+ sprintf(bUsed, "bused:~");
+
+ for (i = 0; i < num; i++)
+ {
+ sprintf(deltaPOC, "%s%d~", deltaPOC, rpsWriter->deltaPOC[i]);
+ sprintf(bUsed, "%s%d~", bUsed, rpsWriter->bUsed[i]);
+ }
+
+ if (fprintf(m_statFileOut,
+ "in:%d out:%d type:%c q:%.2f q-aq:%.2f q-noVbv:%.2f
q-Rceq:%.2f tex:%d mv:%d misc:%d icu:%.2f pcu:%.2f scu:%.2f nump:%d
numnegp:%d numposp:%d %s %s ;\n",
+ rce->poc, rce->encodeOrder,
+ cType, curEncData.m_avgQpRc, curEncData.m_avgQpAq,
+ rce->qpNoVbv, rce->qRceq,
+ curFrame->m_encData->m_frameStats.coeffBits,
+ curFrame->m_encData->m_frameStats.mvBits,
+ curFrame->m_encData->m_frameStats.miscBits,
+ curFrame->m_encData->m_frameStats.percent8x8Intra * m_ncu,
+ curFrame->m_encData->m_frameStats.percent8x8Inter * m_ncu,
+ curFrame->m_encData->m_frameStats.percent8x8Skip * m_ncu,
+ rpsWriter->numberOfPictures,
+ rpsWriter->numberOfNegativePictures,
+ rpsWriter->numberOfPositivePictures,
+ deltaPOC, bUsed) < 0)
+ goto writeFailure;
+ }
/* Don't re-write the data in multi-pass mode. */
if (m_param->rc.cuTree && IS_REFERENCED(curFrame) &&
!m_param->rc.bStatRead)
{
@@ -2736,3 +2790,48 @@
X265_FREE(m_param->rc.zones);
}
+void RateControl::splitdeltaPOC(char deltapoc[], RateControlEntry *rce)
+{
+ int idx = 0, length = 0;
+ char tmpStr[128];
+ char* src = deltapoc;
+ char* buf = strstr(src, "~");
+ while (buf)
+ {
+ memset(tmpStr, 0, sizeof(tmpStr));
+ length = (int)(buf - src);
+ if (length != 0)
+ {
+ strncpy(tmpStr, src, length);
+ rce->rpsData.deltaPOC[idx] = atoi(tmpStr);
+ idx++;
+ if (idx == rce->rpsData.numberOfPictures)
+ break;
+ }
+ src += (length + 1);
+ buf = strstr(src, "~");
+ }
+}
+
+void RateControl::splitbUsed(char bused[], RateControlEntry *rce)
+{
+ int idx = 0, length = 0;
+ char tmpStr[128];
+ char* src = bused;
+ char* buf = strstr(src, "~");
+ while (buf)
+ {
+ memset(tmpStr, 0, sizeof(tmpStr));
+ length = (int)(buf - src);
+ if (length != 0)
+ {
+ strncpy(tmpStr, src, length);
+ rce->rpsData.bUsed[idx] = atoi(tmpStr) > 0;
+ idx++;
+ if (idx == rce->rpsData.numberOfPictures)
+ break;
+ }
+ src += (length + 1);
+ buf = strstr(src, "~");
+ }
+}
diff -r 0e9e52640546 -r b1662beb6486 source/encoder/ratecontrol.h
--- a/source/encoder/ratecontrol.h Wed Oct 12 17:58:49 2016 +0530
+++ b/source/encoder/ratecontrol.h Wed Oct 19 15:50:34 2016 +0800
@@ -111,6 +111,8 @@
bool isIdr;
SEIPictureTiming *picTimingSEI;
HRDTiming *hrdTiming;
+ int rpsIdx;
+ RPS rpsData;
};
class RateControl
@@ -282,6 +284,8 @@
bool findUnderflow(double *fills, int *t0, int *t1, int over, int
framesCount);
bool fixUnderflow(int t0, int t1, double adjustment, double
qscaleMin, double qscaleMax);
double tuneQScaleForGrain(double rcOverflow);
+ void splitdeltaPOC(char deltapoc[], RateControlEntry *rce);
+ void splitbUsed(char deltapoc[], RateControlEntry *rce);
};
}
#endif // ifndef X265_RATECONTROL_H
diff -r 0e9e52640546 -r b1662beb6486 source/x265.h
--- a/source/x265.h Wed Oct 12 17:58:49 2016 +0530
+++ b/source/x265.h Wed Oct 19 15:50:34 2016 +0800
@@ -1063,6 +1063,9 @@
* Default is 0, which is recommended */
int crQpOffset;
+ /* Enable storing commonly RPS in SPS in multi pass mode */
+ int bMultiPassOptRPS;
+
struct
{
/* Explicit mode of rate-control, necessary for API users. It must
diff -r 0e9e52640546 -r b1662beb6486 source/x265cli.h
--- a/source/x265cli.h Wed Oct 12 17:58:49 2016 +0530
+++ b/source/x265cli.h Wed Oct 19 15:50:34 2016 +0800
@@ -236,6 +236,8 @@
{ "pass", required_argument, NULL, 0 },
{ "slow-firstpass", no_argument, NULL, 0 },
{ "no-slow-firstpass", no_argument, NULL, 0 },
+ { "multi-pass-opt-rps", no_argument, NULL, 0 },
+ { "no-multi-pass-opt-rps", no_argument, NULL, 0 },
{ "analysis-mode", required_argument, NULL, 0 },
{ "analysis-file", required_argument, NULL, 0 },
{ "strict-cbr", no_argument, NULL, 0 },
@@ -422,6 +424,7 @@
H1(" MAX_MAX_QP+1 floats for lambda
table, then again for lambda2 table\n");
H1(" Blank lines and lines starting
with hash(#) are ignored\n");
H1(" Comma is considered to be
white-space\n");
+ H0(" --[no-]multi-pass-opt-rps Enable storing commonly RPS in
SPS in multi pass mode. Default %s\n", OPT(param->bMultiPassOptRPS));
H0("\nLoop filters (deblock and SAO):\n");
H0(" --[no-]deblock Enable Deblocking Loop Filter,
optionally specify tC:Beta offsets Default %s\n",
OPT(param->bEnableLoopFilter));
H0(" --[no-]sao Enable Sample Adaptive Offset.
Default %s\n", OPT(param->bEnableSAO));
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20161021/0013c5e2/attachment-0001.html>
More information about the x265-devel
mailing list