[x265] [PATCH 1 of 1 RFC] x265: add x265_encoder_headers() public API

Steve Borho steve at borho.org
Mon Jul 29 08:24:10 CEST 2013


# HG changeset patch
# User Steve Borho <steve at borho.org>
# Date 1374912300 18000
#      Sat Jul 27 03:05:00 2013 -0500
# Node ID 0e44732c8aae6f64f51db116d06255c32b3a1448
# Parent  8f7dc5f4a05caa5a68af271518d1c3d7e973e1f7
x265: add x265_encoder_headers() public API

This brings us more in sync with x264, and makes GOP parallelism almost trivial
to implement above the level of the encoder (so we can remove the internal one)

diff -r 8f7dc5f4a05c -r 0e44732c8aae source/Lib/TLibEncoder/TEncGOP.cpp
--- a/source/Lib/TLibEncoder/TEncGOP.cpp	Mon Jul 29 01:21:21 2013 -0500
+++ b/source/Lib/TLibEncoder/TEncGOP.cpp	Sat Jul 27 03:05:00 2013 -0500
@@ -311,6 +311,82 @@
     m_inputLock.release();
 }
 
+int TEncGOP::getStreamHeaders(std::list<AccessUnit>& accessUnits)
+{
+    x265::FrameEncoder* frameEncoder = &m_frameEncoders[0];
+    TEncEntropy*        entropyCoder = frameEncoder->getEntropyCoder(0);
+    TEncCavlc*          cavlcCoder   = frameEncoder->getCavlcCoder();
+
+    accessUnits.push_back(AccessUnit());
+    AccessUnit& accessUnit = accessUnits.back();
+
+    // TODO: this code should probably be in init()
+    m_sps.setNumLongTermRefPicSPS(m_numLongTermRefPicSPS);
+    for (Int k = 0; k < m_numLongTermRefPicSPS; k++)
+    {
+        m_sps.setLtRefPicPocLsbSps(k, m_ltRefPicPocLsbSps[k]);
+        m_sps.setUsedByCurrPicLtSPSFlag(k, m_ltRefPicUsedByCurrPicFlag[k]);
+    }
+    if (m_cfg->getPictureTimingSEIEnabled() || m_cfg->getDecodingUnitInfoSEIEnabled())
+    {
+        m_sps.getVuiParameters()->getHrdParameters()->setNumDU(0);
+        m_sps.setHrdParameters(m_cfg->getFrameRate(), 0, m_cfg->getTargetBitrate(), m_cfg->getIntraPeriod() > 0);
+    }
+    if (m_cfg->getBufferingPeriodSEIEnabled() || m_cfg->getPictureTimingSEIEnabled() || m_cfg->getDecodingUnitInfoSEIEnabled())
+    {
+        m_sps.getVuiParameters()->setHrdParametersPresentFlag(true);
+    }
+    // TODO: these are hacks
+    m_sps.setScalingListPresentFlag(false);
+    m_sps.setTMVPFlagsPresent(1);
+    m_pps.setScalingListPresentFlag(false);
+
+    entropyCoder->setEntropyCoder(cavlcCoder, NULL);
+
+    /* headers for start of bitstream */
+    OutputNALUnit nalu(NAL_UNIT_VPS);
+    entropyCoder->setBitstream(&nalu.m_Bitstream);
+    entropyCoder->encodeVPS(m_top->getVPS());
+    writeRBSPTrailingBits(nalu.m_Bitstream);
+    accessUnit.push_back(new NALUnitEBSP(nalu));
+
+    nalu = NALUnit(NAL_UNIT_SPS);
+    entropyCoder->setBitstream(&nalu.m_Bitstream);
+    entropyCoder->encodeSPS(&m_sps);
+    writeRBSPTrailingBits(nalu.m_Bitstream);
+    accessUnit.push_back(new NALUnitEBSP(nalu));
+
+    nalu = NALUnit(NAL_UNIT_PPS);
+    entropyCoder->setBitstream(&nalu.m_Bitstream);
+    entropyCoder->encodePPS(&m_pps);
+    writeRBSPTrailingBits(nalu.m_Bitstream);
+    accessUnit.push_back(new NALUnitEBSP(nalu));
+
+    if (m_cfg->getActiveParameterSetsSEIEnabled())
+    {
+        SEIActiveParameterSets *sei = xCreateSEIActiveParameterSets(&m_sps);
+
+        entropyCoder->setBitstream(&nalu.m_Bitstream);
+        m_seiWriter.writeSEImessage(nalu.m_Bitstream, *sei, &m_sps);
+        writeRBSPTrailingBits(nalu.m_Bitstream);
+        accessUnit.push_back(new NALUnitEBSP(nalu));
+        delete sei;
+    }
+
+    if (m_cfg->getDisplayOrientationSEIAngle())
+    {
+        SEIDisplayOrientation *sei = xCreateSEIDisplayOrientation();
+
+        nalu = NALUnit(NAL_UNIT_PREFIX_SEI);
+        entropyCoder->setBitstream(&nalu.m_Bitstream);
+        m_seiWriter.writeSEImessage(nalu.m_Bitstream, *sei, &m_sps);
+        writeRBSPTrailingBits(nalu.m_Bitstream);
+        accessUnit.push_back(new NALUnitEBSP(nalu));
+        delete sei;
+    }
+    return 0;
+}
+
 // ====================================================================================================================
 // Public member functions
 // ====================================================================================================================
