[x265] [PATCH] Refactor SEI code to handle more user SEI types

ashok at multicorewareinc.com ashok at multicorewareinc.com
Mon Jul 23 15:17:55 CEST 2018


# HG changeset patch
# User Ashok Kumar Mishra <ashok at multicorewareinc.com>
# Date 1532100263 -19800
#      Fri Jul 20 20:54:23 2018 +0530
# Node ID 44f14617642334bca3ee83036cb5d4c6ed96abd5
# Parent  c258d214c978a5c64ec8dd3986a3b3cc3d2381ac
Refactor SEI code to handle more user SEI types

diff -r c258d214c978 -r 44f146176423 source/common/param.cpp
--- a/source/common/param.cpp	Mon Jul 23 15:36:44 2018 +0530
+++ b/source/common/param.cpp	Fri Jul 20 20:54:23 2018 +0530
@@ -1415,9 +1415,16 @@
     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));
+	bool isSingleSEI = ( param->bRepeatHeaders 
+		              || param->bEmitHRDSEI
+					  || param->bEmitInfoSEI					  				  				  
+					  || param->bEmitHDRSEI
+					  || param->bEmitIDRRecoverySEI
+					  || !!param->interlaceMode					 
+					  || param->preferredTransferCharacteristics > 1
+					  || param->toneMapFile
+					  || param->naluFile);
+
     if (!isSingleSEI && param->bSingleSeiNal)
     {
         param->bSingleSeiNal = 0;
diff -r c258d214c978 -r 44f146176423 source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp	Mon Jul 23 15:36:44 2018 +0530
+++ b/source/encoder/encoder.cpp	Fri Jul 20 20:54:23 2018 +0530
@@ -442,6 +442,8 @@
     fail:
         m_aborted = true;
     }
+
+	m_seiEncoder.init(p);
 }
 
 void Encoder::stopJobs()
@@ -875,6 +877,77 @@
     }
 }
 
+void Encoder::copyUserSEIMessages(Frame *frame, const x265_picture* pic_in)
+{
+	x265_sei_payload toneMap;
+	toneMap.payload = NULL;
+	int toneMapPayload = 0;
+
+#if ENABLE_HDR10_PLUS
+	if (m_bToneMap)
+	{
+		int currentPOC = m_pocLast;
+		if (currentPOC < m_numCimInfo)
+		{
+			int32_t i = 0;
+			toneMap.payloadSize = 0;
+			while (m_cim[currentPOC][i] == 0xFF)
+				toneMap.payloadSize += m_cim[currentPOC][i++];
+			toneMap.payloadSize += m_cim[currentPOC][i];
+
+			toneMap.payload = (uint8_t*)x265_malloc(sizeof(uint8_t) * toneMap.payloadSize);
+			toneMap.payloadType = USER_DATA_REGISTERED_ITU_T_T35;
+			memcpy(toneMap.payload, &m_cim[currentPOC][i + 1], toneMap.payloadSize);
+			toneMapPayload = 1;
+		}
+	}
+#endif
+	/* seiMsg will contain SEI messages specified in a fixed file format in POC order.
+	* Format of the file : <POC><space><PREFIX><space><NAL UNIT TYPE>/<SEI TYPE><space><SEI Payload> */
+	x265_sei_payload seiMsg;
+	seiMsg.payload = NULL;
+	int userPayload = 0;
+	if (m_enableNal)
+	{
+		readUserSeiFile(seiMsg, m_pocLast);
+		if (seiMsg.payload)
+			userPayload = 1;;
+	}
+
+	int numPayloads = pic_in->userSEI.numPayloads + toneMapPayload + userPayload;
+	frame->m_userSEI.numPayloads = numPayloads;
+
+	if (frame->m_userSEI.numPayloads)
+	{
+		if (!frame->m_userSEI.payloads)
+		{
+			frame->m_userSEI.payloads = new x265_sei_payload[numPayloads];
+			for (int i = 0; i < numPayloads; i++)
+				frame->m_userSEI.payloads[i].payload = NULL;
+		}
+		for (int i = 0; i < numPayloads; i++)
+		{
+			x265_sei_payload input;
+			if ((i == (numPayloads - 1)) && toneMapPayload)
+				input = toneMap;
+			else if (m_enableNal)
+				input = seiMsg;
+			else
+				input = pic_in->userSEI.payloads[i];
+
+			if (!frame->m_userSEI.payloads[i].payload)
+				frame->m_userSEI.payloads[i].payload = new uint8_t[input.payloadSize];
+			memcpy(frame->m_userSEI.payloads[i].payload, input.payload, input.payloadSize);
+			frame->m_userSEI.payloads[i].payloadSize = input.payloadSize;
+			frame->m_userSEI.payloads[i].payloadType = input.payloadType;
+		}
+		if (toneMap.payload)
+			x265_free(toneMap.payload);
+		if (seiMsg.payload)
+			x265_free(seiMsg.payload);
+	}
+}
+
 /**
  * Feed one new input frame into the encoder, get one frame out. If pic_in is
  * NULL, a flush condition is implied and pic_in must be NULL for all subsequent
@@ -919,32 +992,6 @@
             m_latestParam->forceFlush = 0;
         }
 
-        x265_sei_payload toneMap;
-        toneMap.payload = NULL;
-#if ENABLE_HDR10_PLUS
-        if (m_bToneMap)
-        {
-            int currentPOC = m_pocLast + 1;
-            if (currentPOC < m_numCimInfo)
-            {
-                int32_t i = 0;
-                toneMap.payloadSize = 0;
-                while (m_cim[currentPOC][i] == 0xFF)
-                    toneMap.payloadSize += m_cim[currentPOC][i++];
-                toneMap.payloadSize += m_cim[currentPOC][i];
-
-                toneMap.payload = (uint8_t*)x265_malloc(sizeof(uint8_t) * toneMap.payloadSize);
-                toneMap.payloadType = USER_DATA_REGISTERED_ITU_T_T35;
-                memcpy(toneMap.payload, &m_cim[currentPOC][i+1], toneMap.payloadSize);
-            }
-        }
-#endif
-/* seiMsg will contain SEI messages specified in a fixed file format in POC order.
-* Format of the file : <POC><space><PREFIX><space><NAL UNIT TYPE>/<SEI TYPE><space><SEI Payload> */
-        x265_sei_payload seiMsg;
-        seiMsg.payload = NULL;
-        if (m_enableNal)
-            readUserSeiFile(seiMsg, m_pocLast);
         if (pic_in->bitDepth < 8 || pic_in->bitDepth > 16)
         {
             x265_log(m_param, X265_LOG_ERROR, "Input bit depth (%d) must be between 8 and 16\n",
@@ -1026,42 +1073,7 @@
         inFrame->m_forceqp   = pic_in->forceqp;
         inFrame->m_param     = (m_reconfigure || m_reconfigureRc) ? m_latestParam : m_param;
 
-        int toneMapEnable = 0;
-        if (m_bToneMap && toneMap.payload)
-            toneMapEnable = 1;
-        int numPayloads = pic_in->userSEI.numPayloads + toneMapEnable;
-        if (m_enableNal && seiMsg.payload)
-            numPayloads += m_enableNal;
-        inFrame->m_userSEI.numPayloads = numPayloads;
-
-        if (inFrame->m_userSEI.numPayloads)
-        {
-            if (!inFrame->m_userSEI.payloads)
-            {
-                inFrame->m_userSEI.payloads = new x265_sei_payload[numPayloads];
-                for (int i = 0; i < numPayloads; i++)
-                    inFrame->m_userSEI.payloads[i].payload = NULL;
-            }
-            for (int i = 0; i < numPayloads; i++)
-            {
-                x265_sei_payload input;
-                if ((i == (numPayloads - 1)) && toneMapEnable)
-                    input = toneMap;
-                else if (m_enableNal)
-                    input = seiMsg;
-                else
-                    input = pic_in->userSEI.payloads[i];
-                int size = inFrame->m_userSEI.payloads[i].payloadSize = input.payloadSize;
-                inFrame->m_userSEI.payloads[i].payloadType = input.payloadType;
-                if (!inFrame->m_userSEI.payloads[i].payload)
-                    inFrame->m_userSEI.payloads[i].payload = new uint8_t[size];
-                memcpy(inFrame->m_userSEI.payloads[i].payload, input.payload, size);
-            }
-            if (toneMap.payload)
-                x265_free(toneMap.payload);
-            if (seiMsg.payload)
-                x265_free(seiMsg.payload);
-        }
+		copyUserSEIMessages(inFrame, pic_in);
 
         if (pic_in->quantOffsets != NULL)
         {
@@ -2364,29 +2376,21 @@
     sbacCoder.codePPS(m_pps, (m_param->maxSlices <= 1), m_iPPSQpMinus26);
     bs.writeByteAlignment();
     list.serialize(NAL_UNIT_PPS, bs);
-    if (m_param->bSingleSeiNal)
+
+	if (m_seiEncoder.isNestedSEI)
         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;
-        if (!m_param->bSingleSeiNal)
-            bs.resetBits();
-        cllsei.write(bs, m_sps);
-        cllsei.alignAndSerialize(bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, list);
+		SEIContentLightLevel cllsei;
+		cllsei.max_content_light_level = m_param->maxCLL;
+		cllsei.max_pic_average_light_level = m_param->maxFALL;
+		m_seiEncoder.encodeSEIContentLightLevel(cllsei, bs, m_sps, NAL_UNIT_PREFIX_SEI, list);
+
         if (m_param->masteringDisplayColorVolume)
         {
-            SEIMasteringDisplayColorVolume mdsei;
-            if (mdsei.parse(m_param->masteringDisplayColorVolume))
-            {
-                if (!m_param->bSingleSeiNal)
-                    bs.resetBits();
-                mdsei.write(bs, m_sps);
-                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");
+			SEIMasteringDisplayColorVolume mdsei;			
+			m_seiEncoder.encodeSEIMasteringDisplayColorVolume(mdsei, bs, m_sps, NAL_UNIT_PREFIX_SEI, list);
         }
     }
 
@@ -2403,13 +2407,12 @@
                     "Copyright 2013-2018 (c) Multicoreware, Inc - "
                     "http://x265.org - options: %s",
                     X265_BUILD, PFX(version_str), PFX(build_info_str), opts);
-                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);
-                idsei.alignAndSerialize(bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, list);
+
+				SEIuserDataUnregistered idsei;
+				idsei.m_userData = (uint8_t*)buffer;
+				idsei.setSize((uint32_t)strlen(buffer));
+				m_seiEncoder.encodeSEIuserDataUnregistered(idsei, bs, m_sps, NAL_UNIT_PREFIX_SEI, list);
+
                 X265_FREE(buffer);
             }
 
