changeset 12015:2bbff45f761f draft

introduce new CLI single-sei to write all SEI messages in one single NAL
author Santhoshini Sekar <santhoshini@multicorewareinc.com>
date Mon, 02 Apr 2018 18:17:14 +0530
parents 946f82dbf4e8
children 2d95d7ec545e
files doc/reST/cli.rst source/CMakeLists.txt source/common/param.cpp source/encoder/encoder.cpp source/encoder/frameencoder.cpp source/encoder/sei.cpp source/encoder/sei.h source/x265.h source/x265cli.h
diffstat 9 files changed, 76 insertions(+-), 35 deletions(-) [+]
line wrap: on
line diff
--- a/doc/reST/cli.rst	Fri Mar 30 16:44:18 2018 +0530
+++ b/doc/reST/cli.rst	Mon Apr 02 18:17:14 2018 +0530
@@ -2221,6 +2221,10 @@ Bitstream options
 .. 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
 =================
 
--- a/source/CMakeLists.txt	Fri Mar 30 16:44:18 2018 +0530
+++ b/source/CMakeLists.txt	Mon Apr 02 18:17:14 2018 +0530
@@ -29,7 +29,7 @@ option(NATIVE_BUILD "Target the build CP
 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"
--- a/source/common/param.cpp	Fri Mar 30 16:44:18 2018 +0530
+++ b/source/common/param.cpp	Mon Apr 02 18:17:14 2018 +0530
@@ -301,6 +301,7 @@ void x265_param_default(x265_param* para
     /* 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 @@ int x265_param_parse(x265_param* p, cons
         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 @@ int x265_check_params(x265_param* param)
     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 @@ void x265_print_params(x265_param* param
     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 @@ char *x265_param2string(x265_param* p, i
     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;
 }
--- a/source/encoder/encoder.cpp	Fri Mar 30 16:44:18 2018 +0530
+++ b/source/encoder/encoder.cpp	Mon Apr 02 18:17:14 2018 +0530
@@ -2289,26 +2289,26 @@ void Encoder::getStreamHeaders(NALList& 
     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 @@ void Encoder::getStreamHeaders(NALList& 
                     "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 @@ void Encoder::getStreamHeaders(NALList& 
         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);
     }
 }
 
--- a/source/encoder/frameencoder.cpp	Fri Mar 30 16:44:18 2018 +0530
+++ b/source/encoder/frameencoder.cpp	Mon Apr 02 18:17:14 2018 +0530
@@ -393,6 +393,7 @@ void FrameEncoder::compressFrame()
      * 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 @@ void FrameEncoder::compressFrame()
         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 @@ void FrameEncoder::compressFrame()
                 }
 
                 bool isIDR = m_frame->m_lowres.sliceType == X265_TYPE_IDR;
-                writeSei = payloadChange || isIDR;
+                writeSei = (payloadChange || isIDR);
             }
         }
     }
@@ -633,12 +636,12 @@ void FrameEncoder::compressFrame()
             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 @@ void FrameEncoder::compressFrame()
             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 @@ void FrameEncoder::compressFrame()
             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 @@ void FrameEncoder::compressFrame()
         {
             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 @@ void FrameEncoder::compressFrame()
                 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 @@ void FrameEncoder::compressFrame()
 
         m_nalList.serialize(slice->m_nalUnitType, m_bs);
     }
-
+    if (isSei && m_param->bSingleSeiNal)
+        m_bs.resetBits();
 
     if (m_param->decodedPictureHashSEI)
     {
@@ -1085,8 +1097,7 @@ void FrameEncoder::compressFrame()
         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;
--- a/source/encoder/sei.cpp	Fri Mar 30 16:44:18 2018 +0530
+++ b/source/encoder/sei.cpp	Mon Apr 02 18:17:14 2018 +0530
@@ -44,6 +44,15 @@ int SEI::countPayloadSize(const SPS& sps
     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)
--- a/source/encoder/sei.h	Fri Mar 30 16:44:18 2018 +0530
+++ b/source/encoder/sei.h	Mon Apr 02 18:17:14 2018 +0530
@@ -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 @@ public:
     /* 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() {}
--- a/source/x265.h	Fri Mar 30 16:44:18 2018 +0530
+++ b/source/x265.h	Mon Apr 02 18:17:14 2018 +0530
@@ -1563,6 +1563,9 @@ typedef struct x265_param
 
     /* 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:
--- a/source/x265cli.h	Fri Mar 30 16:44:18 2018 +0530
+++ b/source/x265cli.h	Mon Apr 02 18:17:14 2018 +0530
@@ -298,6 +298,8 @@ static const struct option long_options[
     { "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 },