# HG changeset patch # User Shushuang <[email protected]> # 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 <[email protected]> wrote: > # HG changeset patch > # User Shushuang <[email protected]> > # 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 > [email protected] > https://mailman.videolan.org/listinfo/x265-devel >
_______________________________________________ x265-devel mailing list [email protected] https://mailman.videolan.org/listinfo/x265-devel
