shithub: openh264

Download patch

ref: f6fb459a7f7a250a3b5dfdcac36ab7f9811e374d
parent: 25b723c4132f0cb5dcdb617b9517104913603585
author: huili2 <[email protected]>
date: Wed Sep 17 14:06:08 EDT 2014

add freely setoption for EC_idc and UT

--- a/codec/decoder/core/src/decoder.cpp
+++ b/codec/decoder/core/src/decoder.cpp
@@ -277,6 +277,7 @@
   // function pointers
   //initial MC function pointer--
   InitMcFunc (& (pCtx->sMcFunc), pCtx->uiCpuFlag);
+  InitErrorCon (pCtx);
 
   InitExpandPictureFunc (& (pCtx->sExpandPicFunc), pCtx->uiCpuFlag);
   AssignFuncPointerForRec (pCtx);
--- a/codec/decoder/core/src/decoder_core.cpp
+++ b/codec/decoder/core/src/decoder_core.cpp
@@ -1657,7 +1657,6 @@
       WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "sync picture resolution ext failed,  the error is %d", iErr);
       return iErr;
     }
-    InitErrorCon (pCtx); //Do EC initialization here, for sequence start
   }
 
 
@@ -1969,6 +1968,8 @@
         if (NeedErrorCon (pCtx)) {
           ImplementErrorCon (pCtx);
           pCtx->iTotalNumMbRec = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight;
+          pCtx->pDec->iSpsId = pCtx->pSps->iSpsId;
+          pCtx->pDec->iPpsId = pCtx->pPps->iPpsId;
         }
       }
 
@@ -2012,6 +2013,9 @@
       if (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;
+
         DecodeFrameConstruction (pCtx, ppDst, pDstInfo);
         if (pCtx->sLastNalHdrExt.sNalUnitHeader.uiNalRefIdc > 0) {
           pCtx->pPreviousDecodedPictureInDpb = pCtx->pDec; //save ECed pic for future use
--- a/codec/decoder/plus/src/welsDecoderExt.cpp
+++ b/codec/decoder/plus/src/welsDecoderExt.cpp
@@ -51,6 +51,7 @@
 //#include "macros.h"
 #include "decoder.h"
 #include "decoder_core.h"
+#include "error_concealment.h"
 
 extern "C" {
 #include "decoder_core.h"
@@ -263,10 +264,17 @@
 
     return cmResultSuccess;
   } else if (eOptID == DECODER_OPTION_ERROR_CON_IDC) { // Indicate error concealment status
-    WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING,
-             "CWelsDecoder::SetOption for ERROR_CON_IDC not permmited! Current eErrorConMethod = %d. Value can be set in Initialize() only!",
-             (int32_t) m_pDecContext->eErrorConMethod);
-    return cmInitParaError;
+    if (pOption == NULL)
+      return cmInitParaError;
+
+    iVal	= * ((int*)pOption);	// int value for error concealment idc
+    iVal = WELS_CLIP3 (iVal, (int32_t) ERROR_CON_DISABLE, (int32_t) ERROR_CON_SLICE_COPY);
+    m_pDecContext->eErrorConMethod = (ERROR_CON_IDC) iVal;
+    InitErrorCon (m_pDecContext);
+    WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO,
+             "CWelsDecoder::SetOption for ERROR_CON_IDC = %d.", iVal);
+
+    return cmResultSuccess;
   } else if (eOptID == DECODER_OPTION_TRACE_LEVEL) {
     if (m_pWelsTrace) {
       uint32_t level = * ((uint32_t*)pOption);
@@ -422,11 +430,17 @@
         m_pDecContext->iIgnoredErrorInfoPacketCount = 0;
       }
     }
