#include <gtest/gtest.h>

#include "codec_def.h"
#include "codec_app_def.h"
#include "codec_api.h"
#include "error_code.h"
#include "wels_common_basis.h"
#include "memory_align.h"
#include "ls_defines.h"

using namespace WelsDec;
#define BUF_SIZE 100
//payload size exclude 6 bytes: 0001, nal type and final '\0'
#define PAYLOAD_SIZE (BUF_SIZE - 6)
class DecoderInterfaceTest : public ::testing::Test {
 public:
  virtual void SetUp() {
    int rv = WelsCreateDecoder (&m_pDec);
    ASSERT_EQ (0, rv);
    ASSERT_TRUE (m_pDec != NULL);
  }

  virtual void TearDown() {
    if (m_pDec) {
      WelsDestroyDecoder (m_pDec);
    }
  }
  //Init members
  int32_t Init();
  //Init valid members
  int32_t ValidInit();
  //Uninit members
  void Uninit();
  //Mock input data for test
  void MockPacketType (const EWelsNalUnitType eNalUnitType, const int iPacketLength);
  //Decoder real bitstream
  void DecoderBs (const char* sFileName);
  //Test Initialize/Uninitialize
  void TestInitUninit();
  //Test parse only API
  void TestParseOnlyAPI();
  //DECODER_OPTION_END_OF_STREAM
  void TestEndOfStream();
  //DECODER_OPTION_VCL_NAL
  void TestVclNal();
  //DECODER_OPTION_TEMPORAL_ID
  void TestTemporalId();
  //DECODER_OPTION_FRAME_NUM
  void TestFrameNum();
  //DECODER_OPTION_IDR_PIC_ID
  void TestIdrPicId();
  //DECODER_OPTION_LTR_MARKING_FLAG
  void TestLtrMarkingFlag();
  //DECODER_OPTION_LTR_MARKED_FRAME_NUM
  void TestLtrMarkedFrameNum();
  //DECODER_OPTION_ERROR_CON_IDC
  void TestErrorConIdc();
  //DECODER_OPTION_TRACE_LEVEL
  void TestTraceLevel();
  //DECODER_OPTION_TRACE_CALLBACK
  void TestTraceCallback();
  //DECODER_OPTION_TRACE_CALLBACK_CONTEXT
  void TestTraceCallbackContext();
  //DECODER_OPTION_GET_DECODER_STATICTIS
  void TestGetDecStatistics();
  //DECODER_OPTION_GET_SAR_INFO
  void TestGetDecSarInfo();
  //Additional test on correctness of vui in subset sps
  void TestVuiInSubsetSps();
  //Do whole tests here
  void DecoderInterfaceAll();


 public:
  ISVCDecoder* m_pDec;
  SDecodingParam m_sDecParam;
  SBufferInfo m_sBufferInfo;
  SParserBsInfo m_sParserBsInfo;
  uint8_t* m_pData[3];
  unsigned char m_szBuffer[BUF_SIZE]; //for mocking packet
  int m_iBufLength; //record the valid data in m_szBuffer
};

//Init members
int32_t DecoderInterfaceTest::Init() {
  memset (&m_sBufferInfo, 0, sizeof (SBufferInfo));
  memset (&m_sParserBsInfo, 0, sizeof (SParserBsInfo));
  memset (&m_sDecParam, 0, sizeof (SDecodingParam));
  m_sDecParam.pFileNameRestructed = NULL;
  m_sDecParam.uiCpuLoad = rand() % 100;
  m_sDecParam.uiTargetDqLayer = rand() % 100;
  m_sDecParam.eEcActiveIdc = (ERROR_CON_IDC) (rand() & 7);
  m_sDecParam.sVideoProperty.size = sizeof (SVideoProperty);
  m_sDecParam.sVideoProperty.eVideoBsType = (VIDEO_BITSTREAM_TYPE) (rand() % 2);

  m_pData[0] = m_pData[1] = m_pData[2] = NULL;
  m_szBuffer[0] = m_szBuffer[1] = m_szBuffer[2] = 0;
  m_szBuffer[3] = 1;
  m_iBufLength = 4;
  CM_RETURN eRet = (CM_RETURN) m_pDec->Initialize (&m_sDecParam);
  EXPECT_EQ (eRet, cmResultSuccess);
  return (int32_t)eRet;
}