@@ -2420,15 +2423,8 @@
     if ((m_param->bEmitHRDSEI || !!m_param->interlaceMode))
     {
         /* Picture Timing and Buffering Period SEI require the SPS to be "activated" */
-        SEIActiveParameterSets sei;
-        sei.m_selfContainedCvsFlag = true;
-        sei.m_noParamSetUpdateFlag = true;
-        if (!m_param->bSingleSeiNal)
-            bs.resetBits();
-        int payloadSize = sei.countPayloadSize(m_sps);
-        sei.setSize(payloadSize);
-        sei.write(bs, m_sps);
-        sei.alignAndSerialize(bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, list);
+		SEIActiveParameterSets sei;
+		m_seiEncoder.encodeSEIActiveParameterSets(sei, bs, m_sps, NAL_UNIT_PREFIX_SEI, list);
     }
 }
 
@@ -4530,7 +4526,7 @@
         char *base64Decode = SEI::base64Decode(base64Encode, base64EncodeLength);
         if (nalType == NAL_UNIT_PREFIX_SEI && (!strcmp(prefix, "PREFIX")))
         {
-            int currentPOC = curPoc + 1;
+            int currentPOC = curPoc;
             if (currentPOC == poc)
             {
                 seiMsg.payloadSize = (base64EncodeLength / 4) * 3;
diff -r c258d214c978 -r 44f146176423 source/encoder/encoder.h
--- a/source/encoder/encoder.h	Mon Jul 23 15:36:44 2018 +0530
+++ b/source/encoder/encoder.h	Fri Jul 20 20:54:23 2018 +0530
@@ -31,6 +31,7 @@
 #include "x265.h"
 #include "nal.h"
 #include "framedata.h"
+#include "sei.h"
 #ifdef ENABLE_HDR10_PLUS
     #include "dynamicHDR10/hdr10plus.h"
 #endif
@@ -209,16 +210,17 @@
     Lock               m_rpsInSpsLock;
     int                m_rpsInSpsCount;
     /* For HDR*/
-    double                m_cB;
-    double                m_cR;
+    double             m_cB;
+    double             m_cR;
 
-    int                     m_bToneMap; // Enables tone-mapping
-    int                     m_enableNal;
+    int                m_bToneMap; // Enables tone-mapping
+    int                m_enableNal;
+	SEIEncoder         m_seiEncoder;
 
 #ifdef ENABLE_HDR10_PLUS
     const hdr10plus_api     *m_hdr10plus_api;
-    uint8_t                 **m_cim;
-    int                     m_numCimInfo;
+    uint8_t                **m_cim;
+    int                      m_numCimInfo;
 #endif
 
     x265_sei_payload        m_prevTonemapPayload;
@@ -230,7 +232,7 @@
     int32_t                 m_startPoint;
     Lock                    m_dynamicRefineLock;
 
-    bool                    m_saveCTUSize;
+    bool                    m_saveCTUSize;	
 
     Encoder();
     ~Encoder()
@@ -301,6 +303,8 @@
     void analyseRefIdx(int *numRefIdx);
     void updateRefIdx();
     bool computeSPSRPSIndex();
+	
+	void copyUserSEIMessages(Frame *frame, const x265_picture* pic_in);
 
 protected:
 
diff -r c258d214c978 -r 44f146176423 source/encoder/frameencoder.cpp
--- a/source/encoder/frameencoder.cpp	Mon Jul 23 15:36:44 2018 +0530
+++ b/source/encoder/frameencoder.cpp	Fri Jul 20 20:54:23 2018 +0530
@@ -365,6 +365,155 @@
     return length;
 }
 
+bool FrameEncoder::writeToneMapInfo(x265_sei_payload *payload)
+{
+	bool payloadChange = false;
+	if (m_top->m_prevTonemapPayload.payload != NULL && payload->payloadSize == m_top->m_prevTonemapPayload.payloadSize)
+	{
+		if (memcmp(m_top->m_prevTonemapPayload.payload, payload->payload, payload->payloadSize) != 0)
+			payloadChange = true;
+	}
+	else
+	{
+		payloadChange = true;
+		if (m_top->m_prevTonemapPayload.payload != NULL)
+			x265_free(m_top->m_prevTonemapPayload.payload);
+		m_top->m_prevTonemapPayload.payload = (uint8_t*)x265_malloc(sizeof(uint8_t) * payload->payloadSize);
+	}
+
+	if (payloadChange)
+	{
+		m_top->m_prevTonemapPayload.payloadType = payload->payloadType;
+		m_top->m_prevTonemapPayload.payloadSize = payload->payloadSize;
+		memcpy(m_top->m_prevTonemapPayload.payload, payload->payload, payload->payloadSize);
+	}
+
+	bool isIDR = m_frame->m_lowres.sliceType == X265_TYPE_IDR;
+	return (payloadChange || isIDR);
+}
+
+void FrameEncoder::writeTrailingSEIMessages()
+{
+	Slice* slice = m_frame->m_encData->m_slice;
+	int planes = (m_param->internalCsp != X265_CSP_I400) ? 3 : 1;
+	int32_t payloadSize = 0;
+
+	if (m_param->decodedPictureHashSEI == 1)
+	{
+		m_seiReconPictureDigest.m_method = SEIDecodedPictureHash::MD5;
+		for (int i = 0; i < planes; i++)
+			MD5Final(&m_seiReconPictureDigest.m_state[i], m_seiReconPictureDigest.m_digest[i]);
+		payloadSize = 1 + 16 * planes;
+	}
+	else if (m_param->decodedPictureHashSEI == 2)
+	{
+		m_seiReconPictureDigest.m_method = SEIDecodedPictureHash::CRC;
+		for (int i = 0; i < planes; i++)
+			crcFinish(m_seiReconPictureDigest.m_crc[i], m_seiReconPictureDigest.m_digest[i]);
+		payloadSize = 1 + 2 * planes;
+	}
+	else if (m_param->decodedPictureHashSEI == 3)
+	{
+		m_seiReconPictureDigest.m_method = SEIDecodedPictureHash::CHECKSUM;
+		for (int i = 0; i < planes; i++)
+			checksumFinish(m_seiReconPictureDigest.m_checksum[i], m_seiReconPictureDigest.m_digest[i]);
+		payloadSize = 1 + 4 * planes;
+	}
+
+	m_seiReconPictureDigest.setSize(payloadSize);
+	m_top->m_seiEncoder.encodeSEIDecodedPictureHash(m_seiReconPictureDigest, m_bs, slice, NAL_UNIT_SUFFIX_SEI, m_nalList);
+}
+
+void FrameEncoder::writeLeadingSEIMessages()
+{
+	Slice* slice = m_frame->m_encData->m_slice;
+	int prevBPSEI = m_rce.encodeOrder ? m_top->m_lastBPSEI : 0;
+
+	if (m_frame->m_lowres.bKeyframe)
+	{
+		if (m_param->bEmitHRDSEI)
+		{
+			SEIBufferingPeriod* bpSei = &m_top->m_rateControl->m_bufPeriodSEI;
+			// hrdFullness() calculates the initial CPB removal delay and offset
+			m_top->m_rateControl->hrdFullness(bpSei);
+			m_top->m_seiEncoder.encodeSEIBufferingPeriod(bpSei, m_bs, *slice->m_sps, NAL_UNIT_PREFIX_SEI, m_nalList);
+
+			m_top->m_lastBPSEI = m_rce.encodeOrder;
+		}
+
+		if (m_frame->m_lowres.sliceType == X265_TYPE_IDR && m_param->bEmitIDRRecoverySEI)
+		{
+			/* Recovery Point SEI require the SPS to be "activated" */
+			SEIRecoveryPoint rpSei;
+			m_top->m_seiEncoder.encodeSEIRecoveryPoint(rpSei, m_bs, *slice->m_sps, NAL_UNIT_PREFIX_SEI, m_nalList);
+		}
+	}
+
+	if ((m_param->bEmitHRDSEI || !!m_param->interlaceMode))
+	{
+		SEIPictureTiming *ptSei = m_rce.picTimingSEI;
+		const VUI *vui = &slice->m_sps->vuiParameters;
+		const HRDInfo *hrd = &vui->hrdParameters;
+		int poc = slice->m_poc;
+
+		if (vui->hrdParametersPresentFlag)
+		{
+			// The m_aucpbremoval delay specifies how many clock ticks the
+			// access unit associated with the picture timing SEI message has to
+			// wait after removal of the access unit with the most recent
+			// buffering period SEI message
+			ptSei->m_auCpbRemovalDelay = X265_MIN(X265_MAX(1, m_rce.encodeOrder - prevBPSEI), (1 << hrd->cpbRemovalDelayLength));
+			ptSei->m_picDpbOutputDelay = slice->m_sps->numReorderPics + poc - m_rce.encodeOrder;
+		}
+
+		m_top->m_seiEncoder.encodeSEIPictureTiming(ptSei, m_bs, slice, NAL_UNIT_PREFIX_SEI, m_nalList);
+	}
+
+	if (m_param->preferredTransferCharacteristics > -1 && slice->isIRAP())
+	{
+		SEIAlternativeTC seiAlternativeTC;
+		seiAlternativeTC.m_preferredTransferCharacteristics = m_param->preferredTransferCharacteristics;
+		m_top->m_seiEncoder.encodeSEIAlternativeTransferCharacteristics(seiAlternativeTC, m_bs, *slice->m_sps, NAL_UNIT_PREFIX_SEI, m_nalList);
+	}
+
+	/* Write user SEI */
+	for (int i = 0; i < m_frame->m_userSEI.numPayloads; i++)
+	{
+		x265_sei_payload *payload = &m_frame->m_userSEI.payloads[i];
+		if (payload->payloadType == USER_DATA_UNREGISTERED)
+		{
+			SEIuserDataUnregistered sei;
+			sei.m_userData = payload->payload;
+			sei.setSize(payload->payloadSize);
+			m_top->m_seiEncoder.encodeSEIuserDataUnregistered(sei, m_bs, *slice->m_sps, NAL_UNIT_PREFIX_SEI, m_nalList);
+		}
+		else if (payload->payloadType == USER_DATA_REGISTERED_ITU_T_T35)
+		{
+			bool writeSei = m_param->bDhdr10opt ? writeToneMapInfo(payload) : true;
+			if (writeSei)
+			{
+				SEIuserDataRegistered sei;
+				sei.m_userData = payload->payload;
+				sei.setSize(payload->payloadSize);
+				m_top->m_seiEncoder.encodeSEIuserDataRegistered(sei, m_bs, *slice->m_sps, 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_frame->m_lowres.sliceType == X265_TYPE_IDR && m_param->bEmitIDRRecoverySEI))) ||
+		         (m_param->preferredTransferCharacteristics > -1 && slice->isIRAP()) ||
+		         (m_param->bEmitHRDSEI || !!m_param->interlaceMode) ||
+		          m_frame->m_userSEI.numPayloads;
+
+	if (isSei && m_top->m_seiEncoder.isNestedSEI)
+	{
+		m_bs.writeByteAlignment();
+		m_nalList.serialize(NAL_UNIT_PREFIX_SEI, m_bs);
+	}
+}
+
 void FrameEncoder::compressFrame()
 {
     ProfileScopeEvent(frameThread);
@@ -401,7 +550,7 @@
         m_entropyCoder.codeAUD(*slice);
         m_bs.writeByteAlignment();
         m_nalList.serialize(NAL_UNIT_ACCESS_UNIT_DELIMITER, m_bs);
-        if (m_param->bSingleSeiNal)
+		if (m_top->m_seiEncoder.isNestedSEI)
             m_bs.resetBits();
     }
     if (m_frame->m_lowres.bKeyframe && m_param->bRepeatHeaders)
@@ -462,9 +611,7 @@
                 wa.waitForExit();
             else
                 weightAnalyse(*slice, *m_frame, *m_param);
-
         }
-
     }
     else
         slice->disableWeights();