@@ -334,7 +410,6 @@
     TComLoopFilter*       loopFilter   = frameEncoder->getLoopFilter();
     TComBitCounter*       bitCounter   = frameEncoder->getBitCounter();
     TEncSampleAdaptiveOffset* sao      = frameEncoder->getSAO();
-    Bool bActiveParameterSetSEIPresentInAU = false;
     Bool bBufferingPeriodSEIPresentInAU = false;
     Bool bPictureTimingSEIPresentInAU = false;
     Bool bNestedBufferingPeriodSEIPresentInAU = false;
@@ -801,78 +876,6 @@
 
         /* write various header sets. */
 
-        if (pocLast == 0)
-        {
-            /* headers for start of bitstream */
-            OutputNALUnit nalu(NAL_UNIT_VPS);
-            entropyCoder->setBitstream(&nalu.m_Bitstream);
-            entropyCoder->encodeVPS(m_top->getVPS());
-            writeRBSPTrailingBits(nalu.m_Bitstream);
-            accessUnit.push_back(new NALUnitEBSP(nalu));
-            actualTotalBits += UInt(accessUnit.back()->m_nalUnitData.str().size()) * 8;
-
-            nalu = NALUnit(NAL_UNIT_SPS);
-            entropyCoder->setBitstream(&nalu.m_Bitstream);
-            m_sps.setNumLongTermRefPicSPS(m_numLongTermRefPicSPS);
-            for (Int k = 0; k < m_numLongTermRefPicSPS; k++)
-            {
-                m_sps.setLtRefPicPocLsbSps(k, m_ltRefPicPocLsbSps[k]);
-                m_sps.setUsedByCurrPicLtSPSFlag(k, m_ltRefPicUsedByCurrPicFlag[k]);
-            }
-
-            if (m_cfg->getPictureTimingSEIEnabled() || m_cfg->getDecodingUnitInfoSEIEnabled())
-            {
-                // CHECK_ME: maybe HM's bug
-                UInt maxCU = 1500 >> (m_sps.getMaxCUDepth() << 1);
-                UInt numDU = 0;
-                if (pic->getNumCUsInFrame() % maxCU != 0 || numDU == 0)
-                {
-                    numDU++;
-                }
-                m_sps.getVuiParameters()->getHrdParameters()->setNumDU(numDU);
-                m_sps.setHrdParameters(m_cfg->getFrameRate(), numDU, m_cfg->getTargetBitrate(), (m_cfg->getIntraPeriod() > 0));
-            }
-            if (m_cfg->getBufferingPeriodSEIEnabled() || m_cfg->getPictureTimingSEIEnabled() || m_cfg->getDecodingUnitInfoSEIEnabled())
-            {
-                m_sps.getVuiParameters()->setHrdParametersPresentFlag(true);
-            }
-            entropyCoder->encodeSPS(slice->getSPS());
-            writeRBSPTrailingBits(nalu.m_Bitstream);
-            accessUnit.push_back(new NALUnitEBSP(nalu));
-            actualTotalBits += UInt(accessUnit.back()->m_nalUnitData.str().size()) * 8;
-
-            nalu = NALUnit(NAL_UNIT_PPS);
-            entropyCoder->setBitstream(&nalu.m_Bitstream);
-            entropyCoder->encodePPS(slice->getPPS());
-            writeRBSPTrailingBits(nalu.m_Bitstream);
-            accessUnit.push_back(new NALUnitEBSP(nalu));
-            actualTotalBits += UInt(accessUnit.back()->m_nalUnitData.str().size()) * 8;
-
-            if (m_cfg->getActiveParameterSetsSEIEnabled())
-            {
-                SEIActiveParameterSets *sei = xCreateSEIActiveParameterSets(slice->getSPS());
-
-                entropyCoder->setBitstream(&nalu.m_Bitstream);
-                m_seiWriter.writeSEImessage(nalu.m_Bitstream, *sei, slice->getSPS());
-                writeRBSPTrailingBits(nalu.m_Bitstream);
-                accessUnit.push_back(new NALUnitEBSP(nalu));
-                delete sei;
-                bActiveParameterSetSEIPresentInAU = true;
-            }
-
-            if (m_cfg->getDisplayOrientationSEIAngle())
-            {
-                SEIDisplayOrientation *sei = xCreateSEIDisplayOrientation();
-
-                nalu = NALUnit(NAL_UNIT_PREFIX_SEI);
-                entropyCoder->setBitstream(&nalu.m_Bitstream);
-                m_seiWriter.writeSEImessage(nalu.m_Bitstream, *sei, slice->getSPS());
-                writeRBSPTrailingBits(nalu.m_Bitstream);
-                accessUnit.push_back(new NALUnitEBSP(nalu));
-                delete sei;
-            }
-        }
-
         if (writeSOP) // write SOP description SEI (if enabled) at the beginning of GOP
         {
             writeSOP = false;
@@ -986,7 +989,7 @@
             writeRBSPTrailingBits(nalu.m_Bitstream);
             {
                 UInt seiPositionInAu = xGetFirstSeiLocation(accessUnit);
-                UInt offsetPosition = bActiveParameterSetSEIPresentInAU; // Insert BP SEI after APS SEI
+                UInt offsetPosition = 0;
                 AccessUnit::iterator it = accessUnit.begin();
                 for (int j = 0; j < seiPositionInAu + offsetPosition; j++)
                 {
@@ -1007,7 +1010,7 @@
                 m_seiWriter.writeSEImessage(naluTmp.m_Bitstream, scalableNestingSEI, slice->getSPS());
                 writeRBSPTrailingBits(naluTmp.m_Bitstream);
                 UInt seiPositionInAu = xGetFirstSeiLocation(accessUnit);
-                UInt offsetPosition = bActiveParameterSetSEIPresentInAU + bBufferingPeriodSEIPresentInAU + bPictureTimingSEIPresentInAU; // Insert BP SEI after non-nested APS, BP and PT SEIs
+                UInt offsetPosition = bBufferingPeriodSEIPresentInAU + bPictureTimingSEIPresentInAU; // Insert BP SEI after non-nested APS, BP and PT SEIs
                 AccessUnit::iterator it = accessUnit.begin();
                 for (int j = 0; j < seiPositionInAu + offsetPosition; j++)
                 {
@@ -1425,7 +1428,7 @@
                     writeRBSPTrailingBits(onalu.m_Bitstream);
                     UInt seiPositionInAu = xGetFirstSeiLocation(accessUnit);
                     // Insert PT SEI after APS and BP SEI
-                    UInt offsetPosition = bActiveParameterSetSEIPresentInAU + bBufferingPeriodSEIPresentInAU;
+                    UInt offsetPosition = bBufferingPeriodSEIPresentInAU;
                     AccessUnit::iterator it = accessUnit.begin();
                     for (int j = 0; j < seiPositionInAu + offsetPosition; j++)
                     {
@@ -1445,10 +1448,8 @@
                     writeRBSPTrailingBits(onalu.m_Bitstream);
                     UInt seiPositionInAu = xGetFirstSeiLocation(accessUnit);
                     // Insert PT SEI after APS and BP SEI
-                    UInt offsetPosition = bActiveParameterSetSEIPresentInAU +
-                        bBufferingPeriodSEIPresentInAU +
-                        bPictureTimingSEIPresentInAU +
-                        bNestedBufferingPeriodSEIPresentInAU;
+                    UInt offsetPosition = bBufferingPeriodSEIPresentInAU + bPictureTimingSEIPresentInAU +
+                                          bNestedBufferingPeriodSEIPresentInAU;
                     AccessUnit::iterator it = accessUnit.begin();
                     for (int j = 0; j < seiPositionInAu + offsetPosition; j++)
                     {
@@ -1480,9 +1481,7 @@
                         writeRBSPTrailingBits(onalu.m_Bitstream);
                         UInt seiPositionInAu = xGetFirstSeiLocation(accessUnit);
                         // Insert DU info SEI after APS, BP and PT SEI
-                        UInt offsetPosition = bActiveParameterSetSEIPresentInAU +
-                            bBufferingPeriodSEIPresentInAU +
-                            bPictureTimingSEIPresentInAU;
+                        UInt offsetPosition = bBufferingPeriodSEIPresentInAU + bPictureTimingSEIPresentInAU;
                         for (int j = 0; j < seiPositionInAu + offsetPosition; j++)
                         {
                             it++;
@@ -1515,7 +1514,6 @@
             }
         }
 
-        bActiveParameterSetSEIPresentInAU = false;
         bBufferingPeriodSEIPresentInAU    = false;
         bPictureTimingSEIPresentInAU      = false;
         bNestedBufferingPeriodSEIPresentInAU = false;
diff -r 8f7dc5f4a05c -r 0e44732c8aae source/Lib/TLibEncoder/TEncGOP.h
--- a/source/Lib/TLibEncoder/TEncGOP.h	Mon Jul 29 01:21:21 2013 -0500
+++ b/source/Lib/TLibEncoder/TEncGOP.h	Sat Jul 27 03:05:00 2013 -0500
@@ -118,6 +118,8 @@
     // returns count of returned pictures
     int getOutputs(x265_picture_t**, std::list<AccessUnit>& accessUnitsOut);
 
+    int getStreamHeaders(std::list<AccessUnit>& accessUnitsOut);
+
 protected:
 
     void threadMain();
diff -r 8f7dc5f4a05c -r 0e44732c8aae source/Lib/TLibEncoder/TEncTop.cpp
--- a/source/Lib/TLibEncoder/TEncTop.cpp	Mon Jul 29 01:21:21 2013 -0500
+++ b/source/Lib/TLibEncoder/TEncTop.cpp	Sat Jul 27 03:05:00 2013 -0500
@@ -217,6 +217,11 @@
     return ret;
 }
 
+int TEncTop::getStreamHeaders(std::list<AccessUnit>& accessUnitsOut)
+{
+    return m_GOPEncoders->getStreamHeaders(accessUnitsOut);
+}
+
 int TEncTop::flushGopCoders(x265_picture_t **pic_out, std::list<AccessUnit>& accessUnitsOut)
 {
     /* The encoder is being flushed. iterate through GOP coders, starting at the current encoder,
diff -r 8f7dc5f4a05c -r 0e44732c8aae source/Lib/TLibEncoder/TEncTop.h
--- a/source/Lib/TLibEncoder/TEncTop.h	Mon Jul 29 01:21:21 2013 -0500
+++ b/source/Lib/TLibEncoder/TEncTop.h	Sat Jul 27 03:05:00 2013 -0500
@@ -110,6 +110,8 @@
 
     int encode(Bool bEos, const x265_picture_t* pic, x265_picture_t **pic_out, std::list<AccessUnit>& accessUnitsOut);
 
+    int getStreamHeaders(std::list<AccessUnit>& accessUnitsOut);
+
     Double printSummary();
 
 protected:
diff -r 8f7dc5f4a05c -r 0e44732c8aae source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp	Mon Jul 29 01:21:21 2013 -0500
+++ b/source/encoder/encoder.cpp	Sat Jul 27 03:05:00 2013 -0500
@@ -807,6 +807,75 @@
     return encoder;
 }
 
+int x265_encoder_headers(x265_t *encoder, x265_nal_t **pp_nal, int *pi_nal)
+{
+    // there is a lot of duplicated code here, see x265_encoder_encode()
+    list<AccessUnit> outputAccessUnits;
+
+    int ret = encoder->getStreamHeaders(outputAccessUnits);
+    if (pp_nal && !outputAccessUnits.empty())
+    {
+        encoder->m_nals.clear();
+        encoder->m_packetData.clear();
+
+        /* Copy NAL output packets into x265_nal_t structures */
+        list<AccessUnit>::const_iterator iterBitstream = outputAccessUnits.begin();
+        for (size_t i = 0; i < outputAccessUnits.size(); i++)
+        {
+            const AccessUnit &au = *(iterBitstream++);
+
+            for (AccessUnit::const_iterator it = au.begin(); it != au.end(); it++)
+            {
+                const NALUnitEBSP& nalu = **it;
+                int size = 0; /* size of annexB unit in bytes */
+
+                static const Char start_code_prefix[] = { 0, 0, 0, 1 };
+                if (it == au.begin() || nalu.m_nalUnitType == NAL_UNIT_SPS || nalu.m_nalUnitType == NAL_UNIT_PPS)
+                {
+                    /* From AVC, When any of the following conditions are fulfilled, the
+                     * zero_byte syntax element shall be present:
+                     *  - the nal_unit_type within the nal_unit() is equal to 7 (sequence
+                     *    parameter set) or 8 (picture parameter set),
+                     *  - the byte stream NAL unit syntax structure contains the first NAL
+                     *    unit of an access unit in decoding order, as specified by subclause
+                     *    7.4.1.2.3.
+                     */
+                    encoder->m_packetData.append(start_code_prefix, 4);
+                    size += 4;
+                }
+                else
+                {
+                    encoder->m_packetData.append(start_code_prefix + 1, 3);
+                    size += 3;
+                }
+                size_t nalSize = nalu.m_nalUnitData.str().size();
+                encoder->m_packetData.append(nalu.m_nalUnitData.str().c_str(), nalSize);
+                size += (int)nalSize;
+
+                x265_nal_t nal;
+                nal.i_type = nalu.m_nalUnitType;
+                nal.i_payload = size;
+                encoder->m_nals.push_back(nal);
+            }
+        }
+
+        /* Setup payload pointers, now that we're done adding content to m_packetData */
+        size_t offset = 0;
+        for (size_t i = 0; i < encoder->m_nals.size(); i++)
+        {
+            x265_nal_t& nal = encoder->m_nals[i];
+            nal.p_payload = (uint8_t*)encoder->m_packetData.c_str() + offset;
+            offset += nal.i_payload;
+        }
+
+        *pp_nal = &encoder->m_nals[0];
+        if (pi_nal) *pi_nal = (int)encoder->m_nals.size();
+    }
+
+    return ret;
+}
+
+
 extern "C"
 int x265_encoder_encode(x265_t *encoder, x265_nal_t **pp_nal, int *pi_nal, x265_picture_t *pic_in, x265_picture_t **pic_out)
 {
diff -r 8f7dc5f4a05c -r 0e44732c8aae source/x265.cpp
--- a/source/x265.cpp	Mon Jul 29 01:21:21 2013 -0500
+++ b/source/x265.cpp	Sat Jul 27 03:05:00 2013 -0500
@@ -488,6 +488,11 @@
     x265_nal_t *p_nal;
     int nal;
 
+    if (!x265_encoder_headers(encoder, &p_nal, &nal))
+    {
+        cliopt.writeNALs(p_nal, nal);
+    }
+
     // main encoder loop
     uint32_t inFrameCount = 0;
     uint32_t outFrameCount = 0;
diff -r 8f7dc5f4a05c -r 0e44732c8aae source/x265.h
--- a/source/x265.h	Mon Jul 29 01:21:21 2013 -0500
+++ b/source/x265.h	Sat Jul 27 03:05:00 2013 -0500
@@ -253,6 +253,13 @@
  *      create a new encoder handler, all parameters from x265_param_t are copied */
 x265_t *x265_encoder_open(x265_param_t *);
 
+/* x265_encoder_headers:
+ *      return the SPS and PPS that will be used for the whole stream.
+ *      *pi_nal is the number of NAL units outputted in pp_nal.
+ *      returns negative on error.
+ *      the payloads of all output NALs are guaranteed to be sequential in memory. */
+int     x265_encoder_headers(x265_t *, x265_nal_t **pp_nal, int *pi_nal);
+
 /* x265_encoder_encode:
  *      encode one picture.
  *      *pi_nal is the number of NAL units outputted in pp_nal.


More information about the x265-devel mailing list