int32_t DecoderInterfaceTest::ValidInit() {
  memset (&m_sBufferInfo, 0, sizeof (SBufferInfo));
  memset (&m_sDecParam, 0, sizeof (SDecodingParam));
  m_sDecParam.pFileNameRestructed = NULL;
  m_sDecParam.uiCpuLoad = 1;
  m_sDecParam.uiTargetDqLayer = 1;
  m_sDecParam.eEcActiveIdc = (ERROR_CON_IDC) (rand() & 7);
  m_sDecParam.sVideoProperty.size = sizeof (SVideoProperty);
  m_sDecParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT;

  m_pData[0] = m_pData[1] = m_pData[2] = NULL;
  m_szBuffer[0] = m_szBuffer[1] = m_szBuffer[2] = 0;
  m_szBuffer[3] = 1;
  m_iBufLength = 4;
  CM_RETURN eRet = (CM_RETURN) m_pDec->Initialize (&m_sDecParam);
  EXPECT_EQ (eRet, cmResultSuccess);
  return (int32_t)eRet;
}

void DecoderInterfaceTest::Uninit() {
  if (m_pDec) {
    CM_RETURN eRet = (CM_RETURN) m_pDec->Uninitialize();
    ASSERT_EQ (eRet, cmResultSuccess);
  }
  memset (&m_sDecParam, 0, sizeof (SDecodingParam));
  memset (&m_sParserBsInfo, 0, sizeof (SParserBsInfo));
  memset (&m_sBufferInfo, 0, sizeof (SBufferInfo));
  m_pData[0] = m_pData[1] = m_pData[2] = NULL;
  m_iBufLength = 0;
}

void DecoderInterfaceTest::DecoderBs (const char* sFileName) {

  uint8_t* pBuf = NULL;
  int32_t iBufPos = 0;
  int32_t iFileSize;
  int32_t i = 0;
  int32_t iSliceSize;
  int32_t iEndOfStreamFlag = 0;
  FILE* pH264File;
  uint8_t uiStartCode[4] = {0, 0, 0, 1};

#if defined(ANDROID_NDK)
  std::string filename = std::string ("/sdcard/") + sFileName;
  ASSERT_TRUE ((pH264File = fopen (filename.c_str(), "rb")) != NULL);
#else
  ASSERT_TRUE ((pH264File = fopen (sFileName, "rb")) != NULL);
#endif
  fseek (pH264File, 0L, SEEK_END);
  iFileSize = (int32_t) ftell (pH264File);
  fseek (pH264File, 0L, SEEK_SET);
  pBuf = new uint8_t[iFileSize + 4];
  ASSERT_EQ (fread (pBuf, 1, iFileSize, pH264File), (unsigned int) iFileSize);
  memcpy (pBuf + iFileSize, &uiStartCode[0], 4); //confirmed_safe_unsafe_usage
  while (true) {
    if (iBufPos >= iFileSize) {
      iEndOfStreamFlag = true;
      if (iEndOfStreamFlag)
        m_pDec->SetOption (DECODER_OPTION_END_OF_STREAM, (void*)&iEndOfStreamFlag);
      break;
    }
    for (i = 0; i < iFileSize; i++) {
      if ((pBuf[iBufPos + i] == 0 && pBuf[iBufPos + i + 1] == 0 && pBuf[iBufPos + i + 2] == 0 && pBuf[iBufPos + i + 3] == 1
           && i > 0)) {
        break;
      }
    }
    iSliceSize = i;
    m_pDec->DecodeFrame2 (pBuf + iBufPos, iSliceSize, m_pData, &m_sBufferInfo);
    m_pDec->DecodeFrame2 (NULL, 0, m_pData, &m_sBufferInfo);
    iBufPos += iSliceSize;
  }

  fclose (pH264File);
  if (pBuf) {
    delete[] pBuf;
    pBuf = NULL;
  }


}
//Mock input data for test
void DecoderInterfaceTest::MockPacketType (const EWelsNalUnitType eNalUnitType, const int iPacketLength) {
  switch (eNalUnitType) {
  case NAL_UNIT_SEI:
    m_szBuffer[m_iBufLength++] = 6;
    break;
  case NAL_UNIT_SPS:
    m_szBuffer[m_iBufLength++] = 67;
    break;
  case NAL_UNIT_PPS:
    m_szBuffer[m_iBufLength++] = 68;
    break;
  case NAL_UNIT_SUBSET_SPS:
    m_szBuffer[m_iBufLength++] = 15;
    break;
  case NAL_UNIT_PREFIX:
    m_szBuffer[m_iBufLength++] = 14;
    break;
  case NAL_UNIT_CODED_SLICE:
    m_szBuffer[m_iBufLength++] = 61;
    break;
  case NAL_UNIT_CODED_SLICE_IDR:
    m_szBuffer[m_iBufLength++] = 65;
    break;
  default:
    m_szBuffer[m_iBufLength++] = 0; //NAL_UNIT_UNSPEC_0
    break;
  }
  int iAddLength = iPacketLength - 5; //excluding 0001 and type
  if (iAddLength > PAYLOAD_SIZE)
    iAddLength = PAYLOAD_SIZE;
  for (int i = 0; i < iAddLength; ++i) {
    m_szBuffer[m_iBufLength++] = rand() % 256;
  }
  m_szBuffer[m_iBufLength++] = '\0';

}

