[x265] [PATCH MV-HEVC 02/10] Add support to parse Multiview input file

Anusuya Kumarasamy anusuya.kumarasamy at multicorewareinc.com
Tue Aug 6 10:42:31 UTC 2024


>From bed3eac35256040e5003c794cec52ab33d75fa70 Mon Sep 17 00:00:00 2001
From: AnusuyaKumarasamy <anusuya.kumarasamy at multicorewareinc.com>
Date: Wed, 10 Jul 2024 17:10:21 +0530
Subject: [PATCH] Add support to parse Multiview input file

---
 source/abrEncApp.cpp       | 392 ++++++++++++++++++++++---------------
 source/abrEncApp.h         |   6 +-
 source/encoder/encoder.cpp |  56 +++---
 source/x265cli.cpp         | 108 +++++-----
 source/x265cli.h           |   5 +-
 5 files changed, 334 insertions(+), 233 deletions(-)

diff --git a/source/abrEncApp.cpp b/source/abrEncApp.cpp
index fc4262369..6874c4d74 100644
--- a/source/abrEncApp.cpp
+++ b/source/abrEncApp.cpp
@@ -76,7 +76,11 @@ namespace X265_NS {

     bool AbrEncoder::allocBuffers()
     {
+#if ENABLE_MULTIVIEW
+        m_inputPicBuffer = X265_MALLOC(x265_picture**, MAX_VIEWS);
+#else
         m_inputPicBuffer = X265_MALLOC(x265_picture**, m_numEncodes);
+#endif
         m_analysisBuffer = X265_MALLOC(x265_analysis_data*, m_numEncodes);

         m_picWriteCnt = new ThreadSafeInteger[m_numEncodes];
@@ -89,21 +93,48 @@ namespace X265_NS {
         m_analysisRead = X265_MALLOC(ThreadSafeInteger*, m_numEncodes);
         m_readFlag = X265_MALLOC(int*, m_numEncodes);

-        for (uint8_t pass = 0; pass < m_numEncodes; pass++)
+#if ENABLE_MULTIVIEW
+        if (m_passEnc[0]->m_param->numViews > 1)
         {
-            m_inputPicBuffer[pass] = X265_MALLOC(x265_picture*,
m_queueSize);
-            for (uint32_t idx = 0; idx < m_queueSize; idx++)
+            for (uint8_t pass = 0; pass < m_passEnc[0]->m_param->numViews;
pass++)
             {
-                m_inputPicBuffer[pass][idx] = x265_picture_alloc();
-                x265_picture_init(m_passEnc[pass]->m_param,
m_inputPicBuffer[pass][idx]);
+                m_inputPicBuffer[pass] = X265_MALLOC(x265_picture*,
m_queueSize);
+                for (uint32_t idx = 0; idx < m_queueSize; idx++)
+                {
+                    m_inputPicBuffer[pass][idx] = x265_picture_alloc();
+                    x265_picture_init(m_passEnc[0]->m_param,
m_inputPicBuffer[pass][idx]);
+                }
+                if (pass == 0)
+                {
+                    CHECKED_MALLOC_ZERO(m_analysisBuffer[pass],
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);
+                }
             }
+        }
+        else
+        {
+#endif
+            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] = x265_picture_alloc();
+                    x265_picture_init(m_passEnc[pass]->m_param,
m_inputPicBuffer[pass][idx]);
+                }

-            CHECKED_MALLOC_ZERO(m_analysisBuffer[pass],
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);
+                CHECKED_MALLOC_ZERO(m_analysisBuffer[pass],
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);
+            }
+#if ENABLE_MULTIVIEW
         }
+#endif
         return true;
     fail:
         return false;
@@ -112,15 +143,37 @@ namespace X265_NS {
     void AbrEncoder::destroy()
     {
         x265_cleanup(); /* Free library singletons */
-        for (uint8_t pass = 0; pass < m_numEncodes; pass++)
+#if ENABLE_MULTIVIEW
+        for (uint8_t pass = 0; pass < MAX_VIEWS; pass++)
         {
             for (uint32_t index = 0; index < m_queueSize; index++)
             {
                 X265_FREE(m_inputPicBuffer[pass][index]->planes[0]);
                 x265_picture_free(m_inputPicBuffer[pass][index]);
             }
+            X265_FREE(m_inputPicBuffer[pass]);

+            if (pass == 0)
+            {
+                X265_FREE(m_analysisBuffer[pass]);
+                X265_FREE(m_readFlag[pass]);
+                delete[] m_picIdxReadCnt[pass];
+                delete[] m_analysisWrite[pass];
+                delete[] m_analysisRead[pass];
+                m_passEnc[pass]->destroy();
+                delete m_passEnc[pass];
+            }
+        }
+#else
+        for (uint8_t pass = 0; pass < m_numEncodes; pass++)
+        {
+            for (uint32_t index = 0; index < m_queueSize; index++)
+            {
+                X265_FREE(m_inputPicBuffer[pass][index]->planes[0]);
+                x265_picture_free(m_inputPicBuffer[pass][index]);
+            }
             X265_FREE(m_inputPicBuffer[pass]);
+
             X265_FREE(m_analysisBuffer[pass]);
             X265_FREE(m_readFlag[pass]);
             delete[] m_picIdxReadCnt[pass];
@@ -129,6 +182,7 @@ namespace X265_NS {
             m_passEnc[pass]->destroy();
             delete m_passEnc[pass];
         }
+#endif
         X265_FREE(m_inputPicBuffer);
         X265_FREE(m_analysisBuffer);
         X265_FREE(m_readFlag);
@@ -150,8 +204,11 @@ namespace X265_NS {
         m_id = id;
         m_cliopt = cliopt;
         m_parent = parent;
-        if(!(m_cliopt.enableScaler && m_id))
-            m_input = m_cliopt.input;
+        if (!(m_cliopt.enableScaler && m_id))
+        {
+            for (int view = 0; view < m_cliopt.param->numViews; view++)
+                m_input[view] = m_cliopt.input[view];
+        }
         m_param = cliopt.param;
         m_inputOver = false;
         m_lastIdx = -1;
@@ -403,7 +460,7 @@ ret:
     }


-    bool PassEncoder::readPicture(x265_picture *dstPic)
+    bool PassEncoder::readPicture(x265_picture* dstPic, int view)
     {
         /*Check and wait if there any input frames to read*/
         int ipread = m_parent->m_picReadCnt[m_id].get();
@@ -481,7 +538,7 @@ ret:
             }


-            x265_picture *srcPic =
(x265_picture*)(m_parent->m_inputPicBuffer[m_id][readPos]);
+            x265_picture* srcPic = (m_param->numViews > 1) ?
(x265_picture*)(m_parent->m_inputPicBuffer[view][readPos]) :
(x265_picture*)(m_parent->m_inputPicBuffer[m_id][readPos]);

             x265_picture *pic = (x265_picture*)(dstPic);
             pic->colorSpace = srcPic->colorSpace;
@@ -531,12 +588,21 @@ ret:
                 x265_log(m_param, X265_LOG_ERROR, "Unable to register
CTRL+C handler: %s in %s\n",
                     strerror(errno), profileName);

-            x265_picture pic_orig, pic_out[MAX_SCALABLE_LAYERS];
-            x265_picture *pic_in = &pic_orig;
+            x265_picture pic_orig[MAX_VIEWS];
+            x265_picture *pic_in[MAX_VIEWS];
+            for (int view = 0; view < m_param->numViews; view++)
+                pic_in[view] = &pic_orig[view];
             /* 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[MAX_SCALABLE_LAYERS];
-            for(int i = 0; i < m_param->numScalableLayers; i++)
+#if ENABLE_MULTIVIEW
+            x265_picture* pic_recon[MAX_VIEWS];
+            x265_picture pic_out[MAX_VIEWS];
+            for (int i = 0; i < m_param->numViews; i++)
+#else
+            x265_picture* pic_recon[MAX_SCALABLE_LAYERS];
+            x265_picture pic_out[MAX_SCALABLE_LAYERS];
+            for (int i = 0; i < m_param->numScalableLayers; i++)
+#endif
                 pic_recon[i] = (m_cliopt.recon[i] || m_param->analysisSave
|| m_param->analysisLoad || pts_queue || reconPlay || m_param->csvLogLevel)
? &pic_out[i] : NULL;
             uint32_t inFrameCount = 0;
             uint32_t outFrameCount = 0;
@@ -563,22 +629,25 @@ ret:
                     m_cliopt.totalbytes +=
m_cliopt.output->writeHeaders(p_nal, nal);
             }

-            if (m_param->bField && m_param->interlaceMode)
+            for (int view = 0; view < m_param->numViews; view++)
             {
-                api->picture_init(m_param, &picField1);
-                api->picture_init(m_param, &picField2);
-                // return back the original height of input
-                m_param->sourceHeight *= 2;
-                api->picture_init(m_param, &pic_orig);
+                if (m_param->bField && m_param->interlaceMode)
+                {
+                    api->picture_init(m_param, &picField1);
+                    api->picture_init(m_param, &picField2);
+                    // return back the original height of input
+                    m_param->sourceHeight *= 2;
+                    api->picture_init(m_param, &pic_orig[view]);
+                }
+                else
+                    api->picture_init(m_param, &pic_orig[view]);
             }
-            else
-                api->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)
+                pic_in[0]->rpu.payload = rpuPayload;
+                if (pic_in[0]->rpu.payload)
                     bDolbyVisionRPU = true;
             }

@@ -592,132 +661,134 @@ ret:
             }

             // main encoder loop
-            while (pic_in && !b_ctrl_c)
+            while (pic_in[0] && !b_ctrl_c)
             {
-                pic_orig.poc = (m_param->bField && m_param->interlaceMode)
? inFrameCount * 2 : inFrameCount;
-                if (m_cliopt.qpfile)
+                for (int view = 0; view < m_param->numViews; view++)
                 {
-                    if (!m_cliopt.parseQPFile(pic_orig))
+                    pic_orig[view].poc = (m_param->bField &&
m_param->interlaceMode) ? inFrameCount * 2 : inFrameCount;
+                    if (m_cliopt.qpfile)
                     {
-                        x265_log(NULL, X265_LOG_ERROR, "can't parse qpfile
for frame %d in %s\n",
-                            pic_in->poc, profileName);
-                        fclose(m_cliopt.qpfile);
-                        m_cliopt.qpfile = NULL;
-                    }
-                }
-
-                if (m_cliopt.framesToBeEncoded && inFrameCount >=
m_cliopt.framesToBeEncoded)
-                    pic_in = NULL;
-                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;
+                        if (!m_cliopt.parseQPFile(pic_orig[view]))
+                        {
+                            x265_log(NULL, X265_LOG_ERROR, "can't parse
qpfile for frame %d in %s\n",
+                                pic_in[view]->poc, profileName);
+                            fclose(m_cliopt.qpfile);
+                            m_cliopt.qpfile = NULL;
+                        }
                     }
-                    /* Overwrite PTS */
-                    pic_in->pts = pic_in->poc;

-                    // convert to field
-                    if (m_param->bField && m_param->interlaceMode)
+                    if (m_cliopt.framesToBeEncoded && inFrameCount >=
m_cliopt.framesToBeEncoded)
+                        pic_in[view] = NULL;
+                    else if (readPicture(pic_in[view], view) && view ==
m_param->numViews - 1)
+                        inFrameCount++;
+                    else if (!pic_in[view])
+                        pic_in[view] = NULL;
+                    if (pic_in[view])
                     {
-                        int height = pic_in->height >> 1;
+                        if (pic_in[view]->bitDepth >
m_param->internalBitDepth && m_cliopt.bDither)
+                        {
+                            x265_dither_image(pic_in[view],
m_cliopt.input[view]->getWidth(), m_cliopt.input[view]->getHeight(),
errorBuf, m_param->internalBitDepth);
+                            pic_in[view]->bitDepth =
m_param->internalBitDepth;
+                        }
+                        /* Overwrite PTS */
+                        pic_in[view]->pts = pic_in[view]->poc;

-                        int static bCreated = 0;
-                        if (bCreated == 0)
+                        // convert to field
+                        if (m_param->bField && m_param->interlaceMode)
                         {
-                            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++)
+                            int height = pic_in[view]->height >> 1;
+
+                            int static bCreated = 0;
+                            if (bCreated == 0)
                             {
-                                picField1.planes[i] = field1Buf +
framesize;
-                                picField2.planes[i] = field2Buf +
framesize;
+                                bCreated = 1;
+                                inputPicNum = 2;
+                                picField1.fieldNum = 1;
+                                picField2.fieldNum = 2;
+
+                                picField1.bitDepth = picField2.bitDepth =
pic_in[view]->bitDepth;
+                                picField1.colorSpace =
picField2.colorSpace = pic_in[view]->colorSpace;
+                                picField1.height = picField2.height =
pic_in[view]->height >> 1;
+                                picField1.framesize = picField2.framesize
= pic_in[view]->framesize >> 1;
+
+                                size_t fieldFrameSize =
(size_t)pic_in[view]->framesize >> 1;
+                                char* field1Buf = X265_MALLOC(char,
fieldFrameSize);
+                                char* field2Buf = X265_MALLOC(char,
fieldFrameSize);
+
+                                int stride = picField1.stride[0] =
picField2.stride[0] = pic_in[0]->stride[0];
+                                uint64_t framesize = stride * (height >>
x265_cli_csps[pic_in[view]->colorSpace].height[0]);
+                                picField1.planes[0] = field1Buf;
+                                picField2.planes[0] = field2Buf;
+                                for (int i = 1; i <
x265_cli_csps[pic_in[0]->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]));
+                                    stride = picField1.stride[i] =
picField2.stride[i] = pic_in[view]->stride[i];
+                                    framesize += (stride * (height >>
x265_cli_csps[pic_in[view]->colorSpace].height[i]));
+                                }
+                                assert(framesize == picField1.framesize);
                             }
-                            assert(framesize == picField1.framesize);
-                        }

-                        picField1.pts = picField1.poc = pic_in->poc;
-                        picField2.pts = picField2.poc = pic_in->poc + 1;
+                            picField1.pts = picField1.poc =
pic_in[view]->poc;
+                            picField2.pts = picField2.poc =
pic_in[view]->poc + 1;

-                        picField1.userSEI = picField2.userSEI =
pic_in->userSEI;
+                            picField1.userSEI = picField2.userSEI =
pic_in[view]->userSEI;

-                        //if (pic_in->userData)
-                        //{
-                        //    // Have to handle userData here
-                        //}
+                            //if (pic_in->userData)
+                            //{
+                            //    // Have to handle userData here
+                            //}

-                        if (pic_in->framesize)
-                        {
-                            for (int i = 0; i <
x265_cli_csps[pic_in->colorSpace].planes; i++)
+                            if (pic_in[view]->framesize)
                             {
-                                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++)
+                                for (int i = 0; i <
x265_cli_csps[pic_in[view]->colorSpace].planes; i++)
                                 {
-                                    memcpy(p1, srcP1, stride);
-                                    memcpy(p2, srcP2, stride);
-                                    srcP1 += 2 * stride;
-                                    srcP2 += 2 * stride;
-                                    p1 += stride;
-                                    p2 += stride;
+                                    char* srcP1 =
(char*)pic_in[view]->planes[i];
+                                    char* srcP2 =
(char*)pic_in[view]->planes[i] + pic_in[view]->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[view]->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 (bDolbyVisionRPU)
                         {
-                            if (m_cliopt.rpuParser(&picField1) > 0)
-                                goto fail;
-                            if (m_cliopt.rpuParser(&picField2) > 0)
-                                goto fail;
-                        }
-                        else
-                        {
-                            if (m_cliopt.rpuParser(pic_in) > 0)
-                                goto fail;
+                            if (m_param->bField && m_param->interlaceMode)
+                            {
+                                if (m_cliopt.rpuParser(&picField1) > 0)
+                                    goto fail;
+                                if (m_cliopt.rpuParser(&picField2) > 0)
+                                    goto fail;
+                            }
+                            else
+                            {
+                                if (m_cliopt.rpuParser(pic_in[view]) > 0)
+                                    goto fail;
+                            }
                         }
                     }
                 }

                 for (int inputNum = 0; inputNum < inputPicNum; inputNum++)
                 {
-                    x265_picture *picInput = NULL;
+                    x265_picture* picInput = NULL;
                     if (inputPicNum == 2)
                         picInput = pic_in ? (inputNum ? &picField2 :
&picField1) : NULL;
                     else
-                        picInput = pic_in;
+                        picInput = *pic_in;

                     int numEncoded = api->encoder_encode(m_encoder,
&p_nal, &nal, picInput, pic_recon);

@@ -1057,7 +1128,8 @@ ret:
     {
         m_parentEnc = parentEnc;
         m_id = id;
-        m_input = parentEnc->m_input;
+        for (int view = 0; view < MAX_VIEWS; view++)
+            m_input[view] = parentEnc->m_input[view];
     }

     void Reader::threadMain()
@@ -1083,43 +1155,47 @@ ret:
                 read =
m_parentEnc->m_parent->m_picIdxReadCnt[m_id][writeIdx].waitForChange(read);
             }

-            x265_picture* dest =
m_parentEnc->m_parent->m_inputPicBuffer[m_id][writeIdx];
-            if (m_input->readPicture(*src))
+            for (int view = 0; view < m_parentEnc->m_param->numViews;
view++)
             {
-                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]);
+                x265_picture* dest =
m_parentEnc->m_parent->m_inputPicBuffer[view][writeIdx];
+                if (m_input[view]->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]);
 #if ENABLE_ALPHA
-                if (m_parentEnc->m_param->bEnableAlpha)
+                    if (m_parentEnc->m_param->numScalableLayers > 1)
+                    {
+                        dest->planes[3] = (char*)dest->planes[2] +
src->stride[2] * (src->height >> x265_cli_csps[src->colorSpace].height[2]);
+                    }
+#endif
+                    if (view == m_parentEnc->m_param->numViews - 1)
+                        m_parentEnc->m_parent->m_picWriteCnt[m_id].incr();
+                }
+                else
                 {
-                    dest->planes[3] = (char*)dest->planes[2] +
src->stride[2] * (src->height >> x265_cli_csps[src->colorSpace].height[2]);
+                    m_threadActive = false;
+                    m_parentEnc->m_inputOver = true;
+                    m_parentEnc->m_parent->m_picWriteCnt[m_id].poke();
                 }
-#endif
-                m_parentEnc->m_parent->m_picWriteCnt[m_id].incr();
-            }
-            else
-            {
-                m_threadActive = false;
-                m_parentEnc->m_inputOver = true;
-                m_parentEnc->m_parent->m_picWriteCnt[m_id].poke();
             }
         }
         x265_picture_free(src);
diff --git a/source/abrEncApp.h b/source/abrEncApp.h
index f7ff6d96d..43b202cc5 100644
--- a/source/abrEncApp.h
+++ b/source/abrEncApp.h
@@ -86,7 +86,7 @@ namespace X265_NS {
         x265_picture **m_outputRecon;

         CLIOptions m_cliopt;
-        InputFile* m_input;
+        InputFile* m_input[MAX_VIEWS];
         const char* m_reconPlayCmd;
         FILE*    m_qpfile;
         FILE*    m_zoneFile;
@@ -102,7 +102,7 @@ namespace X265_NS {
         void startThreads();
         void copyInfo(x265_analysis_data *src);

-        bool readPicture(x265_picture*);
+        bool readPicture(x265_picture*, int view);
         void destroy();

     private:
@@ -142,7 +142,7 @@ namespace X265_NS {
     public:
         PassEncoder *m_parentEnc;
         int m_id;
-        InputFile* m_input;
+        InputFile* m_input[MAX_VIEWS];
         int m_threadActive;

         Reader(int id, PassEncoder *parentEnc);
diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp
index 88dd4b3fb..55248ff2a 100644
--- a/source/encoder/encoder.cpp
+++ b/source/encoder/encoder.cpp
@@ -1478,7 +1478,7 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
     if (m_aborted)
         return -1;

-    const x265_picture* inputPic = NULL;
+    const x265_picture* inputPic[MAX_VIEWS] = { NULL };
     static int written = 0, read = 0;
     bool dontRead = false;
     bool dropflag = false;
@@ -1576,16 +1576,24 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)

             if (read < written)
             {
-                inputPic = m_dupBuffer[0]->dupPic;
+                inputPic[0] = m_dupBuffer[0]->dupPic;
                 read++;
             }
         }
         else
-            inputPic = pic_in;
+        {
+            for (int view = 0; view < m_param->numViews; view++)
+                inputPic[view] = pic_in + view;
+        }

+        x265_param* p = (m_reconfigure || m_reconfigureRc) ? m_latestParam
: m_param;
+#if ENABLE_MULTIVIEW
+        Frame* inFrame[MAX_VIEWS];
+        for (int layer = 0; layer < m_param->numViews; layer++)
+#else
         Frame* inFrame[MAX_SCALABLE_LAYERS];
-        x265_param *p = (m_reconfigure || m_reconfigureRc) ? m_latestParam
: m_param;
         for (int layer = 0; layer < m_param->numScalableLayers; layer++)
+#endif
         {
             if (m_dpb->m_freeList.empty())
             {
@@ -1593,7 +1601,7 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
                 inFrame[layer]->m_encodeStartTime = x265_mdate();
                 inFrame[layer]->m_sLayerId = layer;
                 inFrame[layer]->m_valid = false;
-                if (inFrame[layer]->create(p, inputPic->quantOffsets))
+                if (inFrame[layer]->create(p,
inputPic[layer]->quantOffsets))
                 {
                     /* the first PicYuv created is asked to generate the
CU and block unit offset
                      * arrays which are then shared with all subsequent
PicYuv (orig and recon)
@@ -1661,11 +1669,11 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
             }

             /* Copy input picture into a Frame and PicYuv, send to
lookahead */
-            inFrame[layer]->m_fencPic->copyFromPicture(*inputPic,
*m_param, m_sps.conformanceWindow.rightOffset,
m_sps.conformanceWindow.bottomOffset, !layer);
+            inFrame[layer]->m_fencPic->copyFromPicture(*inputPic[layer],
*m_param, m_sps.conformanceWindow.rightOffset,
m_sps.conformanceWindow.bottomOffset, !layer);

             inFrame[layer]->m_poc = (!layer) ? (++m_pocLast) : m_pocLast;
-            inFrame[layer]->m_userData = inputPic->userData;
-            inFrame[layer]->m_pts = inputPic->pts;
+            inFrame[layer]->m_userData = inputPic[0]->userData;
+            inFrame[layer]->m_pts = inputPic[0]->pts;

             if ((m_param->bEnableSceneCutAwareQp & BACKWARD) &&
m_param->rc.bStatRead)
             {
@@ -1684,33 +1692,33 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
                 }
             }

-            inFrame[layer]->m_forceqp = inputPic->forceqp;
+            inFrame[layer]->m_forceqp = inputPic[0]->forceqp;
             inFrame[layer]->m_param = (m_reconfigure || m_reconfigureRc) ?
m_latestParam : m_param;
-            inFrame[layer]->m_picStruct = inputPic->picStruct;
+            inFrame[layer]->m_picStruct = inputPic[0]->picStruct;
             if (m_param->bField && m_param->interlaceMode)
-                inFrame[layer]->m_fieldNum = inputPic->fieldNum;
+                inFrame[layer]->m_fieldNum = inputPic[0]->fieldNum;

             /* Encoder holds a reference count until stats collection is
finished */
             ATOMIC_INC(&inFrame[layer]->m_countRefEncoders);
         }
-        copyUserSEIMessages(inFrame[0], inputPic);
+        copyUserSEIMessages(inFrame[0], inputPic[0]);

         /*Copy Dolby Vision RPU from inputPic to frame*/
-        if (inputPic->rpu.payloadSize)
+        if (inputPic[0]->rpu.payloadSize)
         {
-            inFrame[0]->m_rpu.payloadSize = inputPic->rpu.payloadSize;
-            inFrame[0]->m_rpu.payload = new
uint8_t[inputPic->rpu.payloadSize];
-            memcpy(inFrame[0]->m_rpu.payload, inputPic->rpu.payload,
inputPic->rpu.payloadSize);
+            inFrame[0]->m_rpu.payloadSize = inputPic[0]->rpu.payloadSize;
+            inFrame[0]->m_rpu.payload = new
uint8_t[inputPic[0]->rpu.payloadSize];
+            memcpy(inFrame[0]->m_rpu.payload, inputPic[0]->rpu.payload,
inputPic[0]->rpu.payloadSize);
         }

-        if (inputPic->quantOffsets != NULL)
+        if (inputPic[0]->quantOffsets != NULL)
         {
             int cuCount;
             if (m_param->rc.qgSize == 8)
                 cuCount = inFrame[0]->m_lowres.maxBlocksInRowFullRes *
inFrame[0]->m_lowres.maxBlocksInColFullRes;
             else
                 cuCount = inFrame[0]->m_lowres.maxBlocksInRow *
inFrame[0]->m_lowres.maxBlocksInCol;
-            memcpy(inFrame[0]->m_quantOffsets, inputPic->quantOffsets,
cuCount * sizeof(float));
+            memcpy(inFrame[0]->m_quantOffsets, inputPic[0]->quantOffsets,
cuCount * sizeof(float));
         }

         if (m_pocLast == 0)
@@ -1730,7 +1738,7 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)

         /* Use the frame types from the first pass, if available */
         int sliceType = (m_param->rc.bStatRead) ?
m_rateControl->rateControlSliceType(inFrame[0]->m_poc) : X265_TYPE_AUTO;
-        inFrame[0]->m_lowres.sliceTypeReq = inputPic->sliceType;
+        inFrame[0]->m_lowres.sliceTypeReq = inputPic[0]->sliceType;

         /* In analysisSave mode, x265_analysis_data is allocated in
inputPic and inFrame points to this */
         /* Load analysis data before lookahead->addPicture, since
sliceType has been decided */
@@ -1740,7 +1748,7 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
             static int paramBytes = CONF_OFFSET_BYTES;
             if (!inFrame[0]->m_poc && m_param->bAnalysisType != HEVC_INFO)
             {
-                x265_analysis_validate saveParam =
inputPic->analysisData.saveParam;
+                x265_analysis_validate saveParam =
inputPic[0]->analysisData.saveParam;
                 paramBytes += validateAnalysisData(&saveParam, 0);
                 if (paramBytes == -1)
                 {
@@ -1761,10 +1769,10 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
                 uint32_t outOfBoundaryLowresH = extendedHeight -
m_param->sourceHeight / 2;
                 if (outOfBoundaryLowresH * 2 >= m_param->maxCUSize)
                     cuLocInFrame.skipHeight = true;
-                readAnalysisFile(&inFrame[0]->m_analysisData,
inFrame[0]->m_poc, inputPic, paramBytes, cuLocInFrame);
+                readAnalysisFile(&inFrame[0]->m_analysisData,
inFrame[0]->m_poc, inputPic[0], paramBytes, cuLocInFrame);
             }
             else
-                readAnalysisFile(&inFrame[0]->m_analysisData,
inFrame[0]->m_poc, inputPic, paramBytes);
+                readAnalysisFile(&inFrame[0]->m_analysisData,
inFrame[0]->m_poc, inputPic[0], paramBytes);
             inFrame[0]->m_poc = inFrame[0]->m_analysisData.poc;
             sliceType = inFrame[0]->m_analysisData.sliceType;
             inFrame[0]->m_lowres.bScenecut =
!!inFrame[0]->m_analysisData.bScenecut;
@@ -1785,9 +1793,9 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
                 }
             }
         }
-        if (m_param->bUseRcStats && inputPic->rcData)
+        if (m_param->bUseRcStats && inputPic[0]->rcData)
         {
-            RcStats* rc = (RcStats*)inputPic->rcData;
+            RcStats* rc = (RcStats*)inputPic[0]->rcData;
             m_rateControl->m_accumPQp = rc->cumulativePQp;
             m_rateControl->m_accumPNorm = rc->cumulativePNorm;
             m_rateControl->m_isNextGop = true;
diff --git a/source/x265cli.cpp b/source/x265cli.cpp
index 86e1d9bd8..b2b357beb 100755
--- a/source/x265cli.cpp
+++ b/source/x265cli.cpp
@@ -423,9 +423,12 @@ namespace X265_NS {
             free(argString);
         }

-        if (input)
-            input->release();
-        input = NULL;
+        for (int i = 0; i < MAX_VIEWS; i++)
+        {
+            if (input[i])
+                input[i]->release();
+            input[i] = NULL;
+        }
         for (int i = 0; i < MAX_SCALABLE_LAYERS; i++)
         {
             if (recon[i])
@@ -828,9 +831,17 @@ namespace X265_NS {
             }
         }
 #endif
-        if (!inputfn[0] || !outputfn)
+        if (!outputfn)
         {
             x265_log(param, X265_LOG_ERROR, "input or output file not
specified, try --help for help\n");
+            for (int view = 0; view < param->numViews; view++)
+            {
+                if (!inputfn[view])
+                {
+                    x265_log(param, X265_LOG_ERROR, "input or output file
not specified, try --help for help\n");
+                    return true;
+                }
+            }
             return true;
         }

@@ -851,50 +862,53 @@ namespace X265_NS {
             svtParam->encoderBitDepth = inputBitDepth;
         }
 #endif
-
-        InputFileInfo info;
-        info.filename = inputfn[0];
-        info.depth = inputBitDepth;
-        info.csp = param->internalCsp;
-        info.width = param->sourceWidth;
-        info.height = param->sourceHeight;
-        info.fpsNum = param->fpsNum;
-        info.fpsDenom = param->fpsDenom;
-        info.sarWidth = param->vui.sarWidth;
-        info.sarHeight = param->vui.sarHeight;
-        info.skipFrames = seek;
-        info.frameCount = 0;
-        getParamAspectRatio(param, info.sarWidth, info.sarHeight);
-
-        this->input = InputFile::open(info, this->bForceY4m,
param->bEnableAlpha);
-        if (!this->input || this->input->isFail())
+        InputFileInfo info[MAX_VIEWS];
+        for (int i = 0; i < param->numViews; i++)
         {
-            x265_log_file(param, X265_LOG_ERROR, "unable to open input
file <%s>\n", inputfn);
-            return true;
-        }
+            info[i].filename = inputfn[i];
+            info[i].depth = inputBitDepth;
+            info[i].csp = param->internalCsp;
+            info[i].width = param->sourceWidth;
+            info[i].height = param->sourceHeight;
+            info[i].fpsNum = param->fpsNum;
+            info[i].fpsDenom = param->fpsDenom;
+            info[i].sarWidth = param->vui.sarWidth;
+            info[i].sarHeight = param->vui.sarHeight;
+            info[i].skipFrames = seek;
+            info[i].frameCount = 0;
+            getParamAspectRatio(param, info[i].sarWidth,
info[i].sarHeight);
+
+            this->input[i] = InputFile::open(info[i], this->bForceY4m,
param->numScalableLayers > 1);
+            if (!this->input[i] || this->input[i]->isFail())
+            {
+                x265_log_file(param, X265_LOG_ERROR, "unable to open input
file <%s>\n", inputfn[i]);
+                return true;
+            }

-        if (info.depth < 8 || info.depth > 16)
-        {
-            x265_log(param, X265_LOG_ERROR, "Input bit depth (%d) must be
between 8 and 16\n", inputBitDepth);
-            return true;
+            if (info[i].depth < 8 || info[i].depth > 16)
+            {
+                x265_log(param, X265_LOG_ERROR, "Input bit depth (%d) must
be between 8 and 16\n", inputBitDepth);
+                return true;
+            }
         }

+            //TODO:Validate info params of both the views to equal values
         /* Unconditionally accept height/width/csp/bitDepth from file info
*/
-        param->sourceWidth = info.width;
-        param->sourceHeight = info.height;
-        param->internalCsp = info.csp;
-        param->sourceBitDepth = info.depth;
+            param->sourceWidth = info[0].width;
+            param->sourceHeight = info[0].height;
+            param->internalCsp = info[0].csp;
+            param->sourceBitDepth = info[0].depth;

         /* Accept fps and sar from file info if not specified by user */
         if (param->fpsDenom == 0 || param->fpsNum == 0)
         {
-            param->fpsDenom = info.fpsDenom;
-            param->fpsNum = info.fpsNum;
+            param->fpsDenom = info[0].fpsDenom;
+            param->fpsNum = info[0].fpsNum;
         }
-        if (!param->vui.aspectRatioIdc && info.sarWidth && info.sarHeight)
-            setParamAspectRatio(param, info.sarWidth, info.sarHeight);
-        if (this->framesToBeEncoded == 0 && info.frameCount > (int)seek)
-            this->framesToBeEncoded = info.frameCount - seek;
+        if (!param->vui.aspectRatioIdc && info[0].sarWidth &&
info[0].sarHeight)
+            setParamAspectRatio(param, info[0].sarWidth,
info[0].sarHeight);
+        if (this->framesToBeEncoded == 0 && info[0].frameCount > (int)seek)
+            this->framesToBeEncoded = info[0].frameCount - seek;
         param->totalFrames = this->framesToBeEncoded;

 #ifdef SVT_HEVC
@@ -911,8 +925,8 @@ namespace X265_NS {
 #endif

         /* Force CFR until we have support for VFR */
-        info.timebaseNum = param->fpsDenom;
-        info.timebaseDenom = param->fpsNum;
+        info[0].timebaseNum = param->fpsDenom;
+        info[0].timebaseDenom = param->fpsNum;

         if (param->bField && param->interlaceMode)
         {   // Field FPS
@@ -930,22 +944,24 @@ namespace X265_NS {
         {
             char buf[128];
             int p = sprintf(buf, "%dx%d fps %d/%d %sp%d",
param->sourceWidth, param->sourceHeight,
-                param->fpsNum, param->fpsDenom,
x265_source_csp_names[param->internalCsp], info.depth);
+                param->fpsNum, param->fpsDenom,
x265_source_csp_names[param->internalCsp], info[0].depth);

             int width, height;
             getParamAspectRatio(param, width, height);
             if (width && height)
                 p += sprintf(buf + p, " sar %d:%d", width, height);

-            if (framesToBeEncoded <= 0 || info.frameCount <= 0)
+            if (framesToBeEncoded <= 0 || info[0].frameCount <= 0)
                 strcpy(buf + p, " unknown frame count");
             else
-                sprintf(buf + p, " frames %u - %d of %d", this->seek,
this->seek + this->framesToBeEncoded - 1, info.frameCount);
+                sprintf(buf + p, " frames %u - %d of %d", this->seek,
this->seek + this->framesToBeEncoded - 1, info[0].frameCount);

-            general_log(param, input->getName(), X265_LOG_INFO, "%s\n",
buf);
+            for (int view = 0; view < param->numViews; view++)
+                general_log(param, input[view]->getName(), X265_LOG_INFO,
"%s\n", buf);
         }

-        this->input->startReader();
+        for (int view = 0; view < param->numViews; view++)
+            this->input[view]->startReader();

         if (reconfn[0])
         {
@@ -1006,7 +1022,7 @@ namespace X265_NS {
             return true;
         }
 #endif
-        this->output = OutputFile::open(outputfn, info);
+        this->output = OutputFile::open(outputfn, info[0]);
         if (this->output->isFail())
         {
             x265_log_file(param, X265_LOG_ERROR, "failed to open output
file <%s> for writing\n", outputfn);
diff --git a/source/x265cli.h b/source/x265cli.h
index 0fdad9cf3..0613c81e5 100644
--- a/source/x265cli.h
+++ b/source/x265cli.h
@@ -400,7 +400,7 @@ static const struct option long_options[] =

     struct CLIOptions
     {
-        InputFile* input;
+        InputFile* input[MAX_VIEWS];
         ReconFile* recon[MAX_SCALABLE_LAYERS];
         OutputFile* output;
         FILE*       qpfile;
@@ -441,7 +441,8 @@ static const struct option long_options[] =
         static const int UPDATE_INTERVAL = 250000;
         CLIOptions()
         {
-            input = NULL;
+            for (int i = 0; i < MAX_VIEWS; i++)
+                input[i] = NULL;
             for (int i = 0; i < MAX_SCALABLE_LAYERS; i++)
                 recon[i] = NULL;
             output = NULL;
-- 
2.36.0.windows.1
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20240806/c58285cd/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0002-Add-support-to-parse-Multiview-input-file.patch
Type: application/x-patch
Size: 43746 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20240806/c58285cd/attachment-0001.bin>


More information about the x265-devel mailing list