X-Git-Url: https://git.piment-noir.org/?p=deb_x265.git;a=blobdiff_plain;f=source%2Fencoder%2Fencoder.cpp;h=14a2200f8b677609be5cc6643e9b9cea8718b505;hp=44e82afe1ed7b1ffcb9079fc154236d456542e82;hb=b53f7c52d8280ab63876efd6eb292c21430ac607;hpb=5c9b45285dd64723ad1dac380b98a7b1f3095674 diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp index 44e82af..14a2200 100644 --- a/source/encoder/encoder.cpp +++ b/source/encoder/encoder.cpp @@ -51,6 +51,8 @@ static const char *summaryCSVHeader = "B count, B ave-QP, B kpbs, B-PSNR Y, B-PSNR U, B-PSNR V, B-SSIM (dB), " "Version\n"; +const char* defaultAnalysisFileName = "x265_analysis.dat"; + using namespace x265; Encoder::Encoder() @@ -78,6 +80,7 @@ Encoder::Encoder() m_buOffsetC = NULL; m_threadPool = 0; m_numThreadLocalData = 0; + m_analysisFile = NULL; } void Encoder::create() @@ -131,7 +134,7 @@ void Encoder::create() int cpuCount = getCpuCount(); if (!p->bEnableWavefront) p->frameNumThreads = X265_MIN(cpuCount, (rows + 1) / 2); - else if (cpuCount > 32) + else if (cpuCount >= 32) p->frameNumThreads = 6; // dual-socket 10-core IvyBridge or higher else if (cpuCount >= 16) p->frameNumThreads = 5; // 8 HT cores, or dual socket @@ -194,13 +197,13 @@ void Encoder::create() m_csvfpt = fopen(m_param->csvfn, "r"); if (m_csvfpt) { - // file already exists, re-open for append + /* file already exists, re-open for append */ fclose(m_csvfpt); m_csvfpt = fopen(m_param->csvfn, "ab"); } else { - // new CSV file, write header + /* new CSV file, write header */ m_csvfpt = fopen(m_param->csvfn, "wb"); if (m_csvfpt) { @@ -218,7 +221,44 @@ void Encoder::create() } } + if (m_frameEncoder) + { + int numRows = (m_param->sourceHeight + g_maxCUSize - 1) / g_maxCUSize; + int numCols = (m_param->sourceWidth + g_maxCUSize - 1) / g_maxCUSize; + for (int i = 0; i < m_param->frameNumThreads; i++) + { + if (!m_frameEncoder[i].init(this, numRows, numCols, i)) + { + x265_log(m_param, X265_LOG_ERROR, "Unable to initialize frame encoder, aborting\n"); + m_aborted = true; + } + } + } + + if (m_param->bEmitHRDSEI) + m_rateControl->initHRD(&m_sps); + if (!m_rateControl->init(&m_sps)) + m_aborted = true; + + m_lookahead->init(); + + if (m_param->analysisMode) + { + const char* name = m_param->analysisFileName; + if (!name) + name = defaultAnalysisFileName; + const char* mode = m_param->analysisMode == X265_ANALYSIS_LOAD ? "rb" : "wb"; + m_analysisFile = fopen(name, mode); + if (!m_analysisFile) + { + x265_log(NULL, X265_LOG_ERROR, "Analysis load/save: failed to open file %s\n", name); + m_aborted = true; + } + } + m_aborted |= parseLambdaFile(m_param); + + m_encodeStartTime = x265_mdate(); } void Encoder::destroy() @@ -270,6 +310,10 @@ void Encoder::destroy() X265_FREE(m_buOffsetY); X265_FREE(m_buOffsetC); + if (m_analysisFile) + fclose(m_analysisFile); + free(m_param->analysisFileName); + free(m_param->csvfn); if (m_csvfpt) fclose(m_csvfpt); free(m_param->rc.statFileName); // alloc'd by strdup @@ -277,29 +321,6 @@ void Encoder::destroy() X265_FREE(m_param); } -void Encoder::init() -{ - if (m_frameEncoder) - { - int numRows = (m_param->sourceHeight + g_maxCUSize - 1) / g_maxCUSize; - int numCols = (m_param->sourceWidth + g_maxCUSize - 1) / g_maxCUSize; - for (int i = 0; i < m_param->frameNumThreads; i++) - { - if (!m_frameEncoder[i].init(this, numRows, numCols, i)) - { - x265_log(m_param, X265_LOG_ERROR, "Unable to initialize frame encoder, aborting\n"); - m_aborted = true; - } - } - } - if (m_param->bEmitHRDSEI) - m_rateControl->initHRD(&m_sps); - if (!m_rateControl->init(&m_sps)) - m_aborted = true; - m_lookahead->init(); - m_encodeStartTime = x265_mdate(); -} - void Encoder::updateVbvPlan(RateControl* rc) { for (int i = 0; i < m_param->frameNumThreads; i++) @@ -367,14 +388,14 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out) * allocated by this top level encoder */ if (m_cuOffsetY) { - inFrame->m_origPicYuv->m_cuOffsetC = m_cuOffsetC; - inFrame->m_origPicYuv->m_cuOffsetY = m_cuOffsetY; - inFrame->m_origPicYuv->m_buOffsetC = m_buOffsetC; - inFrame->m_origPicYuv->m_buOffsetY = m_buOffsetY; + inFrame->m_fencPic->m_cuOffsetC = m_cuOffsetC; + inFrame->m_fencPic->m_cuOffsetY = m_cuOffsetY; + inFrame->m_fencPic->m_buOffsetC = m_buOffsetC; + inFrame->m_fencPic->m_buOffsetY = m_buOffsetY; } else { - if (!inFrame->m_origPicYuv->createOffsets(m_sps)) + if (!inFrame->m_fencPic->createOffsets(m_sps)) { m_aborted = true; x265_log(m_param, X265_LOG_ERROR, "memory allocation failure, aborting encode\n"); @@ -384,10 +405,10 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out) } else { - m_cuOffsetC = inFrame->m_origPicYuv->m_cuOffsetC; - m_cuOffsetY = inFrame->m_origPicYuv->m_cuOffsetY; - m_buOffsetC = inFrame->m_origPicYuv->m_buOffsetC; - m_buOffsetY = inFrame->m_origPicYuv->m_buOffsetY; + m_cuOffsetC = inFrame->m_fencPic->m_cuOffsetC; + m_cuOffsetY = inFrame->m_fencPic->m_cuOffsetY; + m_buOffsetC = inFrame->m_fencPic->m_buOffsetC; + m_buOffsetY = inFrame->m_fencPic->m_buOffsetY; } } } @@ -405,9 +426,8 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out) /* Copy input picture into a Frame and PicYuv, send to lookahead */ inFrame->m_poc = ++m_pocLast; - inFrame->m_origPicYuv->copyFromPicture(*pic_in, m_sps.conformanceWindow.rightOffset, m_sps.conformanceWindow.bottomOffset); - inFrame->m_intraData = pic_in->analysisData.intraData; - inFrame->m_interData = pic_in->analysisData.interData; + inFrame->m_fencPic->copyFromPicture(*pic_in, m_sps.conformanceWindow.rightOffset, m_sps.conformanceWindow.bottomOffset); + inFrame->m_userData = pic_in->userData; inFrame->m_pts = pic_in->pts; inFrame->m_forceqp = pic_in->forceqp; @@ -436,6 +456,23 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out) /* 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; + + /* 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) + { + x265_picture* inputPic = const_cast(pic_in); + /* readAnalysisFile reads analysis data for the frame and allocates memory based on slicetype */ + readAnalysisFile(&inputPic->analysisData, inFrame->m_poc); + inFrame->m_analysisData.poc = inFrame->m_poc; + inFrame->m_analysisData.sliceType = inputPic->analysisData.sliceType; + inFrame->m_analysisData.numCUsInFrame = inputPic->analysisData.numCUsInFrame; + inFrame->m_analysisData.numPartitions = inputPic->analysisData.numPartitions; + inFrame->m_analysisData.interData = inputPic->analysisData.interData; + inFrame->m_analysisData.intraData = inputPic->analysisData.intraData; + sliceType = inputPic->analysisData.sliceType; + } + m_lookahead->addPicture(inFrame, sliceType); m_numDelayedPic++; } @@ -454,9 +491,14 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out) if (outFrame) { Slice *slice = outFrame->m_encData->m_slice; + + /* Free up pic_in->analysisData since it has already been used */ + if (m_param->analysisMode == X265_ANALYSIS_LOAD) + freeAnalysis(&outFrame->m_analysisData); + if (pic_out) { - PicYuv *recpic = outFrame->m_reconPicYuv; + PicYuv *recpic = outFrame->m_reconPic; pic_out->poc = slice->m_poc; pic_out->bitDepth = X265_DEPTH; pic_out->userData = outFrame->m_userData; @@ -484,16 +526,20 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out) pic_out->stride[1] = (int)(recpic->m_strideC * sizeof(pixel)); pic_out->planes[2] = recpic->m_picOrg[2]; pic_out->stride[2] = (int)(recpic->m_strideC * sizeof(pixel)); - } - if (m_param->analysisMode) - { - pic_out->analysisData.interData = outFrame->m_interData; - pic_out->analysisData.intraData = outFrame->m_intraData; - pic_out->analysisData.numCUsInFrame = slice->m_sps->numCUsInFrame; - pic_out->analysisData.numPartitions = slice->m_sps->numPartitions; + /* Dump analysis data from pic_out to file in save mode and free */ + if (m_param->analysisMode == X265_ANALYSIS_SAVE) + { + pic_out->analysisData.poc = pic_out->poc; + pic_out->analysisData.sliceType = pic_out->sliceType; + pic_out->analysisData.numCUsInFrame = outFrame->m_analysisData.numCUsInFrame; + pic_out->analysisData.numPartitions = outFrame->m_analysisData.numPartitions; + pic_out->analysisData.interData = outFrame->m_analysisData.interData; + pic_out->analysisData.intraData = outFrame->m_analysisData.intraData; + writeAnalysisFile(&pic_out->analysisData); + freeAnalysis(&pic_out->analysisData); + } } - if (slice->m_sliceType == P_SLICE) { if (slice->m_weightPredTable[0][0][0].bPresentFlag) @@ -521,8 +567,8 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out) } if (m_aborted) return -1; - finishFrameStats(outFrame, curEncoder, curEncoder->m_accessUnitBits); + // Allow this frame to be recycled if no frame encoders are using it for reference if (!pic_out) { @@ -557,10 +603,10 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out) slice->m_pps = &m_pps; slice->m_maxNumMergeCand = m_param->maxNumMergeCand; slice->m_endCUAddr = slice->realEndAddress(m_sps.numCUsInFrame * NUM_CU_PARTITIONS); - frameEnc->m_reconPicYuv->m_cuOffsetC = m_cuOffsetC; - frameEnc->m_reconPicYuv->m_cuOffsetY = m_cuOffsetY; - frameEnc->m_reconPicYuv->m_buOffsetC = m_buOffsetC; - frameEnc->m_reconPicYuv->m_buOffsetY = m_buOffsetY; + frameEnc->m_reconPic->m_cuOffsetC = m_cuOffsetC; + frameEnc->m_reconPic->m_cuOffsetY = m_cuOffsetY; + frameEnc->m_reconPic->m_buOffsetC = m_buOffsetC; + frameEnc->m_reconPic->m_buOffsetY = m_buOffsetY; } curEncoder->m_rce.encodeOrder = m_encodedFrameNum++; if (m_bframeDelay) @@ -573,6 +619,20 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out) } else frameEnc->m_dts = frameEnc->m_reorderedPts; + /* Allocate analysis data before encode in save mode. This is allocated in frameEnc*/ + if (m_param->analysisMode == X265_ANALYSIS_SAVE) + { + x265_analysis_data* analysis = &frameEnc->m_analysisData; + analysis->poc = frameEnc->m_poc; + analysis->sliceType = frameEnc->m_lowres.sliceType; + 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; + analysis->numCUsInFrame = numCUsInFrame; + analysis->numPartitions = NUM_CU_PARTITIONS; + allocAnalysis(analysis); + } // determine references, setup RPS, etc m_dpb->prepareEncode(frameEnc); @@ -965,7 +1025,7 @@ static const char*digestToString(const unsigned char digest[3][16], int numChar) void Encoder::finishFrameStats(Frame* curFrame, FrameEncoder *curEncoder, uint64_t bits) { - PicYuv* reconPic = curFrame->m_reconPicYuv; + PicYuv* reconPic = curFrame->m_reconPic; //===== calculate PSNR ===== int width = reconPic->m_picWidth - m_sps.conformanceWindow.rightOffset; @@ -1280,8 +1340,8 @@ void Encoder::initPPS(PPS *pps) pps->maxCuDQPDepth = 0; } - pps->chromaCbQpOffset = m_param->cbQpOffset; - pps->chromaCrQpOffset = m_param->crQpOffset; + pps->chromaQpOffset[0] = m_param->cbQpOffset; + pps->chromaQpOffset[1] = m_param->crQpOffset; pps->bConstrainedIntraPred = m_param->bEnableConstrainedIntra; pps->bUseWeightPred = m_param->bEnableWeightedPred; @@ -1290,13 +1350,10 @@ void Encoder::initPPS(PPS *pps) pps->bTransformSkipEnabled = m_param->bEnableTransformSkip; pps->bSignHideEnabled = m_param->bEnableSignHiding; - /* If offsets are ever configured, enable bDeblockingFilterControlPresent and set - * deblockingFilterBetaOffsetDiv2 / deblockingFilterTcOffsetDiv2 */ - bool bDeblockOffsetInPPS = 0; - pps->bDeblockingFilterControlPresent = !m_param->bEnableLoopFilter || bDeblockOffsetInPPS; + pps->bDeblockingFilterControlPresent = !m_param->bEnableLoopFilter || m_param->deblockingFilterBetaOffset || m_param->deblockingFilterTCOffset; pps->bPicDisableDeblockingFilter = !m_param->bEnableLoopFilter; - pps->deblockingFilterBetaOffsetDiv2 = 0; - pps->deblockingFilterTcOffsetDiv2 = 0; + pps->deblockingFilterBetaOffsetDiv2 = m_param->deblockingFilterBetaOffset; + pps->deblockingFilterTcOffsetDiv2 = m_param->deblockingFilterTCOffset; pps->bEntropyCodingSyncEnabled = m_param->bEnableWavefront; } @@ -1330,6 +1387,12 @@ void Encoder::configure(x265_param *p) p->bBPyramid = 0; /* Disable features which are not supported by the current RD level */ + if (p->rdLevel < 5) + { + if (p->bEnableCbfFastMode) /* impossible */ + x265_log(p, X265_LOG_WARNING, "--fast-cbf disabled, requires --rdlevel 5 or higher\n"); + p->bEnableCbfFastMode = 0; + } if (p->rdLevel < 4) { if (p->psyRdoq > 0) /* impossible */ @@ -1458,35 +1521,189 @@ void Encoder::configure(x265_param *p) x265_log(p, X265_LOG_WARNING, "--tune %s should be used if attempting to benchmark %s!\n", s, s); } - //========= set default display window ================================== + /* initialize the conformance window */ m_conformanceWindow.bEnabled = false; m_conformanceWindow.rightOffset = 0; m_conformanceWindow.topOffset = 0; m_conformanceWindow.bottomOffset = 0; m_conformanceWindow.leftOffset = 0; - //======== set pad size if width is not multiple of the minimum CU size ========= - const uint32_t minCUSize = MIN_CU_SIZE; - if (p->sourceWidth & (minCUSize - 1)) + /* set pad size if width is not multiple of the minimum CU size */ + if (p->sourceWidth & (MIN_CU_SIZE - 1)) { - uint32_t rem = p->sourceWidth & (minCUSize - 1); - uint32_t padsize = minCUSize - rem; + uint32_t rem = p->sourceWidth & (MIN_CU_SIZE - 1); + uint32_t padsize = MIN_CU_SIZE - rem; p->sourceWidth += padsize; - /* set the confirmation window offsets */ m_conformanceWindow.bEnabled = true; m_conformanceWindow.rightOffset = padsize; } - //======== set pad size if height is not multiple of the minimum CU size ========= - if (p->sourceHeight & (minCUSize - 1)) + /* set pad size if height is not multiple of the minimum CU size */ + if (p->sourceHeight & (MIN_CU_SIZE - 1)) { - uint32_t rem = p->sourceHeight & (minCUSize - 1); - uint32_t padsize = minCUSize - rem; + uint32_t rem = p->sourceHeight & (MIN_CU_SIZE - 1); + uint32_t padsize = MIN_CU_SIZE - rem; p->sourceHeight += padsize; - /* set the confirmation window offsets */ m_conformanceWindow.bEnabled = true; m_conformanceWindow.bottomOffset = padsize; } + if (p->bDistributeModeAnalysis && p->analysisMode) + { + p->analysisMode = X265_ANALYSIS_OFF; + x265_log(p, X265_LOG_WARNING, "Analysis save and load mode not supported for distributed mode analysis\n"); + } +} + +void Encoder::allocAnalysis(x265_analysis_data* analysis) +{ + if (analysis->sliceType == X265_TYPE_IDR || analysis->sliceType == X265_TYPE_I) + { + analysis_intra_data *intraData = (analysis_intra_data*)analysis->intraData; + CHECKED_MALLOC_ZERO(intraData, analysis_intra_data, 1); + CHECKED_MALLOC(intraData->depth, uint8_t, analysis->numPartitions * analysis->numCUsInFrame); + CHECKED_MALLOC(intraData->modes, uint8_t, analysis->numPartitions * analysis->numCUsInFrame); + CHECKED_MALLOC(intraData->partSizes, char, analysis->numPartitions * analysis->numCUsInFrame); + analysis->intraData = intraData; + } + else + { + analysis_inter_data *interData = (analysis_inter_data*)analysis->interData; + CHECKED_MALLOC(interData, analysis_inter_data, analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU * 2); + analysis->interData = interData; + } + return; + +fail: + freeAnalysis(analysis); + m_aborted = true; +} + +void Encoder::freeAnalysis(x265_analysis_data* analysis) +{ + if (analysis->sliceType == X265_TYPE_IDR || analysis->sliceType == X265_TYPE_I) + { + X265_FREE(((analysis_intra_data*)analysis->intraData)->depth); + X265_FREE(((analysis_intra_data*)analysis->intraData)->modes); + X265_FREE(((analysis_intra_data*)analysis->intraData)->partSizes); + X265_FREE(analysis->intraData); + } + else + X265_FREE(analysis->interData); +} + +void Encoder::readAnalysisFile(x265_analysis_data* analysis, int curPoc) +{ + +#define X265_FREAD(val, size, readSize, fileOffset)\ + if (fread(val, size, readSize, fileOffset) != readSize)\ + {\ + x265_log(NULL, X265_LOG_ERROR, "Error reading analysis data\n");\ + freeAnalysis(analysis);\ + m_aborted = true;\ + return;\ + }\ + + static uint64_t consumedBytes = 0; + static uint64_t totalConsumedBytes = 0; + fseeko(m_analysisFile, totalConsumedBytes, SEEK_SET); + + int poc; uint32_t frameRecordSize; + X265_FREAD(&frameRecordSize, 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(&poc, sizeof(int), 1, m_analysisFile); + } + + if (poc != curPoc || feof(m_analysisFile)) + { + x265_log(NULL, X265_LOG_WARNING, "Error reading analysis data: Cannot find POC %d\n", curPoc); + freeAnalysis(analysis); + return; + } + + /* Now arrived at the right frame, read the record */ + analysis->poc = poc; + analysis->frameRecordSize = frameRecordSize; + X265_FREAD(&analysis->sliceType, sizeof(int), 1, m_analysisFile); + X265_FREAD(&analysis->numCUsInFrame, sizeof(int), 1, m_analysisFile); + X265_FREAD(&analysis->numPartitions, sizeof(int), 1, m_analysisFile); + + /* Memory is allocated for inter and intra analysis data based on the slicetype */ + allocAnalysis(analysis); + + if (analysis->sliceType == X265_TYPE_IDR || analysis->sliceType == X265_TYPE_I) + { + X265_FREAD(((analysis_intra_data *)analysis->intraData)->depth, sizeof(uint8_t), analysis->numCUsInFrame * analysis->numPartitions, m_analysisFile); + X265_FREAD(((analysis_intra_data *)analysis->intraData)->modes, sizeof(uint8_t), analysis->numCUsInFrame * analysis->numPartitions, m_analysisFile); + X265_FREAD(((analysis_intra_data *)analysis->intraData)->partSizes, sizeof(char), analysis->numCUsInFrame * analysis->numPartitions, m_analysisFile); + analysis->sliceType = X265_TYPE_I; + consumedBytes += frameRecordSize; + } + else if (analysis->sliceType == X265_TYPE_P) + { + X265_FREAD(analysis->interData, sizeof(analysis_inter_data), analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU, m_analysisFile); + consumedBytes += frameRecordSize; + totalConsumedBytes = consumedBytes; + } + else + { + X265_FREAD(analysis->interData, sizeof(analysis_inter_data), analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU * 2, m_analysisFile); + consumedBytes += frameRecordSize; + } +#undef X265_FREAD +} + +void Encoder::writeAnalysisFile(x265_analysis_data* analysis) +{ + +#define X265_FWRITE(val, size, writeSize, fileOffset)\ + if (fwrite(val, size, writeSize, fileOffset) < writeSize)\ + {\ + x265_log(NULL, X265_LOG_ERROR, "Error writing analysis data\n");\ + freeAnalysis(analysis);\ + m_aborted = true;\ + return;\ + }\ + + /* calculate frameRecordSize */ + analysis->frameRecordSize = sizeof(analysis->frameRecordSize) + sizeof(analysis->poc) + sizeof(analysis->sliceType) + + sizeof(analysis->numCUsInFrame) + sizeof(analysis->numPartitions); + if (analysis->sliceType == X265_TYPE_IDR || analysis->sliceType == X265_TYPE_I) + analysis->frameRecordSize += sizeof(uint8_t) * analysis->numCUsInFrame * analysis->numPartitions * 3; + else if (analysis->sliceType == X265_TYPE_P) + analysis->frameRecordSize += sizeof(analysis_inter_data) * analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU; + else + analysis->frameRecordSize += sizeof(analysis_inter_data) * analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU * 2; + + X265_FWRITE(&analysis->frameRecordSize, sizeof(uint32_t), 1, m_analysisFile); + X265_FWRITE(&analysis->poc, sizeof(int), 1, m_analysisFile); + X265_FWRITE(&analysis->sliceType, sizeof(int), 1, m_analysisFile); + X265_FWRITE(&analysis->numCUsInFrame, sizeof(int), 1, m_analysisFile); + X265_FWRITE(&analysis->numPartitions, sizeof(int), 1, m_analysisFile); + + if (analysis->sliceType == X265_TYPE_IDR || analysis->sliceType == X265_TYPE_I) + { + X265_FWRITE(((analysis_intra_data*)analysis->intraData)->depth, sizeof(uint8_t), analysis->numCUsInFrame * analysis->numPartitions, m_analysisFile); + X265_FWRITE(((analysis_intra_data*)analysis->intraData)->modes, sizeof(uint8_t), analysis->numCUsInFrame * analysis->numPartitions, m_analysisFile); + X265_FWRITE(((analysis_intra_data*)analysis->intraData)->partSizes, sizeof(char), analysis->numCUsInFrame * analysis->numPartitions, m_analysisFile); + } + else if (analysis->sliceType == X265_TYPE_P) + { + X265_FWRITE(analysis->interData, sizeof(analysis_inter_data), analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU, m_analysisFile); + } + else + { + X265_FWRITE(analysis->interData, sizeof(analysis_inter_data), analysis->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU * 2, m_analysisFile); + } +#undef X265_FWRITE }