//Test Initialize/Uninitialize
void DecoderInterfaceTest::TestInitUninit() {
  int iOutput;
  CM_RETURN eRet;
  int32_t iRet = ERR_NONE;
  //No initialize, no GetOption can be done
  m_pDec->Uninitialize();
  for (int i = 0; i <= (int) DECODER_OPTION_TRACE_CALLBACK_CONTEXT; ++i) {
    eRet = (CM_RETURN) m_pDec->GetOption ((DECODER_OPTION) i, &iOutput);
    EXPECT_EQ (eRet, cmInitExpected);
  }
  //Initialize first, can get input color format
  iRet = Init();
  ASSERT_EQ (iRet, ERR_NONE);

  m_sDecParam.bParseOnly = false;
  eRet = (CM_RETURN)m_pDec->Initialize (&m_sDecParam);
  ASSERT_EQ (eRet, cmResultSuccess);

  eRet = (CM_RETURN) m_pDec->GetOption (DECODER_OPTION_END_OF_STREAM, &iOutput);
  EXPECT_EQ (eRet, cmResultSuccess);
  EXPECT_EQ (iOutput, 0);

  //Uninitialize, no GetOption can be done
  m_pDec->Uninitialize();
  iOutput = 21;
  for (int i = 0; i <= (int) DECODER_OPTION_TRACE_CALLBACK_CONTEXT; ++i) {
    eRet = (CM_RETURN) m_pDec->GetOption ((DECODER_OPTION) i, &iOutput);
    EXPECT_EQ (iOutput, 21);
    EXPECT_EQ (eRet, cmInitExpected);
  }
}

