<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Apr 9, 2020 at 2:40 PM Kavitha Sampath <<a href="mailto:kavitha@multicorewareinc.com" target="_blank">kavitha@multicorewareinc.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Mar 31, 2020 at 6:22 PM Aruna Matheswaran <<a href="mailto:aruna@multicorewareinc.com" target="_blank">aruna@multicorewareinc.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"># HG changeset patch<br>
# User Aruna Matheswaran <<a href="mailto:aruna@multicorewareinc.com" target="_blank">aruna@multicorewareinc.com</a>><br>
# Date 1585653210 -19800<br>
#      Tue Mar 31 16:43:30 2020 +0530<br>
# Node ID d78121f6445e01f55c2ac7728bdb12c8850fa2f9<br>
# Parent  3eccfeafc04000b68c25ab52c43741a1acac21c8<br>
abr-ladder: Parse config file and launch ABR tiers<br>
<br>
diff -r 3eccfeafc040 -r d78121f6445e doc/reST/cli.rst<br>
--- a/doc/reST/cli.rst  Wed Feb 26 16:37:13 2020 +0530<br>
+++ b/doc/reST/cli.rst  Tue Mar 31 16:43:30 2020 +0530<br>
@@ -2520,6 +2520,28 @@<br>
        --recon-y4m-exec "ffplay -i pipe:0 -autoexit"<br>
<br>
        **CLI ONLY**<br>
+       <br>
+ABR-ladder Options<br>
+==================<br>
+<br>
+.. option:: --abr-ladder <filename><br>
+<br>
+       File containing the encoder configurations to generate ABR ladder.<br>
+       The format of each line is:<br>
+<br>
+       **<encID:reuse-level:refID> <CLI>**<br>
+       <br>
+       where, encID indicates the unique name given to the encode, refID indicates<br>
+       the name of the encode from which analysis info has to be re-used ( set to 'nil'<br>
+       if analysis reuse isn't preferred ), and reuse-level indicates the level ( :option:`--analysis-load-reuse-level`)<br>
+       at which analysis info has to be reused.<br>
+       <br>
+       A sample config file is available in `the downloads page <<a href="https://bitbucket.org/multicoreware/x265/downloads/Sample_ABR_ladder_config" rel="noreferrer" target="_blank">https://bitbucket.org/multicoreware/x265/downloads/Sample_ABR_ladder_config</a>>`_<br>
+       <br>
+       Default: Disabled ( Conventional single encode generation ). Experimental feature.<br>
+<br>
+       **CLI ONLY**<br>
+<br>
<br>
 SVT-HEVC Encoder Options<br>
 ========================<br>
diff -r 3eccfeafc040 -r d78121f6445e source/x265.cpp<br>
--- a/source/x265.cpp   Wed Feb 26 16:37:13 2020 +0530<br>
+++ b/source/x265.cpp   Tue Mar 31 16:43:30 2020 +0530<br>
@@ -27,6 +27,7 @@<br>
<br>
 #include "x265.h"<br>
 #include "x265cli.h"<br>
+#include "abrEncApp.h"<br>
<br>
 #include "input/input.h"<br>
 #include "output/output.h"<br></blockquote><div>[KS] Check if all included headers in x265.cpp are required. For instance svt.h  is no longer required here.</div></div></div></blockquote><div>[AM] Yes, some of the headers are no longer required here. I'll remove them. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
@@ -49,12 +50,13 @@<br>
<br>
 using namespace X265_NS;<br>
<br>
+#ifdef _WIN32<br>
+#define strdup _strdup<br>
+#endif<br>
+<br>
 /* Ctrl-C handler */<br>
 static volatile sig_atomic_t b_ctrl_c /* = 0 */;<br>
-static void sigint_handler(int)<br>
-{<br>
-    b_ctrl_c = 1;<br>
-}<br>
+<br>
 #define START_CODE 0x00000001<br>
 #define START_CODE_BYTES 4<br></blockquote><div>[KS] Same for macros as well. Double check. </div></div></div></blockquote><div>[AM] Sure, I'll double-check and remove the unwanted macros as well. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
@@ -91,59 +93,178 @@<br>
 }<br>
 #endif<br>