-    return (DECODING_STATE)m_pDecContext->iErrorCode;
-  } else { //decoding correct, but may have ECed status
-    if (m_pDecContext->bDecErrorConedFlag) {
+    if ((m_pDecContext->eErrorConMethod != ERROR_CON_DISABLE) && (pDstInfo->iBufferStatus == 1)) {
+      //TODO after dec status updated
+      m_pDecContext->bDecErrorConedFlag = true;
       m_pDecContext->iErrorCode |= dsDataErrorConcealed;
-      return dsDataErrorConcealed;
+    }
+    return (DECODING_STATE) m_pDecContext->iErrorCode;
+  } else { //decoding correct, but may have ECed status
+    if (m_pDecContext->bDecErrorConedFlag) { //TODO after dec status updated
+      if (m_pDecContext->eErrorConMethod != ERROR_CON_DISABLE) //EC is on
+        m_pDecContext->iErrorCode |= dsDataErrorConcealed;
+      return (DECODING_STATE) m_pDecContext->iErrorCode;
     }
   }
 
--- a/test/api/encode_decode_api_test.cpp
+++ b/test/api/encode_decode_api_test.cpp
@@ -62,6 +62,14 @@
     }
   }
 
+  virtual void encToDecSliceData (const int iLayerNum, const int iSliceNum, const SFrameBSInfo& info, int& len) {
+    ASSERT_TRUE (iLayerNum < MAX_LAYER_NUM_OF_FRAME);
+    len = 0;
+    const SLayerBSInfo& layerInfo = info.sLayerInfo[iLayerNum];
+    if (iSliceNum < layerInfo.iNalCount)
+      len = layerInfo.pNalLengthInByte[iSliceNum];
+  }
+
  protected:
   SEncParamExt param_;
   BufferedData buf_;
@@ -739,3 +747,622 @@
 
 INSTANTIATE_TEST_CASE_P (EncodeDecodeTestBase, EncodeDecodeTestAPI,
                          ::testing::ValuesIn (kFileParamArray));