@@ -499,41 +646,6 @@
 
     /* Get the QP for this frame from rate control. This call may block until
      * frames ahead of it in encode order have called rateControlEnd() */
-    m_rce.encodeOrder = m_frame->m_encodeOrder;
-    bool payloadChange = false;
-    bool writeSei = true;
-    if (m_param->bDhdr10opt)
-    {
-        for (int i = 0; i < m_frame->m_userSEI.numPayloads; i++)
-        {
-            x265_sei_payload *payload = &m_frame->m_userSEI.payloads[i];
-            if(payload->payloadType == USER_DATA_REGISTERED_ITU_T_T35)
-            {
-                if (m_top->m_prevTonemapPayload.payload != NULL && payload->payloadSize == m_top->m_prevTonemapPayload.payloadSize)
-                {
-                    if (memcmp(m_top->m_prevTonemapPayload.payload, payload->payload, payload->payloadSize) != 0)
-                        payloadChange = true;
-                }
-                else
-                {
-                    payloadChange = true;
-                    if (m_top->m_prevTonemapPayload.payload != NULL)
-                        x265_free(m_top->m_prevTonemapPayload.payload);
-                    m_top->m_prevTonemapPayload.payload = (uint8_t*)x265_malloc(sizeof(uint8_t) * payload->payloadSize);
-                }
-
-                if (payloadChange)
-                {
-                    m_top->m_prevTonemapPayload.payloadType = payload->payloadType;
-                    m_top->m_prevTonemapPayload.payloadSize = payload->payloadSize;
-                    memcpy(m_top->m_prevTonemapPayload.payload, payload->payload, payload->payloadSize);
-                }
-
-                bool isIDR = m_frame->m_lowres.sliceType == X265_TYPE_IDR;
-                writeSei = (payloadChange || isIDR);
-            }
-        }
-    }
     int qp = m_top->m_rateControl->rateControlStart(m_frame, &m_rce, m_top);
     m_rce.newQp = qp;
 
