add support of SimulcastAVC functions
This commit is contained in:
parent
de68ec6f45
commit
8d5ec6759d
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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<unsigned char*> (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<unsigned char*> (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
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user