[x265] [PATCH] Add codes to support field feature
Dinesh Kumar Reddy
dinesh at multicorewareinc.com
Thu May 23 13:45:41 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
Pushed patch to x265 default public repo.
Thanks & Regards,
Dinesh
On Thu, May 23, 2019 at 12:00 PM <santhoshini at multicorewareinc.com> wrote:
> # 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");
> _______________________________________________
> x265-devel mailing list
> x265-devel at videolan.org
> https://mailman.videolan.org/listinfo/x265-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20190523/812626bb/attachment-0001.html>
More information about the x265-devel
mailing list