[x265] [PATCH] add analysis 2 pass structure
santhoshini at multicorewareinc.com
santhoshini at multicorewareinc.com
Mon Dec 26 16:59:46 CET 2016
# HG changeset patch
# User Santhoshini Sekar <santhoshini at multicorewareinc.com>
# Date 1482758979 -19800
# Mon Dec 26 18:59:39 2016 +0530
# Node ID 82e4e3b0bb460c0fe140953342e12a0a1b3da004
# Parent e40db0bdde4ac9659fae2b5b133fcadecece7412
add analysis 2 pass structure
diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst
--- a/doc/reST/cli.rst
+++ b/doc/reST/cli.rst
@@ -1438,6 +1438,23 @@
* :option:`--subme` = MIN(2, :option:`--subme`)
* :option:`--rd` = MIN(2, :option:`--rd`)
+.. option:: --multi-pass-opt-analysis, --no-multi-pass-opt-analysis
+
+ Enable/Disable multipass analysis refinement along with multipass ratecontrol. Based on
+ the information stored in pass 1, in subsequent passes analysis data is refined
+ and also redundant steps are skipped.
+ In pass 1 analysis information like motion vector, depth, reference and prediction
+ modes of the final best CTU partition is stored for each CTU.
+ Default disabled.
+
+.. option:: --multi-pass-opt-distortion, --no-multi-pass-opt-distortion
+
+ Enable/Disable multipass refinement of qp based on distortion data along with multipass
+ ratecontrol. In pass 1 distortion of best CTU partition is stored. CTUs with high
+ distortion get lower(negative)qp offsets and vice-versa for low distortion CTUs in pass 2.
+ This helps to improve the subjective quality.
+ Default disabled.
+
.. option:: --strict-cbr, --no-strict-cbr
Enables stricter conditions to control bitrate deviance from the
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -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 104)
+set(X265_BUILD 105)
configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
"${PROJECT_BINARY_DIR}/x265.def")
configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
diff --git a/source/common/frame.h b/source/common/frame.h
--- a/source/common/frame.h
+++ b/source/common/frame.h
@@ -98,6 +98,7 @@
Frame* m_prev;
x265_param* m_param; // Points to the latest param set for the frame.
x265_analysis_data m_analysisData;
+ x265_analysis_2Pass m_analysis2Pass;
RcStats* m_rcData;
Frame();
diff --git a/source/common/framedata.h b/source/common/framedata.h
--- a/source/common/framedata.h
+++ b/source/common/framedata.h
@@ -181,5 +181,15 @@
uint8_t* partSize;
uint8_t* mergeFlag;
};
+
+struct analysis2PassFrameData
+{
+ uint8_t* depth;
+ MV* m_mv[2];
+ int* mvpIdx[2];
+ int32_t* ref[2];
+ uint8_t* modes;
+};
+
}
#endif // ifndef X265_FRAMEDATA_H
diff --git a/source/common/param.cpp b/source/common/param.cpp
--- a/source/common/param.cpp
+++ b/source/common/param.cpp
@@ -193,6 +193,8 @@
param->psyRd = 2.0;
param->psyRdoq = 0.0;
param->analysisMode = 0;
+ param->analysisMultiPassRefine = 0;
+ param->analysisMultiPassDistortion = 0;
param->analysisFileName = NULL;
param->bIntraInBFrames = 0;
param->bLossless = 0;
@@ -922,6 +924,8 @@
OPT("scenecut-bias") p->scenecutBias = atof(value);
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);
+ OPT("multi-pass-opt-distortion") p->analysisMultiPassDistortion = atobool(value);
else
return X265_PARAM_BAD_NAME;
}
diff --git a/source/encoder/api.cpp b/source/encoder/api.cpp
--- a/source/encoder/api.cpp
+++ b/source/encoder/api.cpp
@@ -210,6 +210,7 @@
{
pic_in->analysisData.intraData = NULL;
pic_in->analysisData.interData = NULL;
+ pic_in->analysis2Pass.analysisFramedata = NULL;
}
if (pp_nal && numEncoded > 0)
diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp
+++ b/source/encoder/encoder.cpp
@@ -339,6 +339,20 @@
}
}
+ if (m_param->analysisMultiPassRefine || m_param->analysisMultiPassDistortion)
+ {
+ const char* name = m_param->analysisFileName;
+ if (!name)
+ name = defaultAnalysisFileName;
+ const char* mode = m_param->rc.bStatWrite ? "wb" : "rb";
+ m_analysisFile = fopen(name, mode);
+ if (!m_analysisFile)
+ {
+ x265_log(NULL, X265_LOG_ERROR, "Analysis 2 pass: failed to open file %s\n", name);
+ m_aborted = true;
+ }
+ }
+
m_bZeroLatency = !m_param->bframes && !m_param->lookaheadDepth && m_param->frameNumThreads == 1;
m_aborted |= parseLambdaFile(m_param);
@@ -642,7 +656,13 @@
/* Use the frame types from the first pass, if available */
int sliceType = (m_param->rc.bStatRead) ? m_rateControl->rateControlSliceType(inFrame->m_poc) : pic_in->sliceType;
-
+ if (m_param->rc.bStatRead && (m_param->analysisMultiPassRefine || m_param->analysisMultiPassDistortion))
+ {
+ x265_picture* inputPic = const_cast<x265_picture*>(pic_in);
+ readAnalysis2PassFile(&inputPic->analysis2Pass, inFrame->m_poc, sliceType);
+ inFrame->m_analysis2Pass.poc = inFrame->m_poc;
+ inFrame->m_analysis2Pass.analysisFramedata = inputPic->analysis2Pass.analysisFramedata;
+ }
/* In analysisSave mode, x265_analysis_data is allocated in pic_in and inFrame points to this */
/* Load analysis data before lookahead->addPicture, since sliceType has been decided */
if (m_param->analysisMode == X265_ANALYSIS_LOAD)
@@ -696,6 +716,9 @@
if (m_param->analysisMode == X265_ANALYSIS_LOAD)
freeAnalysis(&outFrame->m_analysisData);
+ if ((m_param->analysisMultiPassRefine || m_param->analysisMultiPassDistortion) && m_param->rc.bStatRead)
+ freeAnalysis2Pass(&outFrame->m_analysis2Pass, slice->m_sliceType);
+
if (pic_out)
{
PicYuv *recpic = outFrame->m_reconPic;
@@ -746,6 +769,16 @@
freeAnalysis(&pic_out->analysisData);
}
}
+ if (m_param->rc.bStatWrite && (m_param->analysisMultiPassRefine || m_param->analysisMultiPassDistortion))
+ {
+ if (pic_out)
+ {
+ pic_out->analysis2Pass.poc = pic_out->poc;
+ pic_out->analysis2Pass.analysisFramedata = outFrame->m_analysis2Pass.analysisFramedata;
+ }
+ writeAnalysis2PassFile(&outFrame->m_analysis2Pass, *outFrame->m_encData);
+ freeAnalysis2Pass(&outFrame->m_analysis2Pass, slice->m_sliceType);
+ }
if (m_param->internalCsp == X265_CSP_I400)
{
if (slice->m_sliceType == P_SLICE)
@@ -954,7 +987,12 @@
analysis->numPartitions = NUM_4x4_PARTITIONS;
allocAnalysis(analysis);
}
-
+ if ((m_param->analysisMultiPassRefine || m_param->analysisMultiPassDistortion) && m_param->rc.bStatWrite)
+ {
+ x265_analysis_2Pass* analysisRefine = &frameEnc->m_analysis2Pass;
+ analysisRefine->poc = frameEnc->m_poc;
+ allocAnalysis2Pass(analysisRefine, frameEnc->m_lowres.sliceType);
+ }
/* determine references, setup RPS, etc */
m_dpb->prepareEncode(frameEnc);
@@ -1928,6 +1966,19 @@
p->rc.cuTree = 0;
}
+ if (p->analysisMode && (p->analysisMultiPassRefine || p->analysisMultiPassDistortion))
+ {
+ x265_log(p, X265_LOG_WARNING, "Cannot use Analysis load/save option and multi-pass-opt-analysis/multi-pass-opt-distortion together,"
+ "Disabling Analysis load/save and multi-pass-opt-analysis/multi-pass-opt-distortion\n");
+ p->analysisMode = p->analysisMultiPassRefine = p->analysisMultiPassDistortion = 0;
+ }
+
+ if ((p->analysisMultiPassRefine || p->analysisMultiPassDistortion) && (p->bDistributeModeAnalysis || p->bDistributeMotionEstimation))
+ {
+ x265_log(p, X265_LOG_WARNING, "multi-pass-opt-analysis/multi-pass-opt-distortion incompatible with pmode/pme, Disabling pmode/pme\n");
+ p->bDistributeMotionEstimation = p->bDistributeModeAnalysis = 0;
+ }
+
if (p->rc.bEnableGrain)
{
x265_log(p, X265_LOG_WARNING, "Rc Grain removes qp fluctuations caused by aq/cutree, Disabling aq,cu-tree\n");
@@ -1988,6 +2039,14 @@
p->bDistributeModeAnalysis = 0;
}
+ if (!p->rc.bStatWrite && !p->rc.bStatRead && (p->analysisMultiPassRefine || p->analysisMultiPassDistortion))
+ {
+ x265_log(p, X265_LOG_WARNING, "analysis-multi-pass/distortion is enabled only when rc multi pass is enabled. Disabling multi-pass-opt-analysis and multi-pass-opt-distortion");
+ p->analysisMultiPassRefine = 0;
+ p->analysisMultiPassDistortion = 0;
+ }
+
+
/* some options make no sense if others are disabled */
p->bSaoNonDeblocked &= p->bEnableSAO;
p->bEnableTSkipFast &= p->bEnableTransformSkip;
@@ -2233,6 +2292,55 @@
}
}
+void Encoder::allocAnalysis2Pass(x265_analysis_2Pass* analysis, int sliceType)
+{
+ analysis->analysisFramedata = NULL;
+ analysis2PassFrameData *analysisFrameData = (analysis2PassFrameData*)analysis->analysisFramedata;
+ uint32_t widthInCU = (m_param->sourceWidth + g_maxCUSize - 1) >> g_maxLog2CUSize;
+ uint32_t heightInCU = (m_param->sourceHeight + g_maxCUSize - 1) >> g_maxLog2CUSize;
+
+ uint32_t numCUsInFrame = widthInCU * heightInCU;
+ CHECKED_MALLOC_ZERO(analysisFrameData, analysis2PassFrameData, 1);
+ CHECKED_MALLOC(analysisFrameData->depth, uint8_t, NUM_4x4_PARTITIONS * numCUsInFrame);
+ if (!IS_X265_TYPE_I(sliceType))
+ {
+ CHECKED_MALLOC_ZERO(analysisFrameData->m_mv[0], MV, NUM_4x4_PARTITIONS * numCUsInFrame);
+ CHECKED_MALLOC_ZERO(analysisFrameData->m_mv[1], MV, NUM_4x4_PARTITIONS * numCUsInFrame);
+ CHECKED_MALLOC_ZERO(analysisFrameData->mvpIdx[0], int, NUM_4x4_PARTITIONS * numCUsInFrame);
+ CHECKED_MALLOC_ZERO(analysisFrameData->mvpIdx[1], int, NUM_4x4_PARTITIONS * numCUsInFrame);
+ CHECKED_MALLOC_ZERO(analysisFrameData->ref[0], int32_t, NUM_4x4_PARTITIONS * numCUsInFrame);
+ CHECKED_MALLOC_ZERO(analysisFrameData->ref[1], int32_t, NUM_4x4_PARTITIONS * numCUsInFrame);
+ CHECKED_MALLOC(analysisFrameData->modes, uint8_t, NUM_4x4_PARTITIONS * numCUsInFrame);
+ }
+
+ analysis->analysisFramedata = analysisFrameData;
+
+ return;
+
+fail:
+ freeAnalysis2Pass(analysis, sliceType);
+ m_aborted = true;
+}
+
+void Encoder::freeAnalysis2Pass(x265_analysis_2Pass* analysis, int sliceType)
+{
+ if (analysis->analysisFramedata)
+ {
+ X265_FREE(((analysis2PassFrameData*)analysis->analysisFramedata)->depth);
+ if (!IS_X265_TYPE_I(sliceType))
+ {
+ X265_FREE(((analysis2PassFrameData*)analysis->analysisFramedata)->m_mv[0]);
+ X265_FREE(((analysis2PassFrameData*)analysis->analysisFramedata)->m_mv[1]);
+ X265_FREE(((analysis2PassFrameData*)analysis->analysisFramedata)->mvpIdx[0]);
+ X265_FREE(((analysis2PassFrameData*)analysis->analysisFramedata)->mvpIdx[1]);
+ X265_FREE(((analysis2PassFrameData*)analysis->analysisFramedata)->ref[0]);
+ X265_FREE(((analysis2PassFrameData*)analysis->analysisFramedata)->ref[1]);
+ X265_FREE(((analysis2PassFrameData*)analysis->analysisFramedata)->modes);
+ }
+ X265_FREE(analysis->analysisFramedata);
+ }
+}
+
void Encoder::readAnalysisFile(x265_analysis_data* analysis, int curPoc)
{
@@ -2348,6 +2456,127 @@
#undef X265_FREAD
}
+void Encoder::readAnalysis2PassFile(x265_analysis_2Pass* analysis2Pass, int curPoc, int sliceType)
+{
+
+#define X265_FREAD(val, size, readSize, fileOffset)\
+ if (fread(val, size, readSize, fileOffset) != readSize)\
+ {\
+ x265_log(NULL, X265_LOG_ERROR, "Error reading analysis 2 pass data\n"); \
+ freeAnalysis2Pass(analysis2Pass, sliceType); \
+ m_aborted = true; \
+ return; \
+}\
+
+ static uint64_t consumedBytes = 0;
+ static uint64_t totalConsumedBytes = 0;
+ uint32_t depthBytes = 0;
+ fseeko(m_analysisFile, totalConsumedBytes, SEEK_SET);
+
+ int poc; uint32_t frameRecordSize;
+ X265_FREAD(&frameRecordSize, sizeof(uint32_t), 1, m_analysisFile);
+ X265_FREAD(&depthBytes, sizeof(uint32_t), 1, m_analysisFile);
+ X265_FREAD(&poc, sizeof(int), 1, m_analysisFile);
+
+ uint64_t currentOffset = totalConsumedBytes;
+
+ /* Seeking to the right frame Record */
+ while (poc != curPoc && !feof(m_analysisFile))
+ {
+ currentOffset += frameRecordSize;
+ fseeko(m_analysisFile, currentOffset, SEEK_SET);
+ X265_FREAD(&frameRecordSize, sizeof(uint32_t), 1, m_analysisFile);
+ X265_FREAD(&depthBytes, sizeof(uint32_t), 1, m_analysisFile);
+ X265_FREAD(&poc, sizeof(int), 1, m_analysisFile);
+ }
+
+ if (poc != curPoc || feof(m_analysisFile))
+ {
+ x265_log(NULL, X265_LOG_WARNING, "Error reading analysis 2 pass data: Cannot find POC %d\n", curPoc);
+ freeAnalysis2Pass(analysis2Pass, sliceType);
+ return;
+ }
+ /* Memory is allocated for analysis multi pass data */
+ allocAnalysis2Pass(analysis2Pass, sliceType);
+ /* Now arrived at the right frame, read the record */
+ analysis2Pass->poc = poc;
+ analysis2Pass->frameRecordSize = frameRecordSize;
+
+ uint8_t* tempBuf = NULL, *depthBuf = NULL;
+
+ tempBuf = X265_MALLOC(uint8_t, depthBytes);
+ X265_FREAD(tempBuf, sizeof(uint8_t), depthBytes, m_analysisFile);
+
+ depthBuf = tempBuf;
+
+ size_t count = 0;
+ for (uint32_t d = 0; d < depthBytes; d++)
+ {
+ int bytes = NUM_4x4_PARTITIONS >> (depthBuf[d] * 2);
+ memset(&((analysis2PassFrameData *)analysis2Pass->analysisFramedata)->depth[count], depthBuf[d], bytes);
+ count += bytes;
+ }
+
+ if (!IS_X265_TYPE_I(sliceType))
+ {
+ MV *tempMVBuf[2], *MVBuf[2];
+ int32_t *tempRefBuf[2], *refBuf[2];
+ int *tempMvpBuf[2], *mvpBuf[2];
+ uint8_t* tempModeBuf = NULL, *modeBuf = NULL;
+
+ int numDir = sliceType == X265_TYPE_P ? 1 : 2;
+ for (int i = 0; i < numDir; i++)
+ {
+ tempMVBuf[i] = X265_MALLOC(MV, depthBytes);
+ X265_FREAD(tempMVBuf[i], sizeof(MV), depthBytes, m_analysisFile);
+ MVBuf[i] = tempMVBuf[i];
+ tempMvpBuf[i] = X265_MALLOC(int, depthBytes);
+ X265_FREAD(tempMvpBuf[i], sizeof(int), depthBytes, m_analysisFile);
+ mvpBuf[i] = tempMvpBuf[i];
+ tempRefBuf[i] = X265_MALLOC(int32_t, depthBytes);
+ X265_FREAD(tempRefBuf[i], sizeof(int32_t), depthBytes, m_analysisFile);
+ refBuf[i] = tempRefBuf[i];
+ }
+ tempModeBuf = X265_MALLOC(uint8_t, depthBytes);
+ X265_FREAD(tempModeBuf, sizeof(uint8_t), depthBytes, m_analysisFile);
+ modeBuf = tempModeBuf;
+
+ count = 0;
+ for (uint32_t d = 0; d < depthBytes; d++)
+ {
+ size_t bytes = NUM_4x4_PARTITIONS >> (depthBuf[d] * 2);
+ for (int i = 0; i < numDir; i++)
+ {
+ for (size_t j = count, k = 0; k < bytes; j++, k++)
+ {
+ memcpy(&((analysis2PassFrameData*)analysis2Pass->analysisFramedata)->m_mv[i][j], MVBuf[i] + d, sizeof(MV));
+ memcpy(&((analysis2PassFrameData*)analysis2Pass->analysisFramedata)->mvpIdx[i][j], mvpBuf[i] + d, sizeof(int));
+ memcpy(&((analysis2PassFrameData*)analysis2Pass->analysisFramedata)->ref[i][j], refBuf[i] + d, sizeof(int32_t));
+ }
+ }
+ memset(&((analysis2PassFrameData *)analysis2Pass->analysisFramedata)->modes[count], modeBuf[d], bytes);
+ count += bytes;
+ }
+
+ for (int i = 0; i < numDir; i++)
+ {
+ X265_FREE(tempMVBuf[i]);
+ X265_FREE(tempMvpBuf[i]);
+ X265_FREE(tempRefBuf[i]);
+ }
+ X265_FREE(tempModeBuf);
+ }
+ X265_FREE(tempBuf);
+ consumedBytes += frameRecordSize;
+ if (!IS_X265_TYPE_I(sliceType))
+ {
+ int numDir = sliceType == X265_TYPE_P ? 1 : 2;
+ if (numDir == 1)
+ totalConsumedBytes = consumedBytes;
+ }
+#undef X265_FREAD
+}
+
void Encoder::writeAnalysisFile(x265_analysis_data* analysis, FrameData &curEncData)
{
@@ -2464,6 +2693,101 @@
#undef X265_FWRITE
}
+void Encoder::writeAnalysis2PassFile(x265_analysis_2Pass* analysis2Pass, FrameData &curEncData)
+{
+#define X265_FWRITE(val, size, writeSize, fileOffset)\
+ if (fwrite(val, size, writeSize, fileOffset) < writeSize)\
+ {\
+ x265_log(NULL, X265_LOG_ERROR, "Error writing analysis 2 pass data\n"); \
+ freeAnalysis2Pass(analysis2Pass, curEncData.m_slice->m_sliceType); \
+ m_aborted = true; \
+ return; \
+}\
+
+ uint32_t depthBytes = 0;
+ uint32_t widthInCU = (m_param->sourceWidth + g_maxCUSize - 1) >> g_maxLog2CUSize;
+ uint32_t heightInCU = (m_param->sourceHeight + g_maxCUSize - 1) >> g_maxLog2CUSize;
+ uint32_t numCUsInFrame = widthInCU * heightInCU;
+ analysis2PassFrameData* analysisFrameData = (analysis2PassFrameData*)analysis2Pass->analysisFramedata;
+
+ for (uint32_t cuAddr = 0; cuAddr < numCUsInFrame; cuAddr++)
+ {
+ uint8_t depth = 0;
+
+ CUData* ctu = curEncData.getPicCTU(cuAddr);
+
+ for (uint32_t absPartIdx = 0; absPartIdx < ctu->m_numPartitions; depthBytes++)
+ {
+ depth = ctu->m_cuDepth[absPartIdx];
+ analysisFrameData->depth[depthBytes] = depth;
+ absPartIdx += ctu->m_numPartitions >> (depth * 2);
+ }
+ }
+
+ if (curEncData.m_slice->m_sliceType != I_SLICE)
+ {
+ depthBytes = 0;
+ for (uint32_t cuAddr = 0; cuAddr < numCUsInFrame; cuAddr++)
+ {
+ uint8_t depth = 0;
+ uint8_t predMode = 0;
+
+ CUData* ctu = curEncData.getPicCTU(cuAddr);
+
+ for (uint32_t absPartIdx = 0; absPartIdx < ctu->m_numPartitions; depthBytes++)
+ {
+ depth = ctu->m_cuDepth[absPartIdx];
+ analysisFrameData->m_mv[0][depthBytes] = ctu->m_mv[0][absPartIdx];
+ analysisFrameData->mvpIdx[0][depthBytes] = ctu->m_mvpIdx[0][absPartIdx];
+ analysisFrameData->ref[0][depthBytes] = ctu->m_refIdx[0][absPartIdx];
+ predMode = ctu->m_predMode[absPartIdx];
+ if (ctu->m_refIdx[1][absPartIdx] != -1)
+ {
+ analysisFrameData->m_mv[1][depthBytes] = ctu->m_mv[1][absPartIdx];
+ analysisFrameData->mvpIdx[1][depthBytes] = ctu->m_mvpIdx[1][absPartIdx];
+ analysisFrameData->ref[1][depthBytes] = ctu->m_refIdx[1][absPartIdx];
+ predMode = 4; // used as indiacator if the block is coded as bidir
+ }
+ analysisFrameData->modes[depthBytes] = predMode;
+
+ absPartIdx += ctu->m_numPartitions >> (depth * 2);
+ }
+ }
+ }
+
+ /* calculate frameRecordSize */
+ analysis2Pass->frameRecordSize = sizeof(analysis2Pass->frameRecordSize) + sizeof(depthBytes)+sizeof(analysis2Pass->poc);
+
+ analysis2Pass->frameRecordSize += depthBytes * sizeof(uint8_t);
+
+ if (curEncData.m_slice->m_sliceType != I_SLICE)
+ {
+ int numDir = (curEncData.m_slice->m_sliceType == P_SLICE) ? 1 : 2;
+ analysis2Pass->frameRecordSize += depthBytes * sizeof(MV) * numDir;
+ analysis2Pass->frameRecordSize += depthBytes * sizeof(int32_t) * numDir;
+ analysis2Pass->frameRecordSize += depthBytes * sizeof(int) * numDir;
+ analysis2Pass->frameRecordSize += depthBytes * sizeof(uint8_t);
+ }
+ X265_FWRITE(&analysis2Pass->frameRecordSize, sizeof(uint32_t), 1, m_analysisFile);
+ X265_FWRITE(&depthBytes, sizeof(uint32_t), 1, m_analysisFile);
+ X265_FWRITE(&analysis2Pass->poc, sizeof(uint32_t), 1, m_analysisFile);
+
+ X265_FWRITE(analysisFrameData->depth, sizeof(uint8_t), depthBytes, m_analysisFile);
+
+ if (curEncData.m_slice->m_sliceType != I_SLICE)
+ {
+ int numDir = curEncData.m_slice->m_sliceType == P_SLICE ? 1 : 2;
+ for (int i = 0; i < numDir; i++)
+ {
+ X265_FWRITE(analysisFrameData->m_mv[i], sizeof(MV), depthBytes, m_analysisFile);
+ X265_FWRITE(analysisFrameData->mvpIdx[i], sizeof(int), depthBytes, m_analysisFile);
+ X265_FWRITE(analysisFrameData->ref[i], sizeof(int32_t), depthBytes, m_analysisFile);
+ }
+ X265_FWRITE(analysisFrameData->modes, sizeof(uint8_t), depthBytes, m_analysisFile);
+ }
+#undef X265_FWRITE
+}
+
void Encoder::printReconfigureParams()
{
if (!m_reconfigure)
diff --git a/source/encoder/encoder.h b/source/encoder/encoder.h
--- a/source/encoder/encoder.h
+++ b/source/encoder/encoder.h
@@ -30,6 +30,7 @@
#include "scalinglist.h"
#include "x265.h"
#include "nal.h"
+#include "framedata.h"
struct x265_encoder {};
@@ -197,10 +198,18 @@
void freeAnalysis(x265_analysis_data* analysis);
+ void allocAnalysis2Pass(x265_analysis_2Pass* analysis, int sliceType);
+
+ void freeAnalysis2Pass(x265_analysis_2Pass* analysis, int sliceType);
+
void readAnalysisFile(x265_analysis_data* analysis, int poc);
void writeAnalysisFile(x265_analysis_data* pic, FrameData &curEncData);
+ void readAnalysis2PassFile(x265_analysis_2Pass* analysis2Pass, int poc, int sliceType);
+
+ void writeAnalysis2PassFile(x265_analysis_2Pass* analysis2Pass, FrameData &curEncData);
+
void finishFrameStats(Frame* pic, FrameEncoder *curEncoder, x265_frame_stats* frameStats, int inPoc);
void calcRefreshInterval(Frame* frameEnc);
diff --git a/source/x265.h b/source/x265.h
--- a/source/x265.h
+++ b/source/x265.h
@@ -115,6 +115,14 @@
/* All the above values will add up to 100%. */
} x265_cu_stats;
+
+typedef struct x265_analysis_2Pass
+{
+ uint32_t poc;
+ uint32_t frameRecordSize;
+ void* analysisFramedata;
+}x265_analysis_2Pass;
+
/* Frame level statistics */
typedef struct x265_frame_stats
{
@@ -282,6 +290,8 @@
uint64_t framesize;
int height;
+
+ x265_analysis_2Pass analysis2Pass;
} x265_picture;
typedef enum
@@ -1345,6 +1355,11 @@
/* Optimize CU level QPs to signal consistent deltaQPs in frame for rd level > 4 */
int bOptCUDeltaQP;
+ /* Refine analysis in multipass ratecontrol based on analysis information stored */
+ int analysisMultiPassRefine;
+
+ /* Refine analysis in multipass ratecontrol based on distortion data stored */
+ int analysisMultiPassDistortion;
} x265_param;
/* x265_param_alloc:
diff --git a/source/x265cli.h b/source/x265cli.h
--- a/source/x265cli.h
+++ b/source/x265cli.h
@@ -238,6 +238,11 @@
{ "nr-inter", required_argument, NULL, 0 },
{ "stats", required_argument, NULL, 0 },
{ "pass", required_argument, NULL, 0 },
+ { "multi-pass-opt-analysis", no_argument, NULL, 0 },
+ { "no-multi-pass-opt-analysis", no_argument, NULL, 0 },
+ { "multi-pass-opt-distortion", no_argument, NULL, 0 },
+ { "no-multi-pass-opt-distortion", no_argument, NULL, 0 },
+ { "analysis-2Pass-file", 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 },
@@ -400,6 +405,9 @@
" - 1 : First pass, creates stats file\n"
" - 2 : Last pass, does not overwrite stats file\n"
" - 3 : Nth pass, overwrites stats file\n");
+ H0(" --[no-]multi-pass-opt-analysis Refine analysis in 2 pass based on analysis information from pass 1\n");
+ H0(" --[no-]multi-pass-opt-distortion Use distortion of CTU from pass 1 to refine qp in 2 pass\n");
+ H0(" --analysis-2Pass-file File name to dump analysis data in pass 1 and pass 2\n");
H0(" --stats Filename for stats file in multipass pass rate control. Default x265_2pass.log\n");
H0(" --[no-]analyze-src-pics Motion estimation uses source frame planes. Default disable\n");
H0(" --[no-]slow-firstpass Enable a slow first pass in a multipass rate control mode. Default %s\n", OPT(param->rc.bEnableSlowFirstPass));
-------------- next part --------------
A non-text attachment was scrubbed...
Name: x265.patch
Type: text/x-patch
Size: 24982 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20161226/6766fb2b/attachment-0001.bin>
More information about the x265-devel
mailing list