//Test parse only API
void DecoderInterfaceTest::TestParseOnlyAPI() {
  int iOutput;
  int iRet;

  m_pData[0] = m_pData[1] = m_pData[2] = NULL;
  m_szBuffer[0] = m_szBuffer[1] = m_szBuffer[2] = 0;
  m_szBuffer[3] = 1;
  m_iBufLength = 4;
  MockPacketType (NAL_UNIT_SPS, 12);

  m_pDec->Uninitialize();

  //test 1: bParseOnly = true; eEcActiveIdc = 0,1
  for (int iNum = 0; iNum < 2; ++iNum) { //loop for EC
    memset (&m_sBufferInfo, 0, sizeof (SBufferInfo));
    memset (&m_sParserBsInfo, 0, sizeof (SParserBsInfo));
    memset (&m_sDecParam, 0, sizeof (SDecodingParam));
    m_sDecParam.pFileNameRestructed = NULL;
    m_sDecParam.uiCpuLoad = rand() % 100;
    m_sDecParam.uiTargetDqLayer = -1;
    m_sDecParam.bParseOnly = true;
    m_sDecParam.eEcActiveIdc = (ERROR_CON_IDC) iNum;
    m_sDecParam.sVideoProperty.size = sizeof (SVideoProperty);
    m_sDecParam.sVideoProperty.eVideoBsType = (VIDEO_BITSTREAM_TYPE) (rand() % 2);

    iRet = m_pDec->Initialize (&m_sDecParam);
    ASSERT_EQ (iRet, (int32_t) cmResultSuccess);
    iRet = m_pDec->GetOption (DECODER_OPTION_ERROR_CON_IDC, &iOutput);
    EXPECT_EQ (iRet, (int32_t) cmResultSuccess);
    EXPECT_EQ (iOutput, (int32_t) ERROR_CON_DISABLE); //should be 0
    //call DecodeParser(), correct call
    iRet = (int32_t) m_pDec->DecodeParser (m_szBuffer, m_iBufLength, &m_sParserBsInfo);
    EXPECT_EQ (iRet, (int32_t) dsNoParamSets);
    iRet = m_pDec->GetOption (DECODER_OPTION_ERROR_CON_IDC, &iOutput);
    EXPECT_EQ (iRet, (int32_t) cmResultSuccess);
    EXPECT_EQ (iOutput, (int32_t) ERROR_CON_DISABLE); //should be 0
    //call DecodeFrame2(), incorrect call
    iRet = (int32_t) m_pDec->DecodeFrame2 (m_szBuffer, m_iBufLength, m_pData, &m_sBufferInfo);
    EXPECT_EQ (iRet, (int32_t) dsInvalidArgument);
    iRet = m_pDec->GetOption (DECODER_OPTION_ERROR_CON_IDC, &iOutput);
    EXPECT_EQ (iRet, (int32_t) cmResultSuccess);
    EXPECT_EQ (iOutput, (int32_t) ERROR_CON_DISABLE); //should be 0
    m_pDec->Uninitialize();
  }

  //test 2: bParseOnly = false; eEcActiveIdc = 0,1
  for (int iNum = 0; iNum < 2; ++iNum) { //loop for EC
    memset (&m_sBufferInfo, 0, sizeof (SBufferInfo));
    memset (&m_sParserBsInfo, 0, sizeof (SParserBsInfo));
    memset (&m_sDecParam, 0, sizeof (SDecodingParam));
    m_sDecParam.pFileNameRestructed = NULL;
    m_sDecParam.uiCpuLoad = rand() % 100;
    m_sDecParam.uiTargetDqLayer = -1;
    m_sDecParam.bParseOnly = false;
    m_sDecParam.eEcActiveIdc = (ERROR_CON_IDC) iNum;
    m_sDecParam.sVideoProperty.size = sizeof (SVideoProperty);
    m_sDecParam.sVideoProperty.eVideoBsType = (VIDEO_BITSTREAM_TYPE) (rand() % 2);

    iRet = m_pDec->Initialize (&m_sDecParam);
    ASSERT_EQ (iRet, (int32_t) cmResultSuccess);
    iRet = m_pDec->GetOption (DECODER_OPTION_ERROR_CON_IDC, &iOutput);
    EXPECT_EQ (iRet, (int32_t) cmResultSuccess);
    EXPECT_EQ (iOutput, iNum);
    //call DecodeParser(), incorrect call
    iRet = (int32_t) m_pDec->DecodeParser (m_szBuffer, m_iBufLength, &m_sParserBsInfo);
    EXPECT_EQ (iRet, (int32_t) dsInvalidArgument); //error call
    iRet = m_pDec->GetOption (DECODER_OPTION_ERROR_CON_IDC, &iOutput);
    EXPECT_EQ (iRet, (int32_t) cmResultSuccess);
    EXPECT_EQ (iOutput, iNum);
    //call DecodeFrame2(), correct call
    iRet = (int32_t) m_pDec->DecodeFrame2 (m_szBuffer, m_iBufLength, m_pData, &m_sBufferInfo);
    EXPECT_EQ (iRet, (int32_t) dsNoParamSets);
    iRet = m_pDec->GetOption (DECODER_OPTION_ERROR_CON_IDC, &iOutput);
    EXPECT_EQ (iRet, (int32_t) cmResultSuccess);
    EXPECT_EQ (iOutput, iNum);
    m_pDec->Uninitialize();
  }

}

