Index: branches/SHM-dev/source/App/TAppEncoder/TAppEncCfg.cpp
===================================================================
--- branches/SHM-dev/source/App/TAppEncoder/TAppEncCfg.cpp	(revision 1571)
+++ branches/SHM-dev/source/App/TAppEncoder/TAppEncCfg.cpp	(revision 1572)
@@ -1619,4 +1619,6 @@
   ("SEIPreferredTransferCharacterisics",              m_preferredTransferCharacteristics,                   -1, "Value for the preferred_transfer_characteristics field of the Alternative transfer characteristics SEI which will override the corresponding entry in the VUI. If negative, do not produce the respective SEI message")
 #endif
+  ("SEIGreenMetadataType",                            m_greenMetadataType,                   0u, "Value for the green_metadata_type specifies the type of metadata that is present in the SEI message. If green_metadata_type is 1, then metadata enabling quality recovery after low-power encoding is present")
+  ("SEIXSDMetricType",                                m_xsdMetricType,                      0u, "Value for the xsd_metric_type indicates the type of the objective quality metric. PSNR is the only type currently supported")
 
 #if LAYERS_NOT_PRESENT_SEI
Index: branches/SHM-dev/source/App/TAppEncoder/TAppEncCfg.h
===================================================================
--- branches/SHM-dev/source/App/TAppEncoder/TAppEncCfg.h	(revision 1571)
+++ branches/SHM-dev/source/App/TAppEncoder/TAppEncCfg.h	(revision 1572)
@@ -454,4 +454,6 @@
   Int       m_preferredTransferCharacteristics;
 #endif
+  UInt      m_greenMetadataType;
+  UInt      m_xsdMetricType;
 
   // weighted prediction
Index: branches/SHM-dev/source/App/TAppEncoder/TAppEncTop.cpp
===================================================================
--- branches/SHM-dev/source/App/TAppEncoder/TAppEncTop.cpp	(revision 1571)
+++ branches/SHM-dev/source/App/TAppEncoder/TAppEncTop.cpp	(revision 1572)
@@ -812,4 +812,7 @@
   m_cTEncTop.setSEIPreferredTransferCharacteristics               ( UChar(m_preferredTransferCharacteristics) );
 #endif
+  m_cTEncTop.setSEIGreenMetadataInfoSEIEnable                     ( m_greenMetadataType > 0 );
+  m_cTEncTop.setSEIGreenMetadataType                              ( UChar(m_greenMetadataType) );
+  m_cTEncTop.setSEIXSDMetricType                                  ( UChar(m_xsdMetricType) );
 
   m_cTEncTop.setTileUniformSpacingFlag                            ( m_tileUniformSpacingFlag );
Index: branches/SHM-dev/source/Lib/TLibCommon/SEI.cpp
===================================================================
--- branches/SHM-dev/source/Lib/TLibCommon/SEI.cpp	(revision 1571)
+++ branches/SHM-dev/source/Lib/TLibCommon/SEI.cpp	(revision 1572)
@@ -136,4 +136,5 @@
     case SEI::FRAME_PACKING:                        return "Frame packing arrangement";
     case SEI::DISPLAY_ORIENTATION:                  return "Display orientation";
+    case SEI::GREEN_METADATA:                       return "Green metadata information";
     case SEI::SOP_DESCRIPTION:                      return "Structure of pictures information";
     case SEI::ACTIVE_PARAMETER_SETS:                return "Active parameter sets";
Index: branches/SHM-dev/source/Lib/TLibCommon/SEI.h
===================================================================
--- branches/SHM-dev/source/Lib/TLibCommon/SEI.h	(revision 1571)
+++ branches/SHM-dev/source/Lib/TLibCommon/SEI.h	(revision 1572)
@@ -77,4 +77,5 @@
     FRAME_PACKING                        = 45,
     DISPLAY_ORIENTATION                  = 47,
+    GREEN_METADATA                       = 56,
     SOP_DESCRIPTION                      = 128,
     ACTIVE_PARAMETER_SETS                = 129,
@@ -650,4 +651,17 @@
 #endif
 
+class SEIGreenMetadataInfo : public SEI
+{
+public:
+    PayloadType payloadType() const { return GREEN_METADATA; }
+    SEIGreenMetadataInfo() {}
+    
+    virtual ~SEIGreenMetadataInfo() {}
+    
+    UInt m_greenMetadataType;
+    UInt m_xsdMetricType;
+    UInt m_xsdMetricValue;
+};
+
 #if P0123_ALPHA_CHANNEL_SEI
 class SEIAlphaChannelInfo : public SEI
Index: branches/SHM-dev/source/Lib/TLibDecoder/SEIread.cpp
===================================================================
--- branches/SHM-dev/source/Lib/TLibDecoder/SEIread.cpp	(revision 1571)
+++ branches/SHM-dev/source/Lib/TLibDecoder/SEIread.cpp	(revision 1572)
@@ -414,4 +414,8 @@
         xParseSEIDecodedPictureHash((SEIDecodedPictureHash&) *sei, payloadSize, pDecodedMessageOutputStream);
         break;
+      case SEI::GREEN_METADATA:
+        sei = new SEIGreenMetadataInfo;
+        xParseSEIGreenMetadataInfo((SEIGreenMetadataInfo&) *sei, payloadSize, pDecodedMessageOutputStream);
+        break;
       default:
         for (UInt i = 0; i < payloadSize; i++)
@@ -1460,4 +1464,19 @@
 }
 #endif
+
+Void SEIReader::xParseSEIGreenMetadataInfo(SEIGreenMetadataInfo& sei, UInt payloadSize, ostream* pDecodedMessageOutputStream)
+{
+  UInt code;
+  output_sei_message_header(sei, pDecodedMessageOutputStream, payloadSize);
+  
+  sei_read_code(pDecodedMessageOutputStream, 8, code, "green_metadata_type");
+  sei.m_greenMetadataType = code;
+  
+  sei_read_code(pDecodedMessageOutputStream, 8, code, "xsd_metric_type");
+  sei.m_xsdMetricType = code;
+  
+  sei_read_code(pDecodedMessageOutputStream, 16, code, "xsd_metric_value");
+  sei.m_xsdMetricValue = code;
+}
 
 #if SVC_EXTENSION
Index: branches/SHM-dev/source/Lib/TLibDecoder/SEIread.h
===================================================================
--- branches/SHM-dev/source/Lib/TLibDecoder/SEIread.h	(revision 1571)
+++ branches/SHM-dev/source/Lib/TLibDecoder/SEIread.h	(revision 1572)
@@ -112,4 +112,5 @@
   Void xParseSEIAlternativeTransferCharacteristics(SEIAlternativeTransferCharacteristics& sei,              UInt payLoadSize,                     std::ostream *pDecodedMessageOutputStream);
 #endif
+  Void xParseSEIGreenMetadataInfo             (SEIGreenMetadataInfo& sei,             UInt payLoadSize,                     std::ostream *pDecodedMessageOutputStream);
 
   Void sei_read_code(std::ostream *pOS, UInt uiLength, UInt& ruiCode, const TChar *pSymbolName);
Index: branches/SHM-dev/source/Lib/TLibEncoder/SEIEncoder.cpp
===================================================================
--- branches/SHM-dev/source/Lib/TLibEncoder/SEIEncoder.cpp	(revision 1571)
+++ branches/SHM-dev/source/Lib/TLibEncoder/SEIEncoder.cpp	(revision 1572)
@@ -680,4 +680,14 @@
 #endif
 
+Void SEIEncoder::initSEIGreenMetadataInfo(SEIGreenMetadataInfo *seiGreenMetadataInfo, UInt u)
+{
+    assert (m_isInitialized);
+    assert (seiGreenMetadataInfo!=NULL);
+
+    seiGreenMetadataInfo->m_greenMetadataType = m_pcCfg->getSEIGreenMetadataType();
+    seiGreenMetadataInfo->m_xsdMetricType = m_pcCfg->getSEIXSDMetricType();
+    seiGreenMetadataInfo->m_xsdMetricValue = u;
+}
+
 #if LAYERS_NOT_PRESENT_SEI
 Void SEIEncoder::initSEILayersNotPresent(SEILayersNotPresent *seiLayersNotPresent)
Index: branches/SHM-dev/source/Lib/TLibEncoder/SEIEncoder.h
===================================================================
--- branches/SHM-dev/source/Lib/TLibEncoder/SEIEncoder.h	(revision 1571)
+++ branches/SHM-dev/source/Lib/TLibEncoder/SEIEncoder.h	(revision 1572)
@@ -105,4 +105,5 @@
   Void initDecodedPictureHashSEI(SEIDecodedPictureHash *sei, TComPic *pcPic, std::string &rHashString, const BitDepths &bitDepths);
   Void initTemporalLevel0IndexSEI(SEITemporalLevel0Index *sei, TComSlice *slice);
+  Void initSEIGreenMetadataInfo(SEIGreenMetadataInfo *sei, UInt u);
 
 private:
Index: branches/SHM-dev/source/Lib/TLibEncoder/SEIwrite.cpp
===================================================================
--- branches/SHM-dev/source/Lib/TLibEncoder/SEIwrite.cpp	(revision 1571)
+++ branches/SHM-dev/source/Lib/TLibEncoder/SEIwrite.cpp	(revision 1572)
@@ -163,4 +163,7 @@
     break;
 #endif
+  case SEI::GREEN_METADATA:
+      xWriteSEIGreenMetadataInfo(*static_cast<const SEIGreenMetadataInfo*>(&sei));
+    break;
 
 #if SVC_EXTENSION
@@ -1086,4 +1089,12 @@
 #endif
 
+Void SEIWriter::xWriteSEIGreenMetadataInfo(const SEIGreenMetadataInfo& sei)
+{
+  WRITE_CODE(sei.m_greenMetadataType, 8, "green_metadata_type");
+  
+  WRITE_CODE(sei.m_xsdMetricType, 8, "xsd_metric_type");
+  WRITE_CODE(sei.m_xsdMetricValue, 16, "xsd_metric_value");
+}
+
 #if SVC_EXTENSION
 #if LAYERS_NOT_PRESENT_SEI
Index: branches/SHM-dev/source/Lib/TLibEncoder/SEIwrite.h
===================================================================
--- branches/SHM-dev/source/Lib/TLibEncoder/SEIwrite.h	(revision 1571)
+++ branches/SHM-dev/source/Lib/TLibEncoder/SEIwrite.h	(revision 1572)
@@ -94,4 +94,5 @@
   Void xWriteSEIAlternativeTransferCharacteristics(const SEIAlternativeTransferCharacteristics& sei);
 #endif
+  Void xWriteSEIGreenMetadataInfo(const SEIGreenMetadataInfo &sei);
 
 #if O0164_MULTI_LAYER_HRD
Index: branches/SHM-dev/source/Lib/TLibEncoder/TEncCfg.h
===================================================================
--- branches/SHM-dev/source/Lib/TLibEncoder/TEncCfg.h	(revision 1571)
+++ branches/SHM-dev/source/Lib/TLibEncoder/TEncCfg.h	(revision 1572)
@@ -348,4 +348,7 @@
   UChar     m_preferredTransferCharacteristics;
 #endif
+  Bool      m_greenMetadataInfoSEIEnabled;
+  UChar     m_greenMetadataType;
+  UChar     m_xsdMetricType;
   //====== Weighted Prediction ========
   Bool      m_useWeightedPred;       //< Use of Weighting Prediction (P_SLICE)
@@ -958,4 +961,11 @@
   UChar getSEIPreferredTransferCharacteristics() const               { return m_preferredTransferCharacteristics; }
 #endif
+  Void  setSEIGreenMetadataInfoSEIEnable( Bool b)                    { m_greenMetadataInfoSEIEnabled = b;    }
+  Bool  getSEIGreenMetadataInfoSEIEnable( ) const                    { return m_greenMetadataInfoSEIEnabled; }
+  Void  setSEIGreenMetadataType(UChar v)                             { m_greenMetadataType = v;    }
+  UChar getSEIGreenMetadataType() const                              { return m_greenMetadataType; }
+  Void  setSEIXSDMetricType(UChar v)                                 { m_xsdMetricType = v;    }
+  UChar getSEIXSDMetricType() const                                  { return m_xsdMetricType; }
+
   const TComSEIMasteringDisplay &getMasteringDisplaySEI() const      { return m_masteringDisplay; }
   Void         setUseWP               ( Bool b )                     { m_useWeightedPred   = b;    }
Index: branches/SHM-dev/source/Lib/TLibEncoder/TEncGOP.cpp
===================================================================
--- branches/SHM-dev/source/Lib/TLibEncoder/TEncGOP.cpp	(revision 1571)
+++ branches/SHM-dev/source/Lib/TLibEncoder/TEncGOP.cpp	(revision 1572)
@@ -2746,4 +2746,17 @@
     }
 
+    m_pcCfg->setEncodedFlag(iGOPid, true);
+
+    Double PSNR_Y;
+    xCalculateAddPSNRs( isField, isTff, iGOPid, pcPic, accessUnit, rcListPic, dEncTime, snr_conversion, printFrameMSE, &PSNR_Y );
+    
+    // Only produce the Green Metadata SEI message with the last picture.
+    if( m_pcCfg->getSEIGreenMetadataInfoSEIEnable() && pcSlice->getPOC() == ( m_pcCfg->getFramesToBeEncoded() - 1 )  )
+    {
+      SEIGreenMetadataInfo *seiGreenMetadataInfo = new SEIGreenMetadataInfo;
+      m_seiEncoder.initSEIGreenMetadataInfo(seiGreenMetadataInfo, (UInt)(PSNR_Y * 100 + 0.5));
+      trailingSeiMessages.push_back(seiGreenMetadataInfo);
+    }
+    
 #if O0164_MULTI_LAYER_HRD
     xWriteTrailingSEIMessages(trailingSeiMessages, accessUnit, pcSlice->getTLayer(), pcSlice->getVPS(), pcSlice->getSPS());
@@ -2751,9 +2764,5 @@
     xWriteTrailingSEIMessages(trailingSeiMessages, accessUnit, pcSlice->getTLayer(), pcSlice->getSPS());
 #endif
-
-    m_pcCfg->setEncodedFlag(iGOPid, true);
-
-    xCalculateAddPSNRs( isField, isTff, iGOPid, pcPic, accessUnit, rcListPic, dEncTime, snr_conversion, printFrameMSE );
-
+        
     printHash(m_pcCfg->getDecodedPictureHashSEIType(), digestStr);
 
@@ -3021,7 +3030,7 @@
 }
 
-Void TEncGOP::xCalculateAddPSNRs( const Bool isField, const Bool isFieldTopFieldFirst, const Int iGOPid, TComPic* pcPic, const AccessUnit&accessUnit, TComList<TComPic*> &rcListPic, const Double dEncTime, const InputColourSpaceConversion snr_conversion, const Bool printFrameMSE )
-{
-  xCalculateAddPSNR( pcPic, pcPic->getPicYuvRec(), accessUnit, dEncTime, snr_conversion, printFrameMSE );
+Void TEncGOP::xCalculateAddPSNRs( const Bool isField, const Bool isFieldTopFieldFirst, const Int iGOPid, TComPic* pcPic, const AccessUnit&accessUnit, TComList<TComPic*> &rcListPic, const Double dEncTime, const InputColourSpaceConversion snr_conversion, const Bool printFrameMSE, Double* PSNR_Y )
+{
+  xCalculateAddPSNR( pcPic, pcPic->getPicYuvRec(), accessUnit, dEncTime, snr_conversion, printFrameMSE, PSNR_Y );
 
   //In case of field coding, compute the interlaced PSNR for both fields
@@ -3078,15 +3087,15 @@
       if( (pcPic->isTopField() && isFieldTopFieldFirst) || (!pcPic->isTopField() && !isFieldTopFieldFirst))
       {
-        xCalculateInterlacedAddPSNR(pcPic, correspondingFieldPic, pcPic->getPicYuvRec(), correspondingFieldPic->getPicYuvRec(), snr_conversion, printFrameMSE );
+        xCalculateInterlacedAddPSNR(pcPic, correspondingFieldPic, pcPic->getPicYuvRec(), correspondingFieldPic->getPicYuvRec(), snr_conversion, printFrameMSE, PSNR_Y );
       }
       else
       {
-        xCalculateInterlacedAddPSNR(correspondingFieldPic, pcPic, correspondingFieldPic->getPicYuvRec(), pcPic->getPicYuvRec(), snr_conversion, printFrameMSE );
-      }
-    }
-  }
-}
-
-Void TEncGOP::xCalculateAddPSNR( TComPic* pcPic, TComPicYuv* pcPicD, const AccessUnit& accessUnit, Double dEncTime, const InputColourSpaceConversion conversion, const Bool printFrameMSE )
+        xCalculateInterlacedAddPSNR(correspondingFieldPic, pcPic, correspondingFieldPic->getPicYuvRec(), pcPic->getPicYuvRec(), snr_conversion, printFrameMSE, PSNR_Y );
+      }
+    }
+  }
+}
+
+Void TEncGOP::xCalculateAddPSNR( TComPic* pcPic, TComPicYuv* pcPicD, const AccessUnit& accessUnit, Double dEncTime, const InputColourSpaceConversion conversion, const Bool printFrameMSE, Double* PSNR_Y )
 {
   Double  dPSNR[MAX_NUM_COMPONENT];
@@ -3166,12 +3175,15 @@
   {
     m_gcAnalyzeI.addResult (dPSNR, (Double)uibits, MSEyuvframe);
+    *PSNR_Y = dPSNR[COMPONENT_Y];
   }
   if (pcSlice->isInterP())
   {
     m_gcAnalyzeP.addResult (dPSNR, (Double)uibits, MSEyuvframe);
+    *PSNR_Y = dPSNR[COMPONENT_Y];
   }
   if (pcSlice->isInterB())
   {
     m_gcAnalyzeB.addResult (dPSNR, (Double)uibits, MSEyuvframe);
+    *PSNR_Y = dPSNR[COMPONENT_Y];
   }
 
@@ -3282,5 +3294,5 @@
 Void TEncGOP::xCalculateInterlacedAddPSNR( TComPic* pcPicOrgFirstField, TComPic* pcPicOrgSecondField,
                                            TComPicYuv* pcPicRecFirstField, TComPicYuv* pcPicRecSecondField,
-                                           const InputColourSpaceConversion conversion, const Bool printFrameMSE )
+                                           const InputColourSpaceConversion conversion, const Bool printFrameMSE, Double* PSNR_Y )
 {
   const TComSPS &sps=pcPicOrgFirstField->getPicSym()->getSPS();
@@ -3355,4 +3367,6 @@
   //===== add PSNR =====
   m_gcAnalyzeAll_in.addResult (dPSNR, (Double)uibits, MSEyuvframe);
+
+  *PSNR_Y = dPSNR[COMPONENT_Y];
 
   printf("\n                                      Interlaced frame %d: [Y %6.4lf dB    U %6.4lf dB    V %6.4lf dB]", pcPicOrgSecondField->getPOC()/2 , dPSNR[COMPONENT_Y], dPSNR[COMPONENT_Cb], dPSNR[COMPONENT_Cr] );
Index: branches/SHM-dev/source/Lib/TLibEncoder/TEncGOP.h
===================================================================
--- branches/SHM-dev/source/Lib/TLibEncoder/TEncGOP.h	(revision 1571)
+++ branches/SHM-dev/source/Lib/TLibEncoder/TEncGOP.h	(revision 1572)
@@ -228,9 +228,9 @@
   Void  xGetBuffer        ( TComList<TComPic*>& rcListPic, TComList<TComPicYuv*>& rcListPicYuvRecOut, Int iNumPicRcvd, Int iTimeOffset, TComPic*& rpcPic, TComPicYuv*& rpcPicYuvRecOut, Int pocCurr, Bool isField );
 
-  Void  xCalculateAddPSNRs         ( const Bool isField, const Bool isFieldTopFieldFirst, const Int iGOPid, TComPic* pcPic, const AccessUnit&accessUnit, TComList<TComPic*> &rcListPic, Double dEncTime, const InputColourSpaceConversion snr_conversion, const Bool printFrameMSE );
-  Void  xCalculateAddPSNR          ( TComPic* pcPic, TComPicYuv* pcPicD, const AccessUnit&, Double dEncTime, const InputColourSpaceConversion snr_conversion, const Bool printFrameMSE );
+  Void  xCalculateAddPSNRs         ( const Bool isField, const Bool isFieldTopFieldFirst, const Int iGOPid, TComPic* pcPic, const AccessUnit&accessUnit, TComList<TComPic*> &rcListPic, Double dEncTime, const InputColourSpaceConversion snr_conversion, const Bool printFrameMSE, Double* PSNR_Y );
+  Void  xCalculateAddPSNR          ( TComPic* pcPic, TComPicYuv* pcPicD, const AccessUnit&, Double dEncTime, const InputColourSpaceConversion snr_conversion, const Bool printFrameMSE, Double* PSNR_Y );
   Void  xCalculateInterlacedAddPSNR( TComPic* pcPicOrgFirstField, TComPic* pcPicOrgSecondField,
                                      TComPicYuv* pcPicRecFirstField, TComPicYuv* pcPicRecSecondField,
-                                     const InputColourSpaceConversion snr_conversion, const Bool printFrameMSE );
+                                     const InputColourSpaceConversion snr_conversion, const Bool printFrameMSE, Double* PSNR_Y );
 
   UInt64 xFindDistortionFrame (TComPicYuv* pcPic0, TComPicYuv* pcPic1, const BitDepths &bitDepths);
