# HG changeset patch # User ZhengWang <zh...@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));
_______________________________________________ x265-devel mailing list x265-devel@videolan.org https://mailman.videolan.org/listinfo/x265-devel