//DECODER_OPTION_END_OF_STREAM
void DecoderInterfaceTest::TestEndOfStream() {
  int iTmp, iOut;
  CM_RETURN eRet;
  int32_t iRet = ERR_NONE;

  iRet = ValidInit();
  ASSERT_EQ (iRet, ERR_NONE);

  //invalid input
  eRet = (CM_RETURN) m_pDec->SetOption (DECODER_OPTION_END_OF_STREAM, NULL);
  EXPECT_EQ (eRet, cmInitParaError);

  //valid random input
  for (int i = 0; i < 10; ++i) {
    iTmp = rand();
    eRet = (CM_RETURN) m_pDec->SetOption (DECODER_OPTION_END_OF_STREAM, &iTmp);
    EXPECT_EQ (eRet, cmResultSuccess);
    eRet = (CM_RETURN) m_pDec->GetOption (DECODER_OPTION_END_OF_STREAM, &iOut);
    EXPECT_EQ (eRet, cmResultSuccess);
    EXPECT_EQ (iOut, iTmp != 0 ? 1 : 0);
  }

  //set false as input
  iTmp = false;
  eRet = (CM_RETURN) m_pDec->SetOption (DECODER_OPTION_END_OF_STREAM, &iTmp);
  EXPECT_EQ (eRet, cmResultSuccess);
  eRet = (CM_RETURN) m_pDec->GetOption (DECODER_OPTION_END_OF_STREAM, &iOut);
  EXPECT_EQ (eRet, cmResultSuccess);

  EXPECT_EQ (iOut, 0);

  //set true as input
  iTmp = true;
  eRet = (CM_RETURN) m_pDec->SetOption (DECODER_OPTION_END_OF_STREAM, &iTmp);
  EXPECT_EQ (eRet, cmResultSuccess);
  eRet = (CM_RETURN) m_pDec->GetOption (DECODER_OPTION_END_OF_STREAM, &iOut);
  EXPECT_EQ (eRet, cmResultSuccess);

  EXPECT_EQ (iOut, 1);

  //Mock data packet in
  //Test NULL data input for decoder, should be true for EOS
  eRet = (CM_RETURN) m_pDec->DecodeFrame2 (NULL, 0, m_pData, &m_sBufferInfo);
  EXPECT_EQ (eRet, 0); //decode should return OK
  eRet = (CM_RETURN) m_pDec->GetOption (DECODER_OPTION_END_OF_STREAM, &iOut);
  EXPECT_EQ (iOut, 1); //decoder should have EOS == true

  //Test valid data input for decoder, should be false for EOS
  MockPacketType (NAL_UNIT_UNSPEC_0, 50);
  eRet = (CM_RETURN) m_pDec->DecodeFrame2 (m_szBuffer, m_iBufLength, m_pData, &m_sBufferInfo);
  eRet = (CM_RETURN) m_pDec->GetOption (DECODER_OPTION_END_OF_STREAM, &iOut);
  EXPECT_EQ (iOut, 0); //decoder should have EOS == false
  //Test NULL data input for decoder, should be true for EOS
  eRet = (CM_RETURN) m_pDec->DecodeFrame2 (NULL, 0, m_pData, &m_sBufferInfo);
  eRet = (CM_RETURN) m_pDec->GetOption (DECODER_OPTION_END_OF_STREAM, &iOut);
  EXPECT_EQ (iOut, 1); //decoder should have EOS == true

  Uninit();
}


//DECODER_OPTION_VCL_NAL
//Here Test illegal bitstream input
//legal bitstream decoding test, please see api test
void DecoderInterfaceTest::TestVclNal() {
  int iTmp, iOut;
  CM_RETURN eRet;
  int32_t iRet = ERR_NONE;

  iRet = ValidInit();
  ASSERT_EQ (iRet, ERR_NONE);

  //Test SetOption
  //VclNal never supports SetOption
  iTmp = rand();
  eRet = (CM_RETURN) m_pDec->SetOption (DECODER_OPTION_VCL_NAL, &iTmp);
  EXPECT_EQ (eRet, cmInitParaError);

  //Test GetOption
  //invalid input
  eRet = (CM_RETURN) m_pDec->GetOption (DECODER_OPTION_VCL_NAL, NULL);
  EXPECT_EQ (eRet, cmInitParaError);

  //valid input without actual decoding
  eRet = (CM_RETURN) m_pDec->GetOption (DECODER_OPTION_VCL_NAL, &iOut);
  EXPECT_EQ (eRet, cmResultSuccess);
  EXPECT_EQ (iOut, FEEDBACK_NON_VCL_NAL);

  //valid input with decoding error
  MockPacketType (NAL_UNIT_CODED_SLICE_IDR, 50);
  m_pDec->DecodeFrame2 (m_szBuffer, m_iBufLength, m_pData, &m_sBufferInfo);
  eRet = (CM_RETURN) m_pDec->GetOption (DECODER_OPTION_VCL_NAL, &iOut);
  EXPECT_EQ (eRet, cmResultSuccess);
  EXPECT_EQ (iOut, FEEDBACK_UNKNOWN_NAL);
  m_pDec->DecodeFrame2 (NULL, 0, m_pData, &m_sBufferInfo);
  eRet = (CM_RETURN) m_pDec->GetOption (DECODER_OPTION_VCL_NAL, &iOut);
  EXPECT_EQ (eRet, cmResultSuccess);
  EXPECT_EQ (iOut, FEEDBACK_UNKNOWN_NAL);

  Uninit();
}