@@ -622,139 +734,10 @@
             m_outStreams[i].resetBits();
     }
 
-    int prevBPSEI = m_rce.encodeOrder ? m_top->m_lastBPSEI : 0;
-
-    if (m_frame->m_lowres.bKeyframe)
-    {
-        if (m_param->bEmitHRDSEI)
-        {
-            SEIBufferingPeriod* bpSei = &m_top->m_rateControl->m_bufPeriodSEI;
-
-            // since the temporal layer HRD is not ready, we assumed it is fixed
-            bpSei->m_auCpbRemovalDelayDelta = 1;
-            bpSei->m_cpbDelayOffset = 0;
-            bpSei->m_dpbDelayOffset = 0;
-            // hrdFullness() calculates the initial CPB removal delay and offset
-            m_top->m_rateControl->hrdFullness(bpSei);
-            if (!m_param->bSingleSeiNal)
-                m_bs.resetBits();
-            int payloadSize = bpSei->countPayloadSize(*slice->m_sps);
-            bpSei->setSize(payloadSize);
-            bpSei->write(m_bs, *slice->m_sps);
-            bpSei->alignAndSerialize(m_bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, m_nalList);
-
-            m_top->m_lastBPSEI = m_rce.encodeOrder;
-        }
-
-        if (m_frame->m_lowres.sliceType == X265_TYPE_IDR && m_param->bEmitIDRRecoverySEI)
-        {
-            /* Recovery Point SEI require the SPS to be "activated" */
-            SEIRecoveryPoint sei;
-            sei.m_recoveryPocCnt = 0;
-            sei.m_exactMatchingFlag = true;
-            sei.m_brokenLinkFlag = false;
-            if (!m_param->bSingleSeiNal)
-                m_bs.resetBits();
-            sei.setSize(sei.countPayloadSize(*slice->m_sps));
-            sei.write(m_bs, *slice->m_sps);
-            sei.alignAndSerialize(m_bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, m_nalList);
-        }
-    }
-
-    if ((m_param->bEmitHRDSEI || !!m_param->interlaceMode))
-    {
-        SEIPictureTiming *sei = m_rce.picTimingSEI;
-        const VUI *vui = &slice->m_sps->vuiParameters;
-        const HRDInfo *hrd = &vui->hrdParameters;
-        int poc = slice->m_poc;
-
-        if (vui->frameFieldInfoPresentFlag)
-        {
-            if (m_param->interlaceMode == 2)
-                sei->m_picStruct = (poc & 1) ? 1 /* top */ : 2 /* bottom */;
-            else if (m_param->interlaceMode == 1)
-                sei->m_picStruct = (poc & 1) ? 2 /* bottom */ : 1 /* top */;
-			else
-				sei->m_picStruct = m_param->pictureStructure;
-			
-		    if (m_param->interlaceMode)
-				 sei->m_sourceScanType = 0;
-			else
-				 sei->m_sourceScanType = 1;
-			
-            sei->m_duplicateFlag = false;
-        }
+	m_rce.encodeOrder = m_frame->m_encodeOrder;
+	
+	writeLeadingSEIMessages();
 
-        if (vui->hrdParametersPresentFlag)
-        {
-            // The m_aucpbremoval delay specifies how many clock ticks the
-            // access unit associated with the picture timing SEI message has to
-            // wait after removal of the access unit with the most recent
-            // buffering period SEI message
-            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;
-        }
-        if (!m_param->bSingleSeiNal)
-            m_bs.resetBits();
-        int payloadSize = sei->countPayloadSize(*slice->m_sps);
-        sei->setSize(payloadSize);
-        sei->write(m_bs, *slice->m_sps);
-        sei->alignAndSerialize(m_bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, m_nalList);
-    }
-
-	if (m_param->preferredTransferCharacteristics > -1 && slice->isIRAP())
-	{
-	    SEIAlternativeTC m_seiAlternativeTC;
-		m_seiAlternativeTC.m_preferredTransferCharacteristics = m_param->preferredTransferCharacteristics;
-		m_bs.resetBits();
-		int payloadSize = m_seiAlternativeTC.countPayloadSize(*slice->m_sps);
-		m_seiAlternativeTC.setSize(payloadSize);
-		m_seiAlternativeTC.write(m_bs, *slice->m_sps);
-		m_seiAlternativeTC.alignAndSerialize(m_bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, m_nalList);
-	}
-	
-    bool isSei = false;
-    /* Write user SEI */
-    for (int i = 0; i < m_frame->m_userSEI.numPayloads; i++)
-    {
-        x265_sei_payload *payload = &m_frame->m_userSEI.payloads[i];
-        if (payload->payloadType == USER_DATA_UNREGISTERED)
-        {
-            SEIuserDataUnregistered sei;
-            sei.m_userData = payload->payload;
-            if (!m_param->bSingleSeiNal)
-                m_bs.resetBits();
-            sei.setSize(payload->payloadSize);
-            sei.write(m_bs, *slice->m_sps);
-            sei.alignAndSerialize(m_bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, m_nalList);
-            isSei = true;
-        }
-        else if (payload->payloadType == USER_DATA_REGISTERED_ITU_T_T35)
-        {
-            if (writeSei)
-            {
-                SEICreativeIntentMeta sei;
-                sei.m_payload = payload->payload;
-                if (!m_param->bSingleSeiNal)
-                    m_bs.resetBits();
-                sei.setSize(payload->payloadSize);
-                sei.write(m_bs, *slice->m_sps);
-                sei.alignAndSerialize(m_bs, false, m_param->bSingleSeiNal, NAL_UNIT_PREFIX_SEI, m_nalList);
-                isSei = true;
-            }
-        }
-        else
-            x265_log(m_param, X265_LOG_ERROR, "Unrecognized SEI type\n");
-    }
-
-    isSei |= ((m_frame->m_lowres.bKeyframe && m_param->bRepeatHeaders) || m_param->bEmitHRDSEI ||
-             !!m_param->interlaceMode || (m_frame->m_lowres.sliceType == X265_TYPE_IDR && 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
@@ -888,73 +871,10 @@
 
     if (m_param->maxSlices > 1)
     {
-        PicYuv *reconPic = m_frame->m_reconPic;
-        uint32_t height = reconPic->m_picHeight;
-        uint32_t width = reconPic->m_picWidth;
-        intptr_t stride = reconPic->m_stride;
-        const uint32_t hChromaShift = CHROMA_H_SHIFT(m_param->internalCsp);
-        const uint32_t vChromaShift = CHROMA_V_SHIFT(m_param->internalCsp);
-
-        if (m_param->decodedPictureHashSEI == 1)
-        {
-
-            MD5Init(&m_state[0]);
-
-            updateMD5Plane(m_state[0], reconPic->m_picOrg[0], width, height, stride);
-
-            if (m_param->internalCsp != X265_CSP_I400)
-            {
-                MD5Init(&m_state[1]);
-                MD5Init(&m_state[2]);
-
-                width >>= hChromaShift;
-                height >>= vChromaShift;
-                stride = reconPic->m_strideC;
-
-                updateMD5Plane(m_state[1], reconPic->m_picOrg[1], width, height, stride);
-                updateMD5Plane(m_state[2], reconPic->m_picOrg[2], width, height, stride);
-            }
-        }
-        // TODO: NOT verify code in below mode
-        else if (m_param->decodedPictureHashSEI == 2)
-        {
-            m_crc[0] = 0xffff;
-
-            updateCRC(reconPic->m_picOrg[0], m_crc[0], height, width, stride);
-
-            if (m_param->internalCsp != X265_CSP_I400)
-            {
-                width >>= hChromaShift;
-                height >>= vChromaShift;
-                stride = reconPic->m_strideC;
-                m_crc[1] = m_crc[2] = 0xffff;
-
-                updateCRC(reconPic->m_picOrg[1], m_crc[1], height, width, stride);
-                updateCRC(reconPic->m_picOrg[2], m_crc[2], height, width, stride);
-            }
-        }
-        else if (m_param->decodedPictureHashSEI == 3)
-        {
-            uint32_t cuHeight = m_param->maxCUSize;
-
-            m_checksum[0] = 0;
-
-            updateChecksum(reconPic->m_picOrg[0], m_checksum[0], height, width, stride, 0, cuHeight);
-
-            if (m_param->internalCsp != X265_CSP_I400)
-            {
-                width >>= hChromaShift;
-                height >>= vChromaShift;
-                stride = reconPic->m_strideC;
-                cuHeight >>= vChromaShift;
-
-                m_checksum[1] = m_checksum[2] = 0;
-
-                updateChecksum(reconPic->m_picOrg[1], m_checksum[1], height, width, stride, 0, cuHeight);
-                updateChecksum(reconPic->m_picOrg[2], m_checksum[2], height, width, stride, 0, cuHeight);
-            }
-        }  
-    } // end of (m_param->maxSlices > 1)
+		PicYuv *reconPic = m_frame->m_reconPic;
+		uint32_t height = reconPic->m_picHeight;
+		initDecodedPictureHashSEI(0, 0, height);
+    } 
 
     if (m_param->bDynamicRefine && m_top->m_startPoint <= m_frame->m_encodeOrder) //Avoid collecting data that will not be used by future frames.
         collectDynDataFrame();
@@ -1045,8 +965,6 @@
             m_bs.resetBits();
 
             const uint32_t sliceAddr = nextSliceRow * m_numCols;
-            //CUData* ctu = m_frame->m_encData->getPicCTU(sliceAddr);
-            //const int sliceQp = ctu->m_qp[0];
             if (m_param->bOptRefListLengthPPS)
             {
                 ScopedLock refIdxLock(m_top->m_sliceRefIdxLock);
@@ -1068,7 +986,6 @@
                 m_entropyCoder.codeSliceHeaderWPPEntryPoints(&m_substreamSizes[prevSliceRow], (nextSliceRow - prevSliceRow - 1), maxStreamSize);
             
             m_bs.writeByteAlignment();
-
             m_nalList.serialize(slice->m_nalUnitType, m_bs);
         }
     }