+
+TEST_P (EncodeDecodeTestAPI, SetOptionECIDC_GeneralSliceChange) {
+  uint32_t uiEcIdc;
+  uint32_t uiGet;
+  EncodeDecodeFileParamBase p = GetParam();
+  prepareParam (p.width, p.height, p.frameRate);
+  param_.sSpatialLayers[0].sSliceCfg.uiSliceMode = SM_FIXEDSLCNUM_SLICE;
+  param_.sSpatialLayers[0].sSliceCfg.sSliceArgument.uiSliceNum = p.slicenum;
+  encoder_->Uninitialize();
+  int rv = encoder_->InitializeExt (&param_);
+  ASSERT_TRUE (rv == cmResultSuccess);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_SLICE_COPY); //default value should be ERROR_CON_SLICE_COPY
+
+  uiEcIdc = 0;
+  decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, uiEcIdc);
+
+  //Start for enc/dec
+  int frameSize = p.width * p.height * 3 / 2;
+  buf_.SetLength (frameSize);
+  ASSERT_TRUE (buf_.Length() == (size_t)frameSize);
+  SFrameBSInfo info;
+  memset (&info, 0, sizeof (SFrameBSInfo));
+
+  SSourcePicture pic;
+  memset (&pic, 0, sizeof (SSourcePicture));
+  pic.iPicWidth = p.width;
+  pic.iPicHeight = p.height;
+  pic.iColorFormat = videoFormatI420;
+  pic.iStride[0] = pic.iPicWidth;
+  pic.iStride[1] = pic.iStride[2] = pic.iPicWidth >> 1;
+  pic.pData[0] = buf_.data();
+  pic.pData[1] = pic.pData[0] + p.width * p.height;
+  pic.pData[2] = pic.pData[1] + (p.width * p.height >> 2);
+  int32_t iTraceLevel = WELS_LOG_QUIET;
+  encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel);
+  decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel);
+  int iIdx = 0;
+  bool bVCLLoss = false;
+  int iPacketNum;
+  int len;
+  int iTotalSliceSize;
+
+  //enc/dec pictures
+  while (iIdx <= p.numframes) {
+    memset (buf_.data(), rand() % 256, frameSize);
+    rv = encoder_->EncodeFrame (&pic, &info);
+    ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+    //decoding after each encoding frame
+    len = 0;
+    iPacketNum = 0;
+    iTotalSliceSize = 0;
+    unsigned char* pData[3] = { NULL };
+    memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+    while (iPacketNum < info.sLayerInfo[0].iNalCount) {
+      encToDecSliceData (0, iPacketNum, info, len);
+      uiEcIdc = (ERROR_CON_IDC) (rand() % 2);
+      decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
+      decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+      EXPECT_EQ (uiGet, uiEcIdc);
+
+      bVCLLoss = rand() & 1; //loss or not
+      if (!bVCLLoss) { //not loss
+        rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf + iTotalSliceSize,
+                                     info.sLayerInfo[0].pNalLengthInByte[iPacketNum], pData, &dstBufInfo_);
+        if (uiEcIdc == ERROR_CON_DISABLE)
+         EXPECT_EQ (dstBufInfo_.iBufferStatus, 0);
+      }
+      //EC_IDC should not change till now
+      decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+      EXPECT_EQ (uiGet, uiEcIdc);
+      //Set again inside
+      uiEcIdc = (ERROR_CON_IDC) (rand() % 2);
+      decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
+      decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+      EXPECT_EQ (uiGet, uiEcIdc);
+
+      rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
+      //EXPECT_EQ (dstBufInfo_.iBufferStatus, 0);
+      if (uiEcIdc == ERROR_CON_DISABLE && rv != 0)
+        EXPECT_EQ (dstBufInfo_.iBufferStatus, 0);
+
+      //deal with next slice
+      iTotalSliceSize += len;
+      iPacketNum++;
+    } //while slice
+    iIdx++;
+  } //while frame
+}
+
+//This case contain 1 slice per picture
+//coding order:                 0   1   2   3   4   5   6   7
+//frame type:                   IDR P   P   P   P   P   P   P
+//EC_IDC:                       0   0   0   2   0   0   1   1
+//loss:                         N   Y   N   N   N   Y   Y   N
+
+TEST_F (EncodeDecodeTestAPI, SetOptionECIDC_SpecificFrameChange) {
+  uint32_t uiEcIdc;
+  uint32_t uiGet;
+  EncodeDecodeFileParamBase p = kFileParamArray[0];
+  prepareParam (p.width, p.height, p.frameRate);
+  param_.sSpatialLayers[0].sSliceCfg.uiSliceMode = SM_SINGLE_SLICE;
+  param_.sSpatialLayers[0].sSliceCfg.sSliceArgument.uiSliceNum = p.slicenum;
+  encoder_->Uninitialize();
+  int rv = encoder_->InitializeExt (&param_);
+  ASSERT_TRUE (rv == cmResultSuccess);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, (ERROR_CON_IDC) ERROR_CON_SLICE_COPY); //default value should be ERROR_CON_SLICE_COPY
+  int32_t iTraceLevel = WELS_LOG_QUIET;
+  encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel);
+  decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel);
+
+  //set EC=DISABLE
+  uiEcIdc = (uint32_t) (ERROR_CON_DISABLE);
+  decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, uiEcIdc);
+
+  //Start for enc/dec
+  int frameSize = p.width * p.height * 3 / 2;
+  buf_.SetLength (frameSize);
+  ASSERT_TRUE (buf_.Length() == (size_t)frameSize);
+  SFrameBSInfo info;
+  memset (&info, 0, sizeof (SFrameBSInfo));
+
+  SSourcePicture pic;
+  memset (&pic, 0, sizeof (SSourcePicture));
+  pic.iPicWidth = p.width;
+  pic.iPicHeight = p.height;
+  pic.iColorFormat = videoFormatI420;
+  pic.iStride[0] = pic.iPicWidth;
+  pic.iStride[1] = pic.iStride[2] = pic.iPicWidth >> 1;
+  pic.pData[0] = buf_.data();
+  pic.pData[1] = pic.pData[0] + p.width * p.height;
+  pic.pData[2] = pic.pData[1] + (p.width * p.height >> 2);
+  int iIdx = 0;
+  int len = 0;
+  unsigned char* pData[3] = { NULL };
+
+  //Frame 0: IDR, EC_IDC=DISABLE, loss = 0
+  memset (buf_.data(), rand() % 256, frameSize);
+  rv = encoder_->EncodeFrame (&pic, &info);
+  ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  encToDecData (info, len);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, (ERROR_CON_IDC) ERROR_CON_DISABLE);
+  pData[0] = pData[1] = pData[2] = 0;
+  memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+  rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
+  EXPECT_EQ (rv, 0);
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 0);
+  rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
+  EXPECT_EQ (rv, 0);
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 1);
+  iIdx++;
+
+  //Frame 1: P, EC_IDC=DISABLE, loss = 1
+  memset (buf_.data(), rand() % 256, frameSize);
+  rv = encoder_->EncodeFrame (&pic, &info);
+  ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  iIdx++;
+
+  //Frame 2: P, EC_IDC=DISABLE, loss = 0
+  memset (buf_.data(), rand() % 256, frameSize);
+  rv = encoder_->EncodeFrame (&pic, &info);
+  ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  encToDecData (info, len);
+  pData[0] = pData[1] = pData[2] = 0;
+  memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_DISABLE);
+  rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
+  EXPECT_EQ (rv, 0); //parse correct
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //no output
+  rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
+  EXPECT_TRUE (rv != 0); //construction error due to data loss
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //no output due to EC DISABLE
+  iIdx++;
+
+  //set EC=SLICE_COPY
+  uiEcIdc = (uint32_t) (ERROR_CON_SLICE_COPY);
+  decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, uiEcIdc);
+  //Frame 3: P, EC_IDC=SLICE_COPY, loss = 0
+  memset (buf_.data(), rand() % 256, frameSize);
+  rv = encoder_->EncodeFrame (&pic, &info);
+  ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  encToDecData (info, len);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_SLICE_COPY);
+  pData[0] = pData[1] = pData[2] = 0;
+  memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+  rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
+  EXPECT_EQ (rv, 0); //parse correct
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //no output
+  rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
+  EXPECT_TRUE (rv != 0); //construction error due to data loss
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 1);
+  iIdx++;
+
+  //set EC=DISABLE
+  uiEcIdc = (uint32_t) (ERROR_CON_DISABLE);
+  decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, uiEcIdc);
+  //Frame 4: P, EC_IDC=DISABLE, loss = 0
+  memset (buf_.data(), rand() % 256, frameSize);
+  rv = encoder_->EncodeFrame (&pic, &info);
+  ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  encToDecData (info, len);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_DISABLE);
+  pData[0] = pData[1] = pData[2] = 0;
+  memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+  rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
+  EXPECT_EQ (rv, 0); //parse correct
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //no output
+  rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
+  if (rv == 0) //TODO: should depend on if ref-frame is OK.
+    EXPECT_EQ (dstBufInfo_.iBufferStatus, 1);
+  else
+    EXPECT_EQ (dstBufInfo_.iBufferStatus, 0);
+  iIdx++;
+
+  //Frame 5: P, EC_IDC=DISABLE, loss = 1
+  memset (buf_.data(), rand() % 256, frameSize);
+  rv = encoder_->EncodeFrame (&pic, &info);
+  ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  iIdx++;
+
+  //set EC=FRAME_COPY
+  uiEcIdc = (uint32_t) (ERROR_CON_FRAME_COPY);
+  decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, uiEcIdc);
+  //Frame 6: P, EC_IDC=FRAME_COPY, loss = 1
+  memset (buf_.data(), rand() % 256, frameSize);
+  rv = encoder_->EncodeFrame (&pic, &info);
+  ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  EXPECT_EQ (uiGet, uiEcIdc);
+  iIdx++;
+
+  //Frame 7: P, EC_IDC=FRAME_COPY, loss = 0
+  memset (buf_.data(), rand() % 256, frameSize);
+  rv = encoder_->EncodeFrame (&pic, &info);
+  ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  encToDecData (info, len);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_FRAME_COPY);
+  pData[0] = pData[1] = pData[2] = 0;
+  memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+  rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
+  EXPECT_TRUE (rv != 0); //parse correct, but previous decoding error, ECed
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //no output
+  rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
+  EXPECT_TRUE (rv != 0); //not sure if previous data drop would be detected in construction
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 1);
+  iIdx++;
+
+}
+
+//This case contain 2 slices per picture for IDR loss
+//coding order:                 0   1   2   3   4
+//frame type                    IDR P   P   P   P
+//EC_IDC                        2   2   0   1   0
+//loss (2 slice: 1,2):          2   0   0   1   0
+
+TEST_F (EncodeDecodeTestAPI, SetOptionECIDC_SpecificSliceChange_IDRLoss) {
+  uint32_t uiEcIdc;
+  uint32_t uiGet;
+  EncodeDecodeFileParamBase p = kFileParamArray[0];
+  prepareParam (p.width, p.height, p.frameRate);
+  param_.sSpatialLayers[0].sSliceCfg.uiSliceMode = SM_FIXEDSLCNUM_SLICE;
+  param_.sSpatialLayers[0].sSliceCfg.sSliceArgument.uiSliceNum = 2;
+  encoder_->Uninitialize();
+  int rv = encoder_->InitializeExt (&param_);
+  ASSERT_TRUE (rv == cmResultSuccess);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_SLICE_COPY); //default value should be ERROR_CON_SLICE_COPY
+  int32_t iTraceLevel = WELS_LOG_QUIET;
+  encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel);
+  decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel);
+
+  //Start for enc/dec
+  int frameSize = p.width * p.height * 3 / 2;
+  buf_.SetLength (frameSize);
+  ASSERT_TRUE (buf_.Length() == (size_t)frameSize);
+  SFrameBSInfo info;
+  memset (&info, 0, sizeof (SFrameBSInfo));
+
+  SSourcePicture pic;
+  memset (&pic, 0, sizeof (SSourcePicture));
+  pic.iPicWidth = p.width;
+  pic.iPicHeight = p.height;
+  pic.iColorFormat = videoFormatI420;
+  pic.iStride[0] = pic.iPicWidth;
+  pic.iStride[1] = pic.iStride[2] = pic.iPicWidth >> 1;
+  pic.pData[0] = buf_.data();
+  pic.pData[1] = pic.pData[0] + p.width * p.height;
+  pic.pData[2] = pic.pData[1] + (p.width * p.height >> 2);
+  int iIdx = 0;
+  int len = 0;
+  unsigned char* pData[3] = { NULL };
+  int iTotalSliceSize = 0;
+
+  //Frame 0: IDR, EC_IDC=2, loss = 2
+  memset (buf_.data(), rand() % 256, frameSize);
+  rv = encoder_->EncodeFrame (&pic, &info);
+  ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  iTotalSliceSize = 0;
+  encToDecSliceData (0, 0, info, len); //SPS
+  iTotalSliceSize = len;
+  encToDecSliceData (0, 1, info, len); //PPS
+  iTotalSliceSize += len;
+  encToDecSliceData (1, 0, info, len); //first slice
+  iTotalSliceSize += len;
+  //second slice loss
+  pData[0] = pData[1] = pData[2] = 0;
+  memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_SLICE_COPY);
+  rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, iTotalSliceSize, pData, &dstBufInfo_);
+  EXPECT_EQ (rv, 0); //parse correct
+  rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
+  EXPECT_EQ (rv, 0); //parse correct
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //slice incomplete, no output
+  iIdx++;
+
+  //Frame 1: P, EC_IDC=2, loss = 0
+  //will clean SPS/PPS status
+  memset (buf_.data(), rand() % 256, frameSize);
+  rv = encoder_->EncodeFrame (&pic, &info);
+  ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  encToDecData (info, len); //all slice together
+  pData[0] = pData[1] = pData[2] = 0;
+  memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_SLICE_COPY);
+  rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
+  EXPECT_TRUE (rv & 32); //parse correct, but reconstruct ECed
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 1); //ECed output for frame 0
+  rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //ECed status, reconstruction current frame 1
+  EXPECT_TRUE (rv & 32); //decoder ECed status
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 1); //ECed output for frame 1
+  iIdx++;
+
+  //set EC=DISABLE
+  uiEcIdc = (uint32_t) (ERROR_CON_DISABLE);
+  decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, uiEcIdc);
+  //Frame 2: P, EC_IDC=0, loss = 0
+  /////will clean SPS/PPS status
+  memset (buf_.data(), rand() % 256, frameSize);
+  rv = encoder_->EncodeFrame (&pic, &info);
+  ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  encToDecData (info, len); //all slice together
+  pData[0] = pData[1] = pData[2] = 0;
+  memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_DISABLE);
+  rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
+  EXPECT_EQ (rv, 0); //parse correct
+  rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
+  if (rv == 0) //TODO: should depend on if ref-frame is OK.
+    EXPECT_EQ (dstBufInfo_.iBufferStatus, 1);
+  else
+    EXPECT_EQ (dstBufInfo_.iBufferStatus, 0);
+  iIdx++;
+
+  //set EC=SLICE_COPY
+  uiEcIdc = (uint32_t) (ERROR_CON_FRAME_COPY);
+  decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, uiEcIdc);
+  //Frame 3: P, EC_IDC=2, loss = 1
+  memset (buf_.data(), rand() % 256, frameSize);
+  rv = encoder_->EncodeFrame (&pic, &info);
+  ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  encToDecSliceData (0, 0, info, iTotalSliceSize); //slice 1 lost
+  encToDecSliceData (0, 1, info, len); //slice 2
+  pData[0] = pData[1] = pData[2] = 0;
+  memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_FRAME_COPY);
+  rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf + iTotalSliceSize, len, pData, &dstBufInfo_);
+  EXPECT_TRUE (rv & 32);
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 0);
+  rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
+  EXPECT_TRUE (rv & 32);
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //slice loss
+  iIdx++;
+
+  //set EC=DISABLE
+  uiEcIdc = (uint32_t) (ERROR_CON_DISABLE);
+  decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, uiEcIdc);
+  //Frame 4: P, EC_IDC=0, loss = 0
+  memset (buf_.data(), rand() % 256, frameSize);
+  rv = encoder_->EncodeFrame (&pic, &info);
+  ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  encToDecData (info, len); //all slice
+  pData[0] = pData[1] = pData[2] = 0;
+  memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_DISABLE);
+  rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
+  EXPECT_TRUE (rv != 0);
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //output previous pic
+  rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
+  EXPECT_TRUE (rv != 0);
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //output previous pic
+  iIdx++;
+
+}
+
+
+
+//This case contain 2 slices per picture for no IDR loss
+//coding order:                 0   1   2   3   4   5
+//frame type                    IDR P   P   P   P   IDR
+//EC_IDC                        0   2   0   2   0   ^2^
+//loss (2 slice: 1,2):          0   0   1   2   0   0
+
+TEST_F (EncodeDecodeTestAPI, SetOptionECIDC_SpecificSliceChange_IDRNoLoss) {
+  uint32_t uiEcIdc;
+  uint32_t uiGet;
+  EncodeDecodeFileParamBase p = kFileParamArray[0];
+  prepareParam (p.width, p.height, p.frameRate);
+  param_.sSpatialLayers[0].sSliceCfg.uiSliceMode = SM_FIXEDSLCNUM_SLICE;
+  param_.sSpatialLayers[0].sSliceCfg.sSliceArgument.uiSliceNum = 2;
+  encoder_->Uninitialize();
+  int rv = encoder_->InitializeExt (&param_);
+  ASSERT_TRUE (rv == cmResultSuccess);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_SLICE_COPY); //default value should be ERROR_CON_SLICE_COPY
+  int32_t iTraceLevel = WELS_LOG_QUIET;
+  encoder_->SetOption (ENCODER_OPTION_TRACE_LEVEL, &iTraceLevel);
+  decoder_->SetOption (DECODER_OPTION_TRACE_LEVEL, &iTraceLevel);
+
+  //Start for enc/dec
+  int frameSize = p.width * p.height * 3 / 2;
+  buf_.SetLength (frameSize);
+  ASSERT_TRUE (buf_.Length() == (size_t)frameSize);
+  SFrameBSInfo info;
+  memset (&info, 0, sizeof (SFrameBSInfo));
+
+  SSourcePicture pic;
+  memset (&pic, 0, sizeof (SSourcePicture));
+  pic.iPicWidth = p.width;
+  pic.iPicHeight = p.height;
+  pic.iColorFormat = videoFormatI420;
+  pic.iStride[0] = pic.iPicWidth;
+  pic.iStride[1] = pic.iStride[2] = pic.iPicWidth >> 1;
+  pic.pData[0] = buf_.data();
+  pic.pData[1] = pic.pData[0] + p.width * p.height;
+  pic.pData[2] = pic.pData[1] + (p.width * p.height >> 2);
+  int iIdx = 0;
+  int len = 0;
+  unsigned char* pData[3] = { NULL };
+  int iTotalSliceSize = 0;
+
+  //set EC=DISABLE
+  uiEcIdc = (uint32_t) (ERROR_CON_DISABLE);
+  decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, uiEcIdc);
+  //Frame 0: IDR, EC_IDC=0, loss = 0
+  //Expected result: all OK, 2nd Output
+  memset (buf_.data(), rand() % 256, frameSize);
+  rv = encoder_->EncodeFrame (&pic, &info);
+  ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  encToDecData (info, len); //all slice
+  pData[0] = pData[1] = pData[2] = 0;
+  memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_DISABLE);
+  rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
+  EXPECT_EQ (rv, 0); //parse correct
+  rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
+  EXPECT_EQ (rv, 0); //parse correct
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 1); //output frame 0
+  iIdx++;
+
+  //Frame 1: P, EC_IDC=0, loss = 0
+  //Expected result: all OK, 2nd Output
+  memset (buf_.data(), rand() % 256, frameSize);
+  rv = encoder_->EncodeFrame (&pic, &info);
+  ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  encToDecData (info, len); //all slice together
+  pData[0] = pData[1] = pData[2] = 0;
+  memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_DISABLE);
+  rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
+  EXPECT_EQ (rv, 0); //parse correct
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //ECed output for frame 0
+  rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction current frame 1
+  EXPECT_EQ (rv, 0); //parse correct
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 1); //ECed output for frame 1
+  iIdx++;
+
+  //Frame 2: P, EC_IDC=0, loss = 1
+  //Expected result: all OK, no Output
+  memset (buf_.data(), rand() % 256, frameSize);
+  rv = encoder_->EncodeFrame (&pic, &info);
+  ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  encToDecSliceData (0, 0, info, iTotalSliceSize); // slice 1 lost
+  encToDecSliceData (0, 1, info, len); // slice 2 only
+  pData[0] = pData[1] = pData[2] = 0;
+  memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_DISABLE);
+  rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf + iTotalSliceSize, len, pData, &dstBufInfo_);
+  EXPECT_EQ (rv, 0); //parse correct
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 0);
+  rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
+  EXPECT_EQ (rv, 0); //parse correct
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 0);
+  iIdx++;
+
+  //set EC=SLICE_COPY
+  uiEcIdc = (uint32_t) (ERROR_CON_SLICE_COPY);
+  decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, uiEcIdc);
+  //Frame 3: P, EC_IDC=2, loss = 2
+  //Expected result: neither OK, 1st Output
+  memset (buf_.data(), rand() % 256, frameSize);
+  rv = encoder_->EncodeFrame (&pic, &info);
+  ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  encToDecSliceData (0, 0, info, len); //slice 1 only
+  pData[0] = pData[1] = pData[2] = 0;
+  memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_SLICE_COPY);
+  rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
+  EXPECT_TRUE (rv & 32); //ECed
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 1); //slice loss but ECed output Frame 2
+  rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction
+  EXPECT_TRUE (rv & 32);
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //slice loss
+  iIdx++;
+
+  //set EC=DISABLE
+  uiEcIdc = (uint32_t) (ERROR_CON_DISABLE);
+  decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, uiEcIdc);
+  //Frame 4: P, EC_IDC=0, loss = 0
+  //Expected result: depends on DecodeFrame2 result. If OK, output; else ,no output
+  memset (buf_.data(), rand() % 256, frameSize);
+  rv = encoder_->EncodeFrame (&pic, &info);
+  ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  encToDecData (info, len); //all slice
+  pData[0] = pData[1] = pData[2] = 0;
+  memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, (uint32_t) ERROR_CON_DISABLE);
+  rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, len, pData, &dstBufInfo_);
+  EXPECT_TRUE (rv != 0); //previous slice not outputted, will return error due to incomplete frame
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //output previous pic
+  rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction,
+  //not sure if current frame can be correctly decoded
+  if (rv == 0)
+    EXPECT_EQ (dstBufInfo_.iBufferStatus, 1); //output previous pic
+  else
+    EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //output previous pic
+  iIdx++;
+
+  //Frame 5: IDR, EC_IDC=2->0, loss = 0
+  //Expected result: depends on DecodeFrame2 result. If OK, output; else ,no output
+  int32_t iIDRPeriod = 1;
+  encoder_->SetOption (ENCODER_OPTION_IDR_INTERVAL, &iIDRPeriod);
+  memset (buf_.data(), rand() % 256, frameSize);
+  rv = encoder_->EncodeFrame (&pic, &info);
+  ASSERT_TRUE (rv == cmResultSuccess || rv == cmUnkonwReason);
+  EXPECT_TRUE (info.eFrameType == videoFrameTypeIDR);
+  encToDecSliceData (0, 0, info, len); //SPS
+  iTotalSliceSize = len;
+  encToDecSliceData (0, 1, info, len); //PPS
+  iTotalSliceSize += len;
+  encToDecSliceData (1, 0, info, len); //slice 1
+  iTotalSliceSize += len;
+  //set EC=SLICE_COPY for slice 1
+  uiEcIdc = (uint32_t) (ERROR_CON_SLICE_COPY);
+  decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, uiEcIdc);
+  pData[0] = pData[1] = pData[2] = 0;
+  memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+  rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf, iTotalSliceSize, pData, &dstBufInfo_);
+  EXPECT_TRUE (rv != 0); //TODO: should be correct, now ECed status will return error
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //frame incomplete
+  rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction,
+  EXPECT_TRUE (rv != 0); //TODO: as above
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //output previous pic
+  //set EC=DISABLE for slice 2
+  encToDecSliceData (1, 1, info, len); //slice 1
+  uiEcIdc = (int) (ERROR_CON_DISABLE);
+  decoder_->SetOption (DECODER_OPTION_ERROR_CON_IDC, &uiEcIdc);
+  decoder_->GetOption (DECODER_OPTION_ERROR_CON_IDC, &uiGet);
+  EXPECT_EQ (uiGet, uiEcIdc);
+  pData[0] = pData[1] = pData[2] = 0;
+  memset (&dstBufInfo_, 0, sizeof (SBufferInfo));
+  rv = decoder_->DecodeFrame2 (info.sLayerInfo[0].pBsBuf + iTotalSliceSize, len, pData, &dstBufInfo_);
+  EXPECT_EQ (rv, 0); //Parse correct under no EC
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 0); //frame incomplete
+  rv = decoder_->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); //reconstruction,
+  EXPECT_EQ (rv, 0); //Parse correct under no EC
+  EXPECT_EQ (dstBufInfo_.iBufferStatus, 1); //output previous pic
+  iIdx++;
+
+}
+