//DECODER_OPTION_TEMPORAL_ID
void DecoderInterfaceTest::TestTemporalId() {
  //TODO
}

//DECODER_OPTION_FRAME_NUM
void DecoderInterfaceTest::TestFrameNum() {
  //TODO
}

//DECODER_OPTION_IDR_PIC_ID
void DecoderInterfaceTest::TestIdrPicId() {
  //TODO
}

//DECODER_OPTION_LTR_MARKING_FLAG
void DecoderInterfaceTest::TestLtrMarkingFlag() {
  //TODO
}

//DECODER_OPTION_LTR_MARKED_FRAME_NUM
void DecoderInterfaceTest::TestLtrMarkedFrameNum() {
  //TODO
}

//DECODER_OPTION_ERROR_CON_IDC
void DecoderInterfaceTest::TestErrorConIdc() {
  int iTmp, iOut;
  CM_RETURN eRet;
  int32_t iRet = ERR_NONE;

  iRet = Init();
  ASSERT_EQ (iRet, ERR_NONE);

  //Test GetOption
  //invalid input
  eRet = (CM_RETURN) m_pDec->GetOption (DECODER_OPTION_ERROR_CON_IDC, NULL);
  EXPECT_EQ (eRet, cmInitParaError);

  //Test GetOption
  //valid input
  eRet = (CM_RETURN) m_pDec->GetOption (DECODER_OPTION_ERROR_CON_IDC, &iOut);
  EXPECT_EQ (eRet, cmResultSuccess);

  //Test SetOption
  iTmp = rand() & 7;
  eRet = (CM_RETURN) m_pDec->SetOption (DECODER_OPTION_ERROR_CON_IDC, &iTmp);
  EXPECT_EQ (eRet, cmResultSuccess);

  //Test GetOption
  eRet = (CM_RETURN) m_pDec->GetOption (DECODER_OPTION_ERROR_CON_IDC, &iOut);
  EXPECT_EQ (eRet, cmResultSuccess);
  EXPECT_EQ (iTmp, iOut);

  Uninit();

}

//DECODER_OPTION_TRACE_LEVEL
void DecoderInterfaceTest::TestTraceLevel() {
  //TODO
}

//DECODER_OPTION_TRACE_CALLBACK
void DecoderInterfaceTest::TestTraceCallback() {
  //TODO
}

//DECODER_OPTION_TRACE_CALLBACK_CONTEXT
void DecoderInterfaceTest::TestTraceCallbackContext() {
  //TODO
}