@@ -1088,43 +1005,13 @@
         m_entropyCoder.setBitstream(&m_bs);
         if (slice->m_pps->bEntropyCodingSyncEnabled)
             m_entropyCoder.codeSliceHeaderWPPEntryPoints(m_substreamSizes, (slice->m_sps->numCuInHeight - 1), maxStreamSize);
+
         m_bs.writeByteAlignment();
-
         m_nalList.serialize(slice->m_nalUnitType, m_bs);
     }
-    if (isSei && m_param->bSingleSeiNal)
-        m_bs.resetBits();
 
-    if (m_param->decodedPictureHashSEI)
-    {
-        int planes = (m_frame->m_param->internalCsp != X265_CSP_I400) ? 3 : 1;
-        int32_t payloadSize = 0;
-        if (m_param->decodedPictureHashSEI == 1)
-        {
-            m_seiReconPictureDigest.m_method = SEIDecodedPictureHash::MD5;
-            for (int i = 0; i < planes; i++)
-                MD5Final(&m_state[i], m_seiReconPictureDigest.m_digest[i]);
-            payloadSize = 1 + 16 * planes;
-        }
-        else if (m_param->decodedPictureHashSEI == 2)
-        {
-            m_seiReconPictureDigest.m_method = SEIDecodedPictureHash::CRC;
-            for (int i = 0; i < planes; i++)
-                crcFinish(m_crc[i], m_seiReconPictureDigest.m_digest[i]);
-            payloadSize = 1 + 2 * planes;
-        }
-        else if (m_param->decodedPictureHashSEI == 3)
-        {
-            m_seiReconPictureDigest.m_method = SEIDecodedPictureHash::CHECKSUM;
-            for (int i = 0; i < planes; i++)
-                checksumFinish(m_checksum[i], m_seiReconPictureDigest.m_digest[i]);
-            payloadSize = 1 + 4 * planes;
-        }
-        m_bs.resetBits();
-        m_seiReconPictureDigest.setSize(payloadSize);
-        m_seiReconPictureDigest.write(m_bs, *slice->m_sps);
-        m_seiReconPictureDigest.alignAndSerialize(m_bs, true, m_param->bSingleSeiNal, NAL_UNIT_SUFFIX_SEI, m_nalList);
-    }
+    if (m_param->decodedPictureHashSEI)    
+		writeTrailingSEIMessages();
 
     uint64_t bytes = 0;
     for (uint32_t i = 0; i < m_nalList.m_numNal; i++)
@@ -1216,6 +1103,78 @@
     m_endFrameTime = x265_mdate();  
 }
 
+void FrameEncoder::initDecodedPictureHashSEI(int row, int cuAddr, int height)
+{
+	PicYuv *reconPic = m_frame->m_reconPic;
+	uint32_t width = reconPic->m_picWidth;	
+	intptr_t stride = reconPic->m_stride;
+	uint32_t maxCUHeight = m_param->maxCUSize;
+
+	const uint32_t hChromaShift = CHROMA_H_SHIFT(m_param->internalCsp);
+	const uint32_t vChromaShift = CHROMA_V_SHIFT(m_param->internalCsp);
+
+	if (m_param->decodedPictureHashSEI == 1)
+	{
+		if (!row)
+			MD5Init(&m_seiReconPictureDigest.m_state[0]);
+
+		updateMD5Plane(m_seiReconPictureDigest.m_state[0], reconPic->getLumaAddr(cuAddr), width, height, stride);
+		if (m_param->internalCsp != X265_CSP_I400)
+		{
+			if (!row)
+			{
+				MD5Init(&m_seiReconPictureDigest.m_state[1]);
+				MD5Init(&m_seiReconPictureDigest.m_state[2]);
+			}
+
+			width >>= hChromaShift;
+			height >>= vChromaShift;
+			stride = reconPic->m_strideC;
+
+			updateMD5Plane(m_seiReconPictureDigest.m_state[1], reconPic->getCbAddr(cuAddr), width, height, stride);
+			updateMD5Plane(m_seiReconPictureDigest.m_state[2], reconPic->getCrAddr(cuAddr), width, height, stride);
+		}
+	}
+	else if (m_param->decodedPictureHashSEI == 2)
+	{
+
+		if (!row)
+			m_seiReconPictureDigest.m_crc[0] = 0xffff;
+
+		updateCRC(reconPic->getLumaAddr(cuAddr), m_seiReconPictureDigest.m_crc[0], height, width, stride);
+		if (m_param->internalCsp != X265_CSP_I400)
+		{
+			width >>= hChromaShift;
+			height >>= vChromaShift;
+			stride = reconPic->m_strideC;
+			m_seiReconPictureDigest.m_crc[1] = m_seiReconPictureDigest.m_crc[2] = 0xffff;
+
+			updateCRC(reconPic->getCbAddr(cuAddr), m_seiReconPictureDigest.m_crc[1], height, width, stride);
+			updateCRC(reconPic->getCrAddr(cuAddr), m_seiReconPictureDigest.m_crc[2], height, width, stride);
+		}
+	}
+	else if (m_param->decodedPictureHashSEI == 3)
+	{
+		if (!row)
+			m_seiReconPictureDigest.m_checksum[0] = 0;
+
+		updateChecksum(reconPic->m_picOrg[0], m_seiReconPictureDigest.m_checksum[0], height, width, stride, row, maxCUHeight);
+		if (m_param->internalCsp != X265_CSP_I400)
+		{
+			width >>= hChromaShift;
+			height >>= vChromaShift;
+			stride = reconPic->m_strideC;
+			maxCUHeight >>= vChromaShift;
+
+			if (!row)
+				m_seiReconPictureDigest.m_checksum[1] = m_seiReconPictureDigest.m_checksum[2] = 0;
+
+			updateChecksum(reconPic->m_picOrg[1], m_seiReconPictureDigest.m_checksum[1], height, width, stride, row, maxCUHeight);
+			updateChecksum(reconPic->m_picOrg[2], m_seiReconPictureDigest.m_checksum[2], height, width, stride, row, maxCUHeight);
+		}
+	}
+}
+
 void FrameEncoder::encodeSlice(uint32_t sliceAddr)
 {
     Slice* slice = m_frame->m_encData->m_slice;
diff -r c258d214c978 -r 44f146176423 source/encoder/frameencoder.h
--- a/source/encoder/frameencoder.h	Mon Jul 23 15:36:44 2018 +0530
+++ b/source/encoder/frameencoder.h	Fri Jul 20 20:54:23 2018 +0530
@@ -129,6 +129,8 @@
     /* blocks until worker thread is done, returns access unit */
     Frame *getEncodedPicture(NALList& list);
 
+	void initDecodedPictureHashSEI(int row, int cuAddr, int height);
+
     Event                    m_enable;
     Event                    m_done;
     Event                    m_completionEvent;
@@ -161,9 +163,6 @@
     double                   m_ssim;
     uint64_t                 m_accessUnitBits;
     uint32_t                 m_ssimCnt;
-    MD5Context               m_state[3];
-    uint32_t                 m_crc[3];
-    uint32_t                 m_checksum[3];
 
     volatile int             m_activeWorkerCount;        // count of workers currently encoding or filtering CTUs
     volatile int             m_totalActiveWorkerCount;   // sum of m_activeWorkerCount sampled at end of each CTU
@@ -215,7 +214,7 @@
     protected:
 
         WeightAnalysis operator=(const WeightAnalysis&);
-    };
+    };	
 
 protected:
 
