[x265] [PATCH 1 of 2] app: Add definitions for ABR (Adaptive Bit-Rate) encoding
Aruna Matheswaran
aruna at multicorewareinc.com
Mon Apr 13 17:33:56 CEST 2020
On Mon, Apr 13, 2020 at 5:31 PM Kavitha Sampath <
kavitha at multicorewareinc.com> wrote:
>
>
> On Tue, Mar 31, 2020 at 6:22 PM Aruna Matheswaran <
> aruna at multicorewareinc.com> wrote:
>
>> # HG changeset patch
>> # User Aruna Matheswaran <aruna at multicorewareinc.com>
>> # Date 1582715233 -19800
>> # Wed Feb 26 16:37:13 2020 +0530
>> # Node ID 3eccfeafc04000b68c25ab52c43741a1acac21c8
>> # Parent 7ebf4b9369b3037370a73be24f5f1bd93cce7822
>> app: Add definitions for ABR (Adaptive Bit-Rate) encoding
>>
>> diff -r 7ebf4b9369b3 -r 3eccfeafc040 source/CMakeLists.txt
>> --- a/source/CMakeLists.txt Wed Feb 26 14:40:35 2020 +0530
>> +++ b/source/CMakeLists.txt Wed Feb 26 16:37:13 2020 +0530
>> @@ -745,16 +745,16 @@
>> # Xcode seems unable to link the CLI with libs, so link as one
>> targget
>> if(ENABLE_HDR10_PLUS)
>> add_executable(cli ../COPYING ${InputFiles} ${OutputFiles}
>> ${GETOPT}
>> - x265.cpp x265.h x265cli.cpp x265cli.h
>> + x265.cpp x265.h x265cli.cpp x265cli.h
>> abrEncApp.cpp abrEncApp.h
>> $<TARGET_OBJECTS:encoder>
>> $<TARGET_OBJECTS:common> $<TARGET_OBJECTS:dynamicHDR10> ${ASM_OBJS})
>> else()
>> add_executable(cli ../COPYING ${InputFiles} ${OutputFiles}
>> ${GETOPT}
>> - x265.cpp x265.h x265cli.cpp x265cli.h
>> + x265.cpp x265.h x265cli.cpp x265cli.h
>> abrEncApp.cpp abrEncApp.h
>> $<TARGET_OBJECTS:encoder>
>> $<TARGET_OBJECTS:common> ${ASM_OBJS})
>> endif()
>> else()
>> add_executable(cli ../COPYING ${InputFiles} ${OutputFiles}
>> ${GETOPT} ${X265_RC_FILE}
>> - ${ExportDefs} x265.cpp x265.h x265cli.cpp
>> x265cli.h)
>> + ${ExportDefs} x265.cpp x265.h x265cli.cpp
>> x265cli.h abrEncApp.cpp abrEncApp.h)
>> if(WIN32 OR NOT ENABLE_SHARED OR INTEL_CXX)
>> # The CLI cannot link to the shared library on Windows, it
>> # requires internal APIs not exported from the DLL
>> diff -r 7ebf4b9369b3 -r 3eccfeafc040 source/abrEncApp.cpp
>> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
>> +++ b/source/abrEncApp.cpp Wed Feb 26 16:37:13 2020 +0530
>> @@ -0,0 +1,1150 @@
>>
>> +/*****************************************************************************
>> +* Copyright (C) 2013-2020 MulticoreWare, Inc
>> +*
>> +* Authors: Pooja Venkatesan <pooja at multicorewareinc.com>
>> +* Aruna Matheswaran <aruna at multicorewareinc.com>
>> +*
>> +* This program is free software; you can redistribute it and/or modify
>> +* it under the terms of the GNU General Public License as published by
>> +* the Free Software Foundation; either version 2 of the License, or
>> +* (at your option) any later version.
>> +*
>> +* This program is distributed in the hope that it will be useful,
>> +* but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> +* GNU General Public License for more details.
>> +*
>> +* You should have received a copy of the GNU General Public License
>> +* along with this program; if not, write to the Free Software
>> +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111,
>> USA.
>> +*
>> +* This program is also available under a commercial proprietary license.
>> +* For more information, contact us at license @ x265.com.
>>
>> +*****************************************************************************/
>> +
>> +#include "abrEncApp.h"
>> +#include "mv.h"
>> +#include "slice.h"
>> +#include "param.h"
>> +
>> +#include <signal.h>
>> +#include <errno.h>
>> +
>> +#include <queue>
>> +
>> +using namespace X265_NS;
>> +
>> +/* Ctrl-C handler */
>> +static volatile sig_atomic_t b_ctrl_c /* = 0 */;
>> +static void sigint_handler(int)
>> +{
>> + b_ctrl_c = 1;
>> +}
>> +
>> +#define START_CODE 0x00000001
>> +#define START_CODE_BYTES 4
>> +
>> +/* Parse the RPU file and extract the RPU corresponding to the current
>> picture
>> +* and fill the rpu field of the input picture */
>> +static int rpuParser(x265_picture * pic, FILE * ptr)
>> +{
>> + uint8_t byteVal;
>> + uint32_t code = 0;
>> + int bytesRead = 0;
>> + pic->rpu.payloadSize = 0;
>> +
>> + if (!pic->pts)
>> + {
>> + while (bytesRead++ < 4 && fread(&byteVal, sizeof(uint8_t), 1,
>> ptr))
>> + code = (code << 8) | byteVal;
>> +
>> + if (code != START_CODE)
>> + {
>> + x265_log(NULL, X265_LOG_ERROR, "Invalid Dolby Vision RPU
>> startcode in POC %d\n", pic->pts);
>> + return 1;
>> + }
>> + }
>> +
>> + bytesRead = 0;
>> + while (fread(&byteVal, sizeof(uint8_t), 1, ptr))
>> + {
>> + code = (code << 8) | byteVal;
>> + if (bytesRead++ < 3)
>> + continue;
>> + if (bytesRead >= 1024)
>> + {
>> + x265_log(NULL, X265_LOG_ERROR, "Invalid Dolby Vision RPU
>> size in POC %d\n", pic->pts);
>> + return 1;
>> + }
>> +
>> + if (code != START_CODE)
>> + pic->rpu.payload[pic->rpu.payloadSize++] = (code >> (3 * 8))
>> & 0xFF;
>> + else
>> + return 0;
>> + }
>> +
>> + int ShiftBytes = START_CODE_BYTES - (bytesRead -
>> pic->rpu.payloadSize);
>> + int bytesLeft = bytesRead - pic->rpu.payloadSize;
>> + code = (code << ShiftBytes * 8);
>> + for (int i = 0; i < bytesLeft; i++)
>> + {
>> + pic->rpu.payload[pic->rpu.payloadSize++] = (code >> (3 * 8)) &
>> 0xFF;
>> + code = (code << 8);
>> + }
>> + if (!pic->rpu.payloadSize)
>> + x265_log(NULL, X265_LOG_WARNING, "Dolby Vision RPU not found for
>> POC %d\n", pic->pts);
>> + return 0;
>> +}
>>
> [KS] I see that parsing of most of CLI specified files happen are defined
> in CLIOptions except RPU parsing of dolby? Is there any reason?
>
[AM] No specific reason for keeping this as a utility function. As you said
it makes sense to group CLI file operations in CLIoptions.
I'll move this to CLIoptions.
> +
>> +
>> +namespace X265_NS {
>> + // private namespace
>> +#define X265_INPUT_QUEUE_SIZE 250
>> +
>> + AbrEncoder::AbrEncoder(CLIOptions cliopt[], uint8_t numEncodes, int
>> &ret)
>> + {
>> + m_numEncodes = numEncodes;
>> + m_numActiveEncodes.set(numEncodes);
>> + m_queueSize = X265_INPUT_QUEUE_SIZE;
>>
> [KS] If queueSize is constant, is it necessary to define it as an
> ABrEncoder member?
> [AM] There are plans to make this queueSize configurable in future. Hence,
> I introduced this option.
>
>> + m_passEnc = X265_MALLOC(PassEncoder*, m_numEncodes);
>> +
>> + for (uint8_t i = 0; i < m_numEncodes; i++)
>> + {
>> + m_passEnc[i] = new PassEncoder(i, cliopt[i], this);
>> + if (!m_passEnc[i])
>> + {
>> + x265_log(NULL, X265_LOG_ERROR, "Unable to allocate
>> memory for passEncoder\n");
>> + ret = 4;
>> + }
>> + m_passEnc[i]->init(ret);
>> + }
>> +
>> + if (!allocBuffers())
>> + {
>> + x265_log(NULL, X265_LOG_ERROR, "Unable to allocate memory
>> for buffers\n");
>> + ret = 4;
>> + }
>>
> [KS] Sorry for not noticing that ret defined in main is reset here. Please
> ignore my previous comment.
>
[AM] No problem
> +
>> + /* start passEncoder worker threads */
>> + for (uint8_t pass = 0; pass < m_numEncodes; pass++)
>> + m_passEnc[pass]->startThreads();
>> + }
>> +
>> + bool AbrEncoder::allocBuffers()
>> + {
>> + m_inputPicBuffer = X265_MALLOC(x265_picture**, m_numEncodes);
>> + m_analysisBuffer = X265_MALLOC(x265_analysis_data*,
>> m_numEncodes);
>> +
>> + m_picWriteCnt = new ThreadSafeInteger[m_numEncodes];
>> + m_picReadCnt = new ThreadSafeInteger[m_numEncodes];
>> + m_analysisWriteCnt = new ThreadSafeInteger[m_numEncodes];
>> + m_analysisReadCnt = new ThreadSafeInteger[m_numEncodes];
>> +
>> + m_picIdxReadCnt = X265_MALLOC(ThreadSafeInteger*, m_numEncodes);
>> + m_analysisWrite = X265_MALLOC(ThreadSafeInteger*, m_numEncodes);
>> + m_analysisRead = X265_MALLOC(ThreadSafeInteger*, m_numEncodes);
>> + m_readFlag = X265_MALLOC(int*, m_numEncodes);
>> +
>> + for (uint8_t pass = 0; pass < m_numEncodes; pass++)
>> + {
>> + m_inputPicBuffer[pass] = X265_MALLOC(x265_picture*,
>> m_queueSize);
>> + for (uint32_t idx = 0; idx < m_queueSize; idx++)
>> + {
>> + m_inputPicBuffer[pass][idx] = NULL;
>> + }
>> + m_analysisBuffer[pass] = X265_MALLOC(x265_analysis_data,
>> m_queueSize);
>> + m_picIdxReadCnt[pass] = new ThreadSafeInteger[m_queueSize];
>> + m_analysisWrite[pass] = new ThreadSafeInteger[m_queueSize];
>> + m_analysisRead[pass] = new ThreadSafeInteger[m_queueSize];
>> + m_readFlag[pass] = X265_MALLOC(int, m_queueSize);
>> + }
>> + return true;
>> + }
>> +
>> + void AbrEncoder::closeEncoder()
>> + {
>> + for (uint8_t pidx = 0; pidx < m_numEncodes; pidx++)
>> + {
>> + PassEncoder *passWorker = m_passEnc[pidx];
>> + if (passWorker)
>> + passWorker->close();
>> + }
>> + }
>> +
>> + void AbrEncoder::destroy()
>> + {
>> + closeEncoder();
>> + x265_cleanup(); /* Free library singletons */
>> + for (uint8_t pass = 0; pass < m_numEncodes; pass++)
>> + {
>> + for (uint32_t index = 0; index < m_queueSize; index++)
>> + {
>> + x265_picture_free(m_inputPicBuffer[pass][index]);
>> + }
>> + X265_FREE(m_inputPicBuffer[pass]);
>> + X265_FREE(m_analysisBuffer[pass]);
>> + delete[] m_picIdxReadCnt[pass];
>> + delete[] m_analysisWrite[pass];
>> + delete[] m_analysisRead[pass];
>> + m_passEnc[pass]->destroy();
>> + }
>> + X265_FREE(m_inputPicBuffer);
>> + X265_FREE(m_analysisBuffer);
>> + X265_FREE(m_readFlag);
>> +
>> + delete[] m_picWriteCnt;
>> + delete[] m_picReadCnt;
>> + delete[] m_analysisWriteCnt;
>> + delete[] m_analysisReadCnt;
>> +
>> + X265_FREE(m_picIdxReadCnt);
>> + X265_FREE(m_analysisWrite);
>> + X265_FREE(m_analysisRead);
>> +
>> + X265_FREE(m_passEnc);
>> + }
>> +
>> + PassEncoder::PassEncoder(uint32_t id, CLIOptions cliopt, AbrEncoder
>> *parent)
>> + {
>> + m_id ''= id;
>> + m_cliopt = cliopt;
>> + m_parent = parent;
>> + if(!(m_cliopt.enableScaler && m_id))
>> + m_input = m_cliopt.input;
>> + m_param = x265_param_alloc();
>> + x265_copy_params(m_param, cliopt.param);
>>
> [KS] Is this param alloc/copy essential? Do you foresee problems in just
> pointing it to cliopt.param?
>
[AM] No, I don't foresee any problem; the encoder lib anyway copies this to
encoder->param
I'll modify m_param to point to m_cliopt.input.
> + m_doneReading = false;
>> + m_lastIdx = -1;
>> + m_encoder = NULL;
>> + m_scaler = NULL;
>> + m_reader = NULL;
>> + }
>> +
>> + int PassEncoder::init(int &result)
>> + {
>> + if (m_parent->m_numEncodes > 1)
>> + setReuseLevel();
>> +
>> + if (!(m_cliopt.enableScaler && m_id))
>> + m_reader = new Reader(m_id, this);
>> + else
>> + {
>> + VideoDesc *src = NULL, *dst = NULL;
>> + dst = new VideoDesc(m_param->sourceWidth,
>> m_param->sourceHeight, m_param->internalCsp, m_param->internalBitDepth);
>> + int dstW = m_parent->m_passEnc[m_id -
>> 1]->m_param->sourceWidth;
>> + int dstH = m_parent->m_passEnc[m_id -
>> 1]->m_param->sourceHeight;
>> + src = new VideoDesc(dstW, dstH, m_param->internalCsp,
>> m_param->internalBitDepth);
>> + if (src != NULL && dst != NULL)
>> + {
>> + m_scaler = new Scaler(0, 1, m_id, src, dst, this);
>> + if (!m_scaler)
>> + {
>> + x265_log(m_param, X265_LOG_ERROR, "\n MALLOC failure
>> in Scaler");
>> + result = 4;
>> + }
>> + }
>> + }
>> +
>> + if (m_cliopt.zoneFile)
>> + {
>> + if (!m_cliopt.parseZoneFile())
>> + {
>> + x265_log(NULL, X265_LOG_ERROR, "Unable to parse
>> zonefile\n");
>> + fclose(m_cliopt.zoneFile);
>> + m_cliopt.zoneFile = NULL;
>> + }
>> + }
>> +
>> + if (m_param)
>> + m_encoder = x265_encoder_open(m_param);
>> + if (!m_encoder)
>> + {
>> + x265_log(NULL, X265_LOG_ERROR, "x265_encoder_open() failed
>> for Enc, \n");
>> + return -1;
>> + }
>> + x265_encoder_parameters(m_encoder, m_param);
>> + return 1;
>> + }
>> +
>> + void PassEncoder::setReuseLevel()
>> + {
>> + uint32_t r, padh = 0, padw = 0;
>> +
>> + m_param->confWinBottomOffset = m_param->confWinRightOffset = 0;
>> +
>> + m_isAnalysisSave = m_cliopt.saveLevel ? true : false;
>> + m_isAnalysisLoad = m_cliopt.loadLevel ? true : false;
>>
> [KS] Looks like these two members are redundant?
>
[AM] These two members aren't redundant. An encode can do bo both
analysis-save and analysis-load.
>
>
>> + m_param->analysisLoadReuseLevel = m_cliopt.loadLevel;
>> + m_param->analysisSaveReuseLevel = m_cliopt.saveLevel;
>> + m_param->analysisSave = m_isAnalysisSave ? "save.dat" : NULL;
>> + m_param->analysisLoad = m_isAnalysisLoad ? "load.dat" : NULL;
>> + m_param->bUseAnalysisFile = 0;
>> +
>> + if (m_isAnalysisLoad)
>> + {
>> + x265_param *refParam =
>> m_parent->m_passEnc[m_cliopt.refId]->m_param;
>> +
>> + if (m_param->sourceHeight == (refParam->sourceHeight -
>> refParam->confWinBottomOffset) &&
>> + m_param->sourceWidth == (refParam->sourceWidth -
>> refParam->confWinRightOffset))
>> + {
>> + m_parent->m_passEnc[m_id]->m_param->confWinBottomOffset
>> = refParam->confWinBottomOffset;
>> + m_parent->m_passEnc[m_id]->m_param->confWinRightOffset =
>> refParam->confWinRightOffset;
>> + }
>> + else
>> + {
>> + int srcH = refParam->sourceHeight -
>> refParam->confWinBottomOffset;
>> + int srcW = refParam->sourceWidth -
>> refParam->confWinRightOffset;
>> +
>> + double scaleFactorH = double(m_param->sourceHeight /
>> srcH);
>> + double scaleFactorW = double(m_param->sourceWidth /
>> srcW);
>> +
>> + int absScaleFactorH = (int)(10 * scaleFactorH + 0.5);
>> + int absScaleFactorW = (int)(10 * scaleFactorW + 0.5);
>> +
>> + if (absScaleFactorH == 20 && absScaleFactorW == 20)
>> + {
>> + m_param->scaleFactor = 2;
>> +
>> +
>> m_parent->m_passEnc[m_id]->m_param->confWinBottomOffset =
>> refParam->confWinBottomOffset * 2;
>> +
>> m_parent->m_passEnc[m_id]->m_param->confWinRightOffset =
>> refParam->confWinRightOffset * 2;
>> +
>> + }
>> + }
>> + }
>> +
>> + int h = m_param->sourceHeight + m_param->confWinBottomOffset;
>> + int w = m_param->sourceWidth + m_param->confWinRightOffset;
>> + if (h & (m_param->minCUSize - 1))
>> + {
>> + r = h & (m_param->minCUSize - 1);
>> + padh = m_param->minCUSize - r;
>> + m_param->confWinBottomOffset += padh;
>> +
>> + }
>> +
>> + if (w & (m_param->minCUSize - 1))
>> + {
>> + r = w & (m_param->minCUSize - 1);
>> + padw = m_param->minCUSize - r;
>> + m_param->confWinRightOffset += padw;
>> + }
>> + }
>> +
>> + void PassEncoder::startThreads()
>> + {
>> + /* Start slave worker threads */
>> + m_threadActive = true;
>> + start();
>> + /* Start reader threads*/
>> + if (m_reader != NULL)
>> + {
>> + m_reader->m_threadActive = true;
>> + m_reader->start();
>> + }
>> + /* Start scaling worker threads */
>> + if (m_scaler != NULL)
>> + {
>> + m_scaler->m_threadActive = true;
>> + m_scaler->start();
>> + }
>> + }
>> +
>> + void PassEncoder::copyInfo(x265_analysis_data * src)
>> + {
>> +
>> + uint32_t written = m_parent->m_analysisWriteCnt[m_id].get();
>> +
>> + int index = written % m_parent->m_queueSize;
>> + //If all streams have read analysis data, reuse that position in
>> Queue
>> +
>> + int read = m_parent->m_analysisRead[m_id][index].get();
>> + int write = m_parent->m_analysisWrite[m_id][index].get();
>> +
>> + int overwrite = written / m_parent->m_queueSize;
>> + bool emptyIdxFound = 0;
>> + while (!emptyIdxFound && overwrite)
>> + {
>> + for (uint32_t i = 0; i < m_parent->m_queueSize; i++)
>> + {
>> + read = m_parent->m_analysisRead[m_id][i].get();
>> + write = m_parent->m_analysisWrite[m_id][i].get();
>> + write *= m_cliopt.numRefs;
>> +
>> + if (read == write)
>> + {
>> + index = i;
>> + emptyIdxFound = 1;
>> + }
>> + }
>> + }
>> +
>> + x265_analysis_data *m_analysisInfo =
>> &m_parent->m_analysisBuffer[m_id][index];
>> +
>> + memcpy(m_analysisInfo, src, sizeof(x265_analysis_data));
>> + x265_alloc_analysis_data(m_param, m_analysisInfo);
>> +
>> + bool isVbv = m_param->rc.vbvBufferSize &&
>> m_param->rc.vbvMaxBitrate;
>> + if (m_param->bDisableLookahead && isVbv)
>> + {
>> + memcpy(m_analysisInfo->lookahead.intraSatdForVbv,
>> src->lookahead.intraSatdForVbv, src->numCuInHeight * sizeof(uint32_t));
>> + memcpy(m_analysisInfo->lookahead.satdForVbv,
>> src->lookahead.satdForVbv, src->numCuInHeight * sizeof(uint32_t));
>> + memcpy(m_analysisInfo->lookahead.intraVbvCost,
>> src->lookahead.intraVbvCost, src->numCUsInFrame * sizeof(uint32_t));
>> + memcpy(m_analysisInfo->lookahead.vbvCost,
>> src->lookahead.vbvCost, src->numCUsInFrame * sizeof(uint32_t));
>> + }
>> +
>> + if (src->sliceType == X265_TYPE_IDR || src->sliceType ==
>> X265_TYPE_I)
>> + {
>> + if (m_param->analysisSaveReuseLevel < 2)
>> + goto ret;
>> + x265_analysis_intra_data *intraDst, *intraSrc;
>> + intraDst =
>> (x265_analysis_intra_data*)m_analysisInfo->intraData;
>> + intraSrc = (x265_analysis_intra_data*)src->intraData;
>> + memcpy(intraDst->depth, intraSrc->depth, sizeof(uint8_t) *
>> src->depthBytes);
>> + memcpy(intraDst->modes, intraSrc->modes, sizeof(uint8_t) *
>> src->numCUsInFrame * src->numPartitions);
>> + memcpy(intraDst->partSizes, intraSrc->partSizes,
>> sizeof(char) * src->depthBytes);
>> + memcpy(intraDst->chromaModes, intraSrc->chromaModes,
>> sizeof(uint8_t) * src->depthBytes);
>> + if (m_param->rc.cuTree)
>> + memcpy(intraDst->cuQPOff, intraSrc->cuQPOff,
>> sizeof(int8_t) * src->depthBytes);
>> + }
>> + else
>> + {
>> + bool bIntraInInter = (src->sliceType == X265_TYPE_P ||
>> m_param->bIntraInBFrames);
>> + int numDir = src->sliceType == X265_TYPE_P ? 1 : 2;
>> + memcpy(m_analysisInfo->wt, src->wt, sizeof(WeightParam) * 3
>> * numDir);
>> + if (m_param->analysisSaveReuseLevel < 2)
>> + goto ret;
>> + x265_analysis_inter_data *interDst, *interSrc;
>> + interDst =
>> (x265_analysis_inter_data*)m_analysisInfo->interData;
>> + interSrc = (x265_analysis_inter_data*)src->interData;
>> + memcpy(interDst->depth, interSrc->depth, sizeof(uint8_t) *
>> src->depthBytes);
>> + memcpy(interDst->modes, interSrc->modes, sizeof(uint8_t) *
>> src->depthBytes);
>> + if (m_param->rc.cuTree)
>> + memcpy(interDst->cuQPOff, interSrc->cuQPOff,
>> sizeof(int8_t) * src->depthBytes);
>> + if (m_param->analysisSaveReuseLevel > 4)
>> + {
>> + memcpy(interDst->partSize, interSrc->partSize,
>> sizeof(uint8_t) * src->depthBytes);
>> + memcpy(interDst->mergeFlag, interSrc->mergeFlag,
>> sizeof(uint8_t) * src->depthBytes);
>> + if (m_param->analysisSaveReuseLevel == 10)
>> + {
>> + memcpy(interDst->interDir, interSrc->interDir,
>> sizeof(uint8_t) * src->depthBytes);
>> + for (int dir = 0; dir < numDir; dir++)
>> + {
>> + memcpy(interDst->mvpIdx[dir],
>> interSrc->mvpIdx[dir], sizeof(uint8_t) * src->depthBytes);
>> + memcpy(interDst->refIdx[dir],
>> interSrc->refIdx[dir], sizeof(int8_t) * src->depthBytes);
>> + memcpy(interDst->mv[dir], interSrc->mv[dir],
>> sizeof(MV) * src->depthBytes);
>> + }
>> + if (bIntraInInter)
>> + {
>> + x265_analysis_intra_data *intraDst =
>> (x265_analysis_intra_data*)m_analysisInfo->intraData;
>> + x265_analysis_intra_data *intraSrc =
>> (x265_analysis_intra_data*)src->intraData;
>> + memcpy(intraDst->modes, intraSrc->modes,
>> sizeof(uint8_t) * src->numPartitions * src->numCUsInFrame);
>> + memcpy(intraDst->chromaModes,
>> intraSrc->chromaModes, sizeof(uint8_t) * src->depthBytes);
>> + }
>> + }
>> + }
>> + if (m_param->analysisSaveReuseLevel != 10)
>> + memcpy(interDst->ref, interSrc->ref, sizeof(int32_t) *
>> src->numCUsInFrame * X265_MAX_PRED_MODE_PER_CTU * numDir);
>>
> [KS] Do we support reuse levels other than 1 and 10 ? This condition will
> never hit if we do not have that support
>
[AM] yes, we support all the allowed reuse-levels.
> + }
>> +
>> +ret:
>> + //increment analysis Write counter
>> + m_parent->m_analysisWriteCnt[m_id].incr();
>> + m_parent->m_analysisWrite[m_id][index].incr();
>> + return;
>> + }
>> +
>> +
>> + bool PassEncoder::readPicture(x265_picture *dstPic)
>> + {
>> + /*Check and wait if there any input frames to read*/
>> + int ipread = m_parent->m_picReadCnt[m_id].get();
>> + int ipwrite = m_parent->m_picWriteCnt[m_id].get();
>> +
>> + bool isAbrLoad = m_isAnalysisLoad && (m_parent->m_numEncodes >
>> 1);
>> + while (m_threadActive && (ipread == ipwrite))
>> + {
>> + ipwrite =
>> m_parent->m_picWriteCnt[m_id].waitForChange(ipwrite);
>> + }
>> +
>> + if (m_threadActive && ipread < ipwrite)
>> + {
>> + /*Get input index to read from inputQueue. If doesn't need
>> analysis info, it need not wait to fetch poc from analysisQueue*/
>> + int readPos = ipread % m_parent->m_queueSize;
>> + x265_analysis_data* analysisData = 0;
>> +
>> + if (isAbrLoad)
>> + {
>> + /*If stream is master of each slave pass, then fetch
>> analysis data from prev pass*/
>> + int analysisQId = m_cliopt.refId;
>> + /*Check and wait if there any analysis Data to read*/
>> + int analysisWrite =
>> m_parent->m_analysisWriteCnt[analysisQId].get();
>> + int written = analysisWrite *
>> m_parent->m_passEnc[analysisQId]->m_cliopt.numRefs;
>> + int analysisRead =
>> m_parent->m_analysisReadCnt[analysisQId].get();
>> +
>> + while (m_threadActive && written == analysisRead)
>> + {
>> + analysisWrite =
>> m_parent->m_analysisWriteCnt[analysisQId].waitForChange(analysisWrite);
>> + written = analysisWrite *
>> m_parent->m_passEnc[analysisQId]->m_cliopt.numRefs;
>> + }
>> +
>> + if (analysisRead < written)
>> + {
>> + int analysisIdx = 0;
>> + if (!m_param->bDisableLookahead)
>> + {
>> + bool analysisdRead = false;
>> + while ((analysisRead < written) &&
>> !analysisdRead)
>> + {
>> + while (analysisWrite < ipread)
>> + {
>> + analysisWrite =
>> m_parent->m_analysisWriteCnt[analysisQId].waitForChange(analysisWrite);
>> + written = analysisWrite *
>> m_parent->m_passEnc[analysisQId]->m_cliopt.numRefs;
>> + }
>> + for (uint32_t i = 0; i <
>> m_parent->m_queueSize; i++)
>> + {
>> + analysisData =
>> &m_parent->m_analysisBuffer[analysisQId][i];
>> + int read =
>> m_parent->m_analysisRead[analysisQId][i].get();
>> + int write =
>> m_parent->m_analysisWrite[analysisQId][i].get() *
>> m_parent->m_passEnc[analysisQId]->m_cliopt.numRefs;
>> + if ((analysisData->poc ==
>> (uint32_t)(ipread)) && (read < write))
>> + {
>> + analysisIdx = i;
>> + analysisdRead = true;
>> + break;
>> + }
>> + }
>> + }
>> + }
>> + else
>> + {
>> + analysisIdx = analysisRead %
>> m_parent->m_queueSize;
>> + analysisData =
>> &m_parent->m_analysisBuffer[analysisQId][analysisIdx];
>> + readPos = analysisData->poc %
>> m_parent->m_queueSize;
>> + while ((ipwrite < readPos) || ((ipwrite - 1) <
>> (int)analysisData->poc))
>> + {
>> + ipwrite =
>> m_parent->m_picWriteCnt[m_id].waitForChange(ipwrite);
>> + }
>> + }
>> +
>> + m_lastIdx = analysisIdx;
>> + }
>> + else
>> + return false;
>> + }
>> +
>> +
>> + x265_picture *srcPic =
>> (x265_picture*)(m_parent->m_inputPicBuffer[m_id][readPos]);
>> +
>> + x265_picture *pic = (x265_picture*)(dstPic);
>> + pic->colorSpace = srcPic->colorSpace;
>> + pic->bitDepth = srcPic->bitDepth;
>> + pic->framesize = srcPic->framesize;
>> + pic->height = srcPic->height;
>> + pic->pts = srcPic->pts;
>> + pic->dts = srcPic->dts;
>> + pic->reorderedPts = srcPic->reorderedPts;
>> + pic->poc = srcPic->poc;
>> + pic->analysisData = srcPic->analysisData;
>> + pic->userSEI = srcPic->userSEI;
>> + pic->stride[0] = srcPic->stride[0];
>> + pic->stride[1] = srcPic->stride[1];
>> + pic->stride[2] = srcPic->stride[2];
>> + pic->planes[0] = srcPic->planes[0];
>> + pic->planes[1] = srcPic->planes[1];
>> + pic->planes[2] = srcPic->planes[2];
>> + if (isAbrLoad)
>> + pic->analysisData = *analysisData;
>> + return true;
>> + }
>> + else
>> + return false;
>> + }
>> +
>> + void PassEncoder::threadMain()
>> + {
>> +
>> +#if ENABLE_LIBVMAF
>> + x265_vmaf_data* vmafdata = cliopt.vmafData;
>> +#endif
>>
> [KS] m_cliopt. Have you tested enabling libvmaf?
>
[AM] No, I haven't. Thanks for pointing this out. I'll fix this and test
with libvmaf.
>
> + /* This allows muxers to modify bitstream format */
>> + m_cliopt.output->setParam(m_param);
>> +
>> + ReconPlay* reconPlay = NULL;
>> + if (m_cliopt.reconPlayCmd)
>> + reconPlay = new ReconPlay(m_cliopt.reconPlayCmd, *m_param);
>> +
>>
> [KS] Is there a reason you have moved the encoder_open and zoneparse API
> calls out of threadMain() ?
>
[AM] To inform the AbrEncoder to error out during the initialization phase
itself in the event of encoder_open failures.
I shall, however, move zone-file parsing to passEncoder's threadMain() as
other file operations are handled in threadMain().
>
> + if (signal(SIGINT, sigint_handler) == SIG_ERR)
>> + x265_log(m_param, X265_LOG_ERROR, "Unable to register CTRL+C
>> handler: %s\n", strerror(errno));
>> +
>> + x265_picture pic_orig, pic_out;
>> + x265_picture *pic_in = &pic_orig;
>> + /* Allocate recon picture if analysis save/load is enabled */
>> + std::priority_queue<int64_t>* pts_queue =
>> m_cliopt.output->needPTS() ? new std::priority_queue<int64_t>() : NULL;
>> + x265_picture *pic_recon = (m_cliopt.recon ||
>> m_param->analysisSave || m_param->analysisLoad || pts_queue || reconPlay ||
>> m_param->csvLogLevel) ? &pic_out : NULL;
>> + uint32_t inFrameCount = 0;
>> + uint32_t outFrameCount = 0;
>> + x265_nal *p_nal;
>> + x265_stats stats;
>> + uint32_t nal;
>> + int16_t *errorBuf = NULL;
>> + bool bDolbyVisionRPU = false;
>> + uint8_t *rpuPayload = NULL;
>> + int inputPicNum = 1;
>> + x265_picture picField1, picField2;
>> + x265_analysis_data* analysisInfo =
>> (x265_analysis_data*)(&pic_out.analysisData);
>> + bool isAbrSave = m_isAnalysisSave && (m_parent->m_numEncodes >
>> 1);
>> +
>> + if (!m_param->bRepeatHeaders && !m_param->bEnableSvtHevc)
>> + {
>> + if (x265_encoder_headers(m_encoder, &p_nal, &nal) < 0)
>> + {
>> + x265_log(m_param, X265_LOG_ERROR, "Failure generating
>> stream headers %d\n", m_id);
>> + goto fail;
>> + }
>> + else
>> + m_cliopt.totalbytes +=
>> m_cliopt.output->writeHeaders(p_nal, nal);
>> + }
>> +
>> + if (m_param->bField && m_param->interlaceMode)
>> + {
>> + x265_picture_init(m_param, &picField1);
>> + x265_picture_init(m_param, &picField2);
>> + // return back the original height of input
>> + m_param->sourceHeight *= 2;
>> + x265_picture_init(m_param, &pic_orig);
>> + }
>> + else
>> + x265_picture_init(m_param, &pic_orig);
>> +
>> + if (m_param->dolbyProfile && m_cliopt.dolbyVisionRpu)
>> + {
>> + rpuPayload = X265_MALLOC(uint8_t, 1024);
>> + pic_in->rpu.payload = rpuPayload;
>> + if (pic_in->rpu.payload)
>> + bDolbyVisionRPU = true;
>> + }
>> +
>> + if (m_cliopt.bDither)
>> + {
>> + errorBuf = X265_MALLOC(int16_t, m_param->sourceWidth + 1);
>> + if (errorBuf)
>> + memset(errorBuf, 0, (m_param->sourceWidth + 1) *
>> sizeof(int16_t));
>> + else
>> + m_cliopt.bDither = false;
>> + }
>> +
>> + // main encoder loop
>> + while (pic_in && !b_ctrl_c)
>> + {
>> + pic_orig.poc = (m_param->bField && m_param->interlaceMode) ?
>> inFrameCount * 2 : inFrameCount;
>> + if (m_cliopt.qpfile)
>> + {
>> + if (!m_cliopt.parseQPFile(pic_orig))
>> + {
>> + x265_log(NULL, X265_LOG_ERROR, "can't parse qpfile
>> for frame %d\n", pic_in->poc);
>> + fclose(m_cliopt.qpfile);
>> + m_cliopt.qpfile = NULL;
>> + }
>> + }
>> +
>> + if (m_cliopt.framesToBeEncoded && inFrameCount >=
>> m_cliopt.framesToBeEncoded)
>> + {
>> + pic_in = NULL;
>> + }
>>
> [KS] remove brace
>
[AM] ok
> + else if (readPicture(pic_in))
>> + inFrameCount++;
>> + else
>> + pic_in = NULL;
>> +
>> + if (pic_in)
>> + {
>> + if (pic_in->bitDepth > m_param->internalBitDepth &&
>> m_cliopt.bDither)
>> + {
>> + x265_dither_image(pic_in,
>> m_cliopt.input->getWidth(), m_cliopt.input->getHeight(), errorBuf,
>> m_param->internalBitDepth);
>> + pic_in->bitDepth = m_param->internalBitDepth;
>> + }
>> + /* Overwrite PTS */
>> + pic_in->pts = pic_in->poc;
>> +
>> + // convert to field
>> + if (m_param->bField && m_param->interlaceMode)
>> + {
>> + int height = pic_in->height >> 1;
>> +
>> + int static bCreated = 0;
>> + if (bCreated == 0)
>> + {
>> + bCreated = 1;
>> + inputPicNum = 2;
>> + picField1.fieldNum = 1;
>> + picField2.fieldNum = 2;
>> +
>> + picField1.bitDepth = picField2.bitDepth =
>> pic_in->bitDepth;
>> + picField1.colorSpace = picField2.colorSpace =
>> pic_in->colorSpace;
>> + picField1.height = picField2.height =
>> pic_in->height >> 1;
>> + picField1.framesize = picField2.framesize =
>> pic_in->framesize >> 1;
>> +
>> + size_t fieldFrameSize =
>> (size_t)pic_in->framesize >> 1;
>> + char* field1Buf = X265_MALLOC(char,
>> fieldFrameSize);
>> + char* field2Buf = X265_MALLOC(char,
>> fieldFrameSize);
>> +
>> + int stride = picField1.stride[0] =
>> picField2.stride[0] = pic_in->stride[0];
>> + uint64_t framesize = stride * (height >>
>> x265_cli_csps[pic_in->colorSpace].height[0]);
>> + picField1.planes[0] = field1Buf;
>> + picField2.planes[0] = field2Buf;
>> + for (int i = 1; i <
>> x265_cli_csps[pic_in->colorSpace].planes; i++)
>> + {
>> + picField1.planes[i] = field1Buf + framesize;
>> + picField2.planes[i] = field2Buf + framesize;
>> +
>> + stride = picField1.stride[i] =
>> picField2.stride[i] = pic_in->stride[i];
>> + framesize += (stride * (height >>
>> x265_cli_csps[pic_in->colorSpace].height[i]));
>> + }
>> + assert(framesize == picField1.framesize);
>> + }
>> +
>> + picField1.pts = picField1.poc = pic_in->poc;
>> + picField2.pts = picField2.poc = pic_in->poc + 1;
>> +
>> + picField1.userSEI = picField2.userSEI =
>> pic_in->userSEI;
>> +
>>
> [KS] There was a ToDo to handle userdata of pic-in here. Shall we preserve
> that for the future?
>
[AM] Sure, will retain the ToDO section.
>
>
>> + if (pic_in->framesize)
>> + {
>> + for (int i = 0; i <
>> x265_cli_csps[pic_in->colorSpace].planes; i++)
>> + {
>> + char* srcP1 = (char*)pic_in->planes[i];
>> + char* srcP2 = (char*)pic_in->planes[i] +
>> pic_in->stride[i];
>> + char* p1 = (char*)picField1.planes[i];
>> + char* p2 = (char*)picField2.planes[i];
>> +
>> + int stride = picField1.stride[i];
>> +
>> + for (int y = 0; y < (height >>
>> x265_cli_csps[pic_in->colorSpace].height[i]); y++)
>> + {
>> + memcpy(p1, srcP1, stride);
>> + memcpy(p2, srcP2, stride);
>> + srcP1 += 2 * stride;
>> + srcP2 += 2 * stride;
>> + p1 += stride;
>> + p2 += stride;
>> + }
>> + }
>> + }
>> + }
>> +
>> + if (bDolbyVisionRPU)
>> + {
>> + if (m_param->bField && m_param->interlaceMode)
>> + {
>> + if (rpuParser(&picField1,
>> m_cliopt.dolbyVisionRpu) > 0)
>> + goto fail;
>> + if (rpuParser(&picField2,
>> m_cliopt.dolbyVisionRpu) > 0)
>> + goto fail;
>> + }
>> + else
>> + {
>> + if (rpuParser(pic_in, m_cliopt.dolbyVisionRpu) >
>> 0)
>> + goto fail;
>> + }
>> + }
>> + }
>> +
>> + for (int inputNum = 0; inputNum < inputPicNum; inputNum++)
>> + {
>> + x265_picture *picInput = NULL;
>> + if (inputPicNum == 2)
>> + picInput = pic_in ? (inputNum ? &picField2 :
>> &picField1) : NULL;
>> + else
>> + picInput = pic_in;
>> +
>> + int numEncoded = x265_encoder_encode(m_encoder, &p_nal,
>> &nal, picInput, pic_recon);
>> +
>> + int idx = (inFrameCount - 1) % m_parent->m_queueSize;
>> + m_parent->m_picIdxReadCnt[m_id][idx].incr();
>> + m_parent->m_picReadCnt[m_id].incr();
>> + if (m_cliopt.loadLevel && picInput)
>> + {
>> + m_parent->m_analysisReadCnt[m_cliopt.refId].incr();
>> +
>> m_parent->m_analysisRead[m_cliopt.refId][m_lastIdx].incr();
>> + }
>> +
>> + if (numEncoded < 0)
>> + {
>> + b_ctrl_c = 1;
>> + break;
>> + }
>> +
>> + if (reconPlay && numEncoded)
>> + reconPlay->writePicture(*pic_recon);
>> +
>> + outFrameCount += numEncoded;
>> +
>> + if (isAbrSave && numEncoded)
>> + {
>> + copyInfo(analysisInfo);
>> + }
>> +
>> + if (numEncoded && pic_recon && m_cliopt.recon)
>> + m_cliopt.recon->writePicture(pic_out);
>> + if (nal)
>> + {
>> + m_cliopt.totalbytes +=
>> m_cliopt.output->writeFrame(p_nal, nal, pic_out);
>> + if (pts_queue)
>> + {
>> + pts_queue->push(-pic_out.pts);
>> + if (pts_queue->size() > 2)
>> + pts_queue->pop();
>> + }
>> + }
>> + m_cliopt.printStatus(outFrameCount);
>> + }
>> + }
>> +
>> + /* Flush the encoder */
>> + while (!b_ctrl_c)
>> + {
>> + int numEncoded = x265_encoder_encode(m_encoder, &p_nal,
>> &nal, NULL, pic_recon);
>> + if (numEncoded < 0)
>> + break;
>> +
>> + if (reconPlay && numEncoded)
>> + reconPlay->writePicture(*pic_recon);
>> +
>> + outFrameCount += numEncoded;
>> + if (isAbrSave && numEncoded)
>> + {
>> + copyInfo(analysisInfo);
>> + }
>> +
>> + if (numEncoded && pic_recon && m_cliopt.recon)
>> + m_cliopt.recon->writePicture(pic_out);
>> + if (nal)
>> + {
>> + m_cliopt.totalbytes +=
>> m_cliopt.output->writeFrame(p_nal, nal, pic_out);
>> + if (pts_queue)
>> + {
>> + pts_queue->push(-pic_out.pts);
>> + if (pts_queue->size() > 2)
>> + pts_queue->pop();
>> + }
>> + }
>> +
>> + m_cliopt.printStatus(outFrameCount);
>> +
>> + if (!numEncoded)
>> + break;
>> + }
>> +
>> + if (bDolbyVisionRPU)
>> + {
>> + if (fgetc(m_cliopt.dolbyVisionRpu) != EOF)
>> + x265_log(NULL, X265_LOG_WARNING, "Dolby Vision RPU count
>> is greater than frame count\n");
>> + x265_log(NULL, X265_LOG_INFO, "VES muxing with Dolby Vision
>> RPU file successful\n");
>> + }
>> +
>> + if (bDolbyVisionRPU)
>> + {
>> + if (fgetc(m_cliopt.dolbyVisionRpu) != EOF)
>> + x265_log(NULL, X265_LOG_WARNING, "Dolby Vision RPU count
>> is greater than frame count\n");
>> + x265_log(NULL, X265_LOG_INFO, "VES muxing with Dolby Vision
>> RPU file successful\n");
>> + }
>> +
>> + /* clear progress report */
>> + if (m_cliopt.bProgress)
>> + fprintf(stderr, "%*s\r", 80, " ");
>> +
>> + fail:
>> +
>> + delete reconPlay;
>> +
>> + x265_encoder_get_stats(m_encoder, &stats, sizeof(stats));
>> + if (m_param->csvfn && !b_ctrl_c)
>> +#if ENABLE_LIBVMAF
>> + x265_vmaf_encoder_log(encoder, argc, argv, param, vmafdata);
>> +#else
>> + x265_encoder_log(m_encoder, 0, NULL);
>> +#endif
>> +
>> + int64_t second_largest_pts = 0;
>> + int64_t largest_pts = 0;
>> +
>> + m_cliopt.output->closeFile(largest_pts, second_largest_pts);
>> +
>> + if (b_ctrl_c)
>> + general_log(m_param, NULL, X265_LOG_INFO, "aborted at input
>> frame %d, output frame %d\n",
>> + m_cliopt.seek + inFrameCount, stats.encodedPictureCount);
>> +
>> + X265_FREE(errorBuf);
>> + X265_FREE(rpuPayload);
>> +
>> + m_threadActive = false;
>> + m_parent->m_numActiveEncodes.decr();
>> + }
>> +
>> + void PassEncoder::close()
>> + {
>> + x265_param_free(m_param);
>> + x265_encoder_close(m_encoder);
>> + }
>> +
>> + void PassEncoder::destroy()
>> + {
>> + if (m_reader)
>> + {
>> + delete m_reader;
>> + }
>> + else
>> + {
>> + m_scaler->destroy();
>> + delete m_scaler;
>> + }
>> + }
>> +
>> + Scaler::Scaler(int threadId, int threadNum, int id, VideoDesc *src,
>> VideoDesc *dst, PassEncoder *parentEnc)
>> + {
>> + m_parentEnc = parentEnc;
>> + m_id = id;
>> + m_srcFormat = src;
>> + m_dstFormat = dst;
>> + m_threadActive = false;
>> + m_scaleFrameSize = 0;
>> + m_filterManager = NULL;
>> + m_threadId = threadId;
>> + m_threadTotal = threadNum;
>> +
>> + int csp = dst->m_csp;
>> + uint32_t pixelbytes = dst->m_inputDepth > 8 ? 2 : 1;
>> + for (int i = 0; i < x265_cli_csps[csp].planes; i++)
>> + {
>> + int w = dst->m_width >> x265_cli_csps[csp].width[i];
>> + int h = dst->m_height >> x265_cli_csps[csp].height[i];
>> + m_scalePlanes[i] = w * h * pixelbytes;
>> + m_scaleFrameSize += m_scalePlanes[i];
>> + }
>> +
>> + if (src->m_height != dst->m_height || src->m_width !=
>> dst->m_width)
>> + {
>> + m_filterManager = new ScalerFilterManager;
>> + m_filterManager->init(4, m_srcFormat, m_dstFormat);
>> + }
>> + }
>> +
>> + bool Scaler::scalePic(x265_picture * destination, x265_picture *
>> source)
>> + {
>> + if (!destination || !source)
>> + return false;
>> + x265_param* param = m_parentEnc->m_param;
>> + int pixelBytes = m_dstFormat->m_inputDepth > 8 ? 2 : 1;
>
> + if (m_srcFormat->m_height != m_dstFormat->m_height ||
>> m_srcFormat->m_width != m_dstFormat->m_width)
>> + {
>> + void **srcPlane = NULL, **dstPlane = NULL;
>> + int srcStride[3], dstStride[3];
>> + destination->bitDepth = source->bitDepth;
>> + destination->colorSpace = source->colorSpace;
>> + destination->pts = source->pts;
>> + destination->dts = source->dts;
>> + destination->reorderedPts = source->reorderedPts;
>> + destination->poc = source->poc;
>> + destination->userSEI = source->userSEI;
>> + srcPlane = source->planes;
>> + dstPlane = destination->planes;
>> + srcStride[0] = source->stride[0];
>> + destination->stride[0] = m_dstFormat->m_width * pixelBytes;
>> + dstStride[0] = destination->stride[0];
>> + if (param->internalCsp != X265_CSP_I400)
>> + {
>> + srcStride[1] = source->stride[1];
>> + srcStride[2] = source->stride[2];
>> + destination->stride[1] = destination->stride[0] >>
>> x265_cli_csps[param->internalCsp].width[1];
>> + destination->stride[2] = destination->stride[0] >>
>> x265_cli_csps[param->internalCsp].width[2];
>> + dstStride[1] = destination->stride[1];
>> + dstStride[2] = destination->stride[2];
>> + }
>> + if (m_scaleFrameSize)
>> + {
>> + m_filterManager->scale_pic(srcPlane, dstPlane,
>> srcStride, dstStride);
>> + return true;
>> + }
>> + else
>> + x265_log(param, X265_LOG_INFO, "Empty frame received\n");
>> + }
>> + return false;
>> + }
>> +
>> + void Scaler::threadMain()
>> + {
>> + THREAD_NAME("Scaler", m_id);
>> +
>> + /* unscaled picture is stored in the last index */
>> + uint32_t srcId = m_id - 1;
>> + int QDepth = m_parentEnc->m_parent->m_queueSize;
>> + while (!m_parentEnc->m_doneReading)
>> + {
>> +
>> + uint32_t scaledWritten =
>> m_parentEnc->m_parent->m_picWriteCnt[m_id].get();
>> +
>> + if (m_parentEnc->m_cliopt.framesToBeEncoded && scaledWritten
>> >= m_parentEnc->m_cliopt.framesToBeEncoded)
>> + break;
>> +
>> + if (m_threadTotal > 1 && (m_threadId != scaledWritten %
>> m_threadTotal))
>> + {
>> + continue;
>> + }
>> + uint32_t written =
>> m_parentEnc->m_parent->m_picWriteCnt[srcId].get();
>> +
>> + /*If all the input pictures are scaled by the current scale
>> worker thread wait for input pictures*/
>> + while (m_threadActive && (scaledWritten == written)) {
>> + written =
>> m_parentEnc->m_parent->m_picWriteCnt[srcId].waitForChange(written);
>> + }
>> +
>> + if (m_threadActive && scaledWritten < written)
>> + {
>> +
>> + int scaledWriteIdx = scaledWritten % QDepth;
>> + int overWritePicBuffer = scaledWritten / QDepth;
>> + int read =
>> m_parentEnc->m_parent->m_picIdxReadCnt[m_id][scaledWriteIdx].get();
>> +
>> + while (overWritePicBuffer && read < overWritePicBuffer)
>> + {
>> + read =
>> m_parentEnc->m_parent->m_picIdxReadCnt[m_id][scaledWriteIdx].waitForChange(read);
>> + }
>> +
>> + if
>> (!m_parentEnc->m_parent->m_inputPicBuffer[m_id][scaledWriteIdx])
>> + {
>> + int framesize = 0;
>> + int planesize[3];
>> + int csp = m_dstFormat->m_csp;
>> + int stride[3];
>> + stride[0] = m_dstFormat->m_width;
>> + stride[1] = stride[0] >> x265_cli_csps[csp].width[1];
>> + stride[2] = stride[0] >> x265_cli_csps[csp].width[2];
>> + for (int i = 0; i < x265_cli_csps[csp].planes; i++)
>> + {
>> + uint32_t h = m_dstFormat->m_height >>
>> x265_cli_csps[csp].height[i];
>> + planesize[i] = h * stride[i];
>> + framesize += planesize[i];
>> + }
>> +
>> +
>> m_parentEnc->m_parent->m_inputPicBuffer[m_id][scaledWriteIdx] =
>> x265_picture_alloc();
>> + x265_picture_init(m_parentEnc->m_param,
>> m_parentEnc->m_parent->m_inputPicBuffer[m_id][scaledWriteIdx]);
>> +
>> +
>> ((x265_picture*)m_parentEnc->m_parent->m_inputPicBuffer[m_id][scaledWritten
>> % QDepth])->framesize = framesize;
>> + for (int32_t j = 0; j < x265_cli_csps[csp].planes;
>> j++)
>> + {
>> +
>> m_parentEnc->m_parent->m_inputPicBuffer[m_id][scaledWritten %
>> QDepth]->planes[j] = X265_MALLOC(char, planesize[j]);
>> + }
>> + }
>> +
>> + x265_picture *srcPic =
>> m_parentEnc->m_parent->m_inputPicBuffer[srcId][scaledWritten % QDepth];
>> + x265_picture* destPic =
>> m_parentEnc->m_parent->m_inputPicBuffer[m_id][scaledWriteIdx];
>> +
>> + // Enqueue this picture up with the current encoder so
>> that it will asynchronously encode
>> + if (!scalePic(destPic, srcPic))
>> + x265_log(NULL, X265_LOG_ERROR, "Unable to copy
>> scaled input picture to input queue \n");
>> + else
>> + m_parentEnc->m_parent->m_picWriteCnt[m_id].incr();
>> + m_scaledWriteCnt.incr();
>> +
>> m_parentEnc->m_parent->m_picIdxReadCnt[srcId][scaledWriteIdx].incr();
>> + }
>> + if (m_threadTotal > 1)
>> + {
>> + written =
>> m_parentEnc->m_parent->m_picWriteCnt[srcId].get();
>> + int totalWrite = written / m_threadTotal;
>> + if (written % m_threadTotal > m_threadId)
>> + totalWrite++;
>> + if (totalWrite == m_scaledWriteCnt.get())
>> + {
>> + m_parentEnc->m_parent->m_picWriteCnt[srcId].poke();
>> + m_parentEnc->m_parent->m_picWriteCnt[m_id].poke();
>> + break;
>> + }
>> + }
>> + else
>> + {
>> + /* Once end of video is reached and all frames are
>> scaled, release wait on picwritecount */
>> + scaledWritten =
>> m_parentEnc->m_parent->m_picWriteCnt[m_id].get();
>> + written =
>> m_parentEnc->m_parent->m_picWriteCnt[srcId].get();
>> + if (written == scaledWritten)
>> + {
>> + m_parentEnc->m_parent->m_picWriteCnt[srcId].poke();
>> + m_parentEnc->m_parent->m_picWriteCnt[m_id].poke();
>> + break;
>> + }
>> + }
>> +
>> + }
>> + m_threadActive = false;
>> + destroy();
>> + }
>> +
>> + Reader::Reader(int id, PassEncoder *parentEnc)
>> + {
>> + m_parentEnc = parentEnc;
>> + m_id = id;
>> + m_input = parentEnc->m_input;
>> + }
>> +
>> + void Reader::threadMain()
>> + {
>> + THREAD_NAME("Reader", m_id);
>> +
>> + int QDepth = m_parentEnc->m_parent->m_queueSize;
>> + x265_picture* src = x265_picture_alloc();
>> + x265_picture_init(m_parentEnc->m_param, src);
>> +
>> + while (!m_parentEnc->m_doneReading)
>> + {
>> + uint32_t written =
>> m_parentEnc->m_parent->m_picWriteCnt[m_id].get();
>> + uint32_t writeIdx = written % QDepth;
>> + uint32_t read =
>> m_parentEnc->m_parent->m_picIdxReadCnt[m_id][writeIdx].get();
>> + uint32_t overWritePicBuffer = written / QDepth;
>> +
>> + if (m_parentEnc->m_cliopt.framesToBeEncoded && written >=
>> m_parentEnc->m_cliopt.framesToBeEncoded)
>> + break;
>> +
>> + while (overWritePicBuffer && read < overWritePicBuffer)
>> + {
>> + read =
>> m_parentEnc->m_parent->m_picIdxReadCnt[m_id][writeIdx].waitForChange(read);
>> + }
>> +
>> + if (!m_parentEnc->m_parent->m_inputPicBuffer[m_id][writeIdx])
>> + {
>> + m_parentEnc->m_parent->m_inputPicBuffer[m_id][writeIdx]
>> = x265_picture_alloc();
>> + x265_picture_init(m_parentEnc->m_param,
>> m_parentEnc->m_parent->m_inputPicBuffer[m_id][writeIdx]);
>> + }
>> +
>> + x265_picture* dest =
>> m_parentEnc->m_parent->m_inputPicBuffer[m_id][writeIdx];
>> + if (m_input->readPicture(*src))
>> + {
>> + dest->poc = src->poc;
>> + dest->pts = src->pts;
>> + dest->userSEI = src->userSEI;
>> + dest->bitDepth = src->bitDepth;
>> + dest->framesize = src->framesize;
>> + dest->height = src->height;
>> + dest->width = src->width;
>> + dest->colorSpace = src->colorSpace;
>> + dest->userSEI = src->userSEI;
>> + dest->rpu.payload = src->rpu.payload;
>> + dest->picStruct = src->picStruct;
>> + dest->stride[0] = src->stride[0];
>> + dest->stride[1] = src->stride[1];
>> + dest->stride[2] = src->stride[2];
>> +
>> + if (!dest->planes[0])
>> + dest->planes[0] = X265_MALLOC(char, dest->framesize);
>> +
>> + memcpy(dest->planes[0], src->planes[0], src->framesize *
>> sizeof(char));
>> + dest->planes[1] = (char*)dest->planes[0] +
>> src->stride[0] * src->height;
>> + dest->planes[2] = (char*)dest->planes[1] +
>> src->stride[1] * (src->height >> x265_cli_csps[src->colorSpace].height[1]);
>> + m_parentEnc->m_parent->m_picWriteCnt[m_id].incr();
>> + }
>> + else
>> + {
>> + m_parentEnc->m_parent->m_picWriteCnt[m_id].poke();
>> + break;
>> + }
>> + }
>> + x265_picture_free(src);
>> + m_threadActive = false;
>> + }
>> +}
>> diff -r 7ebf4b9369b3 -r 3eccfeafc040 source/abrEncApp.h
>> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
>> +++ b/source/abrEncApp.h Wed Feb 26 16:37:13 2020 +0530
>> @@ -0,0 +1,160 @@
>>
>> +/*****************************************************************************
>> +* Copyright (C) 2013-2020 MulticoreWare, Inc
>> +*
>> +* Authors: Pooja Venkatesan <pooja at multicorewareinc.com>
>> +* Aruna Matheswaran <aruna at multicorewareinc.com>
>> +*
>> +*
>> +* This program is free software; you can redistribute it and/or modify
>> +* it under the terms of the GNU General Public License as published by
>> +* the Free Software Foundation; either version 2 of the License, or
>> +* (at your option) any later version.
>> +*
>> +* This program is distributed in the hope that it will be useful,
>> +* but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> +* GNU General Public License for more details.
>> +*
>> +* You should have received a copy of the GNU General Public License
>> +* along with this program; if not, write to the Free Software
>> +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111,
>> USA.
>> +*
>> +* This program is also available under a commercial proprietary license.
>> +* For more information, contact us at license @ x265.com.
>>
>> +*****************************************************************************/
>> +
>> +#ifndef ABR_ENCODE_H
>> +#define ABR_ENCODE_H
>> +
>> +#include "x265.h"
>> +#include "scaler.h"
>> +#include "threading.h"
>> +#include "x265cli.h"
>> +
>> +namespace X265_NS {
>> + // private namespace
>> +
>> + class PassEncoder;
>> + class Scaler;
>> + class Reader;
>> +
>> + class AbrEncoder
>> + {
>> + public:
>> + uint8_t m_numEncodes;
>> + PassEncoder **m_passEnc;
>> + uint32_t m_queueSize;
>> + ThreadSafeInteger m_numActiveEncodes;
>> +
>> + x265_picture ***m_inputPicBuffer; //[numEncodes][queueSize]
>> + x265_analysis_data **m_analysisBuffer; //[numEncodes][queueSize]
>> + int **m_readFlag;
>> +
>> + ThreadSafeInteger *m_picWriteCnt;
>> + ThreadSafeInteger *m_picReadCnt;
>> + ThreadSafeInteger **m_picIdxReadCnt;
>> + ThreadSafeInteger *m_analysisWriteCnt; //[numEncodes][queueSize]
>> + ThreadSafeInteger *m_analysisReadCnt; //[numEncodes][queueSize]
>> + ThreadSafeInteger **m_analysisWrite; //[numEncodes][queueSize]
>> + ThreadSafeInteger **m_analysisRead; //[numEncodes][queueSize]
>> +
>> + AbrEncoder(CLIOptions cliopt[], uint8_t numEncodes, int& ret);
>> + bool allocBuffers();
>> + void closeEncoder();
>> + void destroy();
>> +
>> + };
>> +
>> + class PassEncoder : public Thread
>> + {
>> + public:
>> +
>> + uint32_t m_id;
>> + x265_param *m_param;
>> + AbrEncoder *m_parent;
>> + x265_encoder *m_encoder;
>> + Reader *m_reader;
>> + Scaler *m_scaler;
>> +
>> + bool m_reqScale;
>> + bool m_isScaled;
>>
> [KS] unused class members
>
[AM] Will remove this.
> + bool m_isAnalysisSave;
>> + bool m_isAnalysisLoad;
>> + bool m_doneReading;
>> +
>> + int m_threadActive;
>> + int m_lastIdx;
>> + uint32_t m_outputNalsCount;
>> +
>> + x265_picture **m_inputPicBuffer;
>> + x265_analysis_data **m_analysisBuffer;
>> + x265_nal **m_outputNals;
>> + x265_picture **m_outputRecon;
>> +
>> + CLIOptions m_cliopt;
>> + InputFile* m_input;
>> + const char* m_reconPlayCmd;
>> + FILE* m_qpfile;
>> + FILE* m_zoneFile;
>> + FILE* m_dolbyVisionRpu;/* File containing Dolby Vision BL RPU
>> metadata */
>> +
>> +
>> +
>> + PassEncoder(uint32_t id, CLIOptions cliopt, AbrEncoder *parent);
>> + int init(int &result);
>> + void setReuseLevel();
>> +
>> + void startThreads();
>> + void copyInfo(x265_analysis_data *src);
>> +
>> + bool readPicture(x265_picture*);
>> + void close();
>> + void destroy();
>> +
>> + private:
>> + void threadMain();
>> + };
>> +
>> + class Scaler : public Thread
>> + {
>> + public:
>> + PassEncoder *m_parentEnc;
>> + int m_id;
>> + int m_scalePlanes[3];
>> + int m_scaleFrameSize;
>> + uint32_t m_threadId;
>> + uint32_t m_threadTotal;
>> + ThreadSafeInteger m_scaledWriteCnt;
>> + VideoDesc* m_srcFormat;
>> + VideoDesc* m_dstFormat;
>> + int m_threadActive;
>> + ScalerFilterManager* m_filterManager;
>> +
>> + Scaler(int threadId, int threadNum, int id, VideoDesc *src,
>> VideoDesc * dst, PassEncoder *parentEnc);
>> + bool scalePic(x265_picture *destination, x265_picture *source);
>> + void threadMain();
>> + void destroy()
>> + {
>> + if (m_filterManager)
>> + {
>> + delete m_filterManager;
>> + m_filterManager = NULL;
>> + }
>> + }
>> + };
>> +
>> + class Reader : public Thread
>> + {
>> + public:
>> + PassEncoder *m_parentEnc;
>> + int m_id;
>> + InputFile* m_input;
>> + int m_threadActive;
>> +
>> + Reader(int id, PassEncoder *parentEnc);
>> + void threadMain();
>> + };
>> +}
>> +
>> +#endif // ifndef ABR_ENCODE_H
>> +#pragma once
>> diff -r 7ebf4b9369b3 -r 3eccfeafc040 source/common/threading.h
>> --- a/source/common/threading.h Wed Feb 26 14:40:35 2020 +0530
>> +++ b/source/common/threading.h Wed Feb 26 16:37:13 2020 +0530
>> @@ -238,6 +238,14 @@
>> LeaveCriticalSection(&m_cs);
>> }
>>
>> + void decr()
>> + {
>> + EnterCriticalSection(&m_cs);
>> + m_val--;
>> + WakeAllConditionVariable(&m_cv);
>> + LeaveCriticalSection(&m_cs);
>> + }
>> +
>> protected:
>>
>> CRITICAL_SECTION m_cs;
>> @@ -436,6 +444,14 @@
>> pthread_mutex_unlock(&m_mutex);
>> }
>>
>> + void decr()
>> + {
>> + pthread_mutex_lock(&m_mutex);
>> + m_val--;
>> + pthread_cond_broadcast(&m_cond);
>> + pthread_mutex_unlock(&m_mutex);
>> + }
>> +
>> protected:
>>
>> pthread_mutex_t m_mutex;
>> _______________________________________________
>> x265-devel mailing list
>> x265-devel at videolan.org
>> https://mailman.videolan.org/listinfo/x265-devel
>>
>
>
> --
> Regards,
> Kavitha
> _______________________________________________
> x265-devel mailing list
> x265-devel at videolan.org
> https://mailman.videolan.org/listinfo/x265-devel
>
--
Regards,
*Aruna Matheswaran,*
Video Codec Engineer,
Media & AI analytics BU,
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20200413/4bb06eba/attachment-0001.html>
More information about the x265-devel
mailing list