//DECODER_OPTION_GET_STATISTICS
void DecoderInterfaceTest::TestGetDecStatistics() {
  CM_RETURN eRet;
  int32_t iRet;
  SDecoderStatistics sDecStatic;
  int32_t iError = 0;

  iRet = ValidInit();
  ASSERT_EQ (iRet, ERR_NONE);
  //GetOption before decoding
  m_pDec->GetOption (DECODER_OPTION_GET_STATISTICS, &sDecStatic);
  EXPECT_EQ (0u, sDecStatic.uiDecodedFrameCount);
  EXPECT_TRUE (-1 == sDecStatic.iAvgLumaQp);
  // setoption not support,
  eRet = (CM_RETURN)m_pDec->SetOption (DECODER_OPTION_GET_STATISTICS, NULL);
  EXPECT_EQ (eRet, cmInitParaError);
  //EC on UT
  iError = 2;
  m_pDec->SetOption (DECODER_OPTION_ERROR_CON_IDC, &iError);
  //Decoder error bs
  DecoderBs ("res/Error_I_P.264");
  m_pDec->GetOption (DECODER_OPTION_GET_STATISTICS, &sDecStatic);
  EXPECT_EQ (65u, sDecStatic.uiAvgEcRatio);
  EXPECT_EQ (7u, sDecStatic.uiAvgEcPropRatio);
  EXPECT_EQ (5u, sDecStatic.uiDecodedFrameCount);
  EXPECT_EQ (288u, sDecStatic.uiHeight);
  EXPECT_EQ (1u, sDecStatic.uiIDRCorrectNum);
  EXPECT_EQ (3u, sDecStatic.uiResolutionChangeTimes);
  EXPECT_EQ (352u, sDecStatic.uiWidth);
  EXPECT_EQ (4u, sDecStatic.uiEcFrameNum);
  EXPECT_EQ (2u, sDecStatic.uiEcIDRNum);
  EXPECT_EQ (0u, sDecStatic.uiIDRLostNum);
  Uninit();

  //Decoder error bs when the first IDR lost
  iRet = ValidInit();
  ASSERT_EQ (iRet, ERR_NONE);
  iError = 2;
  m_pDec->SetOption (DECODER_OPTION_ERROR_CON_IDC, &iError);
  DecoderBs ("res/BA_MW_D_IDR_LOST.264");
  m_pDec->GetOption (DECODER_OPTION_GET_STATISTICS, &sDecStatic);
  EXPECT_EQ (88u, sDecStatic.uiAvgEcRatio);
  EXPECT_EQ (88u, sDecStatic.uiAvgEcPropRatio);
  EXPECT_EQ (97u, sDecStatic.uiDecodedFrameCount);
  EXPECT_EQ (144u, sDecStatic.uiHeight);
  EXPECT_EQ (3u, sDecStatic.uiIDRCorrectNum);
  EXPECT_EQ (0u, sDecStatic.uiEcIDRNum);
  EXPECT_EQ (1u, sDecStatic.uiResolutionChangeTimes);
  EXPECT_EQ (176u, sDecStatic.uiWidth);
  EXPECT_EQ (27u, sDecStatic.uiEcFrameNum);
  EXPECT_EQ (1u, sDecStatic.uiIDRLostNum);
  Uninit();

  //ecoder error bs when the first P lost
  iRet = ValidInit();
  ASSERT_EQ (iRet, ERR_NONE);

  iError = 2;
  m_pDec->SetOption (DECODER_OPTION_ERROR_CON_IDC, &iError);

  DecoderBs ("res/BA_MW_D_P_LOST.264");

  m_pDec->GetOption (DECODER_OPTION_GET_STATISTICS, &sDecStatic);
  EXPECT_EQ (85u, sDecStatic.uiAvgEcRatio);
  EXPECT_EQ (85u, sDecStatic.uiAvgEcPropRatio);
  EXPECT_EQ (99u, sDecStatic.uiDecodedFrameCount);
  EXPECT_EQ (144u, sDecStatic.uiHeight);
  EXPECT_EQ (4u, sDecStatic.uiIDRCorrectNum);
  EXPECT_EQ (0u, sDecStatic.uiEcIDRNum);
  EXPECT_EQ (1u, sDecStatic.uiResolutionChangeTimes);
  EXPECT_EQ (176u, sDecStatic.uiWidth);
  EXPECT_EQ (28u, sDecStatic.uiEcFrameNum);
  EXPECT_EQ (0u, sDecStatic.uiIDRLostNum);
  Uninit();
  //EC enable

  //EC Off UT just correc bitstream
  iRet = ValidInit();
  ASSERT_EQ (iRet, ERR_NONE);

  iError = 0;
  m_pDec->SetOption (DECODER_OPTION_ERROR_CON_IDC, &iError);
  DecoderBs ("res/test_vd_1d.264");

  m_pDec->GetOption (DECODER_OPTION_GET_STATISTICS, &sDecStatic);

  EXPECT_EQ (0u, sDecStatic.uiAvgEcRatio);
  EXPECT_EQ (0u, sDecStatic.uiAvgEcPropRatio);
  EXPECT_EQ (9u, sDecStatic.uiDecodedFrameCount);
  EXPECT_EQ (192u, sDecStatic.uiHeight);
  EXPECT_EQ (1u, sDecStatic.uiIDRCorrectNum);
  EXPECT_EQ (1u, sDecStatic.uiResolutionChangeTimes);
  EXPECT_EQ (320u, sDecStatic.uiWidth);
  EXPECT_EQ (0u, sDecStatic.uiEcFrameNum);
  EXPECT_EQ (0u, sDecStatic.uiIDRLostNum);
  Uninit();

}