@@ -230,7 +229,9 @@
     void threadMain();
     int  collectCTUStatistics(const CUData& ctu, FrameStats* frameLog);
     void noiseReductionUpdate();
-    void computeAvgTrainingData();
+	void writeTrailingSEIMessages();
+	void writeLeadingSEIMessages();
+	bool writeToneMapInfo(x265_sei_payload *payload);
 
     /* Called by WaveFront::findJob() */
     virtual void processRow(int row, int threadId);
@@ -243,8 +244,9 @@
 #if ENABLE_LIBVMAF
     void vmafFrameLevelScore();
 #endif
-    void collectDynDataRow(CUData& ctu, FrameStats* rowStats);
-    void collectDynDataFrame();
+	void collectDynDataFrame();
+	void computeAvgTrainingData();
+    void collectDynDataRow(CUData& ctu, FrameStats* rowStats);    
 };
 }
 
diff -r c258d214c978 -r 44f146176423 source/encoder/framefilter.cpp
--- a/source/encoder/framefilter.cpp	Mon Jul 23 15:36:44 2018 +0530
+++ b/source/encoder/framefilter.cpp	Fri Jul 20 20:54:23 2018 +0530
@@ -712,78 +712,8 @@
 
     if (m_param->maxSlices == 1)
     {
-        if (m_param->decodedPictureHashSEI == 1)
-        {
-            uint32_t height = m_parallelFilter[row].getCUHeight();
-            uint32_t width = reconPic->m_picWidth;
-            intptr_t stride = reconPic->m_stride;
-
-            if (!row)
-                MD5Init(&m_frameEncoder->m_state[0]);
-
-            updateMD5Plane(m_frameEncoder->m_state[0], reconPic->getLumaAddr(cuAddr), width, height, stride);
-            if (m_param->internalCsp != X265_CSP_I400)
-            {
-                if (!row)
-                {
-                    MD5Init(&m_frameEncoder->m_state[1]);
-                    MD5Init(&m_frameEncoder->m_state[2]);
-                }
-
-                width >>= m_hChromaShift;
-                height >>= m_vChromaShift;
-                stride = reconPic->m_strideC;
-
-                updateMD5Plane(m_frameEncoder->m_state[1], reconPic->getCbAddr(cuAddr), width, height, stride);
-                updateMD5Plane(m_frameEncoder->m_state[2], reconPic->getCrAddr(cuAddr), width, height, stride);
-            }
-        }
-        else if (m_param->decodedPictureHashSEI == 2)
-        {
-            uint32_t height = m_parallelFilter[row].getCUHeight();
-            uint32_t width = reconPic->m_picWidth;
-            intptr_t stride = reconPic->m_stride;
-
-            if (!row)
-                m_frameEncoder->m_crc[0] = 0xffff;
-
-            updateCRC(reconPic->getLumaAddr(cuAddr), m_frameEncoder->m_crc[0], height, width, stride);
-            if (m_param->internalCsp != X265_CSP_I400)
-            {
-                width >>= m_hChromaShift;
-                height >>= m_vChromaShift;
-                stride = reconPic->m_strideC;
-                m_frameEncoder->m_crc[1] = m_frameEncoder->m_crc[2] = 0xffff;
-
-                updateCRC(reconPic->getCbAddr(cuAddr), m_frameEncoder->m_crc[1], height, width, stride);
-                updateCRC(reconPic->getCrAddr(cuAddr), m_frameEncoder->m_crc[2], height, width, stride);
-            }
-        }
-        else if (m_param->decodedPictureHashSEI == 3)
-        {
-            uint32_t width = reconPic->m_picWidth;
-            uint32_t height = m_parallelFilter[row].getCUHeight();
-            intptr_t stride = reconPic->m_stride;
-            uint32_t cuHeight = m_param->maxCUSize;
-
-            if (!row)
-                m_frameEncoder->m_checksum[0] = 0;
-
-            updateChecksum(reconPic->m_picOrg[0], m_frameEncoder->m_checksum[0], height, width, stride, row, cuHeight);
-            if (m_param->internalCsp != X265_CSP_I400)
-            {
-                width >>= m_hChromaShift;
-                height >>= m_vChromaShift;
-                stride = reconPic->m_strideC;
-                cuHeight >>= m_vChromaShift;
-
-                if (!row)
-                    m_frameEncoder->m_checksum[1] = m_frameEncoder->m_checksum[2] = 0;
-
-                updateChecksum(reconPic->m_picOrg[1], m_frameEncoder->m_checksum[1], height, width, stride, row, cuHeight);
-                updateChecksum(reconPic->m_picOrg[2], m_frameEncoder->m_checksum[2], height, width, stride, row, cuHeight);
-            }
-        }
+		uint32_t height = m_parallelFilter[row].getCUHeight();
+		m_frameEncoder->initDecodedPictureHashSEI(row, cuAddr, height);
     } // end of (m_param->maxSlices == 1)
 
     if (ATOMIC_INC(&m_frameEncoder->m_completionCount) == 2 * (int)m_frameEncoder->m_numRows)
diff -r c258d214c978 -r 44f146176423 source/encoder/sei.cpp
--- a/source/encoder/sei.cpp	Mon Jul 23 15:36:44 2018 +0530
+++ b/source/encoder/sei.cpp	Fri Jul 20 20:54:23 2018 +0530
@@ -33,44 +33,39 @@
     0x2C, 0xA2, 0xDE, 0x09, 0xB5, 0x17, 0x47, 0xDB,
     0xBB, 0x55, 0xA4, 0xFE, 0x7F, 0xC2, 0xFC, 0x4E
 };
-/* count the size of the payload and return the size in bits */
-int SEI::countPayloadSize(const SPS& sps)
-{
-    BitCounter counter;
-    m_bitIf = &counter;
-    writeSEI(sps);
-    X265_CHECK(0 == (counter.getNumberOfWrittenBits() & 7), "payload unaligned\n");
-    int count = counter.getNumberOfWrittenBits() >> 3;
-    return count;
-}
 
-void SEI::alignAndSerialize(Bitstream& bs, int lastSei, int isSingleSei, NalUnitType nalUnitType, NALList& list)
+void SEI::writeSEImessages(Bitstream& bs, const SPS& sps, NalUnitType nalUnitType, NALList& list, int isNested)
 {
-    if (lastSei || !isSingleSei)
-    {
-        bs.writeByteAlignment();
-        list.serialize(nalUnitType, bs);
-    }
-}
+	if (!isNested)
+	    bs.resetBits();
 
