shithub: openh264

Download patch

ref: 4a6259cf74617e15a4e0f0b3fdd8a749ed17499e
parent: f00d3ac15fa848c9116dcf282e33b3ac1b9c685d
author: huili2 <huili2@cisco.com>
date: Wed Apr 23 15:55:38 EDT 2014

add slice/frame copy UT for EC

--- /dev/null
+++ b/test/decoder/DecUT_ErrorConcealment.cpp
@@ -1,0 +1,291 @@
+#include<gtest/gtest.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "wels_common_basis.h"
+#include "mem_align.h"
+#include "error_concealment.h"
+#include "ls_defines.h"
+#include "cpu.h"
+
+using namespace WelsDec;
+
+#define MAX_MB_WIDTH 260
+#define MAX_MB_HEIGHT 130
+
+typedef struct TagECInputCtx {
+  int32_t iMbWidth;
+  int32_t iMbHeight;
+  uint32_t iLinesize[3];
+  bool* pMbCorrectlyDecodedFlag; //actual memory
+  PWelsDecoderContext pCtx;
+  SDqLayer sDqLayer;
+  SPicture sAncPic; //Anc picture for comparison
+  SPicture sSrcPic; //Src picture as common input picture data
+  SPicture sWelsPic; //Wels picture to be compared
+} SECInputCtx, *PECInputCtx;
+
+void FreeInputData (PECInputCtx pECCtx) {
+  if (pECCtx != NULL) {
+    if (pECCtx->pCtx != NULL) {
+      WELS_SAFE_FREE (pECCtx->pCtx->pSps, "pECCtx->pCtx->pSps");
+      WELS_SAFE_FREE (pECCtx->pCtx, "pECCtx->pCtx");
+    }
+
+    WELS_SAFE_FREE (pECCtx->pMbCorrectlyDecodedFlag, "pECCtx->pMbCorrectlyDecodedFlag");
+    WELS_SAFE_FREE (pECCtx->sSrcPic.pData[0], "pECCtx->sSrcPic.pData");
+    WELS_SAFE_FREE (pECCtx->sAncPic.pData[0], "pECCtx->sAncPic.pData");
+    WELS_SAFE_FREE (pECCtx->sWelsPic.pData[0], "pECCtx->sWelsPic.pData");
+
+    WELS_SAFE_FREE (pECCtx, "pECCtx");
+  }
+}
+
+int32_t InitAndAllocInputData (PECInputCtx& pECCtx) {
+  FreeInputData (pECCtx);
+
+  pECCtx = (PECInputCtx) WelsMalloc (sizeof (SECInputCtx), "pECCtx");
+  if (pECCtx == NULL)
+    return 1;
+  memset (pECCtx, 0, sizeof (SECInputCtx));
+
+  srand ((uint32_t)time (NULL));
+  pECCtx->iMbWidth = rand() % MAX_MB_WIDTH; //give a constrained max width
+  pECCtx->iMbHeight = rand() % MAX_MB_HEIGHT; //give a constrained max height
+  pECCtx->iLinesize[0] = pECCtx->iMbWidth << 4;
+  pECCtx->iLinesize[1] = pECCtx->iLinesize[2] = pECCtx->iLinesize[0] >> 1;
+
+  const uint32_t kiLumaSize = pECCtx->iMbWidth * pECCtx->iMbHeight * 256;
+
+  //allocate picture data
+  pECCtx->sWelsPic.pData[0] = (uint8_t*) WelsMalloc (kiLumaSize * 3 / 2 * sizeof (uint8_t), "pECCtx->sWelsPic.pData");
+  if (pECCtx->sWelsPic.pData[0] == NULL)
+    return 1;
+  pECCtx->sWelsPic.pData[1] = pECCtx->sWelsPic.pData[0] + kiLumaSize;
+  pECCtx->sWelsPic.pData[2] = pECCtx->sWelsPic.pData[1] + (kiLumaSize >> 2);
+
+  pECCtx->sAncPic.pData[0] = (uint8_t*) WelsMalloc (kiLumaSize * 3 / 2 * sizeof (uint8_t), "pECCtx->sAncPic.pData");
+  if (pECCtx->sAncPic.pData[0] == NULL)
+    return 1;
+  pECCtx->sAncPic.pData[1] = pECCtx->sAncPic.pData[0] + kiLumaSize;
+  pECCtx->sAncPic.pData[2] = pECCtx->sAncPic.pData[1] + (kiLumaSize >> 2);
+
+  pECCtx->sSrcPic.pData[0] = (uint8_t*) WelsMalloc (kiLumaSize * 3 / 2 * sizeof (uint8_t), "pECCtx->sSrcPic.pData");
+  if (pECCtx->sAncPic.pData[0] == NULL)
+    return 1;
+  pECCtx->sSrcPic.pData[1] = pECCtx->sSrcPic.pData[0] + kiLumaSize;
+  pECCtx->sSrcPic.pData[2] = pECCtx->sSrcPic.pData[1] + (kiLumaSize >> 2);
+
+  pECCtx->sWelsPic.iLinesize[0] = pECCtx->sAncPic.iLinesize[0] = pECCtx->sSrcPic.iLinesize[0] = pECCtx->iLinesize[0];
+  pECCtx->sWelsPic.iLinesize[1] = pECCtx->sAncPic.iLinesize[1] = pECCtx->sSrcPic.iLinesize[1] = pECCtx->iLinesize[1];
+  pECCtx->sWelsPic.iLinesize[2] = pECCtx->sAncPic.iLinesize[2] = pECCtx->sSrcPic.iLinesize[2] = pECCtx->iLinesize[2];
+
+  pECCtx->pMbCorrectlyDecodedFlag = (bool*) WelsMalloc (pECCtx->iMbWidth * pECCtx->iMbHeight * sizeof (bool),
+                                    "pECCtx->pMbCorrectlyDecodedFlag");
+  if (pECCtx->pMbCorrectlyDecodedFlag == NULL)
+    return 1;
+
+  pECCtx->pCtx = (PWelsDecoderContext) WelsMalloc (sizeof (SWelsDecoderContext), "pECCtx->pCtx");
+  if (pECCtx->pCtx == NULL)
+    return 1;
+
+  pECCtx->pCtx->pDec = &pECCtx->sWelsPic;
+  pECCtx->pCtx->pCurDqLayer = &pECCtx->sDqLayer;
+  pECCtx->pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag = pECCtx->pMbCorrectlyDecodedFlag;
+
+  pECCtx->pCtx->pSps = (PSps) WelsMalloc (sizeof (SSps), "pECCtx->pCtx->pSps");
+  if (pECCtx->pCtx->pSps == NULL)
+    return 1;
+  pECCtx->pCtx->pSps->iMbWidth = pECCtx->iMbWidth;
+  pECCtx->pCtx->pSps->iMbHeight = pECCtx->iMbHeight;
+
+  return 0;
+}
+
+void InitECCopyData (PECInputCtx pECCtx) {
+  srand ((uint32_t)time (NULL));
+  const int32_t kiMbNum = pECCtx->iMbWidth * pECCtx->iMbHeight;
+  int i;
+  //init pMbCorrectlyDecodedFlag
+  for (i = 0; i < kiMbNum; ++i) {
+    pECCtx->pMbCorrectlyDecodedFlag[i] = !! (rand() & 1);
+  }
+  //init Data
+  const int32_t iPixNum = kiMbNum * 256 * 3 / 2;
+  for (i = 0; i < iPixNum; ++i) {
+    pECCtx->sSrcPic.pData[0][i] = rand() & 0xff;
+  }
+  int32_t iCpuCores = 1;
+  pECCtx->pCtx->uiCpuFlag = WelsCPUFeatureDetect (&iCpuCores);
+  InitErrorCon (pECCtx->pCtx);
+}
+
+void DoAncErrorConSliceCopy (PECInputCtx pECCtx) {
+  int32_t iMbWidth = (int32_t) pECCtx->iMbWidth;
+  int32_t iMbHeight = (int32_t) pECCtx->iMbHeight;
+  PPicture pDstPic = &pECCtx->sAncPic;
+  PPicture pSrcPic = pECCtx->pCtx->pPreviousDecodedPictureInDpb;
+
+  //uint8_t *pDstData[3], *pSrcData[3];
+  bool* pMbCorrectlyDecodedFlag = pECCtx->pMbCorrectlyDecodedFlag;
+
+  //Do slice copy late
+  int32_t iMbXyIndex, i;
+  uint8_t* pSrcData, *pDstData;
+  uint32_t iSrcStride = pECCtx->iLinesize[0];
+  uint32_t iDstStride = pECCtx->iLinesize[0];
+  for (int32_t iMbY = 0; iMbY < iMbHeight; ++iMbY) {
+    for (int32_t iMbX = 0; iMbX < iMbWidth; ++iMbX) {
+      iMbXyIndex = iMbY * iMbWidth + iMbX;
+      if (!pMbCorrectlyDecodedFlag[iMbXyIndex]) {
+        if (pSrcPic != NULL) {
+          //Y component
+          pDstData = pDstPic->pData[0] + iMbY * 16 * iDstStride + iMbX * 16;
+          pSrcData = pSrcPic->pData[0] + iMbY * 16 * iSrcStride + iMbX * 16;
+          for (i = 0; i < 16; ++i) {
+            memcpy (pDstData, pSrcData, 16);
+            pDstData += iDstStride;
+            pSrcData += iSrcStride;
+          }
+          //U component
+          pDstData = pDstPic->pData[1] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
+          pSrcData = pSrcPic->pData[1] + iMbY * 8 * iSrcStride / 2 + iMbX * 8;
+          for (i = 0; i < 8; ++i) {
+            memcpy (pDstData, pSrcData, 8);
+            pDstData += iDstStride;
+            pSrcData += iSrcStride;
+          }
+          //V component
+          pDstData = pDstPic->pData[2] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
+          pSrcData = pSrcPic->pData[2] + iMbY * 8 * iSrcStride / 2 + iMbX * 8;
+          for (i = 0; i < 8; ++i) {
+            memcpy (pDstData, pSrcData, 8);
+            pDstData += iDstStride;
+            pSrcData += iSrcStride;
+          }
+        } else { //pSrcPic == NULL
+          //Y component
+          pDstData = pDstPic->pData[0] + iMbY * 16 * iDstStride + iMbX * 16;
+          for (int32_t i = 0; i < 16; ++i) {
+            memset (pDstData, 0, 16);
+            pDstData += iDstStride;
+          }
+          //U component
+          pDstData = pDstPic->pData[1] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
+          for (int32_t i = 0; i < 8; ++i) {
+            memset (pDstData, 0, 8);
+            pDstData += iDstStride / 2;
+          }
+          //V component
+          pDstData = pDstPic->pData[2] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
+          for (int32_t i = 0; i < 8; ++i) {
+            memset (pDstData, 0, 8);
+            pDstData += iDstStride / 2;
+          }
+        } //
+      } //!pMbCorrectlyDecodedFlag[iMbXyIndex]
+    } //iMbX
+  } //iMbY
+}
+
+
+
+bool ComparePictureDataI420 (uint8_t* pSrcData, uint8_t* pDstData, const uint32_t kiStride, const int32_t kiHeight) {
+  bool bSame = true;
+  uint8_t* pAncData; // = pECCtx->sAncPic.pData[0];
+  uint8_t* pCompData;
+  int32_t iStride;
+  int32_t iCurHeight;
+  int32_t iHeight = kiHeight;
+
+  //Y component
+  iStride = kiStride;
+  pAncData = pSrcData;
+  pCompData = pDstData;
+  for (iCurHeight = 0; bSame && (iCurHeight < kiHeight); ++iCurHeight) {
+    bSame = (memcmp (pAncData, pCompData, iStride * sizeof (uint8_t)) == 0);
+    pAncData += iStride;
+    pCompData += iStride;
+  }
+  //chroma component
+  iHeight >>= 1;
+  iStride >>= 1;
+  //U component
+  for (iCurHeight = 0; bSame && (iCurHeight < kiHeight / 2); ++iCurHeight) {
+    bSame = (memcmp (pAncData, pCompData, iStride * sizeof (uint8_t)) == 0);
+    pAncData += iStride;
+    pCompData += iStride;
+  }
+  //V component
+  for (iCurHeight = 0; bSame && (iCurHeight < kiHeight / 2); ++iCurHeight) {
+    bSame = (memcmp (pAncData, pCompData, iStride * sizeof (uint8_t)) == 0);
+    pAncData += iStride;
+    pCompData += iStride;
+  }
+
+  return bSame;
+}
+
+//TEST cases followed
+TEST (ErrorConTest, DoErrorConFrameCopy) {
+  bool bOK = true;
+  PECInputCtx pECCtx = NULL;
+  if (InitAndAllocInputData (pECCtx)) {
+    FreeInputData (pECCtx);
+    return;
+  }
+
+  pECCtx->pCtx->iErrorConMethod = ERROR_CON_FRAME_COPY;
+  InitECCopyData (pECCtx);
+  //case 1: no reference picture
+  pECCtx->pCtx->pPreviousDecodedPictureInDpb = NULL;
+  DoErrorConFrameCopy (pECCtx->pCtx);
+
+  int32_t iLumaSize = pECCtx->iMbWidth * pECCtx->iMbHeight * 256;
+  memset (pECCtx->sAncPic.pData[0], 0, iLumaSize * 3 / 2); //should be the same as known EC method, here all 0
+  bOK = ComparePictureDataI420 (pECCtx->sAncPic.pData[0], pECCtx->sWelsPic.pData[0], pECCtx->iLinesize[0],
+                                pECCtx->iMbHeight * 16);
+  EXPECT_EQ (bOK, true);
+
+  //case 2: with reference picture
+  pECCtx->pCtx->pPreviousDecodedPictureInDpb = &pECCtx->sSrcPic;
+  DoErrorConFrameCopy (pECCtx->pCtx);
+
+  memcpy (pECCtx->sAncPic.pData[0], pECCtx->sSrcPic.pData[0], iLumaSize * 3 / 2);
+  bOK = ComparePictureDataI420 (pECCtx->sAncPic.pData[0], pECCtx->sWelsPic.pData[0], pECCtx->iLinesize[0],
+                                pECCtx->iMbHeight * 16);
+  EXPECT_EQ (bOK, true);
+
+  FreeInputData (pECCtx);
+}
+
+//TEST cases followed
+TEST (ErrorConTest, DoErrorConSliceCopy) {
+  bool bOK = true;
+  PECInputCtx pECCtx = NULL;
+  if (InitAndAllocInputData (pECCtx)) {
+    FreeInputData (pECCtx);
+    return;
+  }
+  pECCtx->pCtx->iErrorConMethod = ERROR_CON_SLICE_COPY;
+  InitECCopyData (pECCtx);
+  //case 1: no reference picture
+  pECCtx->pCtx->pPreviousDecodedPictureInDpb = NULL;
+  DoAncErrorConSliceCopy (pECCtx);
+  DoErrorConSliceCopy (pECCtx->pCtx);
+
+  bOK = ComparePictureDataI420 (pECCtx->sAncPic.pData[0], pECCtx->sWelsPic.pData[0], pECCtx->iLinesize[0],
+                                pECCtx->iMbHeight * 16);
+  EXPECT_EQ (bOK, true);
+
+  //case 2: with reference picture
+  pECCtx->pCtx->pPreviousDecodedPictureInDpb = &pECCtx->sAncPic;
+  DoAncErrorConSliceCopy (pECCtx);
+  DoErrorConSliceCopy (pECCtx->pCtx);
+
+  bOK = ComparePictureDataI420 (pECCtx->sAncPic.pData[0], pECCtx->sWelsPic.pData[0], pECCtx->iLinesize[0],
+                                pECCtx->iMbHeight * 16);
+  EXPECT_EQ (bOK, true);
+
+  FreeInputData (pECCtx);
+}
--- a/test/decoder/targets.mk
+++ b/test/decoder/targets.mk
@@ -1,5 +1,6 @@
 DECODER_UNITTEST_SRCDIR=test/decoder
 DECODER_UNITTEST_CPP_SRCS=\
+        $(DECODER_UNITTEST_SRCDIR)/DecUT_ErrorConcealment.cpp\
 	$(DECODER_UNITTEST_SRCDIR)/DecUT_ExpandPicture.cpp\
 	$(DECODER_UNITTEST_SRCDIR)/DecUT_IdctResAddPred.cpp\
 	$(DECODER_UNITTEST_SRCDIR)/DecUT_IntraPrediction.cpp\