# HG changeset patch # User Santhoshini Sekar <santhosh...@multicorewareinc.com> # Date 1522673234 -19800 # Mon Apr 02 18:17:14 2018 +0530 # Node ID 6337356c86a4f5a49f275eb466d6fae32e6eb145 # Parent 946f82dbf4e80cb272f43a32a78ba2b186469845 introduce new CLI single-sei to write all SEI messages in one single NAL
diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst --- a/doc/reST/cli.rst +++ b/doc/reST/cli.rst @@ -2221,6 +2221,10 @@ .. option:: --idr-recovery-sei, --no-idr-recoveery-sei Emit RecoveryPoint info as sei in bitstream for each IDR frame. Default disabled. +.. option:: --single-sei, --no-single-sei + Emit SEI messages in a single NAL unit instead of multiple NALs. Default disabled. + When HRD SEI is enabled the HM decoder will throw a warning. + DCT Approximations ================= 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 156) +set(X265_BUILD 157) 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/param.cpp b/source/common/param.cpp --- a/source/common/param.cpp +++ b/source/common/param.cpp @@ -301,6 +301,7 @@ /* DCT Approximations */ param->bLowPassDct = 0; param->bMVType = 0; + param->bSingleSeiNal = 0; } int x265_param_default_preset(x265_param* param, const char* preset, const char* tune) @@ -1017,6 +1018,7 @@ OPT("radl") p->radl = atoi(value); OPT("max-ausize-factor") p->maxAUSizeFactor = atof(value); OPT("dynamic-refine") p->bDynamicRefine = atobool(value); + OPT("single-sei") p->bSingleSeiNal = atobool(value); else return X265_PARAM_BAD_NAME; } @@ -1382,6 +1384,14 @@ if (param->masteringDisplayColorVolume || param->maxFALL || param->maxCLL) param->bEmitHDRSEI = 1; + bool isSingleSEI = ((param->bEmitHRDSEI || param->bEmitInfoSEI || param->decodedPictureHashSEI || + param->masteringDisplayColorVolume || param->maxCLL || param->maxFALL || + param->bEmitHDRSEI || param->bEmitIDRRecoverySEI) && param->bSingleSeiNal); + if (!isSingleSEI) + { + param->bSingleSeiNal = 0; + x265_log(param, X265_LOG_WARNING, "None of the SEI messages are enabled. Diabling Single SEI NAL\n"); + } return check_failed; } @@ -1528,6 +1538,7 @@ TOOLOPT(!param->bSaoNonDeblocked && param->bEnableSAO, "sao"); TOOLOPT(param->rc.bStatWrite, "stats-write"); TOOLOPT(param->rc.bStatRead, "stats-read"); + TOOLOPT(param->bSingleSeiNal, "single-sei"); #if ENABLE_HDR10_PLUS TOOLOPT(param->toneMapFile != NULL, "dhdr10-info"); #endif @@ -1751,6 +1762,7 @@ s += sprintf(s, " copy-pic=%d", p->bCopyPicToFrame); s += sprintf(s, " max-ausize-factor=%.1f", p->maxAUSizeFactor); BOOL(p->bDynamicRefine, "dynamic-refine"); + BOOL(p->bSingleSeiNal, "single-sei"); #undef BOOL return buf; } diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp --- a/source/encoder/encoder.cpp +++ b/source/encoder/encoder.cpp @@ -2289,26 +2289,26 @@ sbacCoder.codePPS(m_pps, (m_param->maxSlices <= 1), m_iPPSQpMinus26); bs.writeByteAlignment(); list.serialize(NAL_UNIT_PPS, bs); - + if (m_param->bSingleSeiNal) + bs.resetBits(); if (m_param->bEmitHDRSEI) { SEIContentLightLevel cllsei; cllsei.max_content_light_level = m_param->maxCLL; cllsei.max_pic_average_light_level = m_param->maxFALL; - bs.resetBits(); + if (!m_param->bSingleSeiNal) + bs.resetBits(); cllsei.write(bs, m_sps); - bs.writeByteAlignment(); - list.serialize(NAL_UNIT_PREFIX_SEI, bs); - + cllsei.alignAndSerialize(bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, list); if (m_param->masteringDisplayColorVolume) { SEIMasteringDisplayColorVolume mdsei; if (mdsei.parse(m_param->masteringDisplayColorVolume)) { - bs.resetBits(); + if (!m_param->bSingleSeiNal) + bs.resetBits(); mdsei.write(bs, m_sps); - bs.writeByteAlignment(); - list.serialize(NAL_UNIT_PREFIX_SEI, bs); + mdsei.alignAndSerialize(bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, list); } else x265_log(m_param, X265_LOG_WARNING, "unable to parse mastering display color volume info\n"); @@ -2328,15 +2328,13 @@ "Copyright 2013-2018 (c) Multicoreware, Inc - " "http://x265.org - options: %s", X265_BUILD, PFX(version_str), PFX(build_info_str), opts); - - bs.resetBits(); + if (!m_param->bSingleSeiNal) + bs.resetBits(); SEIuserDataUnregistered idsei; idsei.m_userData = (uint8_t*)buffer; idsei.setSize((uint32_t)strlen(buffer)); idsei.write(bs, m_sps); - bs.writeByteAlignment(); - list.serialize(NAL_UNIT_PREFIX_SEI, bs); - + idsei.alignAndSerialize(bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, list); X265_FREE(buffer); } @@ -2350,12 +2348,12 @@ SEIActiveParameterSets sei; sei.m_selfContainedCvsFlag = true; sei.m_noParamSetUpdateFlag = true; - bs.resetBits(); + if (!m_param->bSingleSeiNal) + bs.resetBits(); int payloadSize = sei.countPayloadSize(m_sps); sei.setSize(payloadSize); sei.write(bs, m_sps); - bs.writeByteAlignment(); - list.serialize(NAL_UNIT_PREFIX_SEI, bs); + sei.alignAndSerialize(bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, list); } } diff --git a/source/encoder/frameencoder.cpp b/source/encoder/frameencoder.cpp --- a/source/encoder/frameencoder.cpp +++ b/source/encoder/frameencoder.cpp @@ -393,6 +393,7 @@ * not repeating headers (since AUD is supposed to be the first NAL in the access * unit) */ Slice* slice = m_frame->m_encData->m_slice; + if (m_param->bEnableAccessUnitDelimiters && (m_frame->m_poc || m_param->bRepeatHeaders)) { m_bs.resetBits(); @@ -400,6 +401,8 @@ m_entropyCoder.codeAUD(*slice); m_bs.writeByteAlignment(); m_nalList.serialize(NAL_UNIT_ACCESS_UNIT_DELIMITER, m_bs); + if (m_param->bSingleSeiNal) + m_bs.resetBits(); } if (m_frame->m_lowres.bKeyframe && m_param->bRepeatHeaders) { @@ -527,7 +530,7 @@ } bool isIDR = m_frame->m_lowres.sliceType == X265_TYPE_IDR; - writeSei = payloadChange || isIDR; + writeSei = (payloadChange || isIDR); } } } @@ -633,12 +636,12 @@ bpSei->m_dpbDelayOffset = 0; // hrdFullness() calculates the initial CPB removal delay and offset m_top->m_rateControl->hrdFullness(bpSei); - m_bs.resetBits(); + if (!m_param->bSingleSeiNal) + m_bs.resetBits(); int payloadSize = bpSei->countPayloadSize(*slice->m_sps); bpSei->setSize(payloadSize); bpSei->write(m_bs, *slice->m_sps); - m_bs.writeByteAlignment(); - m_nalList.serialize(NAL_UNIT_PREFIX_SEI, m_bs); + bpSei->alignAndSerialize(m_bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, m_nalList); m_top->m_lastBPSEI = m_rce.encodeOrder; } @@ -650,11 +653,11 @@ sei.m_recoveryPocCnt = 0; sei.m_exactMatchingFlag = true; sei.m_brokenLinkFlag = false; - m_bs.resetBits(); + if (!m_param->bSingleSeiNal) + m_bs.resetBits(); sei.setSize(sei.countPayloadSize(*slice->m_sps)); sei.write(m_bs, *slice->m_sps); - m_bs.writeByteAlignment(); - m_nalList.serialize(NAL_UNIT_PREFIX_SEI, m_bs); + sei.alignAndSerialize(m_bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, m_nalList); } } @@ -686,12 +689,12 @@ sei->m_auCpbRemovalDelay = X265_MIN(X265_MAX(1, m_rce.encodeOrder - prevBPSEI), (1 << hrd->cpbRemovalDelayLength)); sei->m_picDpbOutputDelay = slice->m_sps->numReorderPics + poc - m_rce.encodeOrder; } - m_bs.resetBits(); + if (!m_param->bSingleSeiNal) + m_bs.resetBits(); int payloadSize = sei->countPayloadSize(*slice->m_sps); sei->setSize(payloadSize); sei->write(m_bs, *slice->m_sps); - m_bs.writeByteAlignment(); - m_nalList.serialize(NAL_UNIT_PREFIX_SEI, m_bs); + sei->alignAndSerialize(m_bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, m_nalList); } /* Write user SEI */ @@ -702,11 +705,11 @@ { SEIuserDataUnregistered sei; sei.m_userData = payload->payload; - m_bs.resetBits(); + if (!m_param->bSingleSeiNal) + m_bs.resetBits(); sei.setSize(payload->payloadSize); sei.write(m_bs, *slice->m_sps); - m_bs.writeByteAlignment(); - m_nalList.serialize(NAL_UNIT_PREFIX_SEI, m_bs); + sei.alignAndSerialize(m_bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, m_nalList); } else if (payload->payloadType == USER_DATA_REGISTERED_ITU_T_T35) { @@ -717,13 +720,21 @@ m_bs.resetBits(); sei.setSize(payload->payloadSize); sei.write(m_bs, *slice->m_sps); - m_bs.writeByteAlignment(); - m_nalList.serialize(NAL_UNIT_PREFIX_SEI, m_bs); + sei.alignAndSerialize(m_bs, true, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, m_nalList); } } else x265_log(m_param, X265_LOG_ERROR, "Unrecognized SEI type\n"); } + bool isSei = (m_frame->m_lowres.bKeyframe && + (m_param->bRepeatHeaders || m_param->bEmitHRDSEI + || !!m_param->interlaceMode || m_param->bEmitIDRRecoverySEI)); + + if (isSei && m_param->bSingleSeiNal) + { + m_bs.writeByteAlignment(); + m_nalList.serialize(NAL_UNIT_PREFIX_SEI, m_bs); + } /* CQP and CRF (without capped VBV) doesn't use mid-frame statistics to * tune RateControl parameters for other frames. * Hence, for these modes, update m_startEndOrder and unlock RC for previous threads waiting in @@ -1055,7 +1066,8 @@ m_nalList.serialize(slice->m_nalUnitType, m_bs); } - + if (isSei && m_param->bSingleSeiNal) + m_bs.resetBits(); if (m_param->decodedPictureHashSEI) { @@ -1085,8 +1097,7 @@ m_bs.resetBits(); m_seiReconPictureDigest.setSize(payloadSize); m_seiReconPictureDigest.write(m_bs, *slice->m_sps); - m_bs.writeByteAlignment(); - m_nalList.serialize(NAL_UNIT_SUFFIX_SEI, m_bs); + m_seiReconPictureDigest.alignAndSerialize(m_bs, true, m_param->bSingleSeiNal, NAL_UNIT_SUFFIX_SEI, m_nalList); } uint64_t bytes = 0; diff --git a/source/encoder/sei.cpp b/source/encoder/sei.cpp --- a/source/encoder/sei.cpp +++ b/source/encoder/sei.cpp @@ -44,6 +44,15 @@ return count; } +void SEI::alignAndSerialize(Bitstream& bs, int lastSei, int isSingleSei, NalUnitType nalUnitType, NALList& list) +{ + if (lastSei || !isSingleSei) + { + bs.writeByteAlignment(); + list.serialize(nalUnitType, bs); + } +} + /* marshal a single SEI message sei, storing the marshalled representation * in bitstream bs */ void SEI::write(Bitstream& bs, const SPS& sps) diff --git a/source/encoder/sei.h b/source/encoder/sei.h --- a/source/encoder/sei.h +++ b/source/encoder/sei.h @@ -27,6 +27,7 @@ #include "common.h" #include "bitstream.h" #include "slice.h" +#include "nal.h" namespace X265_NS { // private namespace @@ -37,6 +38,7 @@ /* SEI users call write() to marshal an SEI to a bitstream. * The write() method calls writeSEI() which encodes the header */ void write(Bitstream& bs, const SPS& sps); + void alignAndSerialize(Bitstream& bs, int lastSei, int isSingleSei, NalUnitType nalUnitType, NALList& list); int countPayloadSize(const SPS& sps); void setSize(uint32_t size); virtual ~SEI() {} diff --git a/source/x265.h b/source/x265.h --- a/source/x265.h +++ b/source/x265.h @@ -1563,6 +1563,9 @@ /* Dynamically change refine-inter at block level*/ int bDynamicRefine; + + /* Enable writing all SEI messgaes in one single NAL instead of mul*/ + int bSingleSeiNal; } x265_param; /* x265_param_alloc: diff --git a/source/x265cli.h b/source/x265cli.h --- a/source/x265cli.h +++ b/source/x265cli.h @@ -298,6 +298,8 @@ { "max-ausize-factor", required_argument, NULL, 0 }, { "idr-recovery-sei", no_argument, NULL, 0 }, { "no-idr-recovery-sei", no_argument, NULL, 0 }, + { "single-sei", no_argument, NULL, 0 }, + { "no-single-sei", no_argument, NULL, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
# HG changeset patch # User Santhoshini Sekar <santhosh...@multicorewareinc.com> # Date 1522673234 -19800 # Mon Apr 02 18:17:14 2018 +0530 # Node ID 6337356c86a4f5a49f275eb466d6fae32e6eb145 # Parent 946f82dbf4e80cb272f43a32a78ba2b186469845 introduce new CLI single-sei to write all SEI messages in one single NAL diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst --- a/doc/reST/cli.rst +++ b/doc/reST/cli.rst @@ -2221,6 +2221,10 @@ .. option:: --idr-recovery-sei, --no-idr-recoveery-sei Emit RecoveryPoint info as sei in bitstream for each IDR frame. Default disabled. +.. option:: --single-sei, --no-single-sei + Emit SEI messages in a single NAL unit instead of multiple NALs. Default disabled. + When HRD SEI is enabled the HM decoder will throw a warning. + DCT Approximations ================= 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 156) +set(X265_BUILD 157) 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/param.cpp b/source/common/param.cpp --- a/source/common/param.cpp +++ b/source/common/param.cpp @@ -301,6 +301,7 @@ /* DCT Approximations */ param->bLowPassDct = 0; param->bMVType = 0; + param->bSingleSeiNal = 0; } int x265_param_default_preset(x265_param* param, const char* preset, const char* tune) @@ -1017,6 +1018,7 @@ OPT("radl") p->radl = atoi(value); OPT("max-ausize-factor") p->maxAUSizeFactor = atof(value); OPT("dynamic-refine") p->bDynamicRefine = atobool(value); + OPT("single-sei") p->bSingleSeiNal = atobool(value); else return X265_PARAM_BAD_NAME; } @@ -1382,6 +1384,14 @@ if (param->masteringDisplayColorVolume || param->maxFALL || param->maxCLL) param->bEmitHDRSEI = 1; + bool isSingleSEI = ((param->bEmitHRDSEI || param->bEmitInfoSEI || param->decodedPictureHashSEI || + param->masteringDisplayColorVolume || param->maxCLL || param->maxFALL || + param->bEmitHDRSEI || param->bEmitIDRRecoverySEI) && param->bSingleSeiNal); + if (!isSingleSEI) + { + param->bSingleSeiNal = 0; + x265_log(param, X265_LOG_WARNING, "None of the SEI messages are enabled. Diabling Single SEI NAL\n"); + } return check_failed; } @@ -1528,6 +1538,7 @@ TOOLOPT(!param->bSaoNonDeblocked && param->bEnableSAO, "sao"); TOOLOPT(param->rc.bStatWrite, "stats-write"); TOOLOPT(param->rc.bStatRead, "stats-read"); + TOOLOPT(param->bSingleSeiNal, "single-sei"); #if ENABLE_HDR10_PLUS TOOLOPT(param->toneMapFile != NULL, "dhdr10-info"); #endif @@ -1751,6 +1762,7 @@ s += sprintf(s, " copy-pic=%d", p->bCopyPicToFrame); s += sprintf(s, " max-ausize-factor=%.1f", p->maxAUSizeFactor); BOOL(p->bDynamicRefine, "dynamic-refine"); + BOOL(p->bSingleSeiNal, "single-sei"); #undef BOOL return buf; } diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp --- a/source/encoder/encoder.cpp +++ b/source/encoder/encoder.cpp @@ -2289,26 +2289,26 @@ sbacCoder.codePPS(m_pps, (m_param->maxSlices <= 1), m_iPPSQpMinus26); bs.writeByteAlignment(); list.serialize(NAL_UNIT_PPS, bs); - + if (m_param->bSingleSeiNal) + bs.resetBits(); if (m_param->bEmitHDRSEI) { SEIContentLightLevel cllsei; cllsei.max_content_light_level = m_param->maxCLL; cllsei.max_pic_average_light_level = m_param->maxFALL; - bs.resetBits(); + if (!m_param->bSingleSeiNal) + bs.resetBits(); cllsei.write(bs, m_sps); - bs.writeByteAlignment(); - list.serialize(NAL_UNIT_PREFIX_SEI, bs); - + cllsei.alignAndSerialize(bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, list); if (m_param->masteringDisplayColorVolume) { SEIMasteringDisplayColorVolume mdsei; if (mdsei.parse(m_param->masteringDisplayColorVolume)) { - bs.resetBits(); + if (!m_param->bSingleSeiNal) + bs.resetBits(); mdsei.write(bs, m_sps); - bs.writeByteAlignment(); - list.serialize(NAL_UNIT_PREFIX_SEI, bs); + mdsei.alignAndSerialize(bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, list); } else x265_log(m_param, X265_LOG_WARNING, "unable to parse mastering display color volume info\n"); @@ -2328,15 +2328,13 @@ "Copyright 2013-2018 (c) Multicoreware, Inc - " "http://x265.org - options: %s", X265_BUILD, PFX(version_str), PFX(build_info_str), opts); - - bs.resetBits(); + if (!m_param->bSingleSeiNal) + bs.resetBits(); SEIuserDataUnregistered idsei; idsei.m_userData = (uint8_t*)buffer; idsei.setSize((uint32_t)strlen(buffer)); idsei.write(bs, m_sps); - bs.writeByteAlignment(); - list.serialize(NAL_UNIT_PREFIX_SEI, bs); - + idsei.alignAndSerialize(bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, list); X265_FREE(buffer); } @@ -2350,12 +2348,12 @@ SEIActiveParameterSets sei; sei.m_selfContainedCvsFlag = true; sei.m_noParamSetUpdateFlag = true; - bs.resetBits(); + if (!m_param->bSingleSeiNal) + bs.resetBits(); int payloadSize = sei.countPayloadSize(m_sps); sei.setSize(payloadSize); sei.write(bs, m_sps); - bs.writeByteAlignment(); - list.serialize(NAL_UNIT_PREFIX_SEI, bs); + sei.alignAndSerialize(bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, list); } } diff --git a/source/encoder/frameencoder.cpp b/source/encoder/frameencoder.cpp --- a/source/encoder/frameencoder.cpp +++ b/source/encoder/frameencoder.cpp @@ -393,6 +393,7 @@ * not repeating headers (since AUD is supposed to be the first NAL in the access * unit) */ Slice* slice = m_frame->m_encData->m_slice; + if (m_param->bEnableAccessUnitDelimiters && (m_frame->m_poc || m_param->bRepeatHeaders)) { m_bs.resetBits(); @@ -400,6 +401,8 @@ m_entropyCoder.codeAUD(*slice); m_bs.writeByteAlignment(); m_nalList.serialize(NAL_UNIT_ACCESS_UNIT_DELIMITER, m_bs); + if (m_param->bSingleSeiNal) + m_bs.resetBits(); } if (m_frame->m_lowres.bKeyframe && m_param->bRepeatHeaders) { @@ -527,7 +530,7 @@ } bool isIDR = m_frame->m_lowres.sliceType == X265_TYPE_IDR; - writeSei = payloadChange || isIDR; + writeSei = (payloadChange || isIDR); } } } @@ -633,12 +636,12 @@ bpSei->m_dpbDelayOffset = 0; // hrdFullness() calculates the initial CPB removal delay and offset m_top->m_rateControl->hrdFullness(bpSei); - m_bs.resetBits(); + if (!m_param->bSingleSeiNal) + m_bs.resetBits(); int payloadSize = bpSei->countPayloadSize(*slice->m_sps); bpSei->setSize(payloadSize); bpSei->write(m_bs, *slice->m_sps); - m_bs.writeByteAlignment(); - m_nalList.serialize(NAL_UNIT_PREFIX_SEI, m_bs); + bpSei->alignAndSerialize(m_bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, m_nalList); m_top->m_lastBPSEI = m_rce.encodeOrder; } @@ -650,11 +653,11 @@ sei.m_recoveryPocCnt = 0; sei.m_exactMatchingFlag = true; sei.m_brokenLinkFlag = false; - m_bs.resetBits(); + if (!m_param->bSingleSeiNal) + m_bs.resetBits(); sei.setSize(sei.countPayloadSize(*slice->m_sps)); sei.write(m_bs, *slice->m_sps); - m_bs.writeByteAlignment(); - m_nalList.serialize(NAL_UNIT_PREFIX_SEI, m_bs); + sei.alignAndSerialize(m_bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, m_nalList); } } @@ -686,12 +689,12 @@ sei->m_auCpbRemovalDelay = X265_MIN(X265_MAX(1, m_rce.encodeOrder - prevBPSEI), (1 << hrd->cpbRemovalDelayLength)); sei->m_picDpbOutputDelay = slice->m_sps->numReorderPics + poc - m_rce.encodeOrder; } - m_bs.resetBits(); + if (!m_param->bSingleSeiNal) + m_bs.resetBits(); int payloadSize = sei->countPayloadSize(*slice->m_sps); sei->setSize(payloadSize); sei->write(m_bs, *slice->m_sps); - m_bs.writeByteAlignment(); - m_nalList.serialize(NAL_UNIT_PREFIX_SEI, m_bs); + sei->alignAndSerialize(m_bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, m_nalList); } /* Write user SEI */ @@ -702,11 +705,11 @@ { SEIuserDataUnregistered sei; sei.m_userData = payload->payload; - m_bs.resetBits(); + if (!m_param->bSingleSeiNal) + m_bs.resetBits(); sei.setSize(payload->payloadSize); sei.write(m_bs, *slice->m_sps); - m_bs.writeByteAlignment(); - m_nalList.serialize(NAL_UNIT_PREFIX_SEI, m_bs); + sei.alignAndSerialize(m_bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, m_nalList); } else if (payload->payloadType == USER_DATA_REGISTERED_ITU_T_T35) { @@ -717,13 +720,21 @@ m_bs.resetBits(); sei.setSize(payload->payloadSize); sei.write(m_bs, *slice->m_sps); - m_bs.writeByteAlignment(); - m_nalList.serialize(NAL_UNIT_PREFIX_SEI, m_bs); + sei.alignAndSerialize(m_bs, true, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, m_nalList); } } else x265_log(m_param, X265_LOG_ERROR, "Unrecognized SEI type\n"); } + bool isSei = (m_frame->m_lowres.bKeyframe && + (m_param->bRepeatHeaders || m_param->bEmitHRDSEI + || !!m_param->interlaceMode || m_param->bEmitIDRRecoverySEI)); + + if (isSei && m_param->bSingleSeiNal) + { + m_bs.writeByteAlignment(); + m_nalList.serialize(NAL_UNIT_PREFIX_SEI, m_bs); + } /* CQP and CRF (without capped VBV) doesn't use mid-frame statistics to * tune RateControl parameters for other frames. * Hence, for these modes, update m_startEndOrder and unlock RC for previous threads waiting in @@ -1055,7 +1066,8 @@ m_nalList.serialize(slice->m_nalUnitType, m_bs); } - + if (isSei && m_param->bSingleSeiNal) + m_bs.resetBits(); if (m_param->decodedPictureHashSEI) { @@ -1085,8 +1097,7 @@ m_bs.resetBits(); m_seiReconPictureDigest.setSize(payloadSize); m_seiReconPictureDigest.write(m_bs, *slice->m_sps); - m_bs.writeByteAlignment(); - m_nalList.serialize(NAL_UNIT_SUFFIX_SEI, m_bs); + m_seiReconPictureDigest.alignAndSerialize(m_bs, true, m_param->bSingleSeiNal, NAL_UNIT_SUFFIX_SEI, m_nalList); } uint64_t bytes = 0; diff --git a/source/encoder/sei.cpp b/source/encoder/sei.cpp --- a/source/encoder/sei.cpp +++ b/source/encoder/sei.cpp @@ -44,6 +44,15 @@ return count; } +void SEI::alignAndSerialize(Bitstream& bs, int lastSei, int isSingleSei, NalUnitType nalUnitType, NALList& list) +{ + if (lastSei || !isSingleSei) + { + bs.writeByteAlignment(); + list.serialize(nalUnitType, bs); + } +} + /* marshal a single SEI message sei, storing the marshalled representation * in bitstream bs */ void SEI::write(Bitstream& bs, const SPS& sps) diff --git a/source/encoder/sei.h b/source/encoder/sei.h --- a/source/encoder/sei.h +++ b/source/encoder/sei.h @@ -27,6 +27,7 @@ #include "common.h" #include "bitstream.h" #include "slice.h" +#include "nal.h" namespace X265_NS { // private namespace @@ -37,6 +38,7 @@ /* SEI users call write() to marshal an SEI to a bitstream. * The write() method calls writeSEI() which encodes the header */ void write(Bitstream& bs, const SPS& sps); + void alignAndSerialize(Bitstream& bs, int lastSei, int isSingleSei, NalUnitType nalUnitType, NALList& list); int countPayloadSize(const SPS& sps); void setSize(uint32_t size); virtual ~SEI() {} diff --git a/source/x265.h b/source/x265.h --- a/source/x265.h +++ b/source/x265.h @@ -1563,6 +1563,9 @@ /* Dynamically change refine-inter at block level*/ int bDynamicRefine; + + /* Enable writing all SEI messgaes in one single NAL instead of mul*/ + int bSingleSeiNal; } x265_param; /* x265_param_alloc: diff --git a/source/x265cli.h b/source/x265cli.h --- a/source/x265cli.h +++ b/source/x265cli.h @@ -298,6 +298,8 @@ { "max-ausize-factor", required_argument, NULL, 0 }, { "idr-recovery-sei", no_argument, NULL, 0 }, { "no-idr-recovery-sei", no_argument, NULL, 0 }, + { "single-sei", no_argument, NULL, 0 }, + { "no-single-sei", no_argument, NULL, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
_______________________________________________ x265-devel mailing list x265-devel@videolan.org https://mailman.videolan.org/listinfo/x265-devel