-/* marshal a single SEI message sei, storing the marshalled representation
- * in bitstream bs */
-void SEI::write(Bitstream& bs, const SPS& sps)
-{
-    uint32_t type = m_payloadType;
-    m_bitIf = &bs;
-    uint32_t payloadSize = m_payloadSize;
-    if (m_payloadType == USER_DATA_UNREGISTERED)
-        payloadSize = m_payloadSize + 16;
-    uint32_t payloadType = m_payloadType;
-    for (; payloadType >= 0xff; payloadType -= 0xff)
-        WRITE_CODE(0xff, 8, "payload_type");
-    WRITE_CODE(type, 8, "payload_type");
-    for (; payloadSize >= 0xff; payloadSize -= 0xff)
-        WRITE_CODE(0xff, 8, "payload_size");
-    WRITE_CODE(payloadSize, 8, "payload_size");
-    /* virtual writeSEI method, write to bs */
-    writeSEI(sps);
+	BitCounter counter;
+	m_bitIf = &counter;
+	writeSEI(sps);
+	X265_CHECK(0 == (counter.getNumberOfWrittenBits() & 7), "payload unaligned\n");
+	uint32_t payloadData = counter.getNumberOfWrittenBits() >> 3;
+
+	// set bitstream
+	m_bitIf = &bs;	
+
+	uint32_t payloadType = m_payloadType;
+	for (; payloadType >= 0xff; payloadType -= 0xff)
+		WRITE_CODE(0xff, 8, "payload_type");
+	WRITE_CODE(payloadType, 8, "payload_type");
+
+	uint32_t payloadSize = payloadData;
+	for (; payloadSize >= 0xff; payloadSize -= 0xff)
+		WRITE_CODE(0xff, 8, "payload_size");
+	WRITE_CODE(payloadSize, 8, "payload_size");
+
+	// virtual writeSEI method, write to bs 
+	writeSEI(sps);
+
+	if (!isNested)
+	{
+		bs.writeByteAlignment();
+		list.serialize(nalUnitType, bs);
+	}
 }
 
 void SEI::writeByteAlign()
@@ -91,6 +86,88 @@
     m_payloadSize = size;
 }
 
+void SEIEncoder::encodeSEIContentLightLevel(SEIContentLightLevel& cllsei, Bitstream& bs, const SPS& sps, NalUnitType nalUnitType, NALList& list)
+{
+	cllsei.writeSEImessages(bs, sps, nalUnitType, list, isNestedSEI);
+}
+
+void SEIEncoder::encodeSEIMasteringDisplayColorVolume(SEIMasteringDisplayColorVolume& mdsei, Bitstream& bs, const SPS& sps, NalUnitType nalUnitType, NALList& list)
+{	
+	if (mdsei.parse(m_param->masteringDisplayColorVolume))	
+		mdsei.writeSEImessages(bs, sps, nalUnitType, list, isNestedSEI);
+	else
+		x265_log(m_param, X265_LOG_WARNING, "unable to parse mastering display color volume info\n");
+}
+
+void SEIEncoder::encodeSEIActiveParameterSets(SEIActiveParameterSets& sei,Bitstream& bs, const SPS& sps, NalUnitType nalUnitType, NALList& list)
+{
+	sei.m_selfContainedCvsFlag = true;
+	sei.m_noParamSetUpdateFlag = true;
+
+	sei.writeSEImessages(bs, sps, nalUnitType, list, isNestedSEI);
+}
+
+void SEIEncoder::encodeSEIBufferingPeriod(SEIBufferingPeriod* bpSei, Bitstream& bs, const SPS& sps, NalUnitType nalUnitType, NALList& list)
+{
+	// since the temporal layer HRD is not ready, we assumed it is fixed
+	bpSei->m_auCpbRemovalDelayDelta = 1;
+	bpSei->m_cpbDelayOffset = 0;
+	bpSei->m_dpbDelayOffset = 0;	
+
+	bpSei->writeSEImessages(bs, sps, nalUnitType, list, isNestedSEI);
+}
+
+void SEIEncoder::encodeSEIRecoveryPoint(SEIRecoveryPoint& sei, Bitstream& bs, const SPS& sps, NalUnitType nalUnitType, NALList& list)
+{	
+	sei.m_recoveryPocCnt = 0;
+	sei.m_exactMatchingFlag = true;
+	sei.m_brokenLinkFlag = false;
+
+	sei.writeSEImessages(bs, sps, nalUnitType, list, isNestedSEI);
+}
+
+void SEIEncoder::encodeSEIPictureTiming(SEIPictureTiming *sei, Bitstream& bs, Slice* slice, NalUnitType nalUnitType, NALList& list)
+{	
+	const VUI vui = slice->m_sps->vuiParameters;
+	int poc = slice->m_poc;
+
+	if (vui.frameFieldInfoPresentFlag)
+	{
+		if (m_param->interlaceMode == 2)
+			sei->m_picStruct = (poc & 1) ? 1 /* top */ : 2 /* bottom */;
+		else if (m_param->interlaceMode == 1)
+			sei->m_picStruct = (poc & 1) ? 2 /* bottom */ : 1 /* top */;
+		else
+			sei->m_picStruct = m_param->pictureStructure;
+
+		sei->m_sourceScanType = m_param->interlaceMode ? 0 : 1;
+
+		sei->m_duplicateFlag = false;
+	}
+
+	sei->writeSEImessages(bs, *slice->m_sps, nalUnitType, list, isNestedSEI);
+}
+
+void SEIEncoder::encodeSEIAlternativeTransferCharacteristics(SEIAlternativeTC& sei, Bitstream& bs, const SPS& sps, NalUnitType nalUnitType, NALList& list)
+{
+	sei.writeSEImessages(bs, sps, nalUnitType, list, isNestedSEI);
+}
+
+void SEIEncoder::encodeSEIuserDataUnregistered(SEIuserDataUnregistered& sei, Bitstream& bs, const SPS& sps, NalUnitType nalUnitType, NALList& list)
+{
+	sei.writeSEImessages(bs, sps, nalUnitType, list, isNestedSEI);
+}
+
+void SEIEncoder::encodeSEIuserDataRegistered(SEIuserDataRegistered& sei, Bitstream& bs, const SPS& sps, NalUnitType nalUnitType, NALList& list)
+{
+	sei.writeSEImessages(bs, sps, nalUnitType, list, isNestedSEI);
+}
+
+void SEIEncoder::encodeSEIDecodedPictureHash(SEIDecodedPictureHash& sei, Bitstream& bs, Slice* slice, NalUnitType nalUnitType, NALList& list)
+{	
+	sei.writeSEImessages(bs, *slice->m_sps, nalUnitType, list, isNestedSEI && nalUnitType != NAL_UNIT_SUFFIX_SEI);
+}
+
 /* charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" */
 
 char* SEI::base64Decode(char encodedString[], int base64EncodeLength)
@@ -114,8 +191,8 @@
                 bitstream = bitstream << 6;
                 countBits += 6;
             }
+
             // Finding the position of each encoded character in charSet and storing in bitstream, use OR '|' operator to store bits
-
             if (encodedString[i + j] >= 'A' && encodedString[i + j] <= 'Z')
                 bitstream = bitstream | (encodedString[i + j] - 'A');
 
diff -r c258d214c978 -r 44f146176423 source/encoder/sei.h
--- a/source/encoder/sei.h	Mon Jul 23 15:36:44 2018 +0530
+++ b/source/encoder/sei.h	Fri Jul 20 20:54:23 2018 +0530
@@ -28,6 +28,7 @@
 #include "bitstream.h"
 #include "slice.h"
 #include "nal.h"
+#include "md5.h"
 
 namespace X265_NS {
 // private namespace
@@ -35,11 +36,9 @@
 class SEI : public SyntaxElementWriter
 {
 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);
+    /* SEI users call writeSEImessages() to marshal an SEI to a bitstream.
+     * The writeSEImessages() method calls writeSEI() which encodes the header */
+	void writeSEImessages(Bitstream& bs, const SPS& sps, NalUnitType nalUnitType, NALList& list, int isNested);    
     void setSize(uint32_t size);
     static char* base64Decode(char encodedString[], int base64EncodeLength);
     virtual ~SEI() {}
@@ -50,6 +49,32 @@
     void writeByteAlign();
 };
 
+//seongnam.oh at samsung.com :: for the Creative Intent Meta Data Encoding
+class SEIuserDataRegistered : public SEI
+{
+public:
+	SEIuserDataRegistered()
+	{
+		m_payloadType = USER_DATA_REGISTERED_ITU_T_T35;
+		m_payloadSize = 0;
+	}
+
+	uint8_t *m_userData;
+
+	// daniel.vt at samsung.com :: for the Creative Intent Meta Data Encoding ( seongnam.oh at samsung.com )
+	void writeSEI(const SPS&)
+	{
+		if (!m_userData)
+			return;
+
+		uint32_t i = 0;
+		for (; i < m_payloadSize; ++i)
+			WRITE_CODE(m_userData[i], 8, "creative_intent_metadata");
+	}
+};
+
+static const uint32_t ISO_IEC_11578_LEN = 16;
+
 class SEIuserDataUnregistered : public SEI
 {
 public:
@@ -58,11 +83,11 @@
         m_payloadType = USER_DATA_UNREGISTERED;
         m_payloadSize = 0;
     }
-    static const uint8_t m_uuid_iso_iec_11578[16];
+    static const uint8_t m_uuid_iso_iec_11578[ISO_IEC_11578_LEN];
     uint8_t *m_userData;
     void writeSEI(const SPS&)
     {
-        for (uint32_t i = 0; i < 16; i++)
+        for (uint32_t i = 0; i < ISO_IEC_11578_LEN; i++)
             WRITE_CODE(m_uuid_iso_iec_11578[i], 8, "sei.uuid_iso_iec_11578[i]");
         for (uint32_t i = 0; i < m_payloadSize; i++)
             WRITE_CODE(m_userData[i], 8, "user_data");
@@ -136,7 +161,12 @@
         CRC,
         CHECKSUM,
     } m_method;
-    uint8_t m_digest[3][16];
+
+	MD5Context m_state[3];
+	uint32_t   m_crc[3];
+	uint32_t   m_checksum[3];
+    uint8_t    m_digest[3][16];
+
     void writeSEI(const SPS& sps)
     {
         int planes = (sps.chromaFormatIdc != X265_CSP_I400) ? 3 : 1;
@@ -208,8 +238,8 @@
         WRITE_UVLC(0, "bp_seq_parameter_set_id");
         WRITE_FLAG(0, "rap_cpb_params_present_flag");
         WRITE_FLAG(0, "concatenation_flag");
-        WRITE_CODE(m_auCpbRemovalDelayDelta - 1,   hrd.cpbRemovalDelayLength,       "au_cpb_removal_delay_delta_minus1");
-        WRITE_CODE(m_initialCpbRemovalDelay,       hrd.initialCpbRemovalDelayLength,        "initial_cpb_removal_delay");
+        WRITE_CODE(m_auCpbRemovalDelayDelta - 1,   hrd.cpbRemovalDelayLength,        "au_cpb_removal_delay_delta_minus1");
+        WRITE_CODE(m_initialCpbRemovalDelay,       hrd.initialCpbRemovalDelayLength, "initial_cpb_removal_delay");
         WRITE_CODE(m_initialCpbRemovalDelayOffset, hrd.initialCpbRemovalDelayLength, "initial_cpb_removal_delay_offset");
 
         writeByteAlign();
@@ -274,30 +304,6 @@
     }
 };
 
-//seongnam.oh at samsung.com :: for the Creative Intent Meta Data Encoding
-class SEICreativeIntentMeta : public SEI
-{
-public:
-    SEICreativeIntentMeta()
-    {
-        m_payloadType = USER_DATA_REGISTERED_ITU_T_T35;
-        m_payloadSize = 0;
-    }
-
-    uint8_t *m_payload;
-
-    // daniel.vt at samsung.com :: for the Creative Intent Meta Data Encoding ( seongnam.oh at samsung.com )
-    void writeSEI(const SPS&)
-    {
-        if (!m_payload)
-            return;
-
-        uint32_t i = 0;
-        for (; i < m_payloadSize; ++i)
-            WRITE_CODE(m_payload[i], 8, "creative_intent_metadata");
-    }
-};
-
 class SEIAlternativeTC : public SEI
 {
 public:
@@ -315,5 +321,30 @@
 	}
 };
 
+class Encoder;
+
+class SEIEncoder
+{
+public:
+	x265_param*    m_param;
+	int isNestedSEI;
+public:
+	void init(x265_param *p)
+	{ 
+		m_param = p;
+		isNestedSEI = p->bSingleSeiNal;		
+	}
+	void encodeSEIContentLightLevel(SEIContentLightLevel& sei, Bitstream& bs, const SPS& sps, NalUnitType nalUnitType, NALList& list);
+	void encodeSEIMasteringDisplayColorVolume(SEIMasteringDisplayColorVolume& mdsei, Bitstream& bs, const SPS& sps, NalUnitType nalUnitType, NALList& list);	
+	void encodeSEIActiveParameterSets(SEIActiveParameterSets& sei, Bitstream& bs, const SPS& sps, NalUnitType nalUnitType, NALList& list);
+	void encodeSEIBufferingPeriod(SEIBufferingPeriod* bpSei, Bitstream& bs, const SPS& sps, NalUnitType nalUnitType, NALList& list);
+	void encodeSEIRecoveryPoint(SEIRecoveryPoint& sei, Bitstream& bs, const SPS& sps, NalUnitType nalUnitType, NALList& list);
+	void encodeSEIPictureTiming(SEIPictureTiming *sei, Bitstream& bs, Slice* slice, NalUnitType nalUnitType, NALList& list);
+	void encodeSEIAlternativeTransferCharacteristics(SEIAlternativeTC& sei, Bitstream& bs, const SPS& sps, NalUnitType nalUnitType, NALList& list);
+	void encodeSEIuserDataUnregistered(SEIuserDataUnregistered& sei, Bitstream& bs, const SPS& sps, NalUnitType nalUnitType, NALList& list);
+	void encodeSEIuserDataRegistered(SEIuserDataRegistered& sei, Bitstream& bs, const SPS& sps, NalUnitType nalUnitType, NALList& list);
+	void encodeSEIDecodedPictureHash(SEIDecodedPictureHash& sei, Bitstream& bs, Slice* slice, NalUnitType nalUnitType, NALList& list);
+};
+
 }
 #endif // ifndef X265_SEI_H
diff -r c258d214c978 -r 44f146176423 source/x265.h
--- a/source/x265.h	Mon Jul 23 15:36:44 2018 +0530
+++ b/source/x265.h	Fri Jul 20 20:54:23 2018 +0530
@@ -334,6 +334,7 @@
     TONE_MAPPING_INFO                    = 23,
     FRAME_PACKING                        = 45,
     DISPLAY_ORIENTATION                  = 47,
+	GREEN_METADATA                       = 56,
     SOP_DESCRIPTION                      = 128,
     ACTIVE_PARAMETER_SETS                = 129,
     DECODING_UNIT_INFO                   = 130,
@@ -341,9 +342,20 @@
     DECODED_PICTURE_HASH                 = 132,
     SCALABLE_NESTING                     = 133,
     REGION_REFRESH_INFO                  = 134,
+	NO_DISPLAY                           = 135,
+	TIME_CODE                            = 136,
     MASTERING_DISPLAY_INFO               = 137,
+	SEGM_RECT_FRAME_PACKING              = 138,
+	EMP_MOTION_CONSTRAINED_TILE_SETS     = 139,
+	CHROMA_RESAMPLING_FILTER_HINT        = 140,
+	KNEE_FUNCTION_INFO                   = 141,
+	COLOUR_REMAPPING_INFO                = 142,
+	DEINTERLACE_FIELD_IDENTIFICATION     = 143, 
+	DEPENDENT_RAP_INDICATION             = 145, 
+	CODED_REGION_COMPLETION              = 146,
     CONTENT_LIGHT_LEVEL_INFO             = 144,
 	ALTERNATIVE_TRANSFER_CHARACTERISTICS = 147,
+	AMBIENT_VIEWING_ENVIRONMENT          = 148,
 } SEIPayloadType;
 
 typedef struct x265_sei_payload
-------------- next part --------------
A non-text attachment was scrubbed...
Name: x265.patch
Type: text/x-patch
Size: 54480 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20180723/b49116bc/attachment-0001.bin>


More information about the x265-devel mailing list