# HG changeset patch # User Santhoshini Sekar # Date 1493009037 -19800 # Mon Apr 24 10:13:57 2017 +0530 # Node ID 6a9eb27b2b0d1a716911bf19136ceb653a51270b # Parent 7ecd263f6d43966df308d53029a67cfda03bb185 Add API to read CTU Information
diff -r 7ecd263f6d43 -r 6a9eb27b2b0d doc/reST/api.rst --- a/doc/reST/api.rst Tue May 09 12:43:04 2017 +0530 +++ b/doc/reST/api.rst Mon Apr 24 10:13:57 2017 +0530 @@ -192,6 +192,12 @@ * presets is not recommended without a more fine-grained breakdown of * parameters to take this into account. */ int x265_encoder_reconfig(x265_encoder *, x265_param *); +**x265_encoder_ctu_info** + /* x265_encoder_ctu_info: + * Copy CTU information such as ctu address and ctu partition structure of all + * CTUs in each frame. The function is invoked only if "--ctu-info" is enabled and + * the encoder will wait for this copy to complete if enabled. + */ Pictures ======== diff -r 7ecd263f6d43 -r 6a9eb27b2b0d doc/reST/cli.rst --- a/doc/reST/cli.rst Tue May 09 12:43:04 2017 +0530 +++ b/doc/reST/cli.rst Mon Apr 24 10:13:57 2017 +0530 @@ -1221,7 +1221,16 @@ intra cost of a frame used in scenecut detection. For example, a value of 5 indicates, if the inter cost of a frame is greater than or equal to 95 percent of the intra cost of the frame, then detect this frame as scenecut. Values between 5 and 15 are recommended. Default 5. - + +.. option:: --ctu-info <0, 1, 2, 4, 6> + + This value enables receiving CTU information asynchronously and determine reaction to the CTU information. Default 0. + 1: force the partitions if CTU information is present. + 2: functionality of (1) and reduce qp if CTU information has changed. + 4: functionality of (1) and force Inter modes when CTU Information has changed, merge/skip otherwise. + This option should be enabled only when planning to invoke the API function x265_encoder_ctu_info to copy ctu-info asynchronously. + If enabled without calling the API function, the encoder will wait indefinitely. + .. option:: --intra-refresh Enables Periodic Intra Refresh(PIR) instead of keyframe insertion. diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/CMakeLists.txt --- a/source/CMakeLists.txt Tue May 09 12:43:04 2017 +0530 +++ b/source/CMakeLists.txt Mon Apr 24 10:13:57 2017 +0530 @@ -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 116) +set(X265_BUILD 117) configure_file("${PROJECT_SOURCE_DIR}/x265.def.in" "${PROJECT_BINARY_DIR}/x265.def") configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in" diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/common/frame.cpp --- a/source/common/frame.cpp Tue May 09 12:43:04 2017 +0530 +++ b/source/common/frame.cpp Mon Apr 24 10:13:57 2017 +0530 @@ -48,6 +48,8 @@ m_rcData = NULL; m_encodeStartTime = 0; m_reconfigureRc = false; + m_ctuInfo = NULL; + m_prevCtuInfoChange = NULL; } bool Frame::create(x265_param *param, float* quantOffsets) @@ -166,6 +168,23 @@ delete[] m_userSEI.payloads; } + if (m_ctuInfo) + { + 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; + for (uint32_t i = 0; i < numCUsInFrame; i++) + { + X265_FREE((*m_ctuInfo + i)->ctuInfo); + (*m_ctuInfo + i)->ctuInfo = NULL; + } + X265_FREE(*m_ctuInfo); + *m_ctuInfo = NULL; + X265_FREE(m_ctuInfo); + m_ctuInfo = NULL; + X265_FREE(m_prevCtuInfoChange); + m_prevCtuInfoChange = NULL; + } m_lowres.destroy(); X265_FREE(m_rcData); } diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/common/frame.h --- a/source/common/frame.h Tue May 09 12:43:04 2017 +0530 +++ b/source/common/frame.h Mon Apr 24 10:13:57 2017 +0530 @@ -108,6 +108,9 @@ x265_analysis_2Pass m_analysis2Pass; RcStats* m_rcData; + x265_ctu_info_t** m_ctuInfo; + Event m_copied; + int* m_prevCtuInfoChange; int64_t m_encodeStartTime; Frame(); diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/common/param.cpp --- a/source/common/param.cpp Tue May 09 12:43:04 2017 +0530 +++ b/source/common/param.cpp Mon Apr 24 10:13:57 2017 +0530 @@ -275,6 +275,7 @@ param->toneMapFile = NULL; param->bDhdr10opt = 0; + param->bCTUInfo = 0; } int x265_param_default_preset(x265_param* param, const char* preset, const char* tune) @@ -954,6 +955,7 @@ OPT("limit-sao") p->bLimitSAO = atobool(value); OPT("dhdr10-info") p->toneMapFile = strdup(value); OPT("dhdr10-opt") p->bDhdr10opt = atobool(value); + OPT("ctu-info") p->bCTUInfo = atoi(value); else return X265_PARAM_BAD_NAME; } @@ -1294,6 +1296,8 @@ "qpmin exceeds supported range (0 to 69)"); CHECK(param->log2MaxPocLsb < 4 || param->log2MaxPocLsb > 16, "Supported range for log2MaxPocLsb is 4 to 16"); + CHECK(param->bCTUInfo < 0 || (param->bCTUInfo != 0 && param->bCTUInfo != 1 && param->bCTUInfo != 2 && param->bCTUInfo != 4 && param->bCTUInfo != 6) || param->bCTUInfo > 6, + "Supported values for bCTUInfo are 0, 1, 2, 4, 6"); #if !X86_64 CHECK(param->searchMethod == X265_SEA && (param->sourceWidth > 840 || param->sourceHeight > 480), "SEA motion search does not support resolutions greater than 480p in 32 bit build"); @@ -1457,6 +1461,7 @@ TOOLOPT(param->bEnableStrongIntraSmoothing, "strong-intra-smoothing"); TOOLVAL(param->lookaheadSlices, "lslices=%d"); TOOLVAL(param->lookaheadThreads, "lthreads=%d") + TOOLVAL(param->bCTUInfo, "ctu-info=%d"); if (param->maxSlices > 1) TOOLVAL(param->maxSlices, "slices=%d"); if (param->bEnableLoopFilter) @@ -1670,6 +1675,7 @@ BOOL(p->bDhdr10opt, "dhdr10-opt"); s += sprintf(s, " refine-level=%d", p->analysisRefineLevel); BOOL(p->bLimitSAO, "limit-sao"); + s += sprintf(s, " ctu-info=%d", p->bCTUInfo); #undef BOOL return buf; } diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/encoder/api.cpp --- a/source/encoder/api.cpp Tue May 09 12:43:04 2017 +0530 +++ b/source/encoder/api.cpp Mon Apr 24 10:13:57 2017 +0530 @@ -295,6 +295,14 @@ encoder->m_bQueuedIntraRefresh = 1; return 0; } +int x265_encoder_ctu_info(x265_encoder *enc, int poc, x265_ctu_info_t** ctu) +{ + if (!ctu || !enc) + return -1; + Encoder* encoder = static_cast<Encoder*>(enc); + encoder->copyCtuInfo(ctu, poc); + return 0; +} void x265_cleanup(void) { @@ -372,6 +380,7 @@ sizeof(x265_frame_stats), &x265_encoder_intra_refresh, + &x265_encoder_ctu_info, }; typedef const x265_api* (*api_get_func)(int bitDepth); diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/encoder/dpb.cpp --- a/source/encoder/dpb.cpp Tue May 09 12:43:04 2017 +0530 +++ b/source/encoder/dpb.cpp Mon Apr 24 10:13:57 2017 +0530 @@ -105,6 +105,23 @@ } } + if (curFrame->m_ctuInfo != NULL) + { + uint32_t widthInCU = (curFrame->m_param->sourceWidth + g_maxCUSize - 1) >> g_maxLog2CUSize; + uint32_t heightInCU = (curFrame->m_param->sourceHeight + g_maxCUSize - 1) >> g_maxLog2CUSize; + uint32_t numCUsInFrame = widthInCU * heightInCU; + for (uint32_t i = 0; i < numCUsInFrame; i++) + { + X265_FREE((*curFrame->m_ctuInfo + i)->ctuInfo); + (*curFrame->m_ctuInfo + i)->ctuInfo = NULL; + } + X265_FREE(*curFrame->m_ctuInfo); + *(curFrame->m_ctuInfo) = NULL; + X265_FREE(curFrame->m_ctuInfo); + curFrame->m_ctuInfo = NULL; + X265_FREE(curFrame->m_prevCtuInfoChange); + curFrame->m_prevCtuInfoChange = NULL; + } curFrame->m_encData = NULL; curFrame->m_reconPic = NULL; } diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/encoder/encoder.cpp --- a/source/encoder/encoder.cpp Tue May 09 12:43:04 2017 +0530 +++ b/source/encoder/encoder.cpp Mon Apr 24 10:13:57 2017 +0530 @@ -1157,6 +1157,120 @@ return x265_check_params(encParam); } +void Encoder::copyCtuInfo(x265_ctu_info_t** frameCtuInfo, int poc) +{ + uint32_t widthInCU = (m_param->sourceWidth + g_maxCUSize - 1) >> g_maxLog2CUSize; + uint32_t heightInCU = (m_param->sourceHeight + g_maxCUSize - 1) >> g_maxLog2CUSize; + Frame* curFrame; + Frame* prevFrame = NULL; + int32_t* frameCTU; + uint32_t numCUsInFrame = widthInCU * heightInCU; + uint32_t maxNum8x8Partitions = 64; + bool copied = false; + do + { + curFrame = m_lookahead->m_inputQueue.getPOC(poc); + if (!curFrame) + curFrame = m_lookahead->m_outputQueue.getPOC(poc); + + if (poc > 0) + { + prevFrame = m_lookahead->m_inputQueue.getPOC(poc - 1); + if (!prevFrame) + prevFrame = m_lookahead->m_outputQueue.getPOC(poc - 1); + if (!prevFrame) + { + FrameEncoder* prevEncoder; + for (int i = 0; i < m_param->frameNumThreads; i++) + { + prevEncoder = m_frameEncoder[i]; + prevFrame = prevEncoder->m_frame; + if (prevFrame && (prevEncoder->m_frame->m_poc == poc - 1)) + { + prevFrame = prevEncoder->m_frame; + break; + } + } + } + } + x265_ctu_info_t* ctuTemp, *prevCtuTemp; + if (curFrame) + { + if (!curFrame->m_ctuInfo) + CHECKED_MALLOC(curFrame->m_ctuInfo, x265_ctu_info_t*, 1); + CHECKED_MALLOC(*curFrame->m_ctuInfo, x265_ctu_info_t, numCUsInFrame); + CHECKED_MALLOC_ZERO(curFrame->m_prevCtuInfoChange, int, numCUsInFrame * maxNum8x8Partitions); + for (uint32_t i = 0; i < numCUsInFrame; i++) + { + ctuTemp = *curFrame->m_ctuInfo + i; + CHECKED_MALLOC(frameCTU, int32_t, maxNum8x8Partitions); + ctuTemp->ctuInfo = (int32_t*)frameCTU; + ctuTemp->ctuAddress = frameCtuInfo[i]->ctuAddress; + memcpy(ctuTemp->ctuPartitions, frameCtuInfo[i]->ctuPartitions, sizeof(int32_t) * maxNum8x8Partitions); + memcpy(ctuTemp->ctuInfo, frameCtuInfo[i]->ctuInfo, sizeof(int32_t) * maxNum8x8Partitions); + if (prevFrame && curFrame->m_poc > 1) + { + prevCtuTemp = *prevFrame->m_ctuInfo + i; + for (uint32_t j = 0; j < maxNum8x8Partitions; j++) + curFrame->m_prevCtuInfoChange[i * maxNum8x8Partitions + j] = (*((int32_t *)prevCtuTemp->ctuInfo + j) == 2) ? (poc - 1) : prevFrame->m_prevCtuInfoChange[i * maxNum8x8Partitions + j]; + } + } + copied = true; + curFrame->m_copied.trigger(); + } + else + { + FrameEncoder* curEncoder; + for (int i = 0; i < m_param->frameNumThreads; i++) + { + curEncoder = m_frameEncoder[i]; + curFrame = curEncoder->m_frame; + if (curFrame) + { + if (poc == curFrame->m_poc) + { + if (!curFrame->m_ctuInfo) + CHECKED_MALLOC(curFrame->m_ctuInfo, x265_ctu_info_t*, 1); + CHECKED_MALLOC(*curFrame->m_ctuInfo, x265_ctu_info_t, numCUsInFrame); + CHECKED_MALLOC_ZERO(curFrame->m_prevCtuInfoChange, int, numCUsInFrame * maxNum8x8Partitions); + for (uint32_t l = 0; l < numCUsInFrame; l++) + { + ctuTemp = *curFrame->m_ctuInfo + l; + CHECKED_MALLOC(frameCTU, int32_t, maxNum8x8Partitions); + ctuTemp->ctuInfo = (int32_t*)frameCTU; + ctuTemp->ctuAddress = frameCtuInfo[l]->ctuAddress; + memcpy(ctuTemp->ctuPartitions, frameCtuInfo[l]->ctuPartitions, sizeof(int32_t) * maxNum8x8Partitions); + memcpy(ctuTemp->ctuInfo, frameCtuInfo[l]->ctuInfo, sizeof(int32_t) * maxNum8x8Partitions); + if (prevFrame && curFrame->m_poc > 1) + { + prevCtuTemp = *prevFrame->m_ctuInfo + l; + for (uint32_t j = 0; j < maxNum8x8Partitions; j++) + curFrame->m_prevCtuInfoChange[l * maxNum8x8Partitions + j] = (*((int32_t *)prevCtuTemp->ctuInfo + j) == CTU_INFO_CHANGE) ? (poc - 1) : prevFrame->m_prevCtuInfoChange[l * maxNum8x8Partitions + j]; + } + } + copied = true; + curFrame->m_copied.trigger(); + break; + } + } + } + } + } while (!copied); + return; +fail: + for (uint32_t i = 0; i < numCUsInFrame; i++) + { + X265_FREE((*curFrame->m_ctuInfo + i)->ctuInfo); + (*curFrame->m_ctuInfo + i)->ctuInfo = NULL; + } + X265_FREE(*curFrame->m_ctuInfo); + *(curFrame->m_ctuInfo) = NULL; + X265_FREE(curFrame->m_ctuInfo); + curFrame->m_ctuInfo = NULL; + X265_FREE(curFrame->m_prevCtuInfoChange); + curFrame->m_prevCtuInfoChange = NULL; +} + void EncStats::addPsnr(double psnrY, double psnrU, double psnrV) { m_psnrSumY += psnrY; diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/encoder/encoder.h --- a/source/encoder/encoder.h Tue May 09 12:43:04 2017 +0530 +++ b/source/encoder/encoder.h Mon Apr 24 10:13:57 2017 +0530 @@ -199,6 +199,8 @@ int reconfigureParam(x265_param* encParam, x265_param* param); + void copyCtuInfo(x265_ctu_info_t** frameCtuInfo, int poc); + void getStreamHeaders(NALList& list, Entropy& sbacCoder, Bitstream& bs); void fetchStats(x265_stats* stats, size_t statsSizeBytes); diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/encoder/frameencoder.cpp --- a/source/encoder/frameencoder.cpp Tue May 09 12:43:04 2017 +0530 +++ b/source/encoder/frameencoder.cpp Mon Apr 24 10:13:57 2017 +0530 @@ -295,6 +295,11 @@ while (m_threadActive) { + if (m_param->bCTUInfo) + { + while (!m_frame->m_ctuInfo) + m_frame->m_copied.wait(); + } compressFrame(); m_done.trigger(); /* FrameEncoder::getEncodedPicture() blocks for this event */ m_enable.wait(); diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/x265.h --- a/source/x265.h Tue May 09 12:43:04 2017 +0530 +++ b/source/x265.h Mon Apr 24 10:13:57 2017 +0530 @@ -160,6 +160,20 @@ x265_cu_stats cuStats; double totalFrameTime; } x265_frame_stats; +typedef struct x265_ctu_info_t +{ + int32_t ctuAddress; + int32_t ctuPartitions[64]; + void* ctuInfo; +} x265_ctu_info_t; + +typedef enum +{ + NO_CTU_INFO = 0, + HAS_CTU_INFO = 1, + CTU_INFO_CHANGE = 2, +}CTUInfo; + /* Arbitrary User SEI * Payload size is in bytes and the payload pointer must be non-NULL. @@ -1391,6 +1405,9 @@ /* Insert tone mapping information only for IDR frames and when the * tone mapping information changes. */ int bDhdr10opt; + + /* Determine how x265 react to the content information recieved through the API */ + int bCTUInfo; } x265_param; /* x265_param_alloc: * Allocates an x265_param instance. The returned param structure is not @@ -1581,6 +1598,12 @@ int x265_encoder_intra_refresh(x265_encoder *); +/* x265_encoder_ctu_info: + * Copy CTU information such as ctu address and ctu partition structure of all + * CTUs in each frame. The function is invoked only if "--ctu-info" is enabled and + * the encoder will wait for this copy to complete if enabled. + */ +int x265_encoder_ctu_info(x265_encoder *, int poc, x265_ctu_info_t** ctu); /* x265_cleanup: * release library static allocations, reset configured CTU size */ void x265_cleanup(void); @@ -1629,6 +1652,7 @@ int sizeof_frame_stats; /* sizeof(x265_frame_stats) */ int (*encoder_intra_refresh)(x265_encoder*); + int (*encoder_ctu_info)(x265_encoder*, int, x265_ctu_info_t**); /* add new pointers to the end, or increment X265_MAJOR_VERSION */ } x265_api; diff -r 7ecd263f6d43 -r 6a9eb27b2b0d source/x265cli.h --- a/source/x265cli.h Tue May 09 12:43:04 2017 +0530 +++ b/source/x265cli.h Mon Apr 24 10:13:57 2017 +0530 @@ -122,6 +122,7 @@ { "scenecut", required_argument, NULL, 0 }, { "no-scenecut", no_argument, NULL, 0 }, { "scenecut-bias", required_argument, NULL, 0 }, + { "ctu-info", required_argument, NULL, 0 }, { "intra-refresh", no_argument, NULL, 0 }, { "rc-lookahead", required_argument, NULL, 0 }, { "lookahead-slices", required_argument, NULL, 0 }, @@ -367,6 +368,11 @@ H1(" --[no-]tskip-fast Enable fast intra transform skipping. Default %s\n", OPT(param->bEnableTSkipFast)); H1(" --nr-intra <integer> An integer value in range of 0 to 2000, which denotes strength of noise reduction in intra CUs. Default 0\n"); H1(" --nr-inter <integer> An integer value in range of 0 to 2000, which denotes strength of noise reduction in inter CUs. Default 0\n"); + H0(" --ctu-info <integer> Enable receiving ctu information asynchronously and determine reaction to the CTU information (0, 1, 2, 4, 6) Default 0\n" + " - 1: force the partitions if CTU information is present\n" + " - 2: functionality of (1) and reduce qp if CTU information has changed\n" + " - 4: functionality of (1) and force Inter modes when CTU Information has changed, merge/skip otherwise\n" + " Enable this option only when planning to invoke the API function x265_encoder_ctu_info to copy ctu-info asynchronously\n"); H0("\nCoding tools:\n"); H0("-w/--[no-]weightp Enable weighted prediction in P slices. Default %s\n", OPT(param->bEnableWeightedPred)); H0(" --[no-]weightb Enable weighted prediction in B slices. Default %s\n", OPT(param->bEnableWeightedBiPred)); _______________________________________________ x265-devel mailing list x265-devel@videolan.org https://mailman.videolan.org/listinfo/x265-devel