<div dir="ltr">From 9a1baf8cbcfa95be89fd72b00c6b531ede4fb66f Mon Sep 17 00:00:00 2001<br>From: Kirithika <<a href="mailto:kirithika@multicorewareinc.com">kirithika@multicorewareinc.com</a>><br>Date: Fri, 5 Jul 2024 15:28:10 +0530<br>Subject: [PATCH] Add support for reconstructed file corresponding to Alpha<br> layer.<br><br>This commit also does :<br>1.Receive and proccess frames of all layers corresponding to same POC from the Frame encoder thread.<br>---<br> source/abrEncApp.cpp            |  34 ++-<br> source/encoder/api.cpp          |   4 +-<br> source/encoder/encoder.cpp      | 456 ++++++++++++++++----------------<br> source/encoder/encoder.h        |   4 +-<br> source/encoder/frameencoder.cpp |  24 +-<br> source/encoder/frameencoder.h   |   3 +-<br> source/x265.h                   |   4 +-<br> source/x265cli.cpp              |  54 ++--<br> source/x265cli.h                |   5 +-<br> 9 files changed, 320 insertions(+), 268 deletions(-)<br><br>diff --git a/source/abrEncApp.cpp b/source/abrEncApp.cpp<br>index 96c854de6..eabfb7d2b 100644<br>--- a/source/abrEncApp.cpp<br>+++ b/source/abrEncApp.cpp<br>@@ -530,11 +530,13 @@ ret:<br>                 x265_log(m_param, X265_LOG_ERROR, "Unable to register CTRL+C handler: %s in %s\n",<br>                     strerror(errno), profileName);<br> <br>-            x265_picture pic_orig, pic_out;<br>+            x265_picture pic_orig, pic_out[MAX_SCALABLE_LAYERS];<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 = m_cliopt.output->needPTS() ? new std::priority_queue<int64_t>() : NULL;<br>-            x265_picture *pic_recon = (m_cliopt.recon || m_param->analysisSave || m_param->analysisLoad || pts_queue || reconPlay || m_param->csvLogLevel) ? &pic_out : NULL;<br>+            x265_picture *pic_recon[MAX_SCALABLE_LAYERS];<br>+            for(int i = 0; i < m_param->numScalableLayers; i++)<br>+                pic_recon[i] = (m_cliopt.recon[i] || m_param->analysisSave || m_param->analysisLoad || pts_queue || reconPlay || m_param->csvLogLevel) ? &pic_out[i] : NULL;<br>             uint32_t inFrameCount = 0;<br>             uint32_t outFrameCount = 0;<br>             x265_nal *p_nal;<br>@@ -545,7 +547,7 @@ ret:<br>             uint8_t *rpuPayload = NULL;<br>             int inputPicNum = 1;<br>             x265_picture picField1, picField2;<br>-            x265_analysis_data* analysisInfo = (x265_analysis_data*)(&pic_out.analysisData);<br>+            x265_analysis_data* analysisInfo = (x265_analysis_data*)(&pic_out[0].analysisData);<br>             bool isAbrSave = m_cliopt.saveLevel && (m_parent->m_numEncodes > 1);<br> <br>             if (!m_param->bRepeatHeaders && !m_param->bEnableSvtHevc)<br>@@ -735,7 +737,7 @@ ret:<br>                     }<br> <br>                     if (reconPlay && numEncoded)<br>-                        reconPlay->writePicture(*pic_recon);<br>+                        reconPlay->writePicture(*pic_recon[0]);<br> <br>                     outFrameCount += numEncoded;<br> <br>@@ -744,14 +746,17 @@ ret:<br>                         copyInfo(analysisInfo);<br>                     }<br> <br>-                    if (numEncoded && pic_recon && m_cliopt.recon)<br>-                        m_cliopt.recon->writePicture(pic_out);<br>+                    for (int i = 0; i < m_param->numScalableLayers; i++)<br>+                    {<br>+                        if (numEncoded && pic_recon[i] && m_cliopt.recon[i])<br>+                            m_cliopt.recon[i]->writePicture(pic_out[i]);<br>+                    }<br>                     if (nal)<br>                     {<br>-                        m_cliopt.totalbytes += m_cliopt.output->writeFrame(p_nal, nal, pic_out);<br>+                        m_cliopt.totalbytes += m_cliopt.output->writeFrame(p_nal, nal, pic_out[0]);<br>                         if (pts_queue)<br>                         {<br>-                            pts_queue->push(-pic_out.pts);<br>+                            pts_queue->push(-pic_out[0].pts);<br>                             if (pts_queue->size() > 2)<br>                                 pts_queue->pop();<br>                         }<br>@@ -771,7 +776,7 @@ ret:<br>                 }<br> <br>                 if (reconPlay && numEncoded)<br>-                    reconPlay->writePicture(*pic_recon);<br>+                    reconPlay->writePicture(*pic_recon[0]);<br> <br>                 outFrameCount += numEncoded;<br>                 if (isAbrSave && numEncoded)<br>@@ -779,14 +784,17 @@ ret:<br>                     copyInfo(analysisInfo);<br>                 }<br> <br>-                if (numEncoded && pic_recon && m_cliopt.recon)<br>-                    m_cliopt.recon->writePicture(pic_out);<br>+                for (int i = 0; i < m_param->numScalableLayers; i++)<br>+                {<br>+                    if (numEncoded && pic_recon[i] && m_cliopt.recon[i])<br>+                        m_cliopt.recon[i]->writePicture(pic_out[i]);<br>+                }<br>                 if (nal)<br>                 {<br>-                    m_cliopt.totalbytes += m_cliopt.output->writeFrame(p_nal, nal, pic_out);<br>+                    m_cliopt.totalbytes += m_cliopt.output->writeFrame(p_nal, nal, pic_out[0]);<br>                     if (pts_queue)<br>                     {<br>-                        pts_queue->push(-pic_out.pts);<br>+                        pts_queue->push(-pic_out[0].pts);<br>                         if (pts_queue->size() > 2)<br>                             pts_queue->pop();<br>                     }<br>diff --git a/source/encoder/api.cpp b/source/encoder/api.cpp<br>index 33e98a066..60893f4d1 100644<br>--- a/source/encoder/api.cpp<br>+++ b/source/encoder/api.cpp<br>@@ -406,7 +406,7 @@ int x265_encoder_reconfig_zone(x265_encoder* enc, x265_zone* zone_in)<br>     return 0;<br> }<br> <br>-int x265_encoder_encode(x265_encoder *enc, x265_nal **pp_nal, uint32_t *pi_nal, x265_picture *pic_in, x265_picture *pic_out)<br>+int x265_encoder_encode(x265_encoder *enc, x265_nal **pp_nal, uint32_t *pi_nal, x265_picture *pic_in, x265_picture **pic_out)<br> {<br>     if (!enc)<br>         return -1;<br>@@ -602,7 +602,7 @@ fail:<br>         *pi_nal = 0;<br> <br>     if (numEncoded && encoder->m_param->csvLogLevel && encoder->m_outputCount >= encoder->m_latestParam->chunkStart)<br>-        x265_csvlog_frame(encoder->m_param, pic_out);<br>+        x265_csvlog_frame(encoder->m_param, pic_out[0]);<br> <br>     if (numEncoded < 0)<br>         encoder->m_aborted = true;<br>diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp<br>index e61db1ebc..4ac71f654 100644<br>--- a/source/encoder/encoder.cpp<br>+++ b/source/encoder/encoder.cpp<br>@@ -134,7 +134,6 @@ Encoder::Encoder()<br>     m_lookahead = NULL;<br>     m_rateControl = NULL;<br>     m_dpb = NULL;<br>-    m_exportedPic = NULL;<br>     m_numDelayedPic = 0;<br>     m_outputCount = 0;<br>     m_param = NULL;<br>@@ -150,6 +149,8 @@ Encoder::Encoder()<br>     m_rpsInSpsCount = 0;<br>     m_cB = 1.0;<br>     m_cR = 1.0;<br>+    for (int i = 0; i < MAX_SCALABLE_LAYERS; i++)<br>+        m_exportedPic[i] = NULL;<br>     for (int i = 0; i < X265_MAX_FRAME_THREADS; i++)<br>         m_frameEncoder[i] = NULL;<br>     for (uint32_t i = 0; i < DUP_BUFFER; i++)<br>@@ -861,10 +862,13 @@ void Encoder::destroy()<br>         X265_FREE(m_rdCost);<br>         X265_FREE(m_trainingCount);<br>     }<br>-    if (m_exportedPic)<br>+    for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>     {<br>-        ATOMIC_DEC(&m_exportedPic->m_countRefEncoders);<br>-        m_exportedPic = NULL;<br>+        if (m_exportedPic[layer])<br>+        {<br>+            ATOMIC_DEC(&m_exportedPic[layer]->m_countRefEncoders);<br>+            m_exportedPic[layer] = NULL;<br>+        }<br>     }<br> <br>     if (m_param->bEnableFrameDuplication)<br>@@ -1462,7 +1466,7 @@ bool Encoder::generateMcstfRef(Frame* frameEnc, FrameEncoder* currEncoder)<br>  * returns 0 if no frames are currently available for output<br>  *         1 if frame was output, m_nalList contains access unit<br>  *         negative on malloc error or abort */<br>-int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>+int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<br> {<br> #if CHECKED_BUILD || _DEBUG<br>     if (g_checkFailures)<br>@@ -1479,14 +1483,16 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>     bool dontRead = false;<br>     bool dropflag = false;<br> <br>-    if (m_exportedPic)<br>+    if (*m_exportedPic)<br>     {<br>         if (!m_param->bUseAnalysisFile && m_param->analysisSave)<br>-            x265_free_analysis_data(m_param, &m_exportedPic->m_analysisData);<br>-<br>-        ATOMIC_DEC(&m_exportedPic->m_countRefEncoders);<br>+            x265_free_analysis_data(m_param, &m_exportedPic[0]->m_analysisData);<br> <br>-        m_exportedPic = NULL;<br>+        for (int i = 0; i < m_param->numScalableLayers; i++)<br>+        {<br>+            ATOMIC_DEC(&m_exportedPic[i]->m_countRefEncoders);<br>+            m_exportedPic[i] = NULL;<br>+        }<br>         m_dpb->recycleUnreferenced();<br> <br>         if (m_param->bEnableTemporalFilter)<br>@@ -1579,7 +1585,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br> <br>         Frame* inFrame[MAX_SCALABLE_LAYERS];<br>         x265_param *p = (m_reconfigure || m_reconfigureRc) ? m_latestParam : m_param;<br>-        for (int layer = 0; layer < MAX_SCALABLE_LAYERS; layer++)<br>+        for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>         {<br>             if (m_dpb->m_freeList.empty())<br>             {<br>@@ -1648,6 +1654,8 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>                 inFrame[layer]->m_tempLayer = 0;<br>                 inFrame[layer]->m_sameLayerRefPic = 0;<br>                 inFrame[layer]->m_sLayerId = layer;<br>+                inFrame[layer]->m_valid = false;<br>+                inFrame[layer]->m_lowres.bKeyframe = false;<br>             }<br> <br>             /* Copy input picture into a Frame and PicYuv, send to lookahead */<br>@@ -1887,7 +1895,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>      * and then to give it a new frame to work on.  In zero-latency mode, we must encode this<br>      * input picture before returning so the order must be reversed. This do/while() loop allows<br>      * us to alternate the order of the calls without ugly code replication */<br>-    Frame* outFrame = NULL;<br>+    Frame** outFrames = { NULL };<br>     Frame* frameEnc[MAX_SCALABLE_LAYERS] = { NULL };<br>     int pass = 0;<br>     do<br>@@ -1896,243 +1904,246 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>          * encoding the frame.  This is how back-pressure through the API is<br>          * accomplished when the encoder is full */<br>         if (!m_bZeroLatency || pass)<br>-            outFrame = curEncoder->getEncodedPicture(m_nalList);<br>-        if (outFrame)<br>+            outFrames = curEncoder->getEncodedPicture(m_nalList);<br>+        if (outFrames)<br>         {<br>-            Slice *slice = outFrame->m_encData->m_slice;<br>-            x265_frame_stats* frameData = NULL;<br>-<br>-            /* Free up inputPic->analysisData since it has already been used */<br>-            if ((m_param->analysisLoad && !m_param->analysisSave) || ((m_param->bAnalysisType == AVC_INFO) && slice->m_sliceType != I_SLICE))<br>-                x265_free_analysis_data(m_param, &outFrame->m_analysisData);<br>-<br>-            if (pic_out)<br>+            for (int sLayer = 0; sLayer < m_param->numScalableLayers; sLayer++)<br>             {<br>-                PicYuv *recpic = outFrame->m_reconPic;<br>-                pic_out->poc = slice->m_poc;<br>-                pic_out->bitDepth = X265_DEPTH;<br>-                pic_out->userData = outFrame->m_userData;<br>-                pic_out->colorSpace = m_param->internalCsp;<br>-                pic_out->frameData.tLayer = outFrame->m_tempLayer;<br>-                frameData = &(pic_out->frameData);<br>-<br>-                pic_out->pts = outFrame->m_pts;<br>-                pic_out->dts = outFrame->m_dts;<br>-                pic_out->reorderedPts = outFrame->m_reorderedPts;<br>-                pic_out->sliceType = outFrame->m_lowres.sliceType;<br>-                pic_out->planes[0] = recpic->m_picOrg[0];<br>-                pic_out->stride[0] = (int)(recpic->m_stride * sizeof(pixel));<br>-                if (m_param->internalCsp != X265_CSP_I400)<br>+                Frame* outFrame = *(outFrames + sLayer);<br>+                Slice* slice = outFrame->m_encData->m_slice;<br>+                x265_frame_stats* frameData = NULL;<br>+<br>+                /* Free up inputPic->analysisData since it has already been used */<br>+                if ((m_param->analysisLoad && !m_param->analysisSave) || ((m_param->bAnalysisType == AVC_INFO) && slice->m_sliceType != I_SLICE))<br>+                    x265_free_analysis_data(m_param, &outFrame->m_analysisData);<br>+                if (pic_out[sLayer])<br>                 {<br>-                    pic_out->planes[1] = recpic->m_picOrg[1];<br>-                    pic_out->stride[1] = (int)(recpic->m_strideC * sizeof(pixel));<br>-                    pic_out->planes[2] = recpic->m_picOrg[2];<br>-                    pic_out->stride[2] = (int)(recpic->m_strideC * sizeof(pixel));<br>-                }<br>+                    PicYuv* recpic = outFrame->m_reconPic;<br>+                    pic_out[sLayer]->poc = slice->m_poc;<br>+                    pic_out[sLayer]->bitDepth = X265_DEPTH;<br>+                    pic_out[sLayer]->userData = outFrame->m_userData;<br>+                    pic_out[sLayer]->colorSpace = m_param->internalCsp;<br>+                    pic_out[sLayer]->frameData.tLayer = outFrame->m_tempLayer;<br>+                    frameData = &(pic_out[sLayer]->frameData);<br>+<br>+                    pic_out[sLayer]->pts = outFrame->m_pts;<br>+                    pic_out[sLayer]->dts = outFrame->m_dts;<br>+                    pic_out[sLayer]->reorderedPts = outFrame->m_reorderedPts;<br>+                    pic_out[sLayer]->sliceType = outFrame->m_lowres.sliceType;<br>+                    pic_out[sLayer]->planes[0] = recpic->m_picOrg[0];<br>+                    pic_out[sLayer]->stride[0] = (int)(recpic->m_stride * sizeof(pixel));<br>+                    if (m_param->internalCsp != X265_CSP_I400)<br>+                    {<br>+                        pic_out[sLayer]->planes[1] = recpic->m_picOrg[1];<br>+                        pic_out[sLayer]->stride[1] = (int)(recpic->m_strideC * sizeof(pixel));<br>+                        pic_out[sLayer]->planes[2] = recpic->m_picOrg[2];<br>+                        pic_out[sLayer]->stride[2] = (int)(recpic->m_strideC * sizeof(pixel));<br>+                    }<br> <br>-                /* Dump analysis data from pic_out to file in save mode and free */<br>-                if (m_param->analysisSave)<br>-                {<br>-                    pic_out->analysisData.poc = pic_out->poc;<br>-                    pic_out->analysisData.sliceType = pic_out->sliceType;<br>-                    pic_out->analysisData.bScenecut = outFrame->m_lowres.bScenecut;<br>-                    pic_out->analysisData.satdCost  = outFrame->m_lowres.satdCost;<br>-                    pic_out->analysisData.numCUsInFrame = outFrame->m_analysisData.numCUsInFrame;<br>-                    pic_out->analysisData.numPartitions = outFrame->m_analysisData.numPartitions;<br>-                    pic_out->analysisData.wt = outFrame->m_analysisData.wt;<br>-                    pic_out->analysisData.interData = outFrame->m_analysisData.interData;<br>-                    pic_out->analysisData.intraData = outFrame->m_analysisData.intraData;<br>-                    pic_out->analysisData.distortionData = outFrame->m_analysisData.distortionData;<br>-                    pic_out->analysisData.modeFlag[0] = outFrame->m_analysisData.modeFlag[0];<br>-                    pic_out->analysisData.modeFlag[1] = outFrame->m_analysisData.modeFlag[1];<br>-                    if (m_param->bDisableLookahead)<br>+                    /* Dump analysis data from pic_out[sLayer] to file in save mode and free */<br>+                    if (m_param->analysisSave)<br>                     {<br>-                        int factor = 1;<br>-                        if (m_param->scaleFactor)<br>-                            factor = m_param->scaleFactor * 2;<br>-                        pic_out->analysisData.numCuInHeight = outFrame->m_analysisData.numCuInHeight;<br>-                        pic_out->analysisData.lookahead.dts = outFrame->m_dts;<br>-                        pic_out->analysisData.lookahead.reorderedPts = outFrame->m_reorderedPts;<br>-                        pic_out->analysisData.satdCost *= factor;<br>-                        pic_out->analysisData.lookahead.keyframe = outFrame->m_lowres.bKeyframe;<br>-                        pic_out->analysisData.lookahead.lastMiniGopBFrame = outFrame->m_lowres.bLastMiniGopBFrame;<br>-                        if (m_rateControl->m_isVbv)<br>+                        pic_out[sLayer]->analysisData.poc = pic_out[sLayer]->poc;<br>+                        pic_out[sLayer]->analysisData.sliceType = pic_out[sLayer]->sliceType;<br>+                        pic_out[sLayer]->analysisData.bScenecut = outFrame->m_lowres.bScenecut;<br>+                        pic_out[sLayer]->analysisData.satdCost = outFrame->m_lowres.satdCost;<br>+                        pic_out[sLayer]->analysisData.numCUsInFrame = outFrame->m_analysisData.numCUsInFrame;<br>+                        pic_out[sLayer]->analysisData.numPartitions = outFrame->m_analysisData.numPartitions;<br>+                        pic_out[sLayer]->analysisData.wt = outFrame->m_analysisData.wt;<br>+                        pic_out[sLayer]->analysisData.interData = outFrame->m_analysisData.interData;<br>+                        pic_out[sLayer]->analysisData.intraData = outFrame->m_analysisData.intraData;<br>+                        pic_out[sLayer]->analysisData.distortionData = outFrame->m_analysisData.distortionData;<br>+                        pic_out[sLayer]->analysisData.modeFlag[0] = outFrame->m_analysisData.modeFlag[0];<br>+                        pic_out[sLayer]->analysisData.modeFlag[1] = outFrame->m_analysisData.modeFlag[1];<br>+                        if (m_param->bDisableLookahead)<br>                         {<br>-                            int vbvCount = m_param->lookaheadDepth + m_param->bframes + 2;<br>-                            for (int index = 0; index < vbvCount; index++)<br>-                            {<br>-                                pic_out->analysisData.lookahead.plannedSatd[index] = outFrame->m_lowres.plannedSatd[index];<br>-                                pic_out->analysisData.lookahead.plannedType[index] = outFrame->m_lowres.plannedType[index];<br>-                            }<br>-                            for (uint32_t index = 0; index < pic_out->analysisData.numCuInHeight; index++)<br>-                            {<br>-                                outFrame->m_analysisData.lookahead.intraSatdForVbv[index] = outFrame->m_encData->m_rowStat[index].intraSatdForVbv;<br>-                                outFrame->m_analysisData.lookahead.satdForVbv[index] = outFrame->m_encData->m_rowStat[index].satdForVbv;<br>-                            }<br>-                            pic_out->analysisData.lookahead.intraSatdForVbv = outFrame->m_analysisData.lookahead.intraSatdForVbv;<br>-                            pic_out->analysisData.lookahead.satdForVbv = outFrame->m_analysisData.lookahead.satdForVbv;<br>-                            for (uint32_t index = 0; index < pic_out->analysisData.numCUsInFrame; index++)<br>+                            int factor = 1;<br>+                            if (m_param->scaleFactor)<br>+                                factor = m_param->scaleFactor * 2;<br>+                            pic_out[sLayer]->analysisData.numCuInHeight = outFrame->m_analysisData.numCuInHeight;<br>+                            pic_out[sLayer]->analysisData.lookahead.dts = outFrame->m_dts;<br>+                            pic_out[sLayer]->analysisData.lookahead.reorderedPts = outFrame->m_reorderedPts;<br>+                            pic_out[sLayer]->analysisData.satdCost *= factor;<br>+                            pic_out[sLayer]->analysisData.lookahead.keyframe = outFrame->m_lowres.bKeyframe;<br>+                            pic_out[sLayer]->analysisData.lookahead.lastMiniGopBFrame = outFrame->m_lowres.bLastMiniGopBFrame;<br>+                            if (m_rateControl->m_isVbv)<br>                             {<br>-                                outFrame->m_analysisData.lookahead.intraVbvCost[index] = outFrame->m_encData->m_cuStat[index].intraVbvCost;<br>-                                outFrame->m_analysisData.lookahead.vbvCost[index] = outFrame->m_encData->m_cuStat[index].vbvCost;<br>+                                int vbvCount = m_param->lookaheadDepth + m_param->bframes + 2;<br>+                                for (int index = 0; index < vbvCount; index++)<br>+                                {<br>+                                    pic_out[sLayer]->analysisData.lookahead.plannedSatd[index] = outFrame->m_lowres.plannedSatd[index];<br>+                                    pic_out[sLayer]->analysisData.lookahead.plannedType[index] = outFrame->m_lowres.plannedType[index];<br>+                                }<br>+                                for (uint32_t index = 0; index < pic_out[sLayer]->analysisData.numCuInHeight; index++)<br>+                                {<br>+                                    outFrame->m_analysisData.lookahead.intraSatdForVbv[index] = outFrame->m_encData->m_rowStat[index].intraSatdForVbv;<br>+                                    outFrame->m_analysisData.lookahead.satdForVbv[index] = outFrame->m_encData->m_rowStat[index].satdForVbv;<br>+                                }<br>+                                pic_out[sLayer]->analysisData.lookahead.intraSatdForVbv = outFrame->m_analysisData.lookahead.intraSatdForVbv;<br>+                                pic_out[sLayer]->analysisData.lookahead.satdForVbv = outFrame->m_analysisData.lookahead.satdForVbv;<br>+                                for (uint32_t index = 0; index < pic_out[sLayer]->analysisData.numCUsInFrame; index++)<br>+                                {<br>+                                    outFrame->m_analysisData.lookahead.intraVbvCost[index] = outFrame->m_encData->m_cuStat[index].intraVbvCost;<br>+                                    outFrame->m_analysisData.lookahead.vbvCost[index] = outFrame->m_encData->m_cuStat[index].vbvCost;<br>+                                }<br>+                                pic_out[sLayer]->analysisData.lookahead.intraVbvCost = outFrame->m_analysisData.lookahead.intraVbvCost;<br>+                                pic_out[sLayer]->analysisData.lookahead.vbvCost = outFrame->m_analysisData.lookahead.vbvCost;<br>                             }<br>-                            pic_out->analysisData.lookahead.intraVbvCost = outFrame->m_analysisData.lookahead.intraVbvCost;<br>-                            pic_out->analysisData.lookahead.vbvCost = outFrame->m_analysisData.lookahead.vbvCost;<br>                         }<br>+                        writeAnalysisFile(&pic_out[sLayer]->analysisData, *outFrame->m_encData);<br>+                        pic_out[sLayer]->analysisData.saveParam = pic_out[sLayer]->analysisData.saveParam;<br>+                        if (m_param->bUseAnalysisFile)<br>+                            x265_free_analysis_data(m_param, &pic_out[sLayer]->analysisData);<br>                     }<br>-                    writeAnalysisFile(&pic_out->analysisData, *outFrame->m_encData);<br>-                    pic_out->analysisData.saveParam = pic_out->analysisData.saveParam;<br>-                    if (m_param->bUseAnalysisFile)<br>-                        x265_free_analysis_data(m_param, &pic_out->analysisData);<br>-                }<br>-            }<br>-            if (m_param->rc.bStatWrite && (m_param->analysisMultiPassRefine || m_param->analysisMultiPassDistortion))<br>-            {<br>-                if (pic_out)<br>-                {<br>-                    pic_out->analysisData.poc = pic_out->poc;<br>-                    pic_out->analysisData.interData = outFrame->m_analysisData.interData;<br>-                    pic_out->analysisData.intraData = outFrame->m_analysisData.intraData;<br>-                    pic_out->analysisData.distortionData = outFrame->m_analysisData.distortionData;<br>-                }<br>-                writeAnalysisFileRefine(&outFrame->m_analysisData, *outFrame->m_encData);<br>-            }<br>-            if (m_param->analysisMultiPassRefine || m_param->analysisMultiPassDistortion)<br>-                x265_free_analysis_data(m_param, &outFrame->m_analysisData);<br>-            if (m_param->internalCsp == X265_CSP_I400)<br>-            {<br>-                if (slice->m_sliceType == P_SLICE)<br>-                {<br>-                    if (slice->m_weightPredTable[0][0][0].wtPresent)<br>-                        m_numLumaWPFrames++;<br>                 }<br>-                else if (slice->m_sliceType == B_SLICE)<br>+                if (m_param->rc.bStatWrite && (m_param->analysisMultiPassRefine || m_param->analysisMultiPassDistortion))<br>                 {<br>-                    bool bLuma = false;<br>-                    for (int l = 0; l < 2; l++)<br>+                    if (pic_out[sLayer])<br>                     {<br>-                        if (slice->m_weightPredTable[l][0][0].wtPresent)<br>-                            bLuma = true;<br>+                        pic_out[sLayer]->analysisData.poc = pic_out[sLayer]->poc;<br>+                        pic_out[sLayer]->analysisData.interData = outFrame->m_analysisData.interData;<br>+                        pic_out[sLayer]->analysisData.intraData = outFrame->m_analysisData.intraData;<br>+                        pic_out[sLayer]->analysisData.distortionData = outFrame->m_analysisData.distortionData;<br>                     }<br>-                    if (bLuma)<br>-                        m_numLumaWPBiFrames++;<br>+                    writeAnalysisFileRefine(&outFrame->m_analysisData, *outFrame->m_encData);<br>                 }<br>-            }<br>-            else<br>-            {<br>-                if (slice->m_sliceType == P_SLICE)<br>+                if (m_param->analysisMultiPassRefine || m_param->analysisMultiPassDistortion)<br>+                    x265_free_analysis_data(m_param, &outFrame->m_analysisData);<br>+                if (m_param->internalCsp == X265_CSP_I400)<br>                 {<br>-                    if (slice->m_weightPredTable[0][0][0].wtPresent)<br>-                        m_numLumaWPFrames++;<br>-                    if (slice->m_weightPredTable[0][0][1].wtPresent ||<br>-                        slice->m_weightPredTable[0][0][2].wtPresent)<br>-                        m_numChromaWPFrames++;<br>+                    if (slice->m_sliceType == P_SLICE)<br>+                    {<br>+                        if (slice->m_weightPredTable[0][0][0].wtPresent)<br>+                            m_numLumaWPFrames++;<br>+                    }<br>+                    else if (slice->m_sliceType == B_SLICE)<br>+                    {<br>+                        bool bLuma = false;<br>+                        for (int l = 0; l < 2; l++)<br>+                        {<br>+                            if (slice->m_weightPredTable[l][0][0].wtPresent)<br>+                                bLuma = true;<br>+                        }<br>+                        if (bLuma)<br>+                            m_numLumaWPBiFrames++;<br>+                    }<br>                 }<br>-                else if (slice->m_sliceType == B_SLICE)<br>+                else<br>                 {<br>-                    bool bLuma = false, bChroma = false;<br>-                    for (int l = 0; l < 2; l++)<br>+                    if (slice->m_sliceType == P_SLICE)<br>                     {<br>-                        if (slice->m_weightPredTable[l][0][0].wtPresent)<br>-                            bLuma = true;<br>-                        if (slice->m_weightPredTable[l][0][1].wtPresent ||<br>-                            slice->m_weightPredTable[l][0][2].wtPresent)<br>-                            bChroma = true;<br>+                        if (slice->m_weightPredTable[0][0][0].wtPresent)<br>+                            m_numLumaWPFrames++;<br>+                        if (slice->m_weightPredTable[0][0][1].wtPresent ||<br>+                            slice->m_weightPredTable[0][0][2].wtPresent)<br>+                            m_numChromaWPFrames++;<br>                     }<br>+                    else if (slice->m_sliceType == B_SLICE)<br>+                    {<br>+                        bool bLuma = false, bChroma = false;<br>+                        for (int l = 0; l < 2; l++)<br>+                        {<br>+                            if (slice->m_weightPredTable[l][0][0].wtPresent)<br>+                                bLuma = true;<br>+                            if (slice->m_weightPredTable[l][0][1].wtPresent ||<br>+                                slice->m_weightPredTable[l][0][2].wtPresent)<br>+                                bChroma = true;<br>+                        }<br> <br>-                    if (bLuma)<br>-                        m_numLumaWPBiFrames++;<br>-                    if (bChroma)<br>-                        m_numChromaWPBiFrames++;<br>+                        if (bLuma)<br>+                            m_numLumaWPBiFrames++;<br>+                        if (bChroma)<br>+                            m_numChromaWPBiFrames++;<br>+                    }<br>                 }<br>-            }<br>-            if (m_aborted)<br>-                return -1;<br>+                if (m_aborted)<br>+                    return -1;<br> <br>-            if ((m_outputCount + 1)  >= m_param->chunkStart)<br>-                finishFrameStats(outFrame, curEncoder, frameData, m_pocLast);<br>-            if (m_param->analysisSave)<br>-            {<br>-                pic_out->analysisData.frameBits = frameData->bits;<br>-                if (!slice->isIntra())<br>+                if ((m_outputCount + 1) >= m_param->chunkStart && !sLayer)<br>+                    finishFrameStats(outFrame, curEncoder, frameData, m_pocLast);<br>+                if (m_param->analysisSave)<br>                 {<br>-                    for (int ref = 0; ref < MAX_NUM_REF; ref++)<br>-                        pic_out->analysisData.list0POC[ref] = frameData->list0POC[ref];<br>+                    pic_out[sLayer]->analysisData.frameBits = frameData->bits;<br>+                    if (!slice->isIntra())<br>+                    {<br>+                        for (int ref = 0; ref < MAX_NUM_REF; ref++)<br>+                            pic_out[sLayer]->analysisData.list0POC[ref] = frameData->list0POC[ref];<br> <br>-                    double totalIntraPercent = 0;<br>+                        double totalIntraPercent = 0;<br> <br>-                    for (uint32_t depth = 0; depth < m_param->maxCUDepth; depth++)<br>-                        for (uint32_t intramode = 0; intramode < 3; intramode++)<br>-                            totalIntraPercent += frameData->cuStats.percentIntraDistribution[depth][intramode];<br>-                    totalIntraPercent += frameData->cuStats.percentIntraNxN;<br>+                        for (uint32_t depth = 0; depth < m_param->maxCUDepth; depth++)<br>+                            for (uint32_t intramode = 0; intramode < 3; intramode++)<br>+                                totalIntraPercent += frameData->cuStats.percentIntraDistribution[depth][intramode];<br>+                        totalIntraPercent += frameData->cuStats.percentIntraNxN;<br> <br>-                    for (uint32_t depth = 0; depth < m_param->maxCUDepth; depth++)<br>-                        totalIntraPercent += frameData->puStats.percentIntraPu[depth];<br>-                    pic_out->analysisData.totalIntraPercent = totalIntraPercent;<br>+                        for (uint32_t depth = 0; depth < m_param->maxCUDepth; depth++)<br>+                            totalIntraPercent += frameData->puStats.percentIntraPu[depth];<br>+                        pic_out[sLayer]->analysisData.totalIntraPercent = totalIntraPercent;<br> <br>-                    if (!slice->isInterP())<br>-                    {<br>-                        for (int ref = 0; ref < MAX_NUM_REF; ref++)<br>-                            pic_out->analysisData.list1POC[ref] = frameData->list1POC[ref];<br>+                        if (!slice->isInterP())<br>+                        {<br>+                            for (int ref = 0; ref < MAX_NUM_REF; ref++)<br>+                                pic_out[sLayer]->analysisData.list1POC[ref] = frameData->list1POC[ref];<br>+                        }<br>                     }<br>                 }<br>-            }<br>-<br>-            /* Write RateControl Frame level stats in multipass encodes */<br>-            if (m_param->rc.bStatWrite)<br>-                if (m_rateControl->writeRateControlFrameStats(outFrame, &curEncoder->m_rce))<br>-                    m_aborted = true;<br>-            if (pic_out)<br>-            {<br>-                /* m_rcData is allocated for every frame */<br>-                pic_out->rcData = outFrame->m_rcData;<br>-                outFrame->m_rcData->qpaRc = outFrame->m_encData->m_avgQpRc;<br>-                outFrame->m_rcData->qRceq = curEncoder->m_rce.qRceq;<br>-                outFrame->m_rcData->qpNoVbv = curEncoder->m_rce.qpNoVbv;<br>-                outFrame->m_rcData->coeffBits = outFrame->m_encData->m_frameStats.coeffBits;<br>-                outFrame->m_rcData->miscBits = outFrame->m_encData->m_frameStats.miscBits;<br>-                outFrame->m_rcData->mvBits = outFrame->m_encData->m_frameStats.mvBits;<br>-                outFrame->m_rcData->qScale = outFrame->m_rcData->newQScale = x265_qp2qScale(outFrame->m_encData->m_avgQpRc);<br>-                outFrame->m_rcData->poc = curEncoder->m_rce.poc;<br>-                outFrame->m_rcData->encodeOrder = curEncoder->m_rce.encodeOrder;<br>-                outFrame->m_rcData->sliceType = curEncoder->m_rce.sliceType;<br>-                outFrame->m_rcData->keptAsRef = curEncoder->m_rce.sliceType == B_SLICE && !IS_REFERENCED(outFrame) ? 0 : 1;<br>-                outFrame->m_rcData->qpAq = outFrame->m_encData->m_avgQpAq;<br>-                outFrame->m_rcData->iCuCount = outFrame->m_encData->m_frameStats.percent8x8Intra * m_rateControl->m_ncu;<br>-                outFrame->m_rcData->pCuCount = outFrame->m_encData->m_frameStats.percent8x8Inter * m_rateControl->m_ncu;<br>-                outFrame->m_rcData->skipCuCount = outFrame->m_encData->m_frameStats.percent8x8Skip  * m_rateControl->m_ncu;<br>-                outFrame->m_rcData->currentSatd = curEncoder->m_rce.coeffBits;<br>-            }<br> <br>-            if (m_param->bEnableTemporalFilter)<br>-            {<br>-                Frame *curFrame = m_origPicBuffer->m_mcstfPicList.getPOCMCSTF(outFrame->m_poc);<br>-                X265_CHECK(curFrame, "Outframe not found in DPB's mcstfPicList");<br>-                curFrame->m_refPicCnt[0]--;<br>-                curFrame->m_refPicCnt[1]--;<br>-                curFrame = m_origPicBuffer->m_mcstfOrigPicList.getPOCMCSTF(outFrame->m_poc);<br>-                X265_CHECK(curFrame, "Outframe not found in OPB's mcstfOrigPicList");<br>-                curFrame->m_refPicCnt[1]--;<br>-            }<br>+                /* Write RateControl Frame level stats in multipass encodes */<br>+                if (m_param->rc.bStatWrite)<br>+                    if (m_rateControl->writeRateControlFrameStats(outFrame, &curEncoder->m_rce))<br>+                        m_aborted = true;<br>+                if (pic_out[sLayer])<br>+                {<br>+                    /* m_rcData is allocated for every frame */<br>+                    pic_out[sLayer]->rcData = outFrame->m_rcData;<br>+                    outFrame->m_rcData->qpaRc = outFrame->m_encData->m_avgQpRc;<br>+                    outFrame->m_rcData->qRceq = curEncoder->m_rce.qRceq;<br>+                    outFrame->m_rcData->qpNoVbv = curEncoder->m_rce.qpNoVbv;<br>+                    outFrame->m_rcData->coeffBits = outFrame->m_encData->m_frameStats.coeffBits;<br>+                    outFrame->m_rcData->miscBits = outFrame->m_encData->m_frameStats.miscBits;<br>+                    outFrame->m_rcData->mvBits = outFrame->m_encData->m_frameStats.mvBits;<br>+                    outFrame->m_rcData->qScale = outFrame->m_rcData->newQScale = x265_qp2qScale(outFrame->m_encData->m_avgQpRc);<br>+                    outFrame->m_rcData->poc = curEncoder->m_rce.poc;<br>+                    outFrame->m_rcData->encodeOrder = curEncoder->m_rce.encodeOrder;<br>+                    outFrame->m_rcData->sliceType = curEncoder->m_rce.sliceType;<br>+                    outFrame->m_rcData->keptAsRef = curEncoder->m_rce.sliceType == B_SLICE && !IS_REFERENCED(outFrame) ? 0 : 1;<br>+                    outFrame->m_rcData->qpAq = outFrame->m_encData->m_avgQpAq;<br>+                    outFrame->m_rcData->iCuCount = outFrame->m_encData->m_frameStats.percent8x8Intra * m_rateControl->m_ncu;<br>+                    outFrame->m_rcData->pCuCount = outFrame->m_encData->m_frameStats.percent8x8Inter * m_rateControl->m_ncu;<br>+                    outFrame->m_rcData->skipCuCount = outFrame->m_encData->m_frameStats.percent8x8Skip * m_rateControl->m_ncu;<br>+                    outFrame->m_rcData->currentSatd = curEncoder->m_rce.coeffBits;<br>+                }<br> <br>-            /* Allow this frame to be recycled if no frame encoders are using it for reference */<br>-            if (!pic_out)<br>-            {<br>-                ATOMIC_DEC(&outFrame->m_countRefEncoders);<br>-                m_dpb->recycleUnreferenced();<br>                 if (m_param->bEnableTemporalFilter)<br>-                    m_origPicBuffer->recycleOrigPicList();<br>-            }<br>-            else<br>-                m_exportedPic = outFrame;<br>-            <br>-            m_outputCount++;<br>-            if (m_param->chunkEnd == m_outputCount)<br>-                m_numDelayedPic = 0;<br>-            else <br>-                m_numDelayedPic--;<br>+                {<br>+                    Frame* curFrame = m_origPicBuffer->m_mcstfPicList.getPOCMCSTF(outFrame->m_poc);<br>+                    X265_CHECK(curFrame, "Outframe not found in DPB's mcstfPicList");<br>+                    curFrame->m_refPicCnt[0]--;<br>+                    curFrame->m_refPicCnt[1]--;<br>+                    curFrame = m_origPicBuffer->m_mcstfOrigPicList.getPOCMCSTF(outFrame->m_poc);<br>+                    X265_CHECK(curFrame, "Outframe not found in OPB's mcstfOrigPicList");<br>+                    curFrame->m_refPicCnt[1]--;<br>+                }<br>+<br>+                /* Allow this frame to be recycled if no frame encoders are using it for reference */<br>+                if (!pic_out[sLayer])<br>+                {<br>+                    ATOMIC_DEC(&outFrame->m_countRefEncoders);<br>+                    m_dpb->recycleUnreferenced();<br>+                    if (m_param->bEnableTemporalFilter)<br>+                        m_origPicBuffer->recycleOrigPicList();<br>+                }<br>+                else<br>+                    m_exportedPic[sLayer] = outFrame;<br>+<br>+                m_outputCount++;<br>+                if (m_param->chunkEnd == m_outputCount)<br>+                    m_numDelayedPic = 0;<br>+                else if (outFrame->m_sLayerId == m_param->bEnableAlpha)<br>+                    m_numDelayedPic--;<br> <br>-            ret = 1;<br>+                ret = 1;<br>+            }<br>         }<br> <br>         /* pop a single frame from decided list, then provide to frame encoder<br>@@ -2142,9 +2153,12 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>         if (frameEnc[0] && !pass && (!m_param->chunkEnd || (m_encodedFrameNum < m_param->chunkEnd)))<br>         {<br>             //Pop non base view pictures from DPB piclist<br>-            frameEnc[1] = m_dpb->m_picList.getPOC(frameEnc[0]->m_poc, 1);<br>-            m_dpb->m_picList.remove(*frameEnc[1]);<br>-            frameEnc[1]->m_lowres.sliceType = frameEnc[0]->m_lowres.sliceType;<br>+            for (int layer = 1; layer < m_param->numScalableLayers; layer++)<br>+            {<br>+                Frame* currentFrame = m_dpb->m_picList.getPOC(frameEnc[0]->m_poc, layer);<br>+                frameEnc[layer] = m_dpb->m_picList.removeFrame(*currentFrame);<br>+                frameEnc[layer]->m_lowres.sliceType = frameEnc[0]->m_lowres.sliceType;<br>+            }<br> <br>             if ((m_param->bEnableSceneCutAwareQp & FORWARD) && m_param->rc.bStatRead)<br>             {<br>@@ -2208,7 +2222,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>             curEncoder->m_reconfigure = m_reconfigure;<br> <br>             /* give this frame a FrameData instance before encoding */<br>-            for (int layer = 0; layer < MAX_SCALABLE_LAYERS; layer++)<br>+            for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>             {<br>                 if (m_dpb->m_frameDataFreeList)<br>                 {<br>@@ -2339,7 +2353,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>                 }<br>             }<br>             /* determine references, setup RPS, etc */<br>-            for (int layer = 0; layer < MAX_SCALABLE_LAYERS; layer++)<br>+            for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>                 m_dpb->prepareEncode(frameEnc[layer]);<br> <br>             if (m_param->bEnableTemporalFilter)<br>@@ -2361,7 +2375,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br>                 m_origPicBuffer->setOrigPicList(frameEnc[0], m_pocLast);<br>             }<br> <br>-            for (int layer = 0; layer < MAX_SCALABLE_LAYERS; layer++)<br>+            for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>             {<br>                 if (!!m_param->selectiveSAO)<br>                 {<br>diff --git a/source/encoder/encoder.h b/source/encoder/encoder.h<br>index 77e32fe42..22976b180 100644<br>--- a/source/encoder/encoder.h<br>+++ b/source/encoder/encoder.h<br>@@ -202,7 +202,7 @@ public:<br>     ThreadPool*        m_threadPool;<br>     FrameEncoder*      m_frameEncoder[X265_MAX_FRAME_THREADS];<br>     DPB*               m_dpb;<br>-    Frame*             m_exportedPic;<br>+    Frame*             m_exportedPic[MAX_SCALABLE_LAYERS];<br>     FILE*              m_analysisFileIn;<br>     FILE*              m_analysisFileOut;<br>     FILE*              m_naluFile;<br>@@ -300,7 +300,7 @@ public:<br>     void stopJobs();<br>     void destroy();<br> <br>-    int encode(const x265_picture* pic, x265_picture *pic_out);<br>+    int encode(const x265_picture* pic, x265_picture **pic_out);<br> <br>     int reconfigureParam(x265_param* encParam, x265_param* param);<br> <br>diff --git a/source/encoder/frameencoder.cpp b/source/encoder/frameencoder.cpp<br>index ebaf3e840..b36094f33 100644<br>--- a/source/encoder/frameencoder.cpp<br>+++ b/source/encoder/frameencoder.cpp<br>@@ -62,6 +62,7 @@ FrameEncoder::FrameEncoder()<br>     memset(&m_rce, 0, sizeof(RateControlEntry));<br>     for(int layer = 0; layer < MAX_SCALABLE_LAYERS; layer++)<br>         m_frame[layer] = NULL;<br>+    m_retFrameBuffer = { NULL };<br> }<br> <br> void FrameEncoder::destroy()<br>@@ -95,6 +96,7 @@ void FrameEncoder::destroy()<br>     X265_FREE(m_ctuGeomMap);<br>     X265_FREE(m_substreamSizes);<br>     X265_FREE(m_nr);<br>+    X265_FREE(m_retFrameBuffer);<br> <br>     m_frameFilter.destroy();<br> <br>@@ -217,6 +219,9 @@ bool FrameEncoder::init(Encoder *top, int numRows, int numCols)<br>             ok &= !!m_frameEncTF->createRefPicInfo(&m_mcstfRefList[i], m_param);<br>     }<br> <br>+    m_retFrameBuffer = X265_MALLOC(Frame*, m_param->numScalableLayers);<br>+    for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>+        m_retFrameBuffer[layer] = NULL;<br>     return ok;<br> }<br> <br>@@ -286,7 +291,7 @@ bool FrameEncoder::initializeGeoms()<br> bool FrameEncoder::startCompressFrame(Frame* curFrame[MAX_SCALABLE_LAYERS])<br> {<br>     m_slicetypeWaitTime = x265_mdate() - m_prevOutputTime;<br>-    for (int layer = 0; layer < MAX_SCALABLE_LAYERS; layer++)<br>+    for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>     {<br>         m_frame[layer] = curFrame[layer];<br>         curFrame[layer]->m_encData->m_frameEncoderID = m_jpId;<br>@@ -368,7 +373,7 @@ void FrameEncoder::threadMain()<br>                 m_frame[0]->m_copyMVType.wait();<br>         }<br> <br>-        for(int layer = 0; layer < MAX_SCALABLE_LAYERS; layer ++)<br>+        for(int layer = 0; layer < m_param->numScalableLayers; layer ++)<br>             compressFrame(layer);<br>         m_done.trigger(); /* FrameEncoder::getEncodedPicture() blocks for this event */<br>         m_enable.wait();<br>@@ -604,7 +609,7 @@ void FrameEncoder::compressFrame(int layer)<br> <br>     /* Get the QP for this frame from rate control. This call may block until<br>      * frames ahead of it in encode order have called rateControlEnd() */<br>-    int qp = (layer == 0) ? m_top->m_rateControl->rateControlStart(m_frame[layer], &m_rce, m_top) : m_rce.newQp;<br>+    int qp = (layer == 0) ? m_top->m_rateControl->rateControlStart(m_frame[layer], &m_rce, m_top) : (int)m_rce.newQp;<br> <br>     m_rce.newQp = qp;<br> <br>@@ -2267,18 +2272,21 @@ void FrameEncoder::vmafFrameLevelScore()<br> }<br> #endif<br> <br>-Frame *FrameEncoder::getEncodedPicture(NALList& output)<br>+Frame** FrameEncoder::getEncodedPicture(NALList& output)<br> {<br>-    if (m_frame[0])<br>+    if (m_frame && m_frame[0])<br>     {<br>         /* block here until worker thread completes */<br>         m_done.wait();<br> <br>-        Frame *ret = m_frame[0];<br>-        m_frame[0] = NULL;<br>+        for (int i = 0; i < m_param->numScalableLayers; i++)<br>+        {<br>+            m_retFrameBuffer[i] = m_frame[i];<br>+            m_frame[i] = NULL;<br>+        }<br>         output.takeContents(m_nalList);<br>         m_prevOutputTime = x265_mdate();<br>-        return ret;<br>+        return m_retFrameBuffer;<br>     }<br> <br>     return NULL;<br>diff --git a/source/encoder/frameencoder.h b/source/encoder/frameencoder.h<br>index fa4bad60f..9fcd2dcf5 100644<br>--- a/source/encoder/frameencoder.h<br>+++ b/source/encoder/frameencoder.h<br>@@ -159,7 +159,7 @@ public:<br>     bool startCompressFrame(Frame* curFrame[MAX_SCALABLE_LAYERS]);<br> <br>     /* blocks until worker thread is done, returns access unit */<br>-    Frame *getEncodedPicture(NALList& list);<br>+    Frame **getEncodedPicture(NALList& list);<br> <br>     void initDecodedPictureHashSEI(int row, int cuAddr, int height, int layer);<br> <br>@@ -218,6 +218,7 @@ public:<br>     Encoder*                 m_top;<br>     x265_param*              m_param;<br>     Frame*                   m_frame[MAX_SCALABLE_LAYERS];<br>+    Frame**                  m_retFrameBuffer;<br>     NoiseReduction*          m_nr;<br>     ThreadLocalData*         m_tld; /* for --no-wpp */<br>     Bitstream*               m_outStreams;<br>diff --git a/source/x265.h b/source/x265.h<br>index e994ea3e2..7c1acfea3 100644<br>--- a/source/x265.h<br>+++ b/source/x265.h<br>@@ -2441,7 +2441,7 @@ int x265_encoder_headers(x265_encoder *, x265_nal **pp_nal, uint32_t *pi_nal);<br>  *      the payloads of all output NALs are guaranteed to be sequential in memory.<br>  *      To flush the encoder and retrieve delayed output pictures, pass pic_in as NULL.<br>  *      Once flushing has begun, all subsequent calls must pass pic_in as NULL. */<br>-int x265_encoder_encode(x265_encoder *encoder, x265_nal **pp_nal, uint32_t *pi_nal, x265_picture *pic_in, x265_picture *pic_out);<br>+int x265_encoder_encode(x265_encoder *encoder, x265_nal **pp_nal, uint32_t *pi_nal, x265_picture *pic_in, x265_picture **pic_out);<br> <br> /* x265_encoder_reconfig:<br>  *      various parameters from x265_param are copied.<br>@@ -2595,7 +2595,7 @@ typedef struct x265_api<br>     int           (*encoder_reconfig)(x265_encoder*, x265_param*);<br>     int           (*encoder_reconfig_zone)(x265_encoder*, x265_zone*);<br>     int           (*encoder_headers)(x265_encoder*, x265_nal**, uint32_t*);<br>-    int           (*encoder_encode)(x265_encoder*, x265_nal**, uint32_t*, x265_picture*, x265_picture*);<br>+    int           (*encoder_encode)(x265_encoder*, x265_nal**, uint32_t*, x265_picture*, x265_picture**);<br>     void          (*encoder_get_stats)(x265_encoder*, x265_stats*, uint32_t);<br>     void          (*encoder_log)(x265_encoder*, int, char**);<br>     void          (*encoder_close)(x265_encoder*);<br>diff --git a/source/x265cli.cpp b/source/x265cli.cpp<br>index 070011cf0..6bb81f6d4 100755<br>--- a/source/x265cli.cpp<br>+++ b/source/x265cli.cpp<br>@@ -422,9 +422,12 @@ namespace X265_NS {<br>         if (input)<br>             input->release();<br>         input = NULL;<br>-        if (recon)<br>-            recon->release();<br>-        recon = NULL;<br>+        for (int i = 0; i < param->numScalableLayers; i++)<br>+        {<br>+            if (recon[i])<br>+                recon[i]->release();<br>+            recon[i] = NULL;<br>+        }<br>         if (qpfile)<br>             fclose(qpfile);<br>         qpfile = NULL;<br>@@ -581,7 +584,7 @@ namespace X265_NS {<br>         int outputBitDepth = 0;<br>         int reconFileBitDepth = 0;<br>         const char *inputfn = NULL;<br>-        const char *reconfn = NULL;<br>+        const char* reconfn[MAX_SCALABLE_LAYERS] = { NULL };<br>         const char *outputfn = NULL;<br>         const char *preset = NULL;<br>         const char *tune = NULL;<br>@@ -721,7 +724,7 @@ namespace X265_NS {<br>                 OPT("no-progress") this->bProgress = false;<br>                 OPT("output") outputfn = optarg;<br>                 OPT("input") inputfn = optarg;<br>-                OPT("recon") reconfn = optarg;<br>+                OPT("recon") reconfn[0] = optarg;<br>                 OPT("input-depth") inputBitDepth = (uint32_t)x265_atoi(optarg, bError);<br>                 OPT("dither") this->bDither = true;<br>                 OPT("recon-depth") reconFileBitDepth = (uint32_t)x265_atoi(optarg, bError);<br>@@ -915,23 +918,40 @@ namespace X265_NS {<br> <br>         this->input->startReader();<br> <br>-        if (reconfn)<br>+        if (reconfn[0])<br>         {<br>             if (reconFileBitDepth == 0)<br>                 reconFileBitDepth = param->internalBitDepth;<br>-            this->recon = ReconFile::open(reconfn, param->sourceWidth, param->sourceHeight, reconFileBitDepth,<br>-                param->fpsNum, param->fpsDenom, param->internalCsp, param->sourceBitDepth);<br>-            if (this->recon->isFail())<br>+#if ENABLE_ALPHA<br>+            if (param->bEnableAlpha)<br>             {<br>-                x265_log(param, X265_LOG_WARNING, "unable to write reconstructed outputs file\n");<br>-                this->recon->release();<br>-                this->recon = 0;<br>+                char* temp = new char[strlen(reconfn[0])];<br>+                strcpy(temp, reconfn[0]);<br>+                const char* token = strtok(temp, ".");<br>+                for (int view = 0; view < param->numScalableLayers; view++)<br>+                {<br>+                    char* buf = new char[strlen(temp) + 7];<br>+                    sprintf(buf, "%s-%d.yuv", token, view);<br>+                    reconfn[view] = buf;<br>+                }<br>+            }<br>+#endif<br>+            for (int i = 0; i < param->numScalableLayers; i++)<br>+            {<br>+                this->recon[i] = ReconFile::open(reconfn[i], param->sourceWidth, param->sourceHeight, reconFileBitDepth,<br>+                    param->fpsNum, param->fpsDenom, param->internalCsp, param->sourceBitDepth);<br>+                if (this->recon[i]->isFail())<br>+                {<br>+                    x265_log(param, X265_LOG_WARNING, "unable to write reconstructed outputs file\n");<br>+                    this->recon[i]->release();<br>+                    this->recon[i] = 0;<br>+                }<br>+                else<br>+                    general_log(param, this->recon[i]->getName(), X265_LOG_INFO,<br>+                        "reconstructed images %dx%d fps %d/%d %s\n",<br>+                        param->sourceWidth, param->sourceHeight, param->fpsNum, param->fpsDenom,<br>+                        x265_source_csp_names[param->internalCsp]);<br>             }<br>-            else<br>-                general_log(param, this->recon->getName(), X265_LOG_INFO,<br>-                "reconstructed images %dx%d fps %d/%d %s\n",<br>-                param->sourceWidth, param->sourceHeight, param->fpsNum, param->fpsDenom,<br>-                x265_source_csp_names[param->internalCsp]);<br>         }<br> #if ENABLE_LIBVMAF<br>         if (!reconfn)<br>diff --git a/source/x265cli.h b/source/x265cli.h<br>index 9bdaba0f3..7abf91eb8 100644<br>--- a/source/x265cli.h<br>+++ b/source/x265cli.h<br>@@ -397,7 +397,7 @@ static const struct option long_options[] =<br>     struct CLIOptions<br>     {<br>         InputFile* input;<br>-        ReconFile* recon;<br>+        ReconFile* recon[MAX_SCALABLE_LAYERS];<br>         OutputFile* output;<br>         FILE*       qpfile;<br>         FILE*       zoneFile;<br>@@ -435,7 +435,8 @@ static const struct option long_options[] =<br>         CLIOptions()<br>         {<br>             input = NULL;<br>-            recon = NULL;<br>+            for (int i = 0; i < MAX_SCALABLE_LAYERS; i++)<br>+                recon[i] = NULL;<br>             output = NULL;<br>             qpfile = NULL;<br>             zoneFile = NULL;<br>-- <br>2.36.0.windows.1<br><br></div>