From 8d5ec6759d49ed8e87e0e5f603e95732f23435b9 Mon Sep 17 00:00:00 2001 From: Sijia Chen Date: Mon, 26 Jan 2015 15:25:09 +0800 Subject: [PATCH 1/2] add support of SimulcastAVC functions --- codec/encoder/core/inc/param_svc.h | 7 +- codec/encoder/core/src/encoder_ext.cpp | 255 ++++++++++++++++++------- test/api/encode_decode_api_test.cpp | 222 +++++++++++++++++++++ 3 files changed, 415 insertions(+), 69 deletions(-) diff --git a/codec/encoder/core/inc/param_svc.h b/codec/encoder/core/inc/param_svc.h index 53fc220d..167dcd44 100644 --- a/codec/encoder/core/inc/param_svc.h +++ b/codec/encoder/core/inc/param_svc.h @@ -246,7 +246,7 @@ typedef struct TagWelsSvcCodingParam: SEncParamExt { sSpatialLayers->iDLayerQp = SVC_QUALITY_BASE_QP; - uiProfileIdc = PRO_SCALABLE_BASELINE; + uiProfileIdc = (!bSimulcastAVC) ? PRO_SCALABLE_BASELINE : PRO_BASELINE; ++ pDlp; ++ iIdxSpatial; } @@ -287,6 +287,7 @@ typedef struct TagWelsSvcCodingParam: SEncParamExt { /* Rate Control */ iRCMode = pCodingParam.iRCMode; // rc mode + bSimulcastAVC = pCodingParam.bSimulcastAVC; iPaddingFlag = pCodingParam.iPaddingFlag; iTargetBitrate = pCodingParam.iTargetBitrate; // target bitrate @@ -404,7 +405,7 @@ typedef struct TagWelsSvcCodingParam: SEncParamExt { pSpatialLayer->iDLayerQp = pCodingParam.sSpatialLayers[iIdxSpatial].iDLayerQp; - uiProfileIdc = PRO_SCALABLE_BASELINE; + uiProfileIdc = (!bSimulcastAVC) ? PRO_SCALABLE_BASELINE : PRO_BASELINE; ++ pDlp; ++ pSpatialLayer; ++ iIdxSpatial; @@ -474,7 +475,7 @@ typedef struct TagWelsSvcCodingParam: SEncParamExt { return ENC_RETURN_INVALIDINPUT; } - uiProfileIdc = iEntropyCodingModeFlag ? PRO_SCALABLE_HIGH : PRO_SCALABLE_BASELINE; + uiProfileIdc = iEntropyCodingModeFlag ? PRO_SCALABLE_HIGH : ((!bSimulcastAVC) ? PRO_SCALABLE_BASELINE : PRO_BASELINE); ++ pDlp; ++ pSpatialLayer; ++ i; diff --git a/codec/encoder/core/src/encoder_ext.cpp b/codec/encoder/core/src/encoder_ext.cpp index 9a57a6be..4f207715 100644 --- a/codec/encoder/core/src/encoder_ext.cpp +++ b/codec/encoder/core/src/encoder_ext.cpp @@ -342,6 +342,13 @@ int32_t ParamValidationExt (SLogContext* pLogCtx, SWelsSvcCodingParam* pCodingPa pCodingParam->eSpsPpsIdStrategy = CONSTANT_ID; } + if (pCodingParam->bSimulcastAVC && (SPS_LISTING & pCodingParam->eSpsPpsIdStrategy)) { + WelsLog (pLogCtx, WELS_LOG_INFO, + "ParamValidationExt(), eSpsPpsIdStrategy(%d) under bSimulcastAVC(%d) not supported yet, adjusted to INCREASING_ID", + pCodingParam->eSpsPpsIdStrategy, pCodingParam->bSimulcastAVC); + pCodingParam->eSpsPpsIdStrategy = INCREASING_ID; + } + for (i = 0; i < pCodingParam->iSpatialLayerNum; ++ i) { SSpatialLayerConfig* pSpatialLayer = &pCodingParam->sSpatialLayers[i]; const int32_t kiPicWidth = pSpatialLayer->iVideoWidth; @@ -1185,29 +1192,36 @@ static inline int32_t InitDqLayers (sWelsEncCtx** ppCtx, SExistingParasetList* p // for dynamically malloc for parameter sets memory instead of maximal items for standard to reduce size, 3/18/2010 // SPS - if (! (SPS_LISTING & pParam->eSpsPpsIdStrategy)) { - (*ppCtx)->pSpsArray = (SWelsSPS*)pMa->WelsMalloc (sizeof (SWelsSPS), "pSpsArray"); - WELS_VERIFY_RETURN_PROC_IF (1, (NULL == (*ppCtx)->pSpsArray), FreeMemorySvc (ppCtx)) - if (iDlayerCount > 1) { - (*ppCtx)->pSubsetArray = (SSubsetSps*)pMa->WelsMalloc ((iDlayerCount - 1) * sizeof (SSubsetSps), "pSubsetArray"); + if (!pParam->bSimulcastAVC) { + if (! (SPS_LISTING & pParam->eSpsPpsIdStrategy)) { + (*ppCtx)->pSpsArray = (SWelsSPS*)pMa->WelsMalloc (sizeof (SWelsSPS), "pSpsArray"); + WELS_VERIFY_RETURN_PROC_IF (1, (NULL == (*ppCtx)->pSpsArray), FreeMemorySvc (ppCtx)) + if (iDlayerCount > 1) { + (*ppCtx)->pSubsetArray = (SSubsetSps*)pMa->WelsMalloc ((iDlayerCount - 1) * sizeof (SSubsetSps), "pSubsetArray"); + WELS_VERIFY_RETURN_PROC_IF (1, (NULL == (*ppCtx)->pSubsetArray), FreeMemorySvc (ppCtx)) + } + } else { + // pParam->eSpsPpsIdStrategy == SPS_LISTING_AND_PPS_INCREASING + // new memory + (*ppCtx)->pSpsArray = (SWelsSPS*)pMa->WelsMalloc (MAX_SPS_COUNT * sizeof (SWelsSPS), "pSpsArray"); + WELS_VERIFY_RETURN_PROC_IF (1, (NULL == (*ppCtx)->pSpsArray), FreeMemorySvc (ppCtx)) + + (*ppCtx)->pSubsetArray = (SSubsetSps*)pMa->WelsMalloc (MAX_SPS_COUNT * sizeof (SSubsetSps), "pSubsetArray"); WELS_VERIFY_RETURN_PROC_IF (1, (NULL == (*ppCtx)->pSubsetArray), FreeMemorySvc (ppCtx)) + + // copy from existing if the pointer exists + if (NULL != pExistingParasetList) { + (*ppCtx)->sPSOVector.uiInUseSpsNum = pExistingParasetList->uiInUseSpsNum; + (*ppCtx)->sPSOVector.uiInUseSubsetSpsNum = pExistingParasetList->uiInUseSubsetSpsNum; + memcpy ((*ppCtx)->pSpsArray, pExistingParasetList->sSps, MAX_SPS_COUNT * sizeof (SWelsSPS)); + memcpy ((*ppCtx)->pSubsetArray, pExistingParasetList->sSubsetSps, MAX_SPS_COUNT * sizeof (SSubsetSps)); + } } } else { - // pParam->eSpsPpsIdStrategy == SPS_LISTING_AND_PPS_INCREASING - // new memory - (*ppCtx)->pSpsArray = (SWelsSPS*)pMa->WelsMalloc (MAX_SPS_COUNT * sizeof (SWelsSPS), "pSpsArray"); + //bSimulcastAVC + (*ppCtx)->pSpsArray = (SWelsSPS*)pMa->WelsMalloc (iDlayerCount * sizeof (SWelsSPS), "pSpsArray"); WELS_VERIFY_RETURN_PROC_IF (1, (NULL == (*ppCtx)->pSpsArray), FreeMemorySvc (ppCtx)) - - (*ppCtx)->pSubsetArray = (SSubsetSps*)pMa->WelsMalloc (MAX_SPS_COUNT * sizeof (SSubsetSps), "pSubsetArray"); - WELS_VERIFY_RETURN_PROC_IF (1, (NULL == (*ppCtx)->pSubsetArray), FreeMemorySvc (ppCtx)) - - // copy from existing if the pointer exists - if (NULL != pExistingParasetList) { - (*ppCtx)->sPSOVector.uiInUseSpsNum = pExistingParasetList->uiInUseSpsNum; - (*ppCtx)->sPSOVector.uiInUseSubsetSpsNum = pExistingParasetList->uiInUseSubsetSpsNum; - memcpy ((*ppCtx)->pSpsArray, pExistingParasetList->sSps, MAX_SPS_COUNT * sizeof (SWelsSPS)); - memcpy ((*ppCtx)->pSubsetArray, pExistingParasetList->sSubsetSps, MAX_SPS_COUNT * sizeof (SSubsetSps)); - } + (*ppCtx)->pSubsetArray = NULL; } // PPS if (! (SPS_PPS_LISTING == pParam->eSpsPpsIdStrategy)) { @@ -1237,7 +1251,7 @@ static inline int32_t InitDqLayers (sWelsEncCtx** ppCtx, SExistingParasetList* p iDlayerIndex = 0; while (iDlayerIndex < iDlayerCount) { SDqIdc* pDqIdc = & (*ppCtx)->pDqIdcMap[iDlayerIndex]; - const bool bUseSubsetSps = (iDlayerIndex > BASE_DEPENDENCY_ID); + const bool bUseSubsetSps = (!pParam->bSimulcastAVC) && (iDlayerIndex > BASE_DEPENDENCY_ID); SSpatialLayerConfig* pDlayerParam = &pParam->sSpatialLayers[iDlayerIndex]; pDqIdc->uiSpatialId = iDlayerIndex; @@ -1337,7 +1351,7 @@ static inline int32_t InitDqLayers (sWelsEncCtx** ppCtx, SExistingParasetList* p (*ppCtx)->sPSOVector.bPpsIdMappingIntoSubsetsps[iPpsId] = bUseSubsetSps; - if (bUseSubsetSps) + if ((pParam->bSimulcastAVC) || (bUseSubsetSps)) ++ iSpsId; ++ iPpsId; if (bUseSubsetSps) { @@ -2789,7 +2803,7 @@ void WelsInitCurrentLayer (sWelsEncCtx* pCtx, SSlice* pBaseSlice = &pCurDq->sLayerInfo.pSliceInLayer[0]; SSlice* pSlice = NULL; const uint8_t kiCurDid = pCtx->uiDependencyId; - const bool kbUseSubsetSpsFlag = (kiCurDid > BASE_DEPENDENCY_ID); + const bool kbUseSubsetSpsFlag = (!pParam->bSimulcastAVC) && (kiCurDid > BASE_DEPENDENCY_ID); SSpatialLayerConfig* fDlp = &pParam->sSpatialLayers[kiCurDid]; SNalUnitHeaderExt* pNalHdExt = &pCurDq->sLayerInfo.sNalHeaderExt; SNalUnitHeader* pNalHd = &pNalHdExt->sNalHeader; @@ -3108,6 +3122,42 @@ void ParasetIdAdditionIdAdjust (SParaSetOffsetVariable* sParaSetOffsetVariable, sParaSetOffsetVariable->uiNextParaSetIdToUseInBs = uiNextIdInBs; } +int32_t WelsWriteOneSPS (sWelsEncCtx* pCtx, const int32_t kiSpsIdx, int32_t& iNalSize) { + int iNal = pCtx->pOut->iNalIndex; + WelsLoadNal (pCtx->pOut, NAL_UNIT_SPS, NRI_PRI_HIGHEST); + + WelsWriteSpsNal (&pCtx->pSpsArray[kiSpsIdx], &pCtx->pOut->sBsWrite, + & (pCtx->sPSOVector.sParaSetOffsetVariable[PARA_SET_TYPE_AVCSPS].iParaSetIdDelta[0])); + WelsUnloadNal (pCtx->pOut); + + int32_t iReturn = WelsEncodeNal (&pCtx->pOut->sNalList[iNal], NULL, + pCtx->iFrameBsSize - pCtx->iPosBsBuffer,//available buffer to be written, so need to substract the used length + pCtx->pFrameBs + pCtx->iPosBsBuffer, + &iNalSize); + WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS) + + pCtx->iPosBsBuffer += iNalSize; + return ENC_RETURN_SUCCESS; +} +int32_t WelsWriteOnePPS (sWelsEncCtx* pCtx, const int32_t kiPpsIdx, int32_t& iNalSize) { + //TODO + int32_t iNal = pCtx->pOut->iNalIndex; + /* generate picture parameter set */ + WelsLoadNal (pCtx->pOut, NAL_UNIT_PPS, NRI_PRI_HIGHEST); + WelsWritePpsSyntax (&pCtx->pPPSArray[kiPpsIdx], &pCtx->pOut->sBsWrite, + ((SPS_PPS_LISTING != pCtx->pSvcParam->eSpsPpsIdStrategy)) ? (& (pCtx->sPSOVector)) : NULL); + WelsUnloadNal (pCtx->pOut); + + int32_t iReturn = WelsEncodeNal (&pCtx->pOut->sNalList[iNal], NULL, + pCtx->iFrameBsSize - pCtx->iPosBsBuffer, + pCtx->pFrameBs + pCtx->iPosBsBuffer, + &iNalSize); + WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS) + + pCtx->iPosBsBuffer += iNalSize; + return ENC_RETURN_SUCCESS; +} + /*! * \brief write all parameter sets introduced in SVC extension * \return writing results, success or error @@ -3128,8 +3178,7 @@ int32_t WelsWriteParameterSets (sWelsEncCtx* pCtx, int32_t* pNalLen, int32_t* pN /* write all SPS */ iIdx = 0; while (iIdx < pCtx->iSpsNum) { - iNal = pCtx->pOut->iNalIndex; - + // TODO (Sijia) wrap different operation of eSpsPpsIdStrategy to classes to hide the details if (INCREASING_ID == pCtx->pSvcParam->eSpsPpsIdStrategy) { #if _DEBUG pCtx->sPSOVector.eSpsPpsIdStrategy = INCREASING_ID; @@ -3146,19 +3195,9 @@ int32_t WelsWriteParameterSets (sWelsEncCtx* pCtx, int32_t* pNalLen, int32_t* pN /* generate sequence parameters set */ iId = (SPS_LISTING & pCtx->pSvcParam->eSpsPpsIdStrategy) ? iIdx : 0; - WelsLoadNal (pCtx->pOut, NAL_UNIT_SPS, NRI_PRI_HIGHEST); - WelsWriteSpsNal (&pCtx->pSpsArray[iId], &pCtx->pOut->sBsWrite, - & (pCtx->sPSOVector.sParaSetOffsetVariable[PARA_SET_TYPE_AVCSPS].iParaSetIdDelta[0])); - WelsUnloadNal (pCtx->pOut); + WelsWriteOneSPS (pCtx, iId, iNalLength); - iReturn = WelsEncodeNal (&pCtx->pOut->sNalList[iNal], NULL, - pCtx->iFrameBsSize - pCtx->iPosBsBuffer,//available buffer to be written, so need to substract the used length - pCtx->pFrameBs + pCtx->iPosBsBuffer, - &iNalLength); - WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS) pNalLen[iCountNal] = iNalLength; - - pCtx->iPosBsBuffer += iNalLength; iSize += iNalLength; ++ iIdx; @@ -3235,20 +3274,9 @@ int32_t WelsWriteParameterSets (sWelsEncCtx* pCtx, int32_t* pNalLen, int32_t* pN MAX_PPS_COUNT); } - iNal = pCtx->pOut->iNalIndex; - /* generate picture parameter set */ - WelsLoadNal (pCtx->pOut, NAL_UNIT_PPS, NRI_PRI_HIGHEST); - WelsWritePpsSyntax (&pCtx->pPPSArray[iIdx], &pCtx->pOut->sBsWrite, - ((SPS_PPS_LISTING != pCtx->pSvcParam->eSpsPpsIdStrategy)) ? (& (pCtx->sPSOVector)) : NULL); - WelsUnloadNal (pCtx->pOut); + WelsWriteOnePPS (pCtx, iIdx, iNalLength); - iReturn = WelsEncodeNal (&pCtx->pOut->sNalList[iNal], NULL, - pCtx->iFrameBsSize - pCtx->iPosBsBuffer, - pCtx->pFrameBs + pCtx->iPosBsBuffer, - &iNalLength); - WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS) pNalLen[iCountNal] = iNalLength; - pCtx->iPosBsBuffer += iNalLength; iSize += iNalLength; ++ iIdx; @@ -3408,6 +3436,107 @@ int32_t GetSubSequenceId (sWelsEncCtx* pCtx, EVideoFrameType eFrameType) { return iSubSeqId; } +int32_t WriteSsvcParaset (sWelsEncCtx* pCtx, const int32_t kiSpatialNum, + SLayerBSInfo*& pLayerBsInfo, int32_t& iLayerNum, int32_t& iFrameSize) { + int32_t iNonVclSize = 0, iCountNal = 0, iReturn; + iReturn = WelsWriteParameterSets (pCtx, &pLayerBsInfo->pNalLengthInByte[0], &iCountNal, &iNonVclSize); + WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS) + + pLayerBsInfo->uiSpatialId = 0; + pLayerBsInfo->uiTemporalId = 0; + pLayerBsInfo->uiQualityId = 0; + pLayerBsInfo->uiLayerType = NON_VIDEO_CODING_LAYER; + pLayerBsInfo->iNalCount = iCountNal; + + //point to next pLayerBsInfo + ++ pLayerBsInfo; + pLayerBsInfo->pBsBuf = pCtx->pFrameBs + pCtx->iPosBsBuffer; + pLayerBsInfo->pNalLengthInByte = (pLayerBsInfo - 1)->pNalLengthInByte + iCountNal; + //update for external countings + ++ iLayerNum; + iFrameSize += iNonVclSize; + return iReturn; +} + +int32_t WriteSavcParaset (sWelsEncCtx* pCtx, const int32_t kiSpatialNum, + SLayerBSInfo*& pLayerBsInfo, int32_t& iLayerNum, int32_t& iFrameSize) { + int32_t iNonVclSize = 0, iCountNal = 0, iReturn; + + // write SPS + iNonVclSize = 0; + assert (kiSpatialNum == pCtx->iSpsNum); + + for (int32_t iIdx = 0; iIdx < pCtx->iSpsNum; iIdx++) { + //writing one NAL + int32_t iNalSize = 0; + iReturn = WelsWriteOneSPS (pCtx, iIdx, iNalSize); + WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS) + + pLayerBsInfo->pNalLengthInByte[iCountNal] = iNalSize; + iNonVclSize += iNalSize; + iCountNal = 1; + //finish writing one NAL + + + pLayerBsInfo->uiSpatialId = iIdx; + pLayerBsInfo->uiTemporalId = 0; + pLayerBsInfo->uiQualityId = 0; + pLayerBsInfo->uiLayerType = NON_VIDEO_CODING_LAYER; + pLayerBsInfo->iNalCount = iCountNal; + + //point to next pLayerBsInfo + ++ pLayerBsInfo; + pLayerBsInfo->pBsBuf = pCtx->pFrameBs + pCtx->iPosBsBuffer; + pLayerBsInfo->pNalLengthInByte = (pLayerBsInfo - 1)->pNalLengthInByte + iCountNal; + //update for external countings + iCountNal = 0; + ++ iLayerNum; + + } + + // write PPS + + //TODO: under new strategy, will PPS be correctly updated? + + for (int32_t iIdx = 0; iIdx < pCtx->iPpsNum; iIdx++) { + //writing one NAL + int32_t iNalSize = 0; + iReturn = WelsWriteOnePPS (pCtx, iIdx, iNalSize); + WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS) + + pLayerBsInfo->pNalLengthInByte[iCountNal] = iNalSize; + iNonVclSize += iNalSize; + iCountNal = 1; + //finish writing one NAL + + + pLayerBsInfo->uiSpatialId = iIdx; + pLayerBsInfo->uiTemporalId = 0; + pLayerBsInfo->uiQualityId = 0; + pLayerBsInfo->uiLayerType = NON_VIDEO_CODING_LAYER; + pLayerBsInfo->iNalCount = iCountNal; + + //point to next pLayerBsInfo + ++ pLayerBsInfo; + pLayerBsInfo->pBsBuf = pCtx->pFrameBs + pCtx->iPosBsBuffer; + pLayerBsInfo->pNalLengthInByte = (pLayerBsInfo - 1)->pNalLengthInByte + iCountNal; + //update for external countings + iCountNal = 0; + ++ iLayerNum; + } + + // to check number of layers / nals / slices dependencies + if (iLayerNum > MAX_LAYER_NUM_OF_FRAME) { + WelsLog (& pCtx->sLogCtx, WELS_LOG_ERROR, "WriteSavcParaset(), iLayerNum(%d) > MAX_LAYER_NUM_OF_FRAME(%d)!", + iLayerNum, MAX_LAYER_NUM_OF_FRAME); + return 1; + } + + iFrameSize += iNonVclSize; + return iReturn; +} + + /*! * \brief core svc encoding process * @@ -3504,25 +3633,12 @@ int32_t WelsEncoderEncodeExt (sWelsEncCtx* pCtx, SFrameBSInfo* pFbi, const SSour if (eFrameType == videoFrameTypeIDR) { ++ pCtx->uiIdrPicId; - //if ( pSvcParam->bEnableSSEI ) - - // write parameter sets bitstream here - int32_t iNonVclSize = 0; - pCtx->iEncoderError = WelsWriteParameterSets (pCtx, &pLayerBsInfo->pNalLengthInByte[0], &iCountNal, &iNonVclSize); + // write parameter sets bitstream or SEI/SSEI (if any) here + // TODO: use function pointer instead + pCtx->iEncoderError = ((!pSvcParam->bSimulcastAVC) + ? (WriteSsvcParaset (pCtx, iSpatialNum, pLayerBsInfo, iLayerNum, iFrameSize)) + : (WriteSavcParaset (pCtx, iSpatialNum, pLayerBsInfo, iLayerNum, iFrameSize))); WELS_VERIFY_RETURN_IFNEQ (pCtx->iEncoderError, ENC_RETURN_SUCCESS) - - pLayerBsInfo->uiSpatialId = 0; - pLayerBsInfo->uiTemporalId = 0; - pLayerBsInfo->uiQualityId = 0; - pLayerBsInfo->uiLayerType = NON_VIDEO_CODING_LAYER; - pLayerBsInfo->iNalCount = iCountNal; - - ++ pLayerBsInfo; - pLayerBsInfo->pBsBuf = pCtx->pFrameBs + pCtx->iPosBsBuffer; - pLayerBsInfo->pNalLengthInByte = (pLayerBsInfo - 1)->pNalLengthInByte + iCountNal; - ++ iLayerNum; - - iFrameSize += iNonVclSize; } pCtx->pCurDqLayer = pCtx->ppDqLayerList[pSpatialIndexMap->iDid]; @@ -3577,7 +3693,7 @@ int32_t WelsEncoderEncodeExt (sWelsEncCtx* pCtx, SFrameBSInfo* pFbi, const SSour } iNalIdxInLayer = 0; - bAvcBased = (iCurDid == BASE_DEPENDENCY_ID); + bAvcBased = ((pSvcParam->bSimulcastAVC) || (iCurDid == BASE_DEPENDENCY_ID)); pCtx->bNeedPrefixNalFlag = (bAvcBased && (pSvcParam->bPrefixNalAddingCtrl || (pSvcParam->iSpatialLayerNum > 1))); @@ -4077,6 +4193,13 @@ int32_t WelsEncoderEncodeExt (sWelsEncCtx* pCtx, SFrameBSInfo* pFbi, const SSour #endif//ENABLE_FRAME_DUMP + // to check number of layers / nals / slices dependencies + if (iLayerNum > MAX_LAYER_NUM_OF_FRAME) { + WelsLog (& pCtx->sLogCtx, WELS_LOG_ERROR, "WelsEncoderEncodeExt(), iLayerNum(%d) > MAX_LAYER_NUM_OF_FRAME(%d)!", + iLayerNum, MAX_LAYER_NUM_OF_FRAME); + return 1; + } + ++ pCtx->iCodingIndex; pCtx->eLastNalPriority = eNalRefIdc; pFbi->iLayerNum = iLayerNum; diff --git a/test/api/encode_decode_api_test.cpp b/test/api/encode_decode_api_test.cpp index 86c673a3..4893f61c 100644 --- a/test/api/encode_decode_api_test.cpp +++ b/test/api/encode_decode_api_test.cpp @@ -3020,3 +3020,225 @@ TEST_F (EncodeDecodeTestAPI, ParameterSetStrategy_SPS_PPS_LISTING3) { #endif } + +TEST_F (EncodeDecodeTestAPI, SimulcastSVC) { +#define LAYER_NUM (4) + int iSpatialLayerNum = WelsClip3 ((rand() % LAYER_NUM), 2, LAYER_NUM);; + int iWidth = WelsClip3 ((((rand() % MAX_WIDTH) >> 1) + 1) << 1, 1 << iSpatialLayerNum, MAX_WIDTH); + int iHeight = WelsClip3 ((((rand() % MAX_HEIGHT) >> 1) + 1) << 1, 1 << iSpatialLayerNum, MAX_HEIGHT); + float fFrameRate = rand() + 0.5f; + int iEncFrameNum = WelsClip3 ((rand() % ENCODE_FRAME_NUM) + 1, 1, ENCODE_FRAME_NUM); + int iSliceNum = 1; + encoder_->GetDefaultParams (¶m_); + prepareParam (iSpatialLayerNum, iSliceNum, iWidth, iHeight, fFrameRate, ¶m_); + + int rv = encoder_->InitializeExt (¶m_); + ASSERT_TRUE (rv == cmResultSuccess); + + unsigned char* pBsBuf[LAYER_NUM]; + int aLen[LAYER_NUM] = {0}; + ISVCDecoder* decoder[LAYER_NUM]; + +#ifdef DEBUG_FILE_SAVE2 + FILE* fEnc[LAYER_NUM] = { NULL }; + fEnc[0] = fopen ("enc0.264", "wb"); + fEnc[1] = fopen ("enc1.264", "wb"); + fEnc[2] = fopen ("enc2.264", "wb"); + fEnc[3] = fopen ("enc3.264", "wb"); +#endif + + // init decoders + int iIdx = 0; + for (iIdx = 0; iIdx < iSpatialLayerNum; iIdx++) { + pBsBuf[iIdx] = static_cast (malloc (iWidth * iHeight * 3 * sizeof (unsigned char) / 2)); + aLen[iIdx] = 0; + + long rv = WelsCreateDecoder (&decoder[iIdx]); + ASSERT_EQ (0, rv); + ASSERT_TRUE (decoder[iIdx] != NULL); + + SDecodingParam decParam; + memset (&decParam, 0, sizeof (SDecodingParam)); + decParam.eOutputColorFormat = videoFormatI420; + decParam.uiTargetDqLayer = UCHAR_MAX; + decParam.eEcActiveIdc = ERROR_CON_SLICE_COPY; + decParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT; + + rv = decoder[iIdx]->Initialize (&decParam); + ASSERT_EQ (0, rv); + } + + for (int iFrame = 0; iFrame < iEncFrameNum; iFrame++) { + int iResult; + int iLayerLen = 0; + unsigned char* pData[3] = { NULL }; + + InitialEncDec (param_.iPicWidth, param_.iPicHeight); + EncodeOneFrame (0); + + iLayerLen = 0; + for (iIdx = 0; iIdx < iSpatialLayerNum; iIdx++) { + aLen[iIdx] = 0; + } + for (int iLayer = 0; iLayer < info.iLayerNum; ++iLayer) { + iLayerLen = 0; + const SLayerBSInfo& layerInfo = info.sLayerInfo[iLayer]; + for (int iNal = 0; iNal < layerInfo.iNalCount; ++iNal) { + iLayerLen += layerInfo.pNalLengthInByte[iNal]; + } + + if (layerInfo.uiLayerType == NON_VIDEO_CODING_LAYER) { + // under SimulcastSVC, need to copy non-VCL to all layers + for (iIdx = 0; iIdx < iSpatialLayerNum; iIdx++) { + memcpy ((pBsBuf[iIdx] + aLen[iIdx]), layerInfo.pBsBuf, iLayerLen * sizeof (unsigned char)); + aLen[iIdx] += iLayerLen; + } + } else { + iIdx = layerInfo.uiSpatialId; + EXPECT_TRUE (iIdx < iSpatialLayerNum); + memcpy ((pBsBuf[iIdx] + aLen[iIdx]), layerInfo.pBsBuf, iLayerLen * sizeof (unsigned char)); + aLen[iIdx] += iLayerLen; + } + } + + for (iIdx = 0; iIdx < iSpatialLayerNum; iIdx++) { + pData[0] = pData[1] = pData[2] = 0; + memset (&dstBufInfo_, 0, sizeof (SBufferInfo)); + +#ifdef DEBUG_FILE_SAVE2 + fwrite (pBsBuf[iIdx], aLen[iIdx], 1, fEnc[iIdx]); +#endif + iResult = decoder[iIdx]->DecodeFrame2 (pBsBuf[iIdx], aLen[iIdx], pData, &dstBufInfo_); + EXPECT_TRUE (iResult == cmResultSuccess) << "iResult=" << iResult << "LayerIdx=" << iIdx; + iResult = decoder[iIdx]->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); + EXPECT_TRUE (iResult == cmResultSuccess) << "iResult=" << iResult << "LayerIdx=" << iIdx; + EXPECT_EQ (dstBufInfo_.iBufferStatus, 1) << "LayerIdx=" << iIdx; + } + } + + // free all + for (iIdx = 0; iIdx < iSpatialLayerNum; iIdx++) { + if (pBsBuf[iIdx]) { + free (pBsBuf[iIdx]); + } + + if (decoder[iIdx] != NULL) { + decoder[iIdx]->Uninitialize(); + WelsDestroyDecoder (decoder[iIdx]); + } + +#ifdef DEBUG_FILE_SAVE2 + fclose (fEnc[iIdx]); +#endif + } + +} + +TEST_F (EncodeDecodeTestAPI, SimulcastAVC) { +//#define DEBUG_FILE_SAVE3 +#define LAYER_NUM (4) + int iSpatialLayerNum = WelsClip3 ((rand() % LAYER_NUM), 2, LAYER_NUM);; + int iWidth = WelsClip3 ((((rand() % MAX_WIDTH) >> 1) + 1) << 1, 1 << iSpatialLayerNum, MAX_WIDTH); + int iHeight = WelsClip3 ((((rand() % MAX_HEIGHT) >> 1) + 1) << 1, 1 << iSpatialLayerNum, MAX_HEIGHT); + float fFrameRate = rand() + 0.5f; + int iEncFrameNum = WelsClip3 ((rand() % ENCODE_FRAME_NUM) + 1, 1, ENCODE_FRAME_NUM); + int iSliceNum = 1; + encoder_->GetDefaultParams (¶m_); + prepareParam (iSpatialLayerNum, iSliceNum, iWidth, iHeight, fFrameRate, ¶m_); + + //set flag of bSimulcastAVC + param_.bSimulcastAVC = true; + + int rv = encoder_->InitializeExt (¶m_); + ASSERT_TRUE (rv == cmResultSuccess); + + unsigned char* pBsBuf[LAYER_NUM]; + int aLen[LAYER_NUM] = {0}; + ISVCDecoder* decoder[LAYER_NUM]; + +#ifdef DEBUG_FILE_SAVE3 + FILE* fEnc[LAYER_NUM]; + fEnc[0] = fopen ("enc0.264", "wb"); + fEnc[1] = fopen ("enc1.264", "wb"); + fEnc[2] = fopen ("enc2.264", "wb"); + fEnc[3] = fopen ("enc3.264", "wb"); +#endif + + int iIdx = 0; + + //create decoder + for (int iIdx = 0; iIdx < iSpatialLayerNum; iIdx++) { + pBsBuf[iIdx] = static_cast (malloc (iWidth * iHeight * 3 * sizeof (unsigned char) / 2)); + aLen[iIdx] = 0; + + long rv = WelsCreateDecoder (&decoder[iIdx]); + ASSERT_EQ (0, rv); + ASSERT_TRUE (decoder[iIdx] != NULL); + + SDecodingParam decParam; + memset (&decParam, 0, sizeof (SDecodingParam)); + decParam.eOutputColorFormat = videoFormatI420; + decParam.uiTargetDqLayer = UCHAR_MAX; + decParam.eEcActiveIdc = ERROR_CON_SLICE_COPY; + decParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_DEFAULT; + + rv = decoder[iIdx]->Initialize (&decParam); + ASSERT_EQ (0, rv); + } + + iEncFrameNum = 1; + for (int iFrame = 0; iFrame < iEncFrameNum; iFrame++) { + int iResult; + int iLayerLen = 0; + unsigned char* pData[3] = { NULL }; + + InitialEncDec (param_.iPicWidth, param_.iPicHeight); + EncodeOneFrame (0); + + // init + for (iIdx = 0; iIdx < iSpatialLayerNum; iIdx++) { + aLen[iIdx] = 0; + } + for (int iLayer = 0; iLayer < info.iLayerNum; ++iLayer) { + iLayerLen = 0; + const SLayerBSInfo& layerInfo = info.sLayerInfo[iLayer]; + for (int iNal = 0; iNal < layerInfo.iNalCount; ++iNal) { + iLayerLen += layerInfo.pNalLengthInByte[iNal]; + } + + iIdx = layerInfo.uiSpatialId; + EXPECT_TRUE (iIdx < iSpatialLayerNum); + memcpy ((pBsBuf[iIdx] + aLen[iIdx]), layerInfo.pBsBuf, iLayerLen * sizeof (unsigned char)); + aLen[iIdx] += iLayerLen; + } + + for (iIdx = 0; iIdx < iSpatialLayerNum; iIdx++) { + pData[0] = pData[1] = pData[2] = 0; + memset (&dstBufInfo_, 0, sizeof (SBufferInfo)); + +#ifdef DEBUG_FILE_SAVE3 + fwrite (pBsBuf[iIdx], aLen[iIdx], 1, fEnc[iIdx]); +#endif + iResult = decoder[iIdx]->DecodeFrame2 (pBsBuf[iIdx], aLen[iIdx], pData, &dstBufInfo_); + EXPECT_TRUE (iResult == cmResultSuccess) << "iResult=" << iResult << "LayerIdx=" << iIdx; + + iResult = decoder[iIdx]->DecodeFrame2 (NULL, 0, pData, &dstBufInfo_); + EXPECT_TRUE (iResult == cmResultSuccess) << "iResult=" << iResult << "LayerIdx=" << iIdx; + EXPECT_EQ (dstBufInfo_.iBufferStatus, 1) << "LayerIdx=" << iIdx; + } + + } + + for (iIdx = 0; iIdx < iSpatialLayerNum; iIdx++) { + free (pBsBuf[iIdx]); + + if (decoder[iIdx] != NULL) { + decoder[iIdx]->Uninitialize(); + WelsDestroyDecoder (decoder[iIdx]); + } +#ifdef DEBUG_FILE_SAVE3 + fclose (fEnc[iIdx]); +#endif + } +} + From deccd1eadb44b8304f64637e61d4d5ba39237522 Mon Sep 17 00:00:00 2001 From: Sijia Chen Date: Mon, 26 Jan 2015 16:36:42 +0800 Subject: [PATCH 2/2] fix profileidc --- codec/encoder/core/inc/param_svc.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/codec/encoder/core/inc/param_svc.h b/codec/encoder/core/inc/param_svc.h index 167dcd44..fca2dd87 100644 --- a/codec/encoder/core/inc/param_svc.h +++ b/codec/encoder/core/inc/param_svc.h @@ -475,7 +475,8 @@ typedef struct TagWelsSvcCodingParam: SEncParamExt { return ENC_RETURN_INVALIDINPUT; } - uiProfileIdc = iEntropyCodingModeFlag ? PRO_SCALABLE_HIGH : ((!bSimulcastAVC) ? PRO_SCALABLE_BASELINE : PRO_BASELINE); + uiProfileIdc = bSimulcastAVC ? (iEntropyCodingModeFlag ? PRO_HIGH : PRO_BASELINE) : + (iEntropyCodingModeFlag ? PRO_SCALABLE_HIGH : PRO_SCALABLE_BASELINE); ++ pDlp; ++ pSpatialLayer; ++ i;