//DECODER_OPTION_GET_SAR_INFO
void DecoderInterfaceTest::TestGetDecSarInfo() {
  CM_RETURN eRet;
  int32_t iRet;
  SVuiSarInfo sVuiSarInfo;

  iRet = ValidInit();
  ASSERT_EQ (iRet, ERR_NONE);
  //GetOption before decoding
  m_pDec->GetOption (DECODER_OPTION_GET_SAR_INFO, &sVuiSarInfo);
  EXPECT_EQ (0u, sVuiSarInfo.uiSarWidth);
  EXPECT_EQ (0u, sVuiSarInfo.uiSarHeight);
  EXPECT_EQ (sVuiSarInfo.bOverscanAppropriateFlag, false); // EXPECT_EQ does not like "false" as its first arg
  // setoption not support,
  eRet = (CM_RETURN)m_pDec->SetOption (DECODER_OPTION_GET_SAR_INFO, NULL);
  EXPECT_EQ (eRet, cmInitParaError);

  //Decoder specific bs
  DecoderBs ("res/SarVui.264");
  m_pDec->GetOption (DECODER_OPTION_GET_SAR_INFO, &sVuiSarInfo);
  EXPECT_EQ (80u, sVuiSarInfo.uiSarWidth);  //DO NOT MODIFY the data value
  EXPECT_EQ (33u, sVuiSarInfo.uiSarHeight); //DO NOT MODIFY the data value
  EXPECT_EQ (true, sVuiSarInfo.bOverscanAppropriateFlag); //DO NOT MODIFY the data value
  Uninit();
}

//DECODER_OPTION_GET_SAR_INFO, test Vui in subset sps
void DecoderInterfaceTest::TestVuiInSubsetSps() {
  int32_t iRet;
  SVuiSarInfo sVuiSarInfo;

  iRet = ValidInit();
  ASSERT_EQ (iRet, ERR_NONE);

  //GetOption before decoding
  m_pDec->GetOption (DECODER_OPTION_GET_SAR_INFO, &sVuiSarInfo);
  EXPECT_EQ (0u, sVuiSarInfo.uiSarWidth);
  EXPECT_EQ (0u, sVuiSarInfo.uiSarHeight);
  EXPECT_EQ (sVuiSarInfo.bOverscanAppropriateFlag, false);

  DecoderBs ("res/sps_subsetsps_bothVUI.264");
  m_pDec->GetOption (DECODER_OPTION_GET_SAR_INFO, &sVuiSarInfo);
  EXPECT_EQ (1u, sVuiSarInfo.uiSarWidth); //DO NOT MODIFY the data value
  EXPECT_EQ (1u, sVuiSarInfo.uiSarHeight); //DO NOT MODIFY the data value
  EXPECT_EQ (sVuiSarInfo.bOverscanAppropriateFlag, false); //DO NOT MODIFY the data value
  Uninit();
}

//TEST here for whole tests
TEST_F (DecoderInterfaceTest, DecoderInterfaceAll) {

  //Initialize Uninitialize
  TestInitUninit();
  //DECODER_OPTION_END_OF_STREAM
  TestEndOfStream();
  //DECODER_OPTION_VCL_NAL
  TestVclNal();
  //DECODER_OPTION_TEMPORAL_ID
  TestTemporalId();
  //DECODER_OPTION_FRAME_NUM
  TestFrameNum();
  //DECODER_OPTION_IDR_PIC_ID
  TestIdrPicId();
  //DECODER_OPTION_LTR_MARKING_FLAG
  TestLtrMarkingFlag();
  //DECODER_OPTION_LTR_MARKED_FRAME_NUM
  TestLtrMarkedFrameNum();
  //DECODER_OPTION_ERROR_CON_IDC
  TestErrorConIdc();
  //DECODER_OPTION_TRACE_LEVEL
  TestTraceLevel();
  //DECODER_OPTION_TRACE_CALLBACK
  TestTraceCallback();
  //DECODER_OPTION_TRACE_CALLBACK_CONTEXT
  TestTraceCallbackContext();
  //DECODER_OPTION_GET_STATISTICS
  TestGetDecStatistics();
  //DECODER_OPTION_GET_SAR_INFO
  TestGetDecSarInfo();
  //DECODER_OPTION_GET_SAR_INFO with vui in subsetsps
  TestVuiInSubsetSps();
}


