[x265] [PATCH] introduce new CLI single-sei to write all SEI messages in one single NAL

santhoshini at multicorewareinc.com santhoshini at multicorewareinc.com
Mon Apr 2 15:01:14 CEST 2018


# HG changeset patch
# User Santhoshini Sekar <santhoshini at 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 },
-------------- next part --------------
A non-text attachment was scrubbed...
Name: x265.patch
Type: text/x-patch
Size: 13647 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20180402/128ecbb1/attachment-0001.bin>


More information about the x265-devel mailing list