<div dir="ltr"><div dir="ltr">From 9a8ab63259f1e81ca0bb6e013b715354a10edf03 Mon Sep 17 00:00:00 2001<br>From: Niranjan <<a href="mailto:niranjan@multicorewareinc.com">niranjan@multicorewareinc.com</a>><br>Date: Thu, 18 Mar 2021 09:41:49 +0530<br>Subject: [PATCH] Add: End Of Bitstream and End Of Sequence NAL units<br><br>---<br> doc/reST/api.rst                 | 11 +++++++++++<br> doc/reST/cli.rst                 | 10 ++++++++++<br> source/CMakeLists.txt            |  2 +-<br> source/abrEncApp.cpp             | 12 ++++++++++++<br> source/common/param.cpp          |  8 ++++++++<br> source/encoder/api.cpp           | 21 +++++++++++++++++++++<br> source/encoder/encoder.cpp       | 13 +++++++++++++<br> source/encoder/encoder.h         |  2 ++<br> source/encoder/frameencoder.cpp  |  6 ++++++<br> source/test/regression-tests.txt |  1 +<br> source/x265.h                    |  8 ++++++++<br> source/x265cli.cpp               |  2 ++<br> source/x265cli.h                 |  4 ++++<br> 13 files changed, 99 insertions(+), 1 deletion(-)<br><br>diff --git a/doc/reST/api.rst b/doc/reST/api.rst<br>index 7444f35af..3ea11859e 100644<br>--- a/doc/reST/api.rst<br>+++ b/doc/reST/api.rst<br>@@ -381,6 +381,17 @@ When the last of the raw input pictures has been sent to the encoder,<br> returns a value less than or equal to 0 (indicating the output bitstream<br> is complete).<br> <br>+HEVC streams have EOS and EOB NAL units which specify the end of coded video<br>+sequence and end of bitstream respectively. You must explicitly query those<br>+NAL units at the end using::<br>+<br>+ /* x265_encoder_end_nal_units:<br>+        *      return the EOS and EOB NAL units.<br>+  *      *pi_nal is the number of NAL units outputted in pp_nal.<br>+    *      returns negative on error, total byte size of payload data on success<br>+      *      the payloads of all output NALs are guaranteed to be sequential in memory. */<br>+     int x265_encoder_end_nal_units(x265_encoder *enc, x265_nal **pp_nal, uint32_t *pi_nal);<br>+<br> At any time during this process, the application may query running<br> statistics from the encoder::<br> <br>diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst<br>index c39fee83f..2f556326b 100755<br>--- a/doc/reST/cli.rst<br>+++ b/doc/reST/cli.rst<br>@@ -2529,6 +2529,16 @@ Bitstream options<br>         the very first AUD will be skipped since it cannot be placed at the<br>  start of the access unit, where it belongs. Default disabled<br> <br>+.. option:: --eob, --no-eob<br>+<br>+    Emit an end of bitstream NAL unit at the end of the bitstream.<br>+       Default disabled<br>+<br>+.. option:: --eos, --no-eos<br>+<br>+ Emit an end of sequence NAL unit at the end of every coded<br>+   video sequence. Default disabled<br>+<br> .. option:: --hrd, --no-hrd<br> <br>       Enable the signaling of HRD parameters to the decoder. The HRD<br>diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt<br>index a407271b4..b4e57b592 100755<br>--- a/source/CMakeLists.txt<br>+++ b/source/CMakeLists.txt<br>@@ -29,7 +29,7 @@ option(NATIVE_BUILD "Target the build CPU" OFF)<br> option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF)<br> mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)<br> # X265_BUILD must be incremented each time the public API is changed<br>-set(X265_BUILD 199)<br>+set(X265_BUILD 200)<br> configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265.def.in">x265.def.in</a>"<br>                "${PROJECT_BINARY_DIR}/x265.def")<br> configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265_config.h.in">x265_config.h.in</a>"<br>diff --git a/source/abrEncApp.cpp b/source/abrEncApp.cpp<br>index cd85154f1..fcb19785f 100644<br>--- a/source/abrEncApp.cpp<br>+++ b/source/abrEncApp.cpp<br>@@ -797,6 +797,18 @@ ret:<br>                     break;<br>             }<br> <br>+            if ((m_param->bEnableEndOfBitstream || m_param->bEnableEndOfSequence) && outFrameCount == (uint32_t)m_param->totalFrames)<br>+            {<br>+                if (api->encoder_end_nal_units(m_encoder, &p_nal, &nal) < 0)<br>+                {<br>+                    x265_log(NULL, X265_LOG_ERROR, "Failure generating end nal units\n");<br>+                    m_ret = 3;<br>+                    goto fail;<br>+                }<br>+                else<br>+                    m_cliopt.totalbytes += m_cliopt.output->writeHeaders(p_nal, nal);<br>+            }<br>+<br>             if (bDolbyVisionRPU)<br>             {<br>                 if (fgetc(m_cliopt.dolbyVisionRpu) != EOF)<br>diff --git a/source/common/param.cpp b/source/common/param.cpp<br>index fb74d759b..8a27aaef3 100755<br>--- a/source/common/param.cpp<br>+++ b/source/common/param.cpp<br>@@ -145,6 +145,8 @@ void x265_param_default(x265_param* param)<br>     param->bAnnexB = 1;<br>     param->bRepeatHeaders = 0;<br>     param->bEnableAccessUnitDelimiters = 0;<br>+    param->bEnableEndOfBitstream = 0;<br>+    param->bEnableEndOfSequence = 0;<br>     param->bEmitHRDSEI = 0;<br>     param->bEmitInfoSEI = 1;<br>     param->bEmitHDRSEI = 0; /*Deprecated*/<br>@@ -1448,6 +1450,8 @@ int x265_param_parse(x265_param* p, const char* name, const char* value)<br>         OPT("min-vbv-fullness") p->minVbvFullness = atof(value);<br>         OPT("max-vbv-fullness") p->maxVbvFullness = atof(value);<br>         OPT("video-signal-type-preset") p->videoSignalTypePreset = strdup(value);<br>+        OPT("eob") p->bEnableEndOfBitstream = atobool(value);<br>+        OPT("eos") p->bEnableEndOfSequence = atobool(value);<br>         else<br>             return X265_PARAM_BAD_NAME;<br>     }<br>@@ -2130,6 +2134,8 @@ char *x265_param2string(x265_param* p, int padx, int pady)<br>     BOOL(p->bRepeatHeaders, "repeat-headers");<br>     BOOL(p->bAnnexB, "annexb");<br>     BOOL(p->bEnableAccessUnitDelimiters, "aud");<br>+    BOOL(p->bEnableEndOfBitstream, "eob");<br>+    BOOL(p->bEnableEndOfSequence, "eos");<br>     BOOL(p->bEmitHRDSEI, "hrd");<br>     BOOL(p->bEmitInfoSEI, "info");<br>     s += sprintf(s, " hash=%d", p->decodedPictureHashSEI);<br>@@ -2444,6 +2450,8 @@ void x265_copy_params(x265_param* dst, x265_param* src)<br>     dst->bRepeatHeaders = src->bRepeatHeaders;<br>     dst->bAnnexB = src->bAnnexB;<br>     dst->bEnableAccessUnitDelimiters = src->bEnableAccessUnitDelimiters;<br>+    dst->bEnableEndOfBitstream = src->bEnableEndOfBitstream;<br>+    dst->bEnableEndOfSequence = src->bEnableEndOfSequence;<br>     dst->bEmitInfoSEI = src->bEmitInfoSEI;<br>     dst->decodedPictureHashSEI = src->decodedPictureHashSEI;<br>     dst->bEnableTemporalSubLayers = src->bEnableTemporalSubLayers;<br>diff --git a/source/encoder/api.cpp b/source/encoder/api.cpp<br>index a986355e0..72e508f2f 100644<br>--- a/source/encoder/api.cpp<br>+++ b/source/encoder/api.cpp<br>@@ -295,6 +295,26 @@ int x265_encoder_headers(x265_encoder *enc, x265_nal **pp_nal, uint32_t *pi_nal)<br>     return -1;<br> }<br> <br>+int x265_encoder_end_nal_units(x265_encoder *enc, x265_nal **pp_nal, uint32_t *pi_nal)<br>+{<br>+    if (pp_nal && enc)<br>+    {<br>+        Encoder *encoder = static_cast<Encoder*>(enc);<br>+        Bitstream bs;<br>+        encoder->getEndNalUnits(encoder->m_nalList, bs);<br>+        *pp_nal = &encoder->m_nalList.m_nal[0];<br>+        if (pi_nal) *pi_nal = encoder->m_nalList.m_numNal;<br>+        return encoder->m_nalList.m_occupancy;<br>+    }<br>+<br>+    if (enc)<br>+    {<br>+        Encoder *encoder = static_cast<Encoder*>(enc);<br>+        encoder->m_aborted = true;<br>+    }<br>+    return -1;<br>+}<br>+<br> void x265_encoder_parameters(x265_encoder *enc, x265_param *out)<br> {<br>     if (enc && out)<br>@@ -1052,6 +1072,7 @@ static const x265_api libapi =<br>     &x265_encoder_reconfig,<br>     &x265_encoder_reconfig_zone,<br>     &x265_encoder_headers,<br>+    &x265_encoder_end_nal_units,<br>     &x265_encoder_encode,<br>     &x265_encoder_get_stats,<br>     &x265_encoder_log,<br>diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp<br>index 19d15fb0d..c1e1cb46d 100644<br>--- a/source/encoder/encoder.cpp<br>+++ b/source/encoder/encoder.cpp<br>@@ -3374,6 +3374,19 @@ void Encoder::getStreamHeaders(NALList& list, Entropy& sbacCoder, Bitstream& bs)<br>     }<br> }<br> <br>+void Encoder::getEndNalUnits(NALList& list, Bitstream& bs)<br>+{<br>+    NALList nalList;<br>+    bs.resetBits();<br>+<br>+    if (m_param->bEnableEndOfSequence)<br>+        nalList.serialize(NAL_UNIT_EOS, bs);<br>+    if (m_param->bEnableEndOfBitstream)<br>+        nalList.serialize(NAL_UNIT_EOB, bs);<br>+<br>+    list.takeContents(nalList);<br>+}<br>+<br> void Encoder::initVPS(VPS *vps)<br> {<br>     /* Note that much of the VPS is initialized by determineLevel() */<br>diff --git a/source/encoder/encoder.h b/source/encoder/encoder.h<br>index 22a886ef4..2ee5bdaee 100644<br>--- a/source/encoder/encoder.h<br>+++ b/source/encoder/encoder.h<br>@@ -327,6 +327,8 @@ public:<br> <br>     void getStreamHeaders(NALList& list, Entropy& sbacCoder, Bitstream& bs);<br> <br>+    void getEndNalUnits(NALList& list, Bitstream& bs);<br>+<br>     void fetchStats(x265_stats* stats, size_t statsSizeBytes);<br> <br>     void printSummary();<br>diff --git a/source/encoder/frameencoder.cpp b/source/encoder/frameencoder.cpp<br>index efe85282f..1b3875a25 100644<br>--- a/source/encoder/frameencoder.cpp<br>+++ b/source/encoder/frameencoder.cpp<br>@@ -467,6 +467,12 @@ void FrameEncoder::compressFrame()<br>      * unit) */<br>     Slice* slice = m_frame->m_encData->m_slice;<br> <br>+    if (m_param->bEnableEndOfSequence && m_frame->m_lowres.sliceType == X265_TYPE_IDR && m_frame->m_poc)<br>+    {<br>+        m_bs.resetBits();<br>+        m_nalList.serialize(NAL_UNIT_EOS, m_bs);<br>+    }<br>+<br>     if (m_param->bEnableAccessUnitDelimiters && (m_frame->m_poc || m_param->bRepeatHeaders))<br>     {<br>         m_bs.resetBits();<br>diff --git a/source/test/regression-tests.txt b/source/test/regression-tests.txt<br>index a4fcab87f..971c854df 100644<br>--- a/source/test/regression-tests.txt<br>+++ b/source/test/regression-tests.txt<br>@@ -166,6 +166,7 @@ crowd_run_1920x1080_50.yuv, --preset fast --ctu 64 --rskip 2 --rskip-edge-thresh<br> crowd_run_1920x1080_50.yuv, --preset slow --ctu 32 --rskip 2 --rskip-edge-threshold 5 --hist-scenecut --hist-threshold 0.1<br> crowd_run_1920x1080_50.yuv, --preset slower --ctu 16 --rskip 2 --rskip-edge-threshold 5 --hist-scenecut --hist-threshold 0.1 --aq-mode 4<br> crowd_run_1920x1080_50.yuv, --preset ultrafast --video-signal-type-preset BT2100_PQ_YCC:BT2100x108n0005<br>+crowd_run_1920x1080_50.yuv, --preset ultrafast --eob --eos<br>  <br> # Main12 intraCost overflow bug test<br> 720p50_parkrun_ter.y4m,--preset medium<br>diff --git a/source/x265.h b/source/x265.h<br>index 1c51e769d..1d52ece51 100644<br>--- a/source/x265.h<br>+++ b/source/x265.h<br>@@ -1956,6 +1956,13 @@ typedef struct x265_param<br>     * or color-volume, it will be discarded. */<br>     const char* videoSignalTypePreset;<br> <br>+    /* Flag indicating whether the encoder should emit an End of Bitstream<br>+     * NAL at the end of bitstream. Default false */<br>+    int      bEnableEndOfBitstream;<br>+<br>+    /* Flag indicating whether the encoder should emit an End of Sequence<br>+     * NAL at the end of every Coded Video Sequence. Default false */<br>+    int      bEnableEndOfSequence;<br> } x265_param;<br> <br> /* x265_param_alloc:<br>@@ -2269,6 +2276,7 @@ typedef struct x265_api<br>     int           (*encoder_reconfig)(x265_encoder*, x265_param*);<br>     int           (*encoder_reconfig_zone)(x265_encoder*, x265_zone*);<br>     int           (*encoder_headers)(x265_encoder*, x265_nal**, uint32_t*);<br>+    int           (*encoder_end_nal_units)(x265_encoder*, x265_nal**, uint32_t*);<br>     int           (*encoder_encode)(x265_encoder*, x265_nal**, uint32_t*, x265_picture*, x265_picture*);<br>     void          (*encoder_get_stats)(x265_encoder*, x265_stats*, uint32_t);<br>     void          (*encoder_log)(x265_encoder*, int, char**);<br>diff --git a/source/x265cli.cpp b/source/x265cli.cpp<br>index e9af67c09..bfb6293f3 100755<br>--- a/source/x265cli.cpp<br>+++ b/source/x265cli.cpp<br>@@ -351,6 +351,8 @@ namespace X265_NS {<br>         H0("   --[no-]idr-recovery-sei      Emit recovery point infor SEI at each IDR frame \n");<br>         H0("   --[no-]temporal-layers        Enable a temporal sublayer for unreferenced B frames. Default %s\n", OPT(param->bEnableTemporalSubLayers));<br>         H0("   --[no-]aud                    Emit access unit delimiters at the start of each access unit. Default %s\n", OPT(param->bEnableAccessUnitDelimiters));<br>+        H0("   --[no-]eob                    Emit end of bitstream nal unit at the end of the bitstream. Default %s\n", OPT(param->bEnableEndOfBitstream));<br>+        H0("   --[no-]eos                    Emit end of sequence nal unit at the end of every coded video sequence. Default %s\n", OPT(param->bEnableEndOfSequence));<br>         H1("   --hash <integer>              Decoded Picture Hash SEI 0: disabled, 1: MD5, 2: CRC, 3: Checksum. Default %d\n", param->decodedPictureHashSEI);<br>         H0("   --atc-sei <integer>           Emit the alternative transfer characteristics SEI message where the integer is the preferred transfer characteristics. Default disabled\n");<br>         H0("   --pic-struct <integer>        Set the picture structure and emits it in the picture timing SEI message. Values in the range 0..12. See D.3.3 of the HEVC spec. for a detailed explanation.\n");<br>diff --git a/source/x265cli.h b/source/x265cli.h<br>index 9eb571cfb..46a2b68ae 100644<br>--- a/source/x265cli.h<br>+++ b/source/x265cli.h<br>@@ -264,6 +264,10 @@ static const struct option long_options[] =<br>     { "repeat-headers",       no_argument, NULL, 0 },<br>     { "aud",                  no_argument, NULL, 0 },<br>     { "no-aud",               no_argument, NULL, 0 },<br>+    { "eob",                  no_argument, NULL, 0 },<br>+    { "no-eob",               no_argument, NULL, 0 },<br>+    { "eos",                  no_argument, NULL, 0 },<br>+    { "no-eos",               no_argument, NULL, 0 },<br>     { "info",                 no_argument, NULL, 0 },<br>     { "no-info",              no_argument, NULL, 0 },<br>     { "zones",          required_argument, NULL, 0 },<br>-- <br>2.18.0.windows.1<br><br></div><div dir="ltr" class="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div dir="ltr"><div dir="ltr"></div></div></div></div></div></div></div>