<br>
-/* Parse the RPU file and extract the RPU corresponding to the current picture <br>
- * and fill the rpu field of the input picture */<br>
-static int rpuParser(x265_picture * pic, FILE * ptr)<br>
-{<br>
-    uint8_t byteVal;<br>
-    uint32_t code = 0;<br>
-    int bytesRead = 0;<br>
-    pic->rpu.payloadSize = 0;<br>
+/* Checks for abr-ladder config file in the command line.<br>
+ * Returns true if abr-config file is present. Returns <br>
+ * false otherwise */<br>
<br>
-    if (!pic->pts)<br>
-    {<br>
-        while (bytesRead++ < 4 && fread(&byteVal, sizeof(uint8_t), 1, ptr))<br>
-            code = (code << 8) | byteVal;<br>
-      <br>
-        if (code != START_CODE)<br>
-        {<br>
-            x265_log(NULL, X265_LOG_ERROR, "Invalid Dolby Vision RPU startcode in POC %d\n", pic->pts);<br>
-            return 1;<br>
-        }<br>
-    } <br>
-<br>
-    bytesRead = 0;<br>
-    while (fread(&byteVal, sizeof(uint8_t), 1, ptr))<br>
+static bool IsAbrLadder(int argc, char **argv, FILE **abrConfig)<br>
+{<br>
+    for (optind = 0;;)<br>
     {<br>
-        code = (code << 8) | byteVal;<br>
-        if (bytesRead++ < 3)<br>
-            continue;<br>
-        if (bytesRead >= 1024)<br>
+        int long_options_index = -1;<br>
+        int c = getopt_long(argc, argv, short_options, long_options, &long_options_index);<br>
+        if (c == -1)<br>
+            break;<br>
+        if (long_options_index < 0 && c > 0)<br>
         {<br>
-            x265_log(NULL, X265_LOG_ERROR, "Invalid Dolby Vision RPU size in POC %d\n", pic->pts);<br>
-            return 1;<br>
+            for (size_t i = 0; i < sizeof(long_options) / sizeof(long_options[0]); i++)<br>
+            {<br>
+                if (long_options[i].val == c)<br>
+                {<br>
+                    long_options_index = (int)i;<br>
+                    break;<br>
+                }<br>
+            }<br>
+<br>
+            if (long_options_index < 0)<br>
+            {<br>
+                /* getopt_long might have already printed an error message */<br>
+                if (c != 63)<br>
+                    x265_log(NULL, X265_LOG_WARNING, "internal error: short option '%c' has no long option\n", c);<br>
+                return false;<br>
+            }<br>
         }<br>
-        <br>
-        if (code != START_CODE)<br>
-            pic->rpu.payload[pic->rpu.payloadSize++] = (code >> (3 * 8)) & 0xFF;<br>
-        else<br>
-            return 0;       <br>
+        if (long_options_index < 0)<br>
+        {<br>
+            x265_log(NULL, X265_LOG_WARNING, "short option '%c' unrecognized\n", c);<br>
+            return false;<br>
+        }<br>
+        if (!strcmp(long_options[long_options_index].name, "abr-ladder"))<br>
+        {<br>
+            *abrConfig = x265_fopen(optarg, "rb");<br>
+            if (!abrConfig)<br>
+                x265_log_file(NULL, X265_LOG_ERROR, "%s abr-ladder config file not found or error in opening zone file\n", optarg);<br>
+            return true;<br>
+        }<br>
     }<br>
+    return false;<br>
+}<br></blockquote><div>[KS] Do we need a separate parsing just to search for abrLadder option in command? Can this go to cliopt parse ? </div></div></div></blockquote><div>[AM] The --abr-ladder config file has CLI headers in addition to the CLI for each tier in the ABR ladder. To read the file, I have introduced a separate module that parses the CLI header first and then calls the cliopt parse. The application will take one of the 2 flows ( 1. cliopt parse for single encode case and 2. File parse for --abr-ladder case ) based on this option. Hence I have introduced this module. </div><div>This numEncodes count is also required in advance to initialize cliopt structure.</div><div>  </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
-    int ShiftBytes = START_CODE_BYTES - (bytesRead - pic->rpu.payloadSize);<br>
-    int bytesLeft = bytesRead - pic->rpu.payloadSize;<br>
-    code = (code << ShiftBytes * 8);<br>
-    for (int i = 0; i < bytesLeft; i++)<br>
+static uint8_t getNumAbrEncodes(FILE* abrConfig)<br>
+{<br>
+    char line[1024];<br>
+    uint8_t numEncodes = 0;<br>
+<br>
+    while (fgets(line, sizeof(line), abrConfig))<br>
     {<br>
-        pic->rpu.payload[pic->rpu.payloadSize++] = (code >> (3 * 8)) & 0xFF;<br>
-        code = (code << 8);<br>
+        if (strcmp(line, "\n") == 0)<br>
+            continue;<br>
+        else if (!(*line == '#'))<br>
+            numEncodes++;<br>
     }<br>
-    if (!pic->rpu.payloadSize)<br>
-        x265_log(NULL, X265_LOG_WARNING, "Dolby Vision RPU not found for POC %d\n", pic->pts);<br>
-    return 0;<br>
+    rewind(abrConfig);<br>
+    return numEncodes;<br>
 }<br>
<br>
+#define X265_HEAD_ENTRIES 3<br></blockquote><div>[KS] Can we move all #define to the start of the file(for code consistency)? </div></div></div></blockquote><div>[AM] Okay, will do. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
+static bool parseAbrConfig(FILE* abrConfig, CLIOptions cliopt[])<br>
+{<br>
+    char line[1024];<br>
+    char* argLine;<br>
+    uint32_t numEncodes = 0;<br>
+<br>
+    while (fgets(line, sizeof(line), abrConfig))<br>
+    {<br>
+        if (!((*line == '#') || (strcmp(line, "\r\n") == 0)))<br>
+            numEncodes++;<br>
+    }<br>
+    rewind(abrConfig);<br>
+<br></blockquote><div>[KS] Why are we computing numEncodes again? When it is already computed in the getNumEncode() invoked from main</div></div></div></blockquote><div>[AM] Yes, this is redundant. I'll add it to the argument list. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+    for (uint32_t i = 0; i < numEncodes; i++)<br>
+    {<br>
+        while (fgets(line, sizeof(line), abrConfig))<br>
+        {<br>
+            if (*line == '#' || (strcmp(line, "\r\n") == 0))<br>
+                continue;<br>
+            int index = (int)strcspn(line, "\r\n");<br>
+            line[index] = '\0';<br>
+            argLine = line;<br>
+            char* start = strchr(argLine, ' ');<br>
+            while (isspace((unsigned char)*start)) start++;<br>
+            int argCount = 0;<br>
+            char **args = (char**)malloc(256 * sizeof(char *));<br>
+            // Adding a dummy string to avoid file parsing error<br>
+            args[argCount++] = (char *)"x265";<br></blockquote><div>[KS] Can you explain what you are doing here? </div></div></div></blockquote><div>[AM] cliopt parse will ignore the first argument in the argv list ( the exe arg ) . Hence adding this dummy argument so that none of the valid arguments will get dropped.</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+            /* Parse CLI header to identify the ID of the load encode and the reuse level */<br>
+            char *header = strtok(argLine, "[]");<br>
+            uint32_t idCount = 0;<br>
+            char *id = strtok(header, ":");<br>
+            char *head[X265_HEAD_ENTRIES];<br>
+            cliopt[i].encId = i;<br>
+ <br>
+            while (id && (idCount <= X265_HEAD_ENTRIES))<br>
+            {<br>
+                head[idCount] = id;<br>
+                id = strtok(NULL, ":");<br>
+                idCount++;<br>
+            }<br>
+            if (idCount != X265_HEAD_ENTRIES)<br>
+            {<br>
+                x265_log(NULL, X265_LOG_ERROR, "Incorrect number of arguments in ABR CLI header at line %d\n", i);<br>
+                return false;<br>
+            }<br>
+            else<br>
+            {<br>
+                cliopt[i].encName = strdup(head[0]);<br>
+                cliopt[i].loadLevel = atoi(head[1]);<br>
+                cliopt[i].reuseName = strdup(head[2]);<br>
+            }<br>
+<br>
+            char* token = strtok(start, " ");<br>
+            while (token)<br>
+            {<br>
+                args[argCount++] = token;<br>
+                token = strtok(NULL, " ");<br>
+            }<br></blockquote><div>[KS] Are there any string manipulation lib APIs that count words so that we can avoid this loop</div></div></div></blockquote><div>[AM] We have to populate args with the tokens as well. I don't find any lib that does both. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+            args[argCount] = NULL;<br>
+            if (cliopt[i].parse(argCount, args))<br>
+            {<br>
+                cliopt[i].destroy();<br>
+                if (cliopt[i].api)<br>
+                    cliopt[i].api->param_free(cliopt[i].param);<br>
+                exit(1);<br>
+            }<br>
+            break;<br>
+        }<br>
+    }<br>
+    return true;<br>
+}<br>
+<br>
+static bool setRefContext(CLIOptions cliopt[], uint32_t numEncodes)<br>
+{<br>
+    bool hasRef = false;<br>
+    bool isRefFound = false;<br>
+<br>
+    /* Identify reference encode IDs and set save/load reuse levels */<br>
+    for (uint32_t curEnc = 0; curEnc < numEncodes; curEnc++)<br>
+    {<br>
+        isRefFound = false;<br>
+        hasRef = !strcmp(cliopt[curEnc].reuseName, "nil") ? false : true;<br>
+        if (hasRef)<br>
+        {<br>
+            for (uint32_t refEnc = 0; refEnc < numEncodes; refEnc++)<br>
+            {<br>
+                if (!strcmp(cliopt[curEnc].reuseName, cliopt[refEnc].encName))<br>
+                {<br>
+                    cliopt[curEnc].refId = refEnc;<br>
+                    cliopt[refEnc].numRefs++;<br>
+                    cliopt[refEnc].saveLevel = X265_MAX(cliopt[refEnc].saveLevel, cliopt[curEnc].loadLevel);<br>
+                    isRefFound = true;<br>
+                    break;<br>
+                }<br>
+            }<br>
+            if (!isRefFound)<br>
+            {<br>
+                x265_log(NULL, X265_LOG_ERROR, "Reference encode (%s) not found for %s\n", cliopt[curEnc].reuseName,<br>
+                    cliopt[curEnc].encName);<br>
+                return false;<br>
+            }<br>
+        }<br>
+    }<br>
+    return true;<br>
+}<br>
 /* CLI return codes:<br>
  *<br>
  * 0 - encode successful<br></blockquote><div>[KS] Are these CLI codes still valid?</div></div></div></blockquote><div>[AM] This is handled in the subsequent patch. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
@@ -168,354 +289,42 @@<br>
     get_argv_utf8(&argc, &argv);<br>
 #endif<br>
<br>
-    ReconPlay* reconPlay = NULL;<br>
-    CLIOptions cliopt;<br>
+    uint8_t numEncodes = 1;<br>
+    FILE *abrConfig = NULL;<br>
+    bool isAbrLadder = IsAbrLadder(argc, argv, &abrConfig);<br></blockquote><div>[KS] Function naming convention. If there is conflict with variable name, can we change the function name ?</div></div></div></blockquote><div>[AM] Will change the function name.  </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+    if (isAbrLadder)<br>
+        numEncodes = getNumAbrEncodes(abrConfig);<br>
+<br>
+    CLIOptions* cliopt = new CLIOptions[numEncodes];<br>
<br>
-    if (cliopt.parse(argc, argv))<br>
+    if (isAbrLadder)<br>
     {<br>
-        cliopt.destroy();<br>
-        if (cliopt.api)<br>
-            cliopt.api->param_free(cliopt.param);<br>
+        if(!parseAbrConfig(abrConfig, cliopt))<br></blockquote><div>[KS]Space </div></div></div></blockquote><div>[AM] will fix. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+            exit(1);<br>
+        if(!setRefContext(cliopt, numEncodes))<br></blockquote><div>

[KS]Space
</div></div></div></blockquote><div>

[AM] will fix. 

 </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>
 </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+            exit(1);<br>
+    }<br>
+    else if(cliopt[0].parse(argc, argv))<br></blockquote><div>

[KS]Space</div></div></div></blockquote><div>

[AM] will fix. 

 </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>

 </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+    {<br>
+        cliopt[0].destroy();<br>
+        if (cliopt[0].api)<br>
+            cliopt[0].api->param_free(cliopt[0].param);<br>
         exit(1);<br>
     }<br>
<br>
-    x265_param* param = cliopt.param;<br>
-    const x265_api* api = cliopt.api;<br>
-#if ENABLE_LIBVMAF<br>
-    x265_vmaf_data* vmafdata = cliopt.vmafData;<br>
-#endif<br>
-    /* This allows muxers to modify bitstream format */<br>
-    cliopt.output->setParam(param);<br>
-<br>
-    if (cliopt.reconPlayCmd)<br>
-        reconPlay = new ReconPlay(cliopt.reconPlayCmd, *param);<br>
-<br>
-    if (cliopt.zoneFile)<br>
-    {<br>
-        if (!cliopt.parseZoneFile())<br>
-        {<br>
-            x265_log(NULL, X265_LOG_ERROR, "Unable to parse zonefile\n");<br>
-            fclose(cliopt.zoneFile);<br>
-            cliopt.zoneFile = NULL;<br>
-        }<br>
-    }<br>
-<br>
-    /* note: we could try to acquire a different libx265 API here based on<br>
-     * the profile found during option parsing, but it must be done before<br>
-     * opening an encoder */<br>
-<br>
-    x265_encoder *encoder = api->encoder_open(param);<br>
-    if (!encoder)<br>
-    {<br>
-        x265_log(param, X265_LOG_ERROR, "failed to open encoder\n");<br>
-        cliopt.destroy();<br>
-        api->param_free(param);<br>
-        api->cleanup();<br>
-        exit(2);<br>
-    }<br>
-<br>
-    /* get the encoder parameters post-initialization */<br>
-    api->encoder_parameters(encoder, param);<br>
-<br>
-     /* Control-C handler */<br>
-    if (signal(SIGINT, sigint_handler) == SIG_ERR)<br>
-        x265_log(param, X265_LOG_ERROR, "Unable to register CTRL+C handler: %s\n", strerror(errno));<br>
+    int ret = 0;<br></blockquote><div>[KS] Ret is unmodified. Do we need it?</div></div></div></blockquote><div>[AM] Handled in the subsequent patch. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
-    x265_picture pic_orig, pic_out;<br>
-    x265_picture *pic_in = &pic_orig;<br>
-    /* Allocate recon picture if analysis save/load is enabled */<br>
-    std::priority_queue<int64_t>* pts_queue = cliopt.output->needPTS() ? new std::priority_queue<int64_t>() : NULL;<br>
-    x265_picture *pic_recon = (cliopt.recon || param->analysisSave || param->analysisLoad || pts_queue || reconPlay || param->csvLogLevel) ? &pic_out : NULL;<br>
-    uint32_t inFrameCount = 0;<br>
-    uint32_t outFrameCount = 0;<br>
-    x265_nal *p_nal;<br>
-    x265_stats stats;<br>
-    uint32_t nal;<br>
-    int16_t *errorBuf = NULL;<br>
-    bool bDolbyVisionRPU = false;<br>
-    uint8_t *rpuPayload = NULL;<br>
-    int ret = 0;<br>
-    int inputPicNum = 1;<br>
-    x265_picture picField1, picField2;<br>
-<br>
-    if (!param->bRepeatHeaders && !param->bEnableSvtHevc)<br>
+    AbrEncoder* abrEnc = new AbrEncoder(cliopt, numEncodes, ret);<br>
+    int threadsActive = abrEnc->m_numActiveEncodes.get();<br>
+    while (threadsActive)<br>
     {<br>
-        if (api->encoder_headers(encoder, &p_nal, &nal) < 0)<br>
-        {<br>
-            x265_log(param, X265_LOG_ERROR, "Failure generating stream headers\n");<br>
-            ret = 3;<br>
-            goto fail;<br>
-        }<br>
-        else<br>
-            cliopt.totalbytes += cliopt.output->writeHeaders(p_nal, nal);<br>
-    }<br>
-<br>
-    if (param->bField && param->interlaceMode)<br>
-    {<br>
-        api->picture_init(param, &picField1);<br>
-        api->picture_init(param, &picField2);<br>
-        // return back the original height of input<br>
-        param->sourceHeight *= 2;<br>
-        api->picture_init(param, pic_in);<br>
-    }<br>
-    else<br>
-        api->picture_init(param, pic_in);<br>
-<br>
-    if (param->dolbyProfile && cliopt.dolbyVisionRpu)<br>
-    {<br>
-        rpuPayload = X265_MALLOC(uint8_t, 1024);<br>
-        pic_in->rpu.payload = rpuPayload;<br>
-        if (pic_in->rpu.payload)<br>
-            bDolbyVisionRPU = true;<br>
-    }<br>
-    <br>
-    if (cliopt.bDither)<br>
-    {<br>
-        errorBuf = X265_MALLOC(int16_t, param->sourceWidth + 1);<br>
-        if (errorBuf)<br>
-            memset(errorBuf, 0, (param->sourceWidth + 1) * sizeof(int16_t));<br>
-        else<br>
-            cliopt.bDither = false;<br>
+        threadsActive = abrEnc->m_numActiveEncodes.waitForChange(threadsActive);<br>
     }<br>
<br>
-    // main encoder loop<br>
-    while (pic_in && !b_ctrl_c)<br>
-    {<br>
-        pic_orig.poc = (param->bField && param->interlaceMode) ? inFrameCount * 2 : inFrameCount;<br>
-        if (cliopt.qpfile)<br>
-        {<br>
-            if (!cliopt.parseQPFile(pic_orig))<br>
-            {<br>
-                x265_log(NULL, X265_LOG_ERROR, "can't parse qpfile for frame %d\n", pic_in->poc);<br>
-                fclose(cliopt.qpfile);<br>
-                cliopt.qpfile = NULL;<br>
-            }<br>
-        }<br>
-<br>
-        if (cliopt.framesToBeEncoded && inFrameCount >= cliopt.framesToBeEncoded)<br>
-            pic_in = NULL;<br>
-        else if (cliopt.input->readPicture(pic_orig))<br>
-            inFrameCount++;<br>
-        else<br>
-            pic_in = NULL;<br>
-<br>
-        if (pic_in)<br>
-        {<br>
-            if (pic_in->bitDepth > param->internalBitDepth && cliopt.bDither)<br>
-            {<br>
-                x265_dither_image(pic_in, cliopt.input->getWidth(), cliopt.input->getHeight(), errorBuf, param->internalBitDepth);<br>
-                pic_in->bitDepth = param->internalBitDepth;<br>
-            }<br>
-            /* Overwrite PTS */<br>
-            pic_in->pts = pic_in->poc;<br>
-<br>
-            // convert to field<br>
-            if (param->bField && param->interlaceMode)<br>
-            {<br>
-                int height = pic_in->height >> 1;<br>
-                <br>
-                int static bCreated = 0;<br>
-                if (bCreated == 0)<br>
-                {<br>
-                    bCreated = 1;<br>
-                    inputPicNum = 2;<br>
-                    picField1.fieldNum = 1;<br>
-                    picField2.fieldNum = 2;<br>
-<br>
-                    picField1.bitDepth = picField2.bitDepth = pic_in->bitDepth;<br>
-                    picField1.colorSpace = picField2.colorSpace = pic_in->colorSpace;<br>
-                    picField1.height = picField2.height = pic_in->height >> 1;<br>
-                    picField1.framesize = picField2.framesize = pic_in->framesize >> 1;<br>
-<br>
-                    size_t fieldFrameSize = (size_t)pic_in->framesize >> 1;<br>
-                    char* field1Buf = X265_MALLOC(char, fieldFrameSize);<br>
-                    char* field2Buf = X265_MALLOC(char, fieldFrameSize);<br>
-  <br>
-                    int stride = picField1.stride[0] = picField2.stride[0] = pic_in->stride[0];<br>
-                    uint64_t framesize = stride * (height >> x265_cli_csps[pic_in->colorSpace].height[0]);<br>
-                    picField1.planes[0] = field1Buf;<br>
-                    picField2.planes[0] = field2Buf;<br>
-                    for (int i = 1; i < x265_cli_csps[pic_in->colorSpace].planes; i++)<br>
-                    {<br>
-                        picField1.planes[i] = field1Buf + framesize;<br>
-                        picField2.planes[i] = field2Buf + framesize;<br>
-<br>
-                        stride = picField1.stride[i] = picField2.stride[i] = pic_in->stride[i];<br>
-                        framesize += (stride * (height >> x265_cli_csps[pic_in->colorSpace].height[i]));<br>
-                    }<br>
-                    assert(framesize  == picField1.framesize);<br>
-                }<br>
-<br>
-                picField1.pts = picField1.poc = pic_in->poc;<br>
-                picField2.pts = picField2.poc = pic_in->poc + 1;<br>
-<br>
-                picField1.userSEI = picField2.userSEI = pic_in->userSEI;<br>
-<br>
-                //if (pic_in->userData)<br>
-                //{<br>
-                //    // Have to handle userData here<br>
-                //}<br>
-<br>
-                if (pic_in->framesize)<br>
-                {<br>
-                    for (int i = 0; i < x265_cli_csps[pic_in->colorSpace].planes; i++)<br>
-                    {<br>
-                        char* srcP1 = (char*)pic_in->planes[i];<br>
-                        char* srcP2 = (char*)pic_in->planes[i] + pic_in->stride[i];<br>
-                        char* p1 = (char*)picField1.planes[i];<br>
-                        char* p2 = (char*)picField2.planes[i];<br>
-<br>
-                        int stride = picField1.stride[i];<br>
-<br>
-                        for (int y = 0; y < (height >> x265_cli_csps[pic_in->colorSpace].height[i]); y++)<br>
-                        {<br>
-                            memcpy(p1, srcP1, stride);<br>
-                            memcpy(p2, srcP2, stride);<br>
-                            srcP1 += 2*stride;<br>
-                            srcP2 += 2*stride;<br>
-                            p1 += stride;<br>
-                            p2 += stride;<br>
-                        }<br>
-                    }<br>
-                }<br>
-            }<br>
-<br>
-            if (bDolbyVisionRPU)<br>
-            {<br>
-                if (param->bField && param->interlaceMode)<br>
-                {<br>
-                    if (rpuParser(&picField1, cliopt.dolbyVisionRpu) > 0)<br>
-                        goto fail;<br>
-                    if (rpuParser(&picField2, cliopt.dolbyVisionRpu) > 0)<br>
-                        goto fail;<br>
-                }<br>
-                else<br>
-                {<br>
-                    if (rpuParser(pic_in, cliopt.dolbyVisionRpu) > 0)<br>
-                        goto fail;<br>
-                }<br>
-            }<br>
-        }<br>
-                <br>
-        for (int inputNum = 0; inputNum < inputPicNum; inputNum++)<br>
-        {  <br>
-            x265_picture *picInput = NULL;<br>
-            if (inputPicNum == 2)<br>
-                picInput = pic_in ? (inputNum ? &picField2 : &picField1) : NULL;<br>
-            else<br>
-                picInput = pic_in;<br>
-<br>
-            int numEncoded = api->encoder_encode( encoder, &p_nal, &nal, picInput, pic_recon );<br>
-            if( numEncoded < 0 )<br>
-            {<br>
-                b_ctrl_c = 1;<br>
-                ret = 4;<br>
-                break;<br>
-            }<br>
-<br>
-            if (reconPlay && numEncoded)<br>
-                reconPlay->writePicture(*pic_recon);<br>
-<br>
-            outFrameCount += numEncoded;<br>
-<br>
-            if (numEncoded && pic_recon && cliopt.recon)<br>
-                cliopt.recon->writePicture(pic_out);<br>
-            if (nal)<br>
-            {<br>
-                cliopt.totalbytes += cliopt.output->writeFrame(p_nal, nal, pic_out);<br>
-                if (pts_queue)<br>
-                {<br>
-                    pts_queue->push(-pic_out.pts);<br>
-                    if (pts_queue->size() > 2)<br>
-                        pts_queue->pop();<br>
-                }<br>
-            }<br>
-            cliopt.printStatus( outFrameCount );<br>
-        }<br>
-    }<br>
-<br>
-    /* Flush the encoder */<br>
-    while (!b_ctrl_c)<br>
-    {<br>
-        int numEncoded = api->encoder_encode(encoder, &p_nal, &nal, NULL, pic_recon);<br>
-        if (numEncoded < 0)<br>
-        {<br>
-            ret = 4;<br>
-            break;<br>
-        }<br>
-<br>
-        if (reconPlay && numEncoded)<br>
-            reconPlay->writePicture(*pic_recon);<br>
-<br>
-        outFrameCount += numEncoded;<br>
-        if (numEncoded && pic_recon && cliopt.recon)<br>
-            cliopt.recon->writePicture(pic_out);<br>
-        if (nal)<br>
-        {<br>
-            cliopt.totalbytes += cliopt.output->writeFrame(p_nal, nal, pic_out);<br>
-            if (pts_queue)<br>
-            {<br>
-                pts_queue->push(-pic_out.pts);<br>
-                if (pts_queue->size() > 2)<br>
-                    pts_queue->pop();<br>
-            }<br>
-        }<br>
-<br>
-        cliopt.printStatus(outFrameCount);<br>
-<br>
-        if (!numEncoded)<br>
-            break;<br>
-    }<br>
-  <br>
-    if (bDolbyVisionRPU)<br>
-    {<br>
-        if(fgetc(cliopt.dolbyVisionRpu) != EOF)<br>
-            x265_log(NULL, X265_LOG_WARNING, "Dolby Vision RPU count is greater than frame count\n");<br>
-        x265_log(NULL, X265_LOG_INFO, "VES muxing with Dolby Vision RPU file successful\n");<br>
-    }<br>
-<br>
-    /* clear progress report */<br>
-    if (cliopt.bProgress)<br>
-        fprintf(stderr, "%*s\r", 80, " ");<br>
-<br>
-fail:<br>
-<br>
-    delete reconPlay;<br>
-<br>
-    api->encoder_get_stats(encoder, &stats, sizeof(stats));<br>
-    if (param->csvfn && !b_ctrl_c)<br>
-#if ENABLE_LIBVMAF<br>
-        api->vmaf_encoder_log(encoder, argc, argv, param, vmafdata);<br>
-#else<br>
-        api->encoder_log(encoder, argc, argv);<br>
-#endif<br>
-    api->encoder_close(encoder);<br>
-<br>
-    int64_t second_largest_pts = 0;<br>
-    int64_t largest_pts = 0;<br>
-    if (pts_queue && pts_queue->size() >= 2)<br>
-    {<br>
-        second_largest_pts = -pts_queue->top();<br>
-        pts_queue->pop();<br>
-        largest_pts = -pts_queue->top();<br>
-        pts_queue->pop();<br>
-        delete pts_queue;<br>
-        pts_queue = NULL;<br>
-    }<br>
-    cliopt.output->closeFile(largest_pts, second_largest_pts);<br>
-<br>
-    if (b_ctrl_c)<br>
-        general_log(param, NULL, X265_LOG_INFO, "aborted at input frame %d, output frame %d\n",<br>
-                    cliopt.seek + inFrameCount, stats.encodedPictureCount);<br>
-<br>
-    api->cleanup(); /* Free library singletons */<br>
-<br>
-    cliopt.destroy();<br>
-<br>
-    api->param_free(param);<br>
-<br>
-    X265_FREE(errorBuf);<br>
-    X265_FREE(rpuPayload);<br>
+    abrEnc->destroy();<br>
+    for (uint8_t idx = 0; idx < numEncodes; idx++)<br>
+        cliopt[idx].destroy();<br>
<br>
     SetConsoleTitle(orgConsoleTitle);<br>
     SetThreadExecutionState(ES_CONTINUOUS);<br>
diff -r 3eccfeafc040 -r d78121f6445e source/x265cli.cpp<br>
--- a/source/x265cli.cpp        Wed Feb 26 16:37:13 2020 +0530<br>
+++ b/source/x265cli.cpp        Tue Mar 31 16:43:30 2020 +0530<br>
@@ -348,6 +348,8 @@<br>
         H0("   --svt-pred-struct             Select pred structure for SVT HEVC encoder;  Accepts inputs in the range 0-2 \n");<br>
         H0("   --[no-]svt-fps-in-vps         Enable VPS timing info for SVT HEVC encoder  \n");<br>
 #endif<br>
+        H0(" ABR-ladder settings\n");<br>
+        H0("   --abr-ladder <file>           File containing config settings required for the generation of ABR-ladder\n");<br>
         H1("\nExecutable return codes:\n");<br>
         H1("    0 - encode successful\n");<br>
         H1("    1 - unable to parse command line\n");<br>
diff -r 3eccfeafc040 -r d78121f6445e source/x265cli.h<br>
--- a/source/x265cli.h  Wed Feb 26 16:37:13 2020 +0530<br>
+++ b/source/x265cli.h  Tue Mar 31 16:43:30 2020 +0530<br>
@@ -372,6 +372,7 @@<br>
     { "cll", no_argument, NULL, 0 },<br>
     { "no-cll", no_argument, NULL, 0 },<br>
     { "hme-range", required_argument, NULL, 0 },<br>
+    { "abr-ladder", required_argument, NULL, 0 },<br>
     { 0, 0, 0, 0 },<br>
     { 0, 0, 0, 0 },<br>
     { 0, 0, 0, 0 },<br>
@@ -399,6 +400,18 @@<br>
         uint64_t totalbytes;<br>
         int64_t startTime;<br>
         int64_t prevUpdateTime;<br>
+<br>
+        /* ABR ladder settings */<br>
+        bool enableScaler;<br>
+        char*    encName;<br>
+        char*    reuseName;<br>
+        uint32_t encId;<br>
+        int      refId;<br>
+        uint32_t loadLevel;<br>
+        uint32_t saveLevel;<br>
+        uint32_t numRefs;<br>
+<br>
+<br>
         /* in microseconds */<br>
         static const int UPDATE_INTERVAL = 250000;<br>
         CLIOptions()<br>
@@ -420,6 +433,12 @@<br>
             startTime = x265_mdate();<br>
             prevUpdateTime = 0;<br>
             bDither = false;<br>
+            enableScaler = false;<br>
+            encId = 0;<br>
+            refId = -1;<br>
+            loadLevel = 0;<br>
+            saveLevel = 0;<br>
+            numRefs = 0;<br>
         }<br>
<br>
         void destroy();<br>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org" target="_blank">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr"><div dir="ltr"><div><div dir="ltr"><span style="color:rgb(0,0,0)">Regards,<br>Kavitha</span></div></div></div></div></div>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org" target="_blank">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr"><div dir="ltr"><div><div dir="ltr"><div><div dir="ltr"><div><div dir="ltr"><font face="georgia, serif">Regards,</font><div><b><font face="georgia, serif">Aruna Matheswaran,</font></b></div><div><font face="georgia, serif">Video Codec Engineer,</font></div><div><font face="georgia, serif">Media & AI analytics BU,</font></div><div><span><span style="font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap"><span style="border:none;display:inline-block;overflow:hidden;width:153px;height:58px"><img src="https://lh5.googleusercontent.com/gjX5cPNIZgwUrhfqkTwQUZWztIKmmo0qs3kbwvkS5H-bDVE2ftte9pMTVnFLSjOcjYWLtfc6_OGpxW4vraLg2r5QAIf1Q3MpldFDgWtzK_gXi8ptw5B3joIbsGL6mxj-JRdjHzT5" width="96" height="36" style="margin-left:0px;margin-top:0px"></span></span></span><font face="georgia, serif"><br></font></div><div><span><span style="font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap"><span style="border:none;display:inline-block;overflow:hidden;width:153px;height:58px"><img src="https://lh5.googleusercontent.com/gjX5cPNIZgwUrhfqkTwQUZWztIKmmo0qs3kbwvkS5H-bDVE2ftte9pMTVnFLSjOcjYWLtfc6_OGpxW4vraLg2r5QAIf1Q3MpldFDgWtzK_gXi8ptw5B3joIbsGL6mxj-JRdjHzT5" style="margin-left:0px;margin-top:0px"></span></span></span><font face="georgia, serif"><br></font></div><div><font face="georgia, serif"><br></font></div></div></div></div></div></div></div></div></div></div>