[x265] [PATCH] Add codes to support field feature
santhoshini at multicorewareinc.com
santhoshini at multicorewareinc.com
Thu May 23 08:28:55 CEST 2019
# HG changeset patch
# User Shushuang <shushang at multicorewareinc.com>
# Date 1558582124 -28800
# Thu May 23 11:28:44 2019 +0800
# Node ID 220cdb4328a1e2c7419546b50c4d07e652ae1537
# Parent 3f4fb9a2ac6817c9be4acab5c87746d405fcffd4
Add codes to support field feature
diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst
--- a/doc/reST/cli.rst
+++ b/doc/reST/cli.rst
@@ -551,6 +551,10 @@
This feature can be enabled only in closed GOP structures.
Default 0 (disabled).
+.. option:: --field, --no-field
+
+ Enable or disable field coding. Default disabled.
+
Profile, Level, Tier
====================
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -29,7 +29,7 @@
option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF)
mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)
# X265_BUILD must be incremented each time the public API is changed
-set(X265_BUILD 174)
+set(X265_BUILD 175)
configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
"${PROJECT_BINARY_DIR}/x265.def")
configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
diff --git a/source/common/frame.cpp b/source/common/frame.cpp
--- a/source/common/frame.cpp
+++ b/source/common/frame.cpp
@@ -56,6 +56,7 @@
m_addOnCtuInfo = NULL;
m_addOnPrevChange = NULL;
m_classifyFrame = false;
+ m_fieldNum = 0;
}
bool Frame::create(x265_param *param, float* quantOffsets)
diff --git a/source/common/frame.h b/source/common/frame.h
--- a/source/common/frame.h
+++ b/source/common/frame.h
@@ -129,6 +129,7 @@
uint32_t* m_classifyCount;
bool m_classifyFrame;
+ int m_fieldNum;
Frame();
diff --git a/source/common/param.cpp b/source/common/param.cpp
--- a/source/common/param.cpp
+++ b/source/common/param.cpp
@@ -140,6 +140,7 @@
param->uhdBluray = 0;
param->bHighTier = 1; //Allow high tier by default
param->interlaceMode = 0;
+ param->bField = 0;
param->bAnnexB = 1;
param->bRepeatHeaders = 0;
param->bEnableAccessUnitDelimiters = 0;
@@ -1267,6 +1268,7 @@
OPT("svt-fps-in-vps") x265_log(p, X265_LOG_WARNING, "Option %s is SVT-HEVC Encoder specific; Disabling it here \n", name);
#endif
OPT("fades") p->bEnableFades = atobool(value);
+ OPT("field") p->bField = atobool( value );
else
return X265_PARAM_BAD_NAME;
}
@@ -1639,6 +1641,12 @@
if (param->dolbyProfile == 81)
CHECK(!(param->masteringDisplayColorVolume), "Dolby Vision profile - 8.1 requires Mastering display color volume information\n");
}
+
+ if (param->bField && param->interlaceMode)
+ {
+ CHECK( (param->bFrameAdaptive==0), "Adaptive B-frame decision method should be closed for field feature.\n" );
+ // to do
+ }
#if !X86_64
CHECK(param->searchMethod == X265_SEA && (param->sourceWidth > 840 || param->sourceHeight > 480),
"SEA motion search does not support resolutions greater than 480p in 32 bit build");
@@ -2045,6 +2053,7 @@
BOOL(p->bSingleSeiNal, "single-sei");
BOOL(p->rc.hevcAq, "hevc-aq");
BOOL(p->bEnableSvtHevc, "svt");
+ BOOL(p->bField, "field");
s += sprintf(s, " qp-adaptation-range=%.2f", p->rc.qpAdaptationRange);
#undef BOOL
return buf;
@@ -2370,6 +2379,7 @@
dst->dolbyProfile = src->dolbyProfile;
dst->bEnableSvtHevc = src->bEnableSvtHevc;
dst->bEnableFades = src->bEnableFades;
+ dst->bField = src->bField;
#ifdef SVT_HEVC
memcpy(dst->svtHevcParam, src->svtHevcParam, sizeof(EB_H265_ENC_CONFIGURATION));
diff --git a/source/common/slice.h b/source/common/slice.h
--- a/source/common/slice.h
+++ b/source/common/slice.h
@@ -361,6 +361,7 @@
int numRefIdxDefault[2];
int m_iNumRPSInSPS;
const x265_param *m_param;
+ int m_fieldNum;
Slice()
{
@@ -376,6 +377,7 @@
numRefIdxDefault[1] = 1;
m_rpsIdx = -1;
m_chromaQpOffset[0] = m_chromaQpOffset[1] = 0;
+ m_fieldNum = 0;
}
void disableWeights();
diff --git a/source/encoder/dpb.cpp b/source/encoder/dpb.cpp
--- a/source/encoder/dpb.cpp
+++ b/source/encoder/dpb.cpp
@@ -127,6 +127,7 @@
{
Slice* slice = newFrame->m_encData->m_slice;
slice->m_poc = newFrame->m_poc;
+ slice->m_fieldNum = newFrame->m_fieldNum;
int pocCurr = slice->m_poc;
int type = newFrame->m_lowres.sliceType;
diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp
+++ b/source/encoder/encoder.cpp
@@ -1107,6 +1107,8 @@
inFrame->m_pts = pic_in->pts;
inFrame->m_forceqp = pic_in->forceqp;
inFrame->m_param = (m_reconfigure || m_reconfigureRc) ? m_latestParam : m_param;
+ if (m_param->bField && m_param->interlaceMode)
+ inFrame->m_fieldNum = pic_in->fieldNum;
copyUserSEIMessages(inFrame, pic_in);
diff --git a/source/encoder/frameencoder.cpp b/source/encoder/frameencoder.cpp
--- a/source/encoder/frameencoder.cpp
+++ b/source/encoder/frameencoder.cpp
@@ -686,10 +686,25 @@
if (vui->frameFieldInfoPresentFlag)
{
- if (m_param->interlaceMode == 2)
- sei->m_picStruct = (poc & 1) ? 1 /* top */ : 2 /* bottom */;
- else if (m_param->interlaceMode == 1)
- sei->m_picStruct = (poc & 1) ? 2 /* bottom */ : 1 /* top */;
+ if (m_param->interlaceMode > 0)
+ {
+ if( m_param->interlaceMode == 2 )
+ {
+ // m_picStruct should be set to 3 or 4 when field feature is enabled
+ if (m_param->bField)
+ // 3: Top field, bottom field, in that order; 4: Bottom field, top field, in that order
+ sei->m_picStruct = (slice->m_fieldNum == 1) ? 4 : 3;
+ else
+ sei->m_picStruct = (poc & 1) ? 1 /* top */ : 2 /* bottom */;
+ }
+ else if (m_param->interlaceMode == 1)
+ {
+ if (m_param->bField)
+ sei->m_picStruct = (slice->m_fieldNum == 1) ? 3: 4;
+ else
+ sei->m_picStruct = (poc & 1) ? 2 /* bottom */ : 1 /* top */;
+ }
+ }
else
sei->m_picStruct = m_param->pictureStructure;
diff --git a/source/x265.cpp b/source/x265.cpp
--- a/source/x265.cpp
+++ b/source/x265.cpp
@@ -575,6 +575,15 @@
info.timebaseNum = param->fpsDenom;
info.timebaseDenom = param->fpsNum;
+ if (param->bField && param->interlaceMode)
+ { // Field FPS
+ param->fpsNum *= 2;
+ // Field height
+ param->sourceHeight = param->sourceHeight >> 1;
+ // Number of fields to encode
+ param->totalFrames *= 2;
+ }
+
if (api->param_apply_profile(param, profile))
return true;
@@ -916,7 +925,8 @@
bool bDolbyVisionRPU = false;
uint8_t *rpuPayload = NULL;
int ret = 0;
-
+ int inputPicNum = 1;
+ x265_picture picField1, picField2;
if (!param->bRepeatHeaders && !param->bEnableSvtHevc)
{
@@ -930,7 +940,16 @@
cliopt.totalbytes += cliopt.output->writeHeaders(p_nal, nal);
}
- api->picture_init(param, pic_in);
+ if (param->bField && param->interlaceMode)
+ {
+ api->picture_init(param, &picField1);
+ api->picture_init(param, &picField2);
+ // return back the original height of input
+ param->sourceHeight *= 2;
+ api->picture_init(param, pic_in);
+ }
+ else
+ api->picture_init(param, pic_in);
if (param->dolbyProfile && cliopt.dolbyVisionRpu)
{
@@ -952,7 +971,7 @@
// main encoder loop
while (pic_in && !b_ctrl_c)
{
- pic_orig.poc = inFrameCount;
+ pic_orig.poc = (param->bField && param->interlaceMode) ? inFrameCount * 2 : inFrameCount;
if (cliopt.qpfile)
{
if (!cliopt.parseQPFile(pic_orig))
@@ -980,39 +999,128 @@
/* Overwrite PTS */
pic_in->pts = pic_in->poc;
+ // convert to field
+ if (param->bField && param->interlaceMode)
+ {
+ int height = pic_in->height >> 1;
+
+ int static bCreated = 0;
+ if (bCreated == 0)
+ {
+ bCreated = 1;
+ inputPicNum = 2;
+ picField1.fieldNum = 1;
+ picField2.fieldNum = 2;
+
+ picField1.bitDepth = picField2.bitDepth = pic_in->bitDepth;
+ picField1.colorSpace = picField2.colorSpace = pic_in->colorSpace;
+ picField1.height = picField2.height = pic_in->height >> 1;
+ picField1.framesize = picField2.framesize = pic_in->framesize >> 1;
+
+ char* field1Buf = X265_MALLOC( char, pic_in->framesize >> 1 );
+ char* field2Buf = X265_MALLOC( char, pic_in->framesize >> 1 );
+
+ int stride = picField1.stride[0] = picField2.stride[0] = pic_in->stride[0];
+ int framesize = stride * (height >> x265_cli_csps[pic_in->colorSpace].height[0]);
+ picField1.planes[0] = field1Buf;
+ picField2.planes[0] = field2Buf;
+ for (int i = 1; i < x265_cli_csps[pic_in->colorSpace].planes; i++)
+ {
+ picField1.planes[i] = field1Buf + framesize;
+ picField2.planes[i] = field2Buf + framesize;
+
+ stride = picField1.stride[i] = picField2.stride[i] = pic_in->stride[i];
+ framesize += (stride * (height >> x265_cli_csps[pic_in->colorSpace].height[i]));
+ }
+ assert(framesize == picField1.framesize);
+ }
+
+ picField1.pts = picField1.poc = pic_in->poc;
+ picField2.pts = picField2.poc = pic_in->poc + 1;
+
+ picField1.userSEI = picField2.userSEI = pic_in->userSEI;
+
+ //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++)
+ {
+ char* srcP1 = (char*)pic_in->planes[i];
+ char* srcP2 = (char*)pic_in->planes[i] + pic_in->stride[i];
+ char* p1 = (char*)picField1.planes[i];
+ char* p2 = (char*)picField2.planes[i];
+
+ int stride = picField1.stride[i];
+
+ for (int y = 0; y < (height >> x265_cli_csps[pic_in->colorSpace].height[i]); y++)
+ {
+ memcpy(p1, srcP1, stride);
+ memcpy(p2, srcP2, stride);
+ srcP1 += 2*stride;
+ srcP2 += 2*stride;
+ p1 += stride;
+ p2 += stride;
+ }
+ }
+ }
+ }
+
if (bDolbyVisionRPU)
{
- if (rpuParser(pic_in, cliopt.dolbyVisionRpu) > 0)
- goto fail;
+ if (param->bField && param->interlaceMode)
+ {
+ if (rpuParser(&picField1, cliopt.dolbyVisionRpu) > 0)
+ goto fail;
+ if (rpuParser(&picField2, cliopt.dolbyVisionRpu) > 0)
+ goto fail;
+ }
+ else
+ {
+ if (rpuParser(pic_in, cliopt.dolbyVisionRpu) > 0)
+ goto fail;
+ }
}
}
- int numEncoded = api->encoder_encode(encoder, &p_nal, &nal, pic_in, pic_recon);
- if (numEncoded < 0)
- {
- b_ctrl_c = 1;
- ret = 4;
- break;
+
+ for (int inputNum = 0; inputNum < inputPicNum; inputNum++)
+ {
+ x265_picture *picInput = NULL;
+ if (inputPicNum == 2)
+ picInput = pic_in ? (inputNum ? &picField2 : &picField1) : NULL;
+ else
+ picInput = pic_in;
+
+ int numEncoded = api->encoder_encode( encoder, &p_nal, &nal, picInput, pic_recon );
+ if( numEncoded < 0 )
+ {
+ b_ctrl_c = 1;
+ ret = 4;
+ break;
+ }
+
+ if (reconPlay && numEncoded)
+ reconPlay->writePicture(*pic_recon);
+
+ outFrameCount += numEncoded;
+
+ if (numEncoded && pic_recon && cliopt.recon)
+ cliopt.recon->writePicture(pic_out);
+ if (nal)
+ {
+ cliopt.totalbytes += cliopt.output->writeFrame(p_nal, nal, pic_out);
+ if (pts_queue)
+ {
+ pts_queue->push(-pic_out.pts);
+ if (pts_queue->size() > 2)
+ pts_queue->pop();
+ }
+ }
+ cliopt.printStatus( outFrameCount );
}
-
- if (reconPlay && numEncoded)
- reconPlay->writePicture(*pic_recon);
-
- outFrameCount += numEncoded;
-
- if (numEncoded && pic_recon && cliopt.recon)
- cliopt.recon->writePicture(pic_out);
- if (nal)
- {
- cliopt.totalbytes += cliopt.output->writeFrame(p_nal, nal, pic_out);
- if (pts_queue)
- {
- pts_queue->push(-pic_out.pts);
- if (pts_queue->size() > 2)
- pts_queue->pop();
- }
- }
-
- cliopt.printStatus(outFrameCount);
}
/* Flush the encoder */
diff --git a/source/x265.h b/source/x265.h
--- a/source/x265.h
+++ b/source/x265.h
@@ -464,6 +464,8 @@
//Dolby Vision RPU metadata
x265_dolby_vision_rpu rpu;
+
+ int fieldNum;
} x265_picture;
typedef enum
@@ -1775,6 +1777,9 @@
/* Detect fade-in regions. Enforces I-slice for the brightest point.
Re-init RC history at that point in ABR mode. Default is disabled. */
int bEnableFades;
+
+ /* Enable field coding */
+ int bField;
} x265_param;
/* x265_param_alloc:
* Allocates an x265_param instance. The returned param structure is not
diff --git a/source/x265cli.h b/source/x265cli.h
--- a/source/x265cli.h
+++ b/source/x265cli.h
@@ -73,6 +73,8 @@
{ "input-csp", required_argument, NULL, 0 },
{ "interlace", required_argument, NULL, 0 },
{ "no-interlace", no_argument, NULL, 0 },
+ { "field", no_argument, NULL, 0 },
+ { "no-field", no_argument, NULL, 0 },
{ "fps", required_argument, NULL, 0 },
{ "seek", required_argument, NULL, 0 },
{ "frame-skip", required_argument, NULL, 0 },
@@ -391,6 +393,7 @@
H0("-f/--frames <integer> Maximum number of frames to encode. Default all\n");
H0(" --seek <integer> First frame to encode\n");
H1(" --[no-]interlace <bff|tff> Indicate input pictures are interlace fields in temporal order. Default progressive\n");
+ H0(" --[no-]field Enable or disable field coding. Default %s\n", OPT( param->bField));
H1(" --dither Enable dither if downscaling to 8 bit pixels. Default disabled\n");
H0(" --[no-]copy-pic Copy buffers of input picture in frame. Default %s\n", OPT(param->bCopyPicToFrame));
H0("\nQuality reporting metrics:\n");
-------------- next part --------------
A non-text attachment was scrubbed...
Name: x265.patch
Type: text/x-patch
Size: 15999 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20190523/c2527458/attachment-0001.bin>
More information about the x265-devel
mailing list