[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