shithub: openh264

Download patch

ref: b231e3f00006240dbc45725f9f93a5ab17d705c9
parent: 53c14dccf0b24a7d42009ebbde5c7094fa4f59d6
author: huili2 <[email protected]>
date: Sun Nov 23 18:56:39 EST 2014

parse only add and UT

--- a/codec/api/svc/codec_app_def.h
+++ b/codec/api/svc/codec_app_def.h
@@ -457,6 +457,7 @@
   unsigned char	uiTargetDqLayer;       ///< setting target dq layer id
 
   ERROR_CON_IDC eEcActiveIdc;          ///< whether active error concealment feature in decoder
+  bool bParseOnly;                     ///< decoder for parse only, no reconstruction
 
   SVideoProperty   sVideoProperty;    ///< video stream property
 } SDecodingParam, *PDecodingParam;
@@ -574,7 +575,7 @@
   unsigned char* pDstBuff;                     ///< outputted dst buffer for parsed bitstream
   int iSpsWidthInPixel;                        ///< required SPS width info
   int iSpsHeightInPixel;                       ///< required SPS height info
-} SParserBsInfo, PParserBsInfo;
+} SParserBsInfo, *PParserBsInfo;
 
 /**
 * @brief Structure for encoder statistics
--- a/codec/decoder/core/inc/au_parser.h
+++ b/codec/decoder/core/inc/au_parser.h
@@ -86,7 +86,7 @@
 uint8_t* ParseNalHeader (PWelsDecoderContext pCtx, SNalUnitHeader* pNalUnitHeader, uint8_t* pSrcRbsp,
                          int32_t iSrcRbspLen, uint8_t* pSrcNal, int32_t iSrcNalLen, int32_t* pConsumedBytes);
 
-int32_t ParseNonVclNal (PWelsDecoderContext pCtx, uint8_t* pRbsp, const int32_t kiSrcLen);
+int32_t ParseNonVclNal (PWelsDecoderContext pCtx, uint8_t* pRbsp, const int32_t kiSrcLen, uint8_t* pSrcNal, const int32_t kSrcNalLen);
 
 int32_t ParseRefBasePicMarking (PBitStringAux pBs, PRefBasePicMarking pRefBasePicMarking);
 
@@ -113,7 +113,7 @@
  * \note	Call it in case eNalUnitType is SPS.
  *************************************************************************************
  */
-int32_t ParseSps (PWelsDecoderContext pCtx, PBitStringAux pBsAux, int32_t* pPicWidth, int32_t* pPicHeight);
+int32_t ParseSps (PWelsDecoderContext pCtx, PBitStringAux pBsAux, int32_t* pPicWidth, int32_t* pPicHeight, uint8_t* pSrcNal, const int32_t kSrcNalLen);
 
 /*!
  *************************************************************************************
@@ -129,7 +129,7 @@
  * \note	Call it in case eNalUnitType is PPS.
  *************************************************************************************
  */
-int32_t ParsePps (PWelsDecoderContext pCtx, PPps pPpsList, PBitStringAux pBsAux);
+int32_t ParsePps (PWelsDecoderContext pCtx, PPps pPpsList, PBitStringAux pBsAux, uint8_t* pSrcNal, const int32_t kSrcNalLen);
 
 /*!
  *************************************************************************************
--- a/codec/decoder/core/inc/bit_stream.h
+++ b/codec/decoder/core/inc/bit_stream.h
@@ -65,7 +65,15 @@
 
 int32_t InitReadBits (PBitStringAux pBitString, intX_t iEndOffset);
 
-
+//The following for writing bs in decoder for Parse Only purpose
+void DecInitBitsForEncoding (PBitStringAux pBitString, uint8_t* kpBuf, const int32_t kiSize);
+int32_t DecBsWriteBits (PBitStringAux pBitString, int32_t iLen, const uint32_t kuiValue);
+int32_t DecBsWriteOneBit (PBitStringAux pBitString, const uint32_t kuiValue);
+int32_t DecBsFlush (PBitStringAux pBitString);
+int32_t DecBsWriteUe (PBitStringAux pBitString, const uint32_t kuiValue);
+int32_t DecBsWriteSe (PBitStringAux pBitString, const int32_t kiValue);
+int32_t DecBsRbspTrailingBits (PBitStringAux pBitString);
+void RBSP2EBSP (uint8_t* pDstBuf, uint8_t* pSrcBuf, const int32_t kiSize);
 
 } // namespace WelsDec
 
--- a/codec/decoder/core/inc/decoder.h
+++ b/codec/decoder/core/inc/decoder.h
@@ -68,7 +68,7 @@
  * \note	N/A
  *************************************************************************************
  */
-int32_t WelsInitDecoder (PWelsDecoderContext pCtx, SLogContext* pLogCtx);
+int32_t WelsInitDecoder (PWelsDecoderContext pCtx, const bool bParseOnly, SLogContext* pLogCtx);
 
 /*!
  *************************************************************************************
@@ -101,7 +101,7 @@
  */
 
 int32_t WelsDecodeBs (PWelsDecoderContext pCtx, const uint8_t* kpBsBuf, const int32_t kiBsLen,
-                      uint8_t** ppDst, SBufferInfo* pDstBufInfo);
+                      uint8_t** ppDst, SBufferInfo* pDstBufInfo, SParserBsInfo* pDstBsInfo);
 
 /*
  *	request memory blocks for decoder avc part
--- a/codec/decoder/core/inc/decoder_context.h
+++ b/codec/decoder/core/inc/decoder_context.h
@@ -102,6 +102,19 @@
 uint8_t* pCurPos;
 } SDataBuffer;
 
+//limit size for SPS PPS total permitted size for parse_only
+#define SPS_PPS_BS_SIZE 128
+typedef struct TagSpsBsInfo {
+  uint8_t pSpsBsBuf [SPS_PPS_BS_SIZE];
+  int32_t iSpsId;
+  uint16_t uiSpsBsLen;
+} SSpsBsInfo;
+
+typedef struct TagPpsBsInfo {
+  uint8_t pPpsBsBuf [SPS_PPS_BS_SIZE];
+  int32_t iPpsId;
+  uint16_t uiPpsBsLen;
+} SPpsBsInfo;
 //#ifdef __cplusplus
 //extern "C" {
 //#endif//__cplusplus
@@ -210,6 +223,7 @@
 void*				pArgDec;			// structured arguments for decoder, reserved here for extension in the future
 
 SDataBuffer                     sRawData;
+SDataBuffer                     sSavedData; //for parse only purpose
 
 // Configuration
 SDecodingParam*                 pParam;
@@ -334,6 +348,14 @@
 bool       bNextNewSeqBegin;
 int        iOverwriteFlags;
 ERROR_CON_IDC eErrorConMethod; //
+
+//for Parse only
+bool bParseOnly;
+SSpsBsInfo sSpsBsInfo [MAX_SPS_COUNT];
+SSpsBsInfo sSubsetSpsBsInfo [MAX_PPS_COUNT];
+SPpsBsInfo sPpsBsInfo [MAX_PPS_COUNT];
+SParserBsInfo* pParserBsInfo;
+
 PPicture pPreviousDecodedPictureInDpb; //pointer to previously decoded picture in DPB for error concealment
 PGetIntraPredFunc pGetI16x16LumaPredFunc[7];		//h264_predict_copy_16x16;
 PGetIntraPredFunc pGetI4x4LumaPredFunc[14];		// h264_predict_4x4_t
--- a/codec/decoder/core/src/au_parser.cpp
+++ b/codec/decoder/core/src/au_parser.cpp
@@ -43,6 +43,8 @@
 #include "error_code.h"
 #include "memmgr_nal_unit.h"
 #include "decoder_core.h"
+#include "bit_stream.h"
+#include "mem_align.h"
 
 namespace WelsDec {
 /*!
@@ -110,6 +112,7 @@
   bool bExtensionFlag = false;
   int32_t iErr	= ERR_NONE;
   int32_t iBitSize = 0;
+  SDataBuffer* pSavedData = &pCtx->sSavedData;
   SLogContext* pLogCtx = & (pCtx->sLogCtx);
   pNalUnitHeader->eNalUnitType = NAL_UNIT_UNSPEC_0;//SHOULD init it. because pCtx->sCurNalHead is common variable.
 
@@ -296,9 +299,28 @@
       iNalSize        -= NAL_UNIT_HEADER_EXT_SIZE;
       *pConsumedBytes += NAL_UNIT_HEADER_EXT_SIZE;
 
+      if (pCtx->bParseOnly) {
+        pCurNal->sNalData.sVclNal.pNalPos = pSavedData->pCurPos;
+        pCurNal->sNalData.sVclNal.iNalLength = iSrcNalLen - NAL_UNIT_HEADER_EXT_SIZE;
+        if (pCurNal->sNalHeaderExt.bIdrFlag) {
+          * (pSrcNal + 3) &= 0xE0;
+          * (pSrcNal + 3) |= 0x05;
+        } else {
+          * (pSrcNal + 3) &= 0xE0;
+          * (pSrcNal + 3) |= 0x01;
+        }
+        memcpy (pSavedData->pCurPos, pSrcNal, 4);
+        pSavedData->pCurPos += 4;
+        memcpy (pSavedData->pCurPos, pSrcNal + 7, iSrcNalLen - 7);
+        pSavedData->pCurPos += iSrcNalLen - 7;
+      }
     } else {
-
-
+      if (pCtx->bParseOnly) {
+        pCurNal->sNalData.sVclNal.pNalPos = pSavedData->pCurPos;
+        pCurNal->sNalData.sVclNal.iNalLength = iSrcNalLen;
+        memcpy (pSavedData->pCurPos, pSrcNal, iSrcNalLen);
+        pSavedData->pCurPos += iSrcNalLen;
+      }
       if (NAL_UNIT_PREFIX == pCtx->sPrefixNal.sNalHeaderExt.sNalUnitHeader.eNalUnitType) {
         if (pCtx->sPrefixNal.sNalData.sPrefixNal.bPrefixNalCorrectFlag) {
           PrefetchNalHeaderExtSyntax (pCtx, pCurNal, &pCtx->sPrefixNal);
@@ -501,7 +523,8 @@
  *
  *************************************************************************************
  */
-int32_t ParseNonVclNal (PWelsDecoderContext pCtx, uint8_t* pRbsp, const int32_t kiSrcLen) {
+int32_t ParseNonVclNal (PWelsDecoderContext pCtx, uint8_t* pRbsp, const int32_t kiSrcLen, uint8_t* pSrcNal,
+                        const int32_t kSrcNalLen) {
   PBitStringAux	pBs = NULL;
   EWelsNalUnitType eNalType	= NAL_UNIT_UNSPEC_0; // make initial value as unspecified
   int32_t iPicWidth		= 0;
@@ -528,7 +551,7 @@
         return iErr;
       }
     }
-    iErr = ParseSps (pCtx, pBs, &iPicWidth, &iPicHeight);
+    iErr = ParseSps (pCtx, pBs, &iPicWidth, &iPicHeight, pSrcNal, kSrcNalLen);
     if (ERR_NONE != iErr) {	// modified for pSps/pSubsetSps invalid, 12/1/2009
       if (pCtx->eErrorConMethod == ERROR_CON_DISABLE)
         pCtx->iErrorCode |= dsNoParamSets;
@@ -550,7 +573,7 @@
         return iErr;
       }
     }
-    iErr = ParsePps (pCtx, &pCtx->sPpsBuffer[0], pBs);
+    iErr = ParsePps (pCtx, &pCtx->sPpsBuffer[0], pBs, pSrcNal, kSrcNalLen);
     if (ERR_NONE != iErr) {	// modified for pps invalid, 12/1/2009
       if (pCtx->eErrorConMethod == ERROR_CON_DISABLE)
         pCtx->iErrorCode |= dsNoParamSets;
@@ -795,7 +818,8 @@
  *************************************************************************************
  */
 
-int32_t ParseSps (PWelsDecoderContext pCtx, PBitStringAux pBsAux, int32_t* pPicWidth, int32_t* pPicHeight) {
+int32_t ParseSps (PWelsDecoderContext pCtx, PBitStringAux pBsAux, int32_t* pPicWidth, int32_t* pPicHeight,
+                  uint8_t* pSrcNal, const int32_t kSrcNalLen) {
   PBitStringAux pBs		= pBsAux;
   SSubsetSps sTempSubsetSps;
   PSps pSps				= NULL;
@@ -995,6 +1019,79 @@
   WELS_READ_VERIFY (BsGetOneBit (pBs, &uiCode)); //vui_parameters_present_flag
   pSps->bVuiParamPresentFlag			= !!uiCode;
 
+  if (pCtx->bParseOnly) {
+    if (kSrcNalLen >= SPS_PPS_BS_SIZE - 4) { //sps bs exceeds!
+      pCtx->iErrorCode |= dsOutOfMemory;
+      return GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_OUT_OF_MEMORY);
+    }
+    if (!kbUseSubsetFlag) { //SPS
+      SSpsBsInfo* pSpsBs = &pCtx->sSpsBsInfo [iSpsId];
+      pSpsBs->iSpsId = iSpsId;
+      memcpy (pSpsBs->pSpsBsBuf, pSrcNal, kSrcNalLen);
+      pSpsBs->uiSpsBsLen = (uint32_t) kSrcNalLen;
+    } else { //subset SPS
+      SSpsBsInfo* pSpsBs = &pCtx->sSubsetSpsBsInfo [iSpsId];
+      pSpsBs->iSpsId = iSpsId;
+      pSpsBs->pSpsBsBuf [0] = pSpsBs->pSpsBsBuf [1] = pSpsBs->pSpsBsBuf [2] = 0x00;
+      pSpsBs->pSpsBsBuf [3] = 0x01;
+      pSpsBs->pSpsBsBuf [4] = 0x67;
+
+      //re-write subset SPS to SPS
+      SBitStringAux sSubsetSpsBs;
+      uint8_t* pBsBuf = static_cast<uint8_t*> (WelsMalloc (SPS_PPS_BS_SIZE + 4,
+                        "Temp buffer for parse only usage.")); //to reserve 4 bytes for UVLC writing buffer
+      if (NULL == pBsBuf) {
+        pCtx->iErrorCode |= dsOutOfMemory;
+        return pCtx->iErrorCode;
+      }
+      DecInitBitsForEncoding (&sSubsetSpsBs, pBsBuf, pBs->pEndBuf - pBs->pStartBuf);
+      DecBsWriteBits (&sSubsetSpsBs, 8, 77); //profile_idc, forced to Main profile
+      DecBsWriteOneBit (&sSubsetSpsBs, pSps->bConstraintSet0Flag); // constraint_set0_flag
+      DecBsWriteOneBit (&sSubsetSpsBs, pSps->bConstraintSet1Flag); // constraint_set1_flag
+      DecBsWriteOneBit (&sSubsetSpsBs, pSps->bConstraintSet2Flag); // constraint_set2_flag
+      DecBsWriteOneBit (&sSubsetSpsBs, pSps->bConstraintSet3Flag); // constraint_set3_flag
+      DecBsWriteBits (&sSubsetSpsBs, 4, 0); //constraint_set4_flag, constraint_set5_flag, reserved_zero_2bits
+      DecBsWriteBits (&sSubsetSpsBs, 8, pSps->uiLevelIdc); //level_idc
+      DecBsWriteUe (&sSubsetSpsBs, pSps->iSpsId); //sps_id
+      DecBsWriteUe (&sSubsetSpsBs, pSps->uiLog2MaxFrameNum - 4); //log2_max_frame_num_minus4
+      DecBsWriteUe (&sSubsetSpsBs, pSps->uiPocType); //pic_order_cnt_type
+      if (pSps->uiPocType == 0) {
+        DecBsWriteUe (&sSubsetSpsBs, pSps->iLog2MaxPocLsb - 4); //log2_max_pic_order_cnt_lsb_minus4
+      } else if (pSps->uiPocType == 1) {
+        DecBsWriteOneBit (&sSubsetSpsBs, pSps->bDeltaPicOrderAlwaysZeroFlag); //delta_pic_order_always_zero_flag
+        DecBsWriteSe (&sSubsetSpsBs, pSps->iOffsetForNonRefPic); //offset_for_no_ref_pic
+        DecBsWriteSe (&sSubsetSpsBs, pSps->iOffsetForTopToBottomField); //offset_for_top_to_bottom_field
+        DecBsWriteUe (&sSubsetSpsBs, pSps->iNumRefFramesInPocCycle); //num_ref_frames_in_pic_order_cnt_cycle
+        for (int32_t i = 0; i < pSps->iNumRefFramesInPocCycle; ++i) {
+          DecBsWriteSe (&sSubsetSpsBs, pSps->iOffsetForRefFrame[i]); //offset_for_ref_frame[i]
+        }
+      }
+      DecBsWriteUe (&sSubsetSpsBs, pSps->iNumRefFrames); //max_num_ref_frames
+      DecBsWriteOneBit (&sSubsetSpsBs, pSps->bGapsInFrameNumValueAllowedFlag); //gaps_in_frame_num_value_allowed_flag
+      DecBsWriteUe (&sSubsetSpsBs, pSps->iMbWidth - 1); //pic_width_in_mbs_minus1
+      DecBsWriteUe (&sSubsetSpsBs, pSps->iMbHeight - 1); //pic_height_in_map_units_minus1
+      DecBsWriteOneBit (&sSubsetSpsBs, pSps->bFrameMbsOnlyFlag); //frame_mbs_only_flag
+      if (!pSps->bFrameMbsOnlyFlag) {
+        DecBsWriteOneBit (&sSubsetSpsBs, pSps->bMbaffFlag); //mb_adaptive_frame_field_flag
+      }
+      DecBsWriteOneBit (&sSubsetSpsBs, pSps->bDirect8x8InferenceFlag); //direct_8x8_inference_flag
+      DecBsWriteOneBit (&sSubsetSpsBs, pSps->bFrameCroppingFlag); //frame_cropping_flag
+      if (pSps->bFrameCroppingFlag) {
+        DecBsWriteUe (&sSubsetSpsBs, pSps->sFrameCrop.iLeftOffset); //frame_crop_left_offset
+        DecBsWriteUe (&sSubsetSpsBs, pSps->sFrameCrop.iRightOffset); //frame_crop_right_offset
+        DecBsWriteUe (&sSubsetSpsBs, pSps->sFrameCrop.iTopOffset); //frame_crop_top_offset
+        DecBsWriteUe (&sSubsetSpsBs, pSps->sFrameCrop.iBottomOffset); //frame_crop_bottom_offset
+      }
+      DecBsWriteOneBit (&sSubsetSpsBs, 0); //vui_parameters_present_flag
+      DecBsRbspTrailingBits (&sSubsetSpsBs); //finished, rbsp trailing bit
+      int32_t iRbspSize = sSubsetSpsBs.pCurBuf - sSubsetSpsBs.pStartBuf;
+      RBSP2EBSP (pSpsBs->pSpsBsBuf + 5, sSubsetSpsBs.pStartBuf, iRbspSize);
+      pSpsBs->uiSpsBsLen = sSubsetSpsBs.pCurBuf - sSubsetSpsBs.pStartBuf + 5;
+      if (pBsBuf) {
+        WelsFree (pBsBuf, "pBsBuf for parse only usage");
+      }
+    }
+  }
   // Check if SPS SVC extension applicated
   if (kbUseSubsetFlag && (PRO_SCALABLE_BASELINE == uiProfileIdc || PRO_SCALABLE_HIGH == uiProfileIdc)) {
     if (DecodeSpsSvcExt (pCtx, pSubsetSps, pBs) != ERR_NONE) {
@@ -1080,7 +1177,8 @@
  * \note	Call it in case eNalUnitType is PPS.
  *************************************************************************************
  */
-int32_t ParsePps (PWelsDecoderContext pCtx, PPps pPpsList, PBitStringAux pBsAux) {
+int32_t ParsePps (PWelsDecoderContext pCtx, PPps pPpsList, PBitStringAux pBsAux, uint8_t* pSrcNal,
+                  const int32_t kSrcNalLen) {
 
   PPps pPps = NULL;
   SPps sTempPps;
@@ -1193,6 +1291,16 @@
   } else {
     memcpy (&pCtx->sPpsBuffer[uiPpsId], pPps, sizeof (SPps));
     pCtx->bPpsAvailFlags[uiPpsId] = true;
+  }
+  if (pCtx->bParseOnly) {
+    if (kSrcNalLen >= SPS_PPS_BS_SIZE - 4) { //pps bs exceeds
+      pCtx->iErrorCode |= dsOutOfMemory;
+      return GENERATE_ERROR_NO (ERR_LEVEL_PARAM_SETS, ERR_INFO_OUT_OF_MEMORY);
+    }
+    SPpsBsInfo* pPpsBs = &pCtx->sPpsBsInfo [uiPpsId];
+    pPpsBs->iPpsId = (int32_t) uiPpsId;
+    memcpy (pPpsBs->pPpsBsBuf, pSrcNal, kSrcNalLen);
+    pPpsBs->uiPpsBsLen = kSrcNalLen;
   }
   return ERR_NONE;
 }
--- a/codec/decoder/core/src/bit_stream.cpp
+++ b/codec/decoder/core/src/bit_stream.cpp
@@ -49,7 +49,7 @@
 }
 
 int32_t InitReadBits (PBitStringAux pBitString, intX_t iEndOffset) {
-  if(pBitString->pCurBuf>=(pBitString->pEndBuf - iEndOffset)) {
+  if (pBitString->pCurBuf >= (pBitString->pEndBuf - iEndOffset)) {
     return ERR_INFO_INVALID_ACCESS;
   }
   pBitString->uiCurBits  = GetValue4Bytes (pBitString->pCurBuf);
@@ -79,10 +79,140 @@
   pBitString->iBits	    = kiSize;				// count bits of overall bitstreaming inputindex;
   pBitString->pCurBuf   = pBitString->pStartBuf;
   int32_t iErr = InitReadBits (pBitString, 0);
-  if(iErr) {
+  if (iErr) {
     return iErr;
   }
   return ERR_NONE;
+}
+
+//Following for write bs in decoder
+void DecInitBitsForEncoding (PBitStringAux pBitString, uint8_t* pBuf, const int32_t kiSize) {
+  uint8_t* pPtr = pBuf;
+  pBitString->pStartBuf = pPtr;
+  pBitString->pCurBuf = pPtr;
+  pBitString->pEndBuf = pPtr + kiSize;
+  pBitString->iLeftBits = 32;
+  pBitString->uiCurBits = 0;
+}
+
+#define WRITE_BE_32(ptr, val) do { \
+    (ptr)[0] = (val) >> 24; \
+    (ptr)[1] = (val) >> 16; \
+    (ptr)[2] = (val) >>  8; \
+    (ptr)[3] = (val) >>  0; \
+  } while (0);
+
+int32_t DecBsWriteBits (PBitStringAux pBitString, int32_t iLen, const uint32_t kuiValue) {
+  if (iLen < pBitString->iLeftBits) {
+    pBitString->uiCurBits = (pBitString->uiCurBits << iLen) | kuiValue;
+    pBitString->iLeftBits -= iLen;
+  } else {
+    iLen -= pBitString->iLeftBits;
+    pBitString->uiCurBits = (pBitString->uiCurBits << pBitString->iLeftBits) | (kuiValue >> iLen);
+    WRITE_BE_32 (pBitString->pCurBuf, pBitString->uiCurBits);
+    pBitString->pCurBuf += 4;
+    pBitString->uiCurBits = kuiValue & ((1 << iLen) - 1);
+    pBitString->iLeftBits = 32 - iLen;
+  }
+  return 0;
+}
+
+int32_t DecBsWriteOneBit (PBitStringAux pBitString, const uint32_t kuiValue) {
+  DecBsWriteBits (pBitString, 1, kuiValue);
+  return 0;
+}
+
+int32_t DecBsFlush (PBitStringAux pBitString) {
+  WRITE_BE_32 (pBitString->pCurBuf, pBitString->uiCurBits << pBitString->iLeftBits);
+  pBitString->pCurBuf += 4 - pBitString->iLeftBits / 8;
+  pBitString->iLeftBits = 32;
+  pBitString->uiCurBits = 0;
+  return 0;
+}
+
+const uint32_t g_kuiDecGolombUELength[256] = {
+  1,  3,  3,  5,  5,  5,  5,  7,  7,  7,  7,  7,  7,  7,  7,     //14
+  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9, //30
+  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,//46
+  11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,//62
+  13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,//
+  13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+  13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+  13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+  15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+  15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+  15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+  15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+  15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+  15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+  15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+  15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+  17
+};
+
+int32_t DecBsWriteUe (PBitStringAux pBitString, const uint32_t kuiValue) {
+  uint32_t iTmpValue = kuiValue + 1;
+  if (256 > kuiValue) {
+    DecBsWriteBits (pBitString, g_kuiDecGolombUELength[kuiValue], kuiValue + 1);
+  } else {
+    uint32_t n = 0;
+    if (iTmpValue & 0xffff0000) {
+      iTmpValue >>= 16;
+      n += 16;
+    }
+    if (iTmpValue & 0xff) {
+      iTmpValue >>= 8;
+      n += 8;
+    }
+
+    //n += (g_kuiDecGolombUELength[iTmpValue] >> 1);
+
+    n += (g_kuiDecGolombUELength[iTmpValue - 1] >> 1);
+    DecBsWriteBits (pBitString, (n << 1) + 1, kuiValue + 1);
+  }
+  return 0;
+}
+
+int32_t DecBsWriteSe (PBitStringAux pBitString, const int32_t kiValue) {
+  uint32_t iTmpValue;
+  if (0 == kiValue) {
+    DecBsWriteOneBit (pBitString, 1);
+  } else if (0 < kiValue) {
+    iTmpValue = (kiValue << 1) - 1;
+    DecBsWriteUe (pBitString, iTmpValue);
+  } else {
+    iTmpValue = ((-kiValue) << 1);
+    DecBsWriteUe (pBitString, iTmpValue);
+  }
+  return 0;
+}
+
+int32_t DecBsRbspTrailingBits (PBitStringAux pBitString) {
+  DecBsWriteOneBit (pBitString, 1);
+  DecBsFlush (pBitString);
+
+  return 0;
+}
+
+void RBSP2EBSP (uint8_t* pDstBuf, uint8_t* pSrcBuf, const int32_t kiSize) {
+  uint8_t* pSrcPointer = pSrcBuf;
+  uint8_t* pDstPointer = pDstBuf;
+  uint8_t* pSrcEnd = pSrcBuf + kiSize;
+  int32_t iZeroCount = 0;
+
+  while (pSrcPointer < pSrcEnd) {
+    if (iZeroCount == 2 && *pSrcPointer <= 3) {
+      //add the code 0x03
+      *pDstPointer++ = 3;
+      iZeroCount = 0;
+    }
+    if (*pSrcPointer == 0) {
+      ++ iZeroCount;
+    } else {
+      iZeroCount = 0;
+    }
+    *pDstPointer++ = *pSrcPointer++;
+  }
 }
 
 } // namespace WelsDec
--- a/codec/decoder/core/src/decoder.cpp
+++ b/codec/decoder/core/src/decoder.cpp
@@ -350,6 +350,9 @@
     return iRet;
   pCtx->eErrorConMethod = pCtx->pParam->eEcActiveIdc;
 
+  if (pCtx->bParseOnly) //parse only, disable EC method
+    pCtx->eErrorConMethod = ERROR_CON_DISABLE;
+
   if (VIDEO_BITSTREAM_SVC == pCtx->pParam->sVideoProperty.eVideoBsType ||
       VIDEO_BITSTREAM_AVC == pCtx->pParam->sVideoProperty.eVideoBsType) {
     pCtx->eVideoType = pCtx->pParam->sVideoProperty.eVideoBsType;
@@ -374,7 +377,7 @@
  * \note	N/A
  *************************************************************************************
  */
-int32_t WelsInitDecoder (PWelsDecoderContext pCtx, SLogContext* pLogCtx) {
+int32_t WelsInitDecoder (PWelsDecoderContext pCtx, const bool bParseOnly, SLogContext* pLogCtx) {
   if (pCtx == NULL) {
     return ERR_INFO_INVALID_PTR;
   }
@@ -382,6 +385,7 @@
   // default
   WelsDecoderDefaults (pCtx, pLogCtx);
 
+  pCtx->bParseOnly = bParseOnly;
   // open decoder
   return WelsOpenDecoder (pCtx);
 }
@@ -427,9 +431,10 @@
  *************************************************************************************
  */
 int32_t WelsDecodeBs (PWelsDecoderContext pCtx, const uint8_t* kpBsBuf, const int32_t kiBsLen,
-                      uint8_t** ppDst, SBufferInfo* pDstBufInfo) {
+                      uint8_t** ppDst, SBufferInfo* pDstBufInfo, SParserBsInfo* pDstBsInfo) {
   if (!pCtx->bEndOfStreamFlag) {
     SDataBuffer* pRawData   = &pCtx->sRawData;
+    SDataBuffer* pSavedData = NULL;
 
     int32_t iSrcIdx        = 0; //the index of source bit-stream till now after parsing one or more NALs
     int32_t iSrcConsumed   = 0; // consumed bit count of source bs
@@ -457,7 +462,12 @@
       pRawData->pCurPos = pRawData->pHead;
     }
 
-
+    if (pCtx->bParseOnly) {
+      pSavedData = &pCtx->sSavedData;
+      if ((kiBsLen + 4) > (pSavedData->pEnd - pSavedData->pCurPos)) {
+        pSavedData->pCurPos = pSavedData->pHead;
+      }
+    }
     //copy raw data from source buffer (application) to raw data buffer (codec inside)
     //0x03 removal and extract all of NAL Unit from current raw data
     pDstNal = pRawData->pCurPos;
@@ -481,7 +491,7 @@
             CheckAndFinishLastPic (pCtx, ppDst, pDstBufInfo);
           }
           if (IS_PARAM_SETS_NALS (pCtx->sCurNalHead.eNalUnitType) && pNalPayload) {
-            iRet = ParseNonVclNal (pCtx, pNalPayload, iDstIdx - iConsumedBytes);
+            iRet = ParseNonVclNal (pCtx, pNalPayload, iDstIdx - iConsumedBytes, pSrcNal - 3, iSrcIdx + 3);
           }
           if (pCtx->bAuReadyFlag) {
             ConstructAccessUnit (pCtx, ppDst, pDstBufInfo);
@@ -542,7 +552,7 @@
       CheckAndFinishLastPic (pCtx, ppDst, pDstBufInfo);
     }
     if (IS_PARAM_SETS_NALS (pCtx->sCurNalHead.eNalUnitType) && pNalPayload) {
-      iRet = ParseNonVclNal (pCtx, pNalPayload, iDstIdx - iConsumedBytes);
+      iRet = ParseNonVclNal (pCtx, pNalPayload, iDstIdx - iConsumedBytes, pSrcNal - 3, iSrcIdx + 3);
     }
     if (pCtx->bAuReadyFlag) {
       ConstructAccessUnit (pCtx, ppDst, pDstBufInfo);
--- a/codec/decoder/core/src/decoder_core.cpp
+++ b/codec/decoder/core/src/decoder_core.cpp
@@ -88,21 +88,23 @@
 
   pCtx->iTotalNumMbRec = 0;
 
-  //////output:::normal path
-  ppDst[0]      = pPic->pData[0];
-  ppDst[1]      = pPic->pData[1];
-  ppDst[2]      = pPic->pData[2];
+  if (!pCtx->bParseOnly) {
+    //////output:::normal path
+    ppDst[0]      = pPic->pData[0];
+    ppDst[1]      = pPic->pData[1];
+    ppDst[2]      = pPic->pData[2];
 
-  pDstInfo->UsrData.sSystemBuffer.iFormat = videoFormatI420;
+    pDstInfo->UsrData.sSystemBuffer.iFormat = videoFormatI420;
 
-  pDstInfo->UsrData.sSystemBuffer.iWidth = kiWidth - (pCtx->sFrameCrop.iLeftOffset + pCtx->sFrameCrop.iRightOffset) * 2;
-  pDstInfo->UsrData.sSystemBuffer.iHeight = kiHeight - (pCtx->sFrameCrop.iTopOffset + pCtx->sFrameCrop.iBottomOffset) * 2;
-  pDstInfo->UsrData.sSystemBuffer.iStride[0] = pPic->iLinesize[0];
-  pDstInfo->UsrData.sSystemBuffer.iStride[1] = pPic->iLinesize[1];
-  ppDst[0] = ppDst[0] + pCtx->sFrameCrop.iTopOffset * 2 * pPic->iLinesize[0] + pCtx->sFrameCrop.iLeftOffset * 2;
-  ppDst[1] = ppDst[1] + pCtx->sFrameCrop.iTopOffset  * pPic->iLinesize[1] + pCtx->sFrameCrop.iLeftOffset;
-  ppDst[2] = ppDst[2] + pCtx->sFrameCrop.iTopOffset  * pPic->iLinesize[1] + pCtx->sFrameCrop.iLeftOffset;
-  pDstInfo->iBufferStatus = 1;
+    pDstInfo->UsrData.sSystemBuffer.iWidth = kiWidth - (pCtx->sFrameCrop.iLeftOffset + pCtx->sFrameCrop.iRightOffset) * 2;
+    pDstInfo->UsrData.sSystemBuffer.iHeight = kiHeight - (pCtx->sFrameCrop.iTopOffset + pCtx->sFrameCrop.iBottomOffset) * 2;
+    pDstInfo->UsrData.sSystemBuffer.iStride[0] = pPic->iLinesize[0];
+    pDstInfo->UsrData.sSystemBuffer.iStride[1] = pPic->iLinesize[1];
+    ppDst[0] = ppDst[0] + pCtx->sFrameCrop.iTopOffset * 2 * pPic->iLinesize[0] + pCtx->sFrameCrop.iLeftOffset * 2;
+    ppDst[1] = ppDst[1] + pCtx->sFrameCrop.iTopOffset  * pPic->iLinesize[1] + pCtx->sFrameCrop.iLeftOffset;
+    ppDst[2] = ppDst[2] + pCtx->sFrameCrop.iTopOffset  * pPic->iLinesize[1] + pCtx->sFrameCrop.iLeftOffset;
+    pDstInfo->iBufferStatus = 1;
+  }
 
   bool bOutResChange = (pCtx->iLastImgWidthInPixel != pDstInfo->UsrData.sSystemBuffer.iWidth)
                        || (pCtx->iLastImgHeightInPixel != pDstInfo->UsrData.sSystemBuffer.iHeight);
@@ -114,7 +116,6 @@
   else if (pCtx->eErrorConMethod == ERROR_CON_SLICE_COPY_CROSS_IDR_FREEZE_RES_CHANGE && pCtx->iErrorCode && bOutResChange)
     pCtx->bFreezeOutput = true;
 
-
   if ((pDstInfo->iBufferStatus == 1) && (pCurDq->sLayerInfo.sNalHeaderExt.bIdrFlag)) {
     if (pPic->bIsComplete)
       pCtx->sDecoderStatistics.uiIDRRecvNum++;
@@ -331,6 +332,14 @@
   }
   pCtx->sRawData.pStartPos = pCtx->sRawData.pCurPos = pCtx->sRawData.pHead;
   pCtx->sRawData.pEnd = pCtx->sRawData.pHead + pCtx->iMaxBsBufferSizeInByte;
+  if (pCtx->bParseOnly) {
+    if ((pCtx->sSavedData.pHead = static_cast<uint8_t*> (WelsMalloc (pCtx->iMaxBsBufferSizeInByte,
+                                  "pCtx->sSavedData.pHead"))) == NULL) {
+      return ERR_INFO_OUT_OF_MEMORY;
+    }
+    pCtx->sSavedData.pStartPos = pCtx->sSavedData.pCurPos = pCtx->sSavedData.pHead;
+    pCtx->sSavedData.pEnd = pCtx->sSavedData.pHead + pCtx->iMaxBsBufferSizeInByte;
+  }
   return ERR_NONE;
 }
 
@@ -434,6 +443,13 @@
   pCtx->sRawData.pEnd                 = NULL;
   pCtx->sRawData.pStartPos	        = NULL;
   pCtx->sRawData.pCurPos             = NULL;
+  if (pCtx->sSavedData.pHead) {
+    WelsFree (pCtx->sSavedData.pHead, "pCtx->sSavedData->pHead");
+  }
+  pCtx->sSavedData.pHead                = NULL;
+  pCtx->sSavedData.pEnd                 = NULL;
+  pCtx->sSavedData.pStartPos	        = NULL;
+  pCtx->sSavedData.pCurPos              = NULL;
 }
 
 /*
@@ -1692,7 +1708,8 @@
 
   if (ERR_NONE != iErr) {
     ForceResetCurrentAccessUnit (pCtx->pAccessUnitList);
-    pDstInfo->iBufferStatus = 0;
+    if (!pCtx->bParseOnly)
+      pDstInfo->iBufferStatus = 0;
     return iErr;
   }
 
@@ -1713,6 +1730,53 @@
 
   iErr = DecodeCurrentAccessUnit (pCtx, ppDst, pDstInfo);
 
+  if (pCtx->bParseOnly) {
+    if (dsErrorFree == pCtx->iErrorCode) {
+      SParserBsInfo* pParser = pCtx->pParserBsInfo;
+      uint8_t* pDstBuf = pParser->pDstBuff;
+      SNalUnit* pCurNal = NULL;
+      int32_t iNalLen = 0;
+      int32_t iIdx = pCurAu->uiStartPos;
+      int32_t iEndIdx = pCurAu->uiEndPos;
+      uint8_t* pNalBs = NULL;
+
+      pParser->iNalNum = 0;
+      pParser->iSpsWidthInPixel = (pCtx->pSps->iMbWidth << 4);
+      pParser->iSpsHeightInPixel = (pCtx->pSps->iMbHeight << 4);
+
+      if (pCurAu->pNalUnitsList [iIdx]->sNalHeaderExt.bIdrFlag) { //IDR
+        bool bSubSps = (NAL_UNIT_CODED_SLICE_EXT == pCurAu->pNalUnitsList [iIdx]->sNalHeaderExt.sNalUnitHeader.eNalUnitType);
+        SSpsBsInfo* pSpsBs = NULL;
+        SPpsBsInfo* pPpsBs = NULL;
+        int32_t iSpsId = pCtx->pSps->iSpsId;
+        int32_t iPpsId = pCtx->pPps->iPpsId;
+        pCtx->bParamSetsLostFlag = false;
+        //find required sps, pps and write into dst buff
+        pSpsBs = bSubSps ? &pCtx->sSubsetSpsBsInfo [iSpsId] : &pCtx->sSpsBsInfo [iSpsId];
+        memcpy (pDstBuf, pSpsBs->pSpsBsBuf, pSpsBs->uiSpsBsLen);
+        pParser->iNalLenInByte [pParser->iNalNum ++] = pSpsBs->uiSpsBsLen;
+        pDstBuf += pSpsBs->uiSpsBsLen;
+        pPpsBs = &pCtx->sPpsBsInfo [iPpsId];
+        memcpy (pDstBuf, pPpsBs->pPpsBsBuf, pPpsBs->uiPpsBsLen);
+        pParser->iNalLenInByte [pParser->iNalNum ++] = pPpsBs->uiPpsBsLen;
+        pDstBuf += pPpsBs->uiPpsBsLen;
+      } //IDR required SPS, PPS
+      //then VCL data re-write
+      while (iIdx <= iEndIdx) {
+        pCurNal = pCurAu->pNalUnitsList [iIdx ++];
+        iNalLen = pCurNal->sNalData.sVclNal.iNalLength;
+        pNalBs = pCurNal->sNalData.sVclNal.pNalPos;
+        pParser->iNalLenInByte [pParser->iNalNum ++] = iNalLen;
+        memcpy (pDstBuf, pNalBs, iNalLen);
+        pDstBuf += iNalLen;
+      }
+    } else { //error
+      pCtx->pParserBsInfo->iNalNum = 0;
+      pCtx->pParserBsInfo->iSpsWidthInPixel = 0;
+      pCtx->pParserBsInfo->iSpsHeightInPixel = 0;
+    }
+  }
+
   WelsDecodeAccessUnitEnd (pCtx);
 
   pCtx->bNewSeqBegin = false;
@@ -1985,10 +2049,13 @@
             return iRet;
           }
         }
-        if (bReconstructSlice)	{
-          if (WelsDecodeConstructSlice (pCtx, pNalCur)) {
-            pCtx->pDec->bIsComplete = false; // reconstruction error, directly set the flag false
-            return -1;
+
+        if (!pCtx->bParseOnly) {
+          if (bReconstructSlice) {
+            if (WelsDecodeConstructSlice (pCtx, pNalCur)) {
+              pCtx->pDec->bIsComplete = false; // reconstruction error, directly set the flag false
+              return -1;
+            }
           }
         }
         if (bAllRefComplete && (pCtx->sRefPic.uiRefCount[LIST_0] > 0 || pCtx->eSliceType != I_SLICE)) {
@@ -2031,20 +2098,21 @@
 #endif//#if !CODEC_FOR_TESTBED
 
     if (dq_cur->uiLayerDqId == kuiTargetLayerDqId) {
-      if (!pCtx->bInstantDecFlag) {
-        //Do error concealment here
-        if ((NeedErrorCon (pCtx)) && (pCtx->eErrorConMethod != ERROR_CON_DISABLE)) {
-          ImplementErrorCon (pCtx);
-          pCtx->iTotalNumMbRec = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight;
-          pCtx->pDec->iSpsId = pCtx->pSps->iSpsId;
-          pCtx->pDec->iPpsId = pCtx->pPps->iPpsId;
+      if (!pCtx->bParseOnly) {
+        if (!pCtx->bInstantDecFlag) {
+          //Do error concealment here
+          if ((NeedErrorCon (pCtx)) && (pCtx->eErrorConMethod != ERROR_CON_DISABLE)) {
+            ImplementErrorCon (pCtx);
+            pCtx->iTotalNumMbRec = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight;
+            pCtx->pDec->iSpsId = pCtx->pSps->iSpsId;
+            pCtx->pDec->iPpsId = pCtx->pPps->iPpsId;
+          }
         }
-      }
 
-      if (DecodeFrameConstruction (pCtx, ppDst, pDstInfo)) {
-        return ERR_NONE;
+        if (DecodeFrameConstruction (pCtx, ppDst, pDstInfo)) {
+          return ERR_NONE;
+        }
       }
-
       if (uiNalRefIdc > 0) {
         pCtx->pPreviousDecodedPictureInDpb = pCtx->pDec; //store latest decoded picture for EC
         iRet = WelsMarkAsRef (pCtx);
--- a/codec/decoder/core/src/manage_dec_ref.cpp
+++ b/codec/decoder/core/src/manage_dec_ref.cpp
@@ -256,6 +256,8 @@
 
   pCtx->pDec->uiQualityId = pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt.uiQualityId;
   pCtx->pDec->uiTemporalId = pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt.uiTemporalId;
+  pCtx->pDec->iSpsId = pCtx->pCurDqLayer->sLayerInfo.sSliceInLayer.sSliceHeaderExt.sSliceHeader.iSpsId;
+  pCtx->pDec->iPpsId = pCtx->pCurDqLayer->sLayerInfo.sSliceInLayer.sSliceHeaderExt.sSliceHeader.iPpsId;
 
   for (j = pCurAU->uiStartPos; j <= pCurAU->uiEndPos; j++) {
     if (pCurAU->pNalUnitsList[j]->sNalHeaderExt.sNalUnitHeader.eNalUnitType == NAL_UNIT_CODED_SLICE_IDR
--- a/codec/decoder/plus/inc/welsDecoderExt.h
+++ b/codec/decoder/plus/inc/welsDecoderExt.h
@@ -104,7 +104,7 @@
 PWelsDecoderContext 				m_pDecContext;
 welsCodecTrace*			m_pWelsTrace;
 
-int32_t InitDecoder (void);
+int32_t InitDecoder (const bool);
 void UninitDecoder (void);
 
 #ifdef OUTPUT_BIT_STREAM
--- a/codec/decoder/plus/src/welsDecoderExt.cpp
+++ b/codec/decoder/plus/src/welsDecoderExt.cpp
@@ -197,7 +197,7 @@
   }
 
   // H.264 decoder initialization,including memory allocation,then open it ready to decode
-  iRet = InitDecoder();
+  iRet = InitDecoder (pParam->bParseOnly);
   if (iRet)
     return iRet;
 
@@ -232,16 +232,18 @@
 }
 
 // the return value of this function is not suitable, it need report failure info to upper layer.
-int32_t CWelsDecoder::InitDecoder (void) {
+int32_t CWelsDecoder::InitDecoder (const bool bParseOnly) {
 
   WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::init_decoder(), openh264 codec version = %s",
            VERSION_NUMBER);
 
+  if (m_pDecContext) //free
+    UninitDecoder();
   m_pDecContext	= (PWelsDecoderContext)WelsMalloc (sizeof (SWelsDecoderContext), "m_pDecContext");
   if (NULL == m_pDecContext)
     return cmMallocMemeError;
 
-  return WelsInitDecoder (m_pDecContext, &m_pWelsTrace->m_sLogCtx);
+  return WelsInitDecoder (m_pDecContext, bParseOnly, &m_pWelsTrace->m_sLogCtx);
 }
 
 /*
@@ -422,7 +424,7 @@
   m_pDecContext->iFeedbackTidInAu             = -1; //initialize
 
   WelsDecodeBs (m_pDecContext, kpSrc, kiSrcLen, ppDst,
-                pDstInfo); //iErrorCode has been modified in this function
+                pDstInfo, NULL); //iErrorCode has been modified in this function
   m_pDecContext->bInstantDecFlag = false; //reset no-delay flag
   if (m_pDecContext->iErrorCode) {
     EWelsNalUnitType eNalType =
@@ -500,7 +502,30 @@
 DECODING_STATE CWelsDecoder::DecodeParser (const unsigned char* kpSrc,
     const int kiSrcLen,
     SParserBsInfo* pDstInfo) {
-//TODO, add function here
+  if (CheckBsBuffer (m_pDecContext, kiSrcLen)) {
+    return dsOutOfMemory;
+  }
+  if (kiSrcLen > 0 && kpSrc != NULL) {
+#ifdef OUTPUT_BITSTREAM
+    if (m_pFBS) {
+      WelsFwrite (kpSrc, sizeof (unsigned char), kiSrcLen, m_pFBS);
+      WelsFflush (m_pFBS);
+    }
+#endif//OUTPUT_BIT_STREAM
+    m_pDecContext->bEndOfStreamFlag = false;
+  } else {
+    //For application MODE, the error detection should be added for safe.
+    //But for CONSOLE MODE, when decoding LAST AU, kiSrcLen==0 && kpSrc==NULL.
+    m_pDecContext->bEndOfStreamFlag = true;
+    m_pDecContext->bInstantDecFlag = true;
+  }
+
+  m_pDecContext->iErrorCode = dsErrorFree; //initialize at the starting of AU decoding.
+  m_pDecContext->pParserBsInfo = pDstInfo;
+  pDstInfo->iNalNum = 0;
+  pDstInfo->iSpsWidthInPixel = pDstInfo->iSpsHeightInPixel = 0;
+  WelsDecodeBs (m_pDecContext, kpSrc, kiSrcLen, NULL, NULL, pDstInfo);
+
   return (DECODING_STATE) m_pDecContext->iErrorCode;
 }
 
--- a/test/api/encode_decode_api_test.cpp
+++ b/test/api/encode_decode_api_test.cpp
@@ -5,6 +5,7 @@
 #include "BaseDecoderTest.h"
 #include "BaseEncoderTest.h"
 #include "wels_common_defs.h"
+#include "utils/HashFunctions.h"
 #include <string>
 #include <vector>
 using namespace WelsCommon;
@@ -69,6 +70,8 @@
 class EncodeDecodeTestBase : public ::testing::TestWithParam<EncodeDecodeFileParamBase>,
   public BaseEncoderTest, public BaseDecoderTest {
  public:
+  uint8_t iRandValue;
+ public:
   virtual void SetUp() {
     BaseEncoderTest::SetUp();
     BaseDecoderTest::SetUp();
@@ -103,6 +106,26 @@
 
 
   }
+  virtual void prepareEncDecParam (const EncodeDecodeFileParamBase EncDecFileParam) {
+    //for encoder
+    //I420: 1(Y) + 1/4(U) + 1/4(V)
+    int frameSize = EncDecFileParam.width * EncDecFileParam.height * 3 / 2;
+    buf_.SetLength (frameSize);
+    ASSERT_TRUE (buf_.Length() == (size_t)frameSize);
+    memset (&EncPic, 0, sizeof (SSourcePicture));
+    EncPic.iPicWidth = EncDecFileParam.width;
+    EncPic.iPicHeight = EncDecFileParam.height;
+    EncPic.iColorFormat = videoFormatI420;
+    EncPic.iStride[0] = EncPic.iPicWidth;
+    EncPic.iStride[1] = EncPic.iStride[2] = EncPic.iPicWidth >> 1;
+    EncPic.pData[0] = buf_.data();
+    EncPic.pData[1] = EncPic.pData[0] + EncDecFileParam.width * EncDecFileParam.height;
+    EncPic.pData[2] = EncPic.pData[1] + (EncDecFileParam.width * EncDecFileParam.height >> 2);
+    //for decoder
+    memset (&info, 0, sizeof (SFrameBSInfo));
+    //set a fixed random value
+    iRandValue = rand() % 256;
+  }
 
   virtual void encToDecData (const SFrameBSInfo& info, int& len) {
     len = 0;
@@ -1983,7 +2006,6 @@
   }
 }
 
-
 TEST_F (EncodeDecodeTestAPI, SetOptionEncParamExt) {
   int iWidth       = (((rand() % MAX_WIDTH) >> 1) + 16) << 1;
   int iHeight      = (((rand() % MAX_HEIGHT) >> 1) + 16) << 1;
@@ -2237,3 +2259,154 @@
 #endif
 
 }
+
+const uint32_t kiTotalLayer = 3; //DO NOT CHANGE!
+const uint32_t kiSliceNum = 2; //DO NOT CHANGE!
+const uint32_t kiWidth = 160; //DO NOT CHANGE!
+const uint32_t kiHeight = 96; //DO NOT CHANGE!
+const uint32_t kiFrameRate = 12; //DO NOT CHANGE!
+const uint32_t kiFrameNum = 100; //DO NOT CHANGE!
+const uint32_t kiMaxBsSize = 10000000; //DO NOT CHANGE!
+const char* pHashStr[] = { //DO NOT CHANGE!
+  "c58322f886a3ba958c6f60b46b98f67b5d860866",
+  "f2799e1e5f6e33c6274f4e1f6273c721475492d0",
+  "8f0fafeaa2746e04d42fb17104efb61c9dbd1a6f"
+};
+
+class DecodeParseAPI : public EncodeDecodeTestBase {
+ public:
+  void SetUp() {
+    SHA1Reset (&ctx_);
+    EncodeDecodeTestBase::SetUp();
+
+    if (decoder_)
+      decoder_->Uninitialize();
+    SDecodingParam decParam;
+    memset (&decParam, 0, sizeof (SDecodingParam));
+    decParam.eOutputColorFormat = videoFormatI420;
+    decParam.uiTargetDqLayer = UCHAR_MAX;
+    decParam.eEcActiveIdc = ERROR_CON_SLICE_COPY;
+    decParam.bParseOnly = true;
+    decParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT;
+
+    int rv = decoder_->Initialize (&decParam);
+    ASSERT_EQ (0, rv);
+    memset (&BsInfo_, 0, sizeof (SParserBsInfo));
+    BsInfo_.pDstBuff = NULL;
+    BsInfo_.pDstBuff = new unsigned char [kiMaxBsSize];
+    ASSERT_TRUE (BsInfo_.pDstBuff != NULL);
+    fYuv_ = fopen ("./res/CiscoVT2people_160x96_6fps.yuv", "rb");
+    ASSERT_TRUE (fYuv_ != NULL);
+    iWidth_ = kiWidth;
+    iHeight_ = kiHeight;
+  }
+  void TearDown() {
+    EncodeDecodeTestBase::TearDown();
+    if (BsInfo_.pDstBuff) {
+      delete[] BsInfo_.pDstBuff;
+      BsInfo_.pDstBuff = NULL;
+    }
+    fclose (fYuv_);
+  }
+
+  void prepareEncDecParam (const EncodeDecodeFileParamBase p) {
+    EncodeDecodeTestBase::prepareEncDecParam (p);
+    unsigned char* pTmpPtr = BsInfo_.pDstBuff; //store for restore
+    memset (&BsInfo_, 0, sizeof (SParserBsInfo));
+    BsInfo_.pDstBuff = pTmpPtr;
+  }
+
+  void EncodeOneFrame (int iIdx) {
+    int iFrameSize = iWidth_ * iHeight_ * 3 / 2;
+    int iSize = fread (buf_.data(), sizeof (char), iFrameSize, fYuv_);
+    if (feof (fYuv_) || iSize != iFrameSize) {
+      rewind (fYuv_);
+      iSize = fread (buf_.data(), sizeof (char), iFrameSize, fYuv_);
+      ASSERT_TRUE (iSize == iFrameSize);
+    }
+    int rv = encoder_->EncodeFrame (&EncPic, &info);
+    ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  }
+
+ protected:
+  SParserBsInfo BsInfo_;
+  FILE* fYuv_;
+  int iWidth_;
+  int iHeight_;
+  SHA1Context ctx_;
+};
+
+//#define DEBUG_FILE_SAVE
+TEST_F (DecodeParseAPI, ParseOnly_General) {
+  EncodeDecodeFileParamBase p;
+  p.width = iWidth_;
+  p.height = iHeight_;
+  p.frameRate = kiFrameRate;
+  p.numframes = kiFrameNum;
+  prepareParam (kiTotalLayer, kiSliceNum, p.width, p.height, p.frameRate);
+  param_.iSpatialLayerNum = kiTotalLayer;
+  encoder_->Uninitialize();
+  int rv = encoder_->InitializeExt (&param_);
+  ASSERT_TRUE (rv == 0);
+  int32_t iTraceLevel = WELS_LOG_QUIET;
+  encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel);
+  decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel);
+  uint32_t uiTargetLayerId = rand() % kiTotalLayer; //run only once
+#ifdef DEBUG_FILE_SAVE
+  FILE* fDec = fopen ("output.264", "wb");
+  FILE* fEnc = fopen ("enc.264", "wb");
+  FILE* fExtract = fopen ("extract.264", "wb");
+#endif
+  if (uiTargetLayerId < kiTotalLayer) { //should always be true
+    //Start for enc
+    int iLen = 0;
+    prepareEncDecParam (p);
+    int iFrame = 0;
+
+    while (iFrame < p.numframes) {
+      //encode
+      EncodeOneFrame (iFrame);
+      //extract target layer data
+      encToDecData (info, iLen);
+#ifdef DEBUG_FILE_SAVE
+      fwrite (info.sLayerInfo[0].pBsBuf, iLen, 1, fEnc);
+#endif
+      ExtractDidNal (&info, iLen, &m_SLostSim, uiTargetLayerId);
+#ifdef DEBUG_FILE_SAVE
+      fwrite (info.sLayerInfo[0].pBsBuf, iLen, 1, fExtract);
+#endif
+      //parseonly
+      //BsInfo_.pDstBuff = new unsigned char [1000000];
+      rv = decoder_->DecodeParser (info.sLayerInfo[0].pBsBuf, iLen, &BsInfo_);
+      EXPECT_TRUE (rv == 0);
+      EXPECT_TRUE (BsInfo_.iNalNum == 0);
+      rv = decoder_->DecodeParser (NULL, 0, &BsInfo_);
+      EXPECT_TRUE (rv == 0);
+      EXPECT_TRUE (BsInfo_.iNalNum != 0);
+      //get final output bs
+      iLen = 0;
+      int i = 0;
+      while (i < BsInfo_.iNalNum) {
+        iLen += BsInfo_.iNalLenInByte[i];
+        i++;
+      }
+#ifdef DEBUG_FILE_SAVE
+      fwrite (BsInfo_.pDstBuff, iLen, 1, fDec);
+#endif
+      SHA1Input (&ctx_, BsInfo_.pDstBuff, iLen);
+      iFrame++;
+    }
+    //calculate final SHA1 value
+    unsigned char digest[SHA_DIGEST_LENGTH];
+    SHA1Result (&ctx_, digest);
+    if (!HasFatalFailure()) {
+      CompareHash (digest, pHashStr[uiTargetLayerId]);
+    }
+  } //while
+#ifdef DEBUG_FILE_SAVE
+  fclose (fEnc);
+  fclose (fExtract);
+  fclose (fDec);
+#endif
+}
+