Merge pull request #2206 from sijchen/thp42

[Encoder] adjust encoder tasks, add ut and enable new thread pool under some cases
This commit is contained in:
sijchen 2015-11-03 09:05:43 -08:00
commit b0c6ea9385
15 changed files with 392 additions and 44 deletions

View File

@ -112,6 +112,18 @@ class CWelsCircleQueue {
}
return NULL;
}
TNodeType* GetIndexNode (const int32_t iIdx) {
if (size() > 0) {
if ((iIdx + m_iCurrentListStart) < m_iMaxNodeCount) {
return m_pCurrentQueue[m_iCurrentListStart + iIdx];
} else {
return m_pCurrentQueue[m_iCurrentListStart + iIdx - m_iMaxNodeCount];
}
}
return NULL;
}
private:
int32_t InternalPushBack (TNodeType* pNode) {
m_pCurrentQueue[m_iCurrentListEnd] = pNode;

View File

@ -313,6 +313,7 @@ WELS_THREAD_ERROR_CODE WelsEventOpen (WELS_EVENT* p_event, const char* event_
*p_event = NULL;
return WELS_THREAD_ERROR_GENERAL;
} else {
//printf("event_open:%x, %s\n", p_event, event_name);
return WELS_THREAD_ERROR_OK;
}
#else
@ -329,6 +330,7 @@ WELS_THREAD_ERROR_CODE WelsEventOpen (WELS_EVENT* p_event, const char* event_
#endif
}
WELS_THREAD_ERROR_CODE WelsEventClose (WELS_EVENT* event, const char* event_name) {
//printf("event_close:%x, %s\n", event, event_name);
#ifdef __APPLE__
WELS_THREAD_ERROR_CODE err = sem_close (*event); // match with sem_open
if (event_name)

View File

@ -57,6 +57,7 @@
#include "mt_defs.h" // for multiple threadin,
#include "WelsThreadLib.h"
#include "wels_task_management.h"
namespace WelsEnc {
@ -134,7 +135,7 @@ typedef struct TagWelsEncCtx {
SWelsFuncPtrList* pFuncList;
SSliceThreading* pSliceThreading;
//IWelsTaskManage* pTaskManage; //was planning to put it under CWelsH264SVCEncoder but it may be updated (lock/no lock) when param is changed
IWelsTaskManage* pTaskManage; //was planning to put it under CWelsH264SVCEncoder but it may be updated (lock/no lock) when param is changed
// SSlice context
SSliceCtx* pSliceCtxList;// slice context table for each dependency quality layer

View File

@ -61,6 +61,7 @@ class CWelsSliceEncodingTask : public CWelsBaseTask {
virtual WelsErrorType Execute();
virtual WelsErrorType InitTask();
virtual WelsErrorType ExecuteTask();
virtual void FinishTask();
virtual uint32_t GetTaskType() const {

View File

@ -56,7 +56,7 @@ class IWelsTaskManage {
virtual WelsErrorType Init (sWelsEncCtx* pEncCtx) = 0;
virtual void Uninit() = 0;
virtual void InitFrame() {}
virtual void InitFrame (const int32_t kiCurDid) {}
virtual WelsErrorType ExecuteTasks() = 0;
static IWelsTaskManage* CreateTaskManage (sWelsEncCtx* pCtx, bool bNeedLock);
@ -75,7 +75,7 @@ class CWelsTaskManageBase : public IWelsTaskManage, public WelsCommon::IWelsThr
virtual WelsErrorType Init (sWelsEncCtx* pEncCtx);
void Uninit();
virtual void InitFrame();
virtual void InitFrame (const int32_t kiCurDid);
virtual WelsErrorType ExecuteTasks();
//IWelsThreadPoolSink
@ -88,13 +88,13 @@ class CWelsTaskManageBase : public IWelsTaskManage, public WelsCommon::IWelsThr
protected:
sWelsEncCtx* m_pEncCtx;
WelsCommon::CWelsThreadPool* m_pThreadPool;
TASKLIST_TYPE* m_cTaskList;
int32_t m_iTaskNum;
//SLICE_PAIR_LIST *m_cSliceList;
WelsCommon::CWelsThreadPool* m_pThreadPool;
int32_t m_iThreadNum;
int32_t m_iWaitTaskNum;
@ -104,6 +104,7 @@ class CWelsTaskManageBase : public IWelsTaskManage, public WelsCommon::IWelsThr
private:
DISALLOW_COPY_AND_ASSIGN (CWelsTaskManageBase);
void OnTaskMinusOne();
};
class CWelsTaskManageOne : public CWelsTaskManageBase {

View File

@ -2930,6 +2930,10 @@ void WelsInitCurrentLayer (sWelsEncCtx* pCtx,
} else {
pCurDq->bBaseLayerAvailableFlag = false;
}
if (pCtx->pTaskManage) {
pCtx->pTaskManage->InitFrame(kiCurDid);
}
}
static inline void SetFastCodingFunc (SWelsFuncPtrList* pFuncList) {
@ -4016,7 +4020,7 @@ int32_t WelsEncoderEncodeExt (sWelsEncCtx* pCtx, SFrameBSInfo* pFbi, const SSour
iSliceCount);
return ENC_RETURN_UNEXPECTED;
}
if (SM_AUTO_SLICE == pParam->sSliceCfg.uiSliceMode) {
if (pSvcParam->iCountThreadsNum >= iSliceCount) { //THREAD_FULLY_FIRE_MODE
#if defined(MT_DEBUG)
int64_t t_bs_append = 0;
@ -4105,6 +4109,19 @@ int32_t WelsEncoderEncodeExt (sWelsEncCtx* pCtx, SFrameBSInfo* pFbi, const SSour
// append exclusive slice 0 bs to pFrameBs
iLayerSize = AppendSliceToFrameBs (pCtx, pLayerBsInfo, iSliceCount);
}
} else {
pLayerBsInfo->pBsBuf = pCtx->pFrameBs + pCtx->iPosBsBuffer;
pLayerBsInfo->uiLayerType = VIDEO_CODING_LAYER;
pLayerBsInfo->uiSpatialId = pCtx->uiDependencyId;
pLayerBsInfo->uiTemporalId = pCtx->uiTemporalId;
pLayerBsInfo->uiQualityId = 0;
pLayerBsInfo->iNalCount = 0;
pCtx->pSliceBs[0].pBs = pLayerBsInfo->pBsBuf;
pCtx->pTaskManage->ExecuteTasks();
iLayerSize = AppendSliceToFrameBs (pCtx, pLayerBsInfo, iSliceCount);
}
}
// THREAD_FULLY_FIRE_MODE && SM_DYN_SLICE
else if ((SM_DYN_SLICE == pParam->sSliceCfg.uiSliceMode) && (pSvcParam->iMultipleThreadIdc > 1)) {

View File

@ -333,6 +333,7 @@ int32_t RequestMtResource (sWelsEncCtx** ppCtx, SWelsSvcCodingParam* pCodingPara
int32_t iIdx = 0;
int16_t iMaxSliceNum = 1;
int32_t iReturn = ENC_RETURN_SUCCESS;
bool bWillUseTaskManage = false;
if (NULL == ppCtx || NULL == pCodingParam || NULL == *ppCtx || iCountBsLen <= 0)
return 1;
@ -372,6 +373,10 @@ int32_t RequestMtResource (sWelsEncCtx** ppCtx, SWelsSvcCodingParam* pCodingPara
pSmt->pSliceConsumeTime[iIdx] = NULL;
pSmt->pSliceComplexRatio[iIdx] = NULL;
}
if ( pMso->uiSliceMode == SM_FIXEDSLCNUM_SLICE || pMso->uiSliceMode == SM_RASTER_SLICE || pMso->uiSliceMode == SM_ROWMB_SLICE) {
bWillUseTaskManage = true;
}
++ iIdx;
}
// NULL for pSliceConsumeTime[iIdx]: iIdx from iNumSpatialLayers to MAX_DEPENDENCY_LAYERS
@ -430,9 +435,11 @@ int32_t RequestMtResource (sWelsEncCtx** ppCtx, SWelsSvcCodingParam* pCodingPara
pSmt->pThreadBsBuffer[iIdx] = NULL;
}
//previous conflict
WelsSnprintf (name, SEM_NAME_MAX, "scm%s", pSmt->eventNamespace);
err = WelsEventOpen (&pSmt->pSliceCodedMasterEvent, name);
MT_TRACE_LOG (*ppCtx, WELS_LOG_INFO, "[MT] Open pSliceCodedMasterEvent named(%s) ret%d err%d", name, err, errno);
//previous conflict ends
iReturn = SetMultiSliceBuffer (ppCtx, pMa, pSmt, iMaxSliceNum,
@ -444,6 +451,11 @@ int32_t RequestMtResource (sWelsEncCtx** ppCtx, SWelsSvcCodingParam* pCodingPara
iReturn = WelsMutexInit (&pSmt->mutexSliceNumUpdate);
WELS_VERIFY_RETURN_PROC_IF (1, (WELS_THREAD_ERROR_OK != iReturn), FreeMemorySvc (ppCtx))
if (bWillUseTaskManage) {
(*ppCtx)->pTaskManage = IWelsTaskManage::CreateTaskManage(*ppCtx, bDynamicSlice);
WELS_VERIFY_RETURN_PROC_IF (iReturn, (NULL == (*ppCtx)->pTaskManage), FreeMemorySvc (ppCtx))
}
memset(&pSmt->bThreadBsBufferUsage, 0, MAX_THREADS_NUM * sizeof(bool));
iReturn = WelsMutexInit (&pSmt->mutexThreadBsBufferUsage);
WELS_VERIFY_RETURN_PROC_IF (1, (WELS_THREAD_ERROR_OK != iReturn), FreeMemorySvc (ppCtx))
@ -530,6 +542,12 @@ void ReleaseMtResource (sWelsEncCtx** ppCtx) {
pMa->WelsFree ((*ppCtx)->pSliceBs, "pSliceBs");
(*ppCtx)->pSliceBs = NULL;
}
if ((*ppCtx)->pTaskManage != NULL) {
delete (*ppCtx)->pTaskManage;
(*ppCtx)->pTaskManage = NULL;
}
iIdx = 0;
while (iIdx < pCodingParam->iSpatialLayerNum) {
if (pSmt->pSliceConsumeTime[iIdx]) {
@ -1171,6 +1189,7 @@ void TrackSliceConsumeTime (sWelsEncCtx* pCtx, int32_t* pDidList, const int32_t
void SetOneSliceBsBufferUnderMultithread (sWelsEncCtx* pCtx, const int32_t kiThreadIdx, const int32_t iSliceIdx) {
pCtx->pSliceBs[iSliceIdx].pBsBuffer = pCtx->pSliceThreading->pThreadBsBuffer[kiThreadIdx];
pCtx->pSliceBs[iSliceIdx].uiBsPos = 0;
//printf("SetOneSliceBsBufferUnderMultithread, thread %d, slice %d, buffer=%x\n", kiThreadIdx, iSliceIdx, pCtx->pSliceBs[iSliceIdx].pBsBuffer);
}
}

View File

@ -63,6 +63,18 @@ CWelsSliceEncodingTask::CWelsSliceEncodingTask (sWelsEncCtx* pCtx, const int32_t
CWelsSliceEncodingTask::~CWelsSliceEncodingTask() {
}
WelsErrorType CWelsSliceEncodingTask::Execute() {
WelsThreadSetName ("OpenH264Enc_CWelsSliceEncodingTask_Execute");
int32_t iReturn = InitTask();
WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
iReturn = ExecuteTask();
FinishTask();
return ENC_RETURN_SUCCESS;
}
WelsErrorType CWelsSliceEncodingTask::SetBoundary (int32_t iStartIdx, int32_t iEndIdx) {
m_iStartMbIdx = iStartIdx;
m_iEndMbIdx = iEndIdx;
@ -88,10 +100,11 @@ WelsErrorType CWelsSliceEncodingTask::InitTask() {
m_iThreadIdx = QueryEmptyThread (m_pCtx->pSliceThreading->bThreadBsBufferUsage);
WelsMutexUnlock (&m_pCtx->pSliceThreading->mutexThreadBsBufferUsage);
if (m_iThreadIdx < 0) {
printf ("cannot find avaialble thread %d\n", m_iThreadIdx);
WelsLog (&m_pCtx->sLogCtx, WELS_LOG_WARNING,
"[MT] CWelsSliceEncodingTask InitTask(), Cannot find available thread for m_iSliceIdx = %d", m_iSliceIdx);
return ENC_RETURN_UNEXPECTED;
}
SetOneSliceBsBufferUnderMultithread (m_pCtx, m_iSliceIdx, m_iThreadIdx);
SetOneSliceBsBufferUnderMultithread (m_pCtx, m_iThreadIdx, m_iSliceIdx);
m_pSlice = &m_pCtx->pCurDqLayer->sLayerInfo.pSliceInLayer[m_iSliceIdx];
m_pSliceBs = &m_pCtx->pSliceBs[m_iSliceIdx];
@ -101,18 +114,18 @@ WelsErrorType CWelsSliceEncodingTask::InitTask() {
assert ((void*) (&m_pSliceBs->sBsWrite) == (void*)m_pSlice->pSliceBsa);
InitBits (&m_pSliceBs->sBsWrite, m_pSliceBs->pBsBuffer, m_pSliceBs->uiSize);
//printf ("CWelsSliceEncodingTask_InitTask slice %d\n", m_iSliceIdx);
return ENC_RETURN_SUCCESS;
}
void CWelsSliceEncodingTask::FinishTask() {
WelsMutexLock (&m_pCtx->pSliceThreading->mutexThreadBsBufferUsage);
m_pCtx->pSliceThreading->bThreadBsBufferUsage[m_iThreadIdx] = false;
WelsMutexUnlock (&m_pCtx->pSliceThreading->mutexThreadBsBufferUsage);
}
WelsErrorType CWelsSliceEncodingTask::Execute() {
WelsThreadSetName ("OpenH264Enc_CWelsSliceEncodingTask_Execute");
WelsErrorType CWelsSliceEncodingTask::ExecuteTask() {
#if MT_DEBUG_BS_WR
m_pSliceBs->bSliceCodedFlag = false;
#endif//MT_DEBUG_BS_WR
@ -144,6 +157,10 @@ WelsErrorType CWelsSliceEncodingTask::Execute() {
iLeftBufferSize,
m_iSliceIdx, m_iSliceSize);
if (ENC_RETURN_SUCCESS != iReturn) {
WelsLog (&m_pCtx->sLogCtx, WELS_LOG_WARNING,
"[MT] CWelsSliceEncodingTask ExecuteTask(), WriteSliceBs not successful: coding_idx %d, um_iSliceIdx %d",
m_pCtx->iCodingIndex,
m_iSliceIdx);
return iReturn;
}
if (0 == m_iSliceIdx) {
@ -152,15 +169,11 @@ WelsErrorType CWelsSliceEncodingTask::Execute() {
m_pCtx->pFuncList->pfDeblocking.pfDeblockingFilterSlice (m_pCtx->pCurDqLayer, m_pCtx->pFuncList, m_iSliceIdx);
#if defined(SLICE_INFO_OUTPUT)
fprintf (stderr,
"@pSlice=%-6d sliceType:%c idc:%d size:%-6d\n",
m_iSliceIdx,
(pEncPEncCtx->eSliceType == P_SLICE ? 'P' : 'I'),
eNalRefIdc,
iSliceSize
);
#endif//SLICE_INFO_OUTPUT
WelsLog (&m_pCtx->sLogCtx, WELS_LOG_DETAIL,
"@pSlice=%-6d sliceType:%c idc:%d size:%-6d", m_iSliceIdx,
(m_pCtx->eSliceType == P_SLICE ? 'P' : 'I'),
m_eNalRefIdc,
m_iSliceSize);
#if MT_DEBUG_BS_WR
m_pSliceBs->bSliceCodedFlag = true;

View File

@ -41,6 +41,7 @@
#include <assert.h>
#include "typedefs.h"
#include "utils.h"
#include "WelsLock.h"
#include "memory_align.h"
@ -74,8 +75,8 @@ IWelsTaskManage* IWelsTaskManage::CreateTaskManage (sWelsEncCtx* pCtx, bool bN
CWelsTaskManageBase::CWelsTaskManageBase()
: m_pEncCtx (NULL),
m_iTaskNum (0),
m_pThreadPool (NULL),
m_iTaskNum (0),
m_iWaitTaskNum (0) {
m_cTaskList = new TASKLIST_TYPE();
WelsEventOpen (&m_hTaskEvent);
@ -120,8 +121,9 @@ WelsErrorType CWelsTaskManageBase::CreateTasks (sWelsEncCtx* pEncCtx, const int3
}
void CWelsTaskManageBase::DestroyTasks() {
if (m_iTaskNum == 0)
if (m_iTaskNum == 0) {
return;
}
if (m_cTaskList->size() != m_iTaskNum) {
//printf("m_cTaskList %d %d\n", static_cast<int32_t>(m_cTaskList->size()), m_iTaskNum);
@ -133,41 +135,47 @@ void CWelsTaskManageBase::DestroyTasks() {
WELS_DELETE_OP (pTask);
m_cTaskList->pop_front();
}
//WelsLog (&m_pEncCtx->sLogCtx, WELS_LOG_INFO,
// "[MT] CWelsTaskManageParallel()DestroyTasks, cleaned %d tasks", m_iTaskNum);
//printf ("[MT] CWelsTaskManageBase() DestroyTasks, cleaned %d tasks\n", m_iTaskNum);
m_iTaskNum = 0;
}
void CWelsTaskManageBase::InitFrame() {
void CWelsTaskManageBase::OnTaskMinusOne() {
WelsCommon::CWelsAutoLock cAutoLock (m_cWaitTaskNumLock);
m_iWaitTaskNum --;
if (m_iWaitTaskNum <= 0) {
WelsEventSignal (&m_hTaskEvent);
}
//printf("OnTaskMinusOne m_iWaitTaskNum=%d\n", m_iWaitTaskNum);
}
WelsErrorType CWelsTaskManageBase::ExecuteTasks() {
m_iWaitTaskNum = static_cast<int32_t> (m_cTaskList->size());
while (NULL != m_cTaskList->begin()) {
m_pThreadPool->QueueTask (m_cTaskList->begin());
m_cTaskList->pop_front();
}
WelsEventWait (&m_hTaskEvent);
WelsErrorType CWelsTaskManageBase::OnTaskCancelled (WelsCommon::IWelsTask* pTask) {
OnTaskMinusOne();
return ENC_RETURN_SUCCESS;
}
WelsErrorType CWelsTaskManageBase::OnTaskExecuted (WelsCommon::IWelsTask* pTask) {
WelsCommon::CWelsAutoLock cAutoLock (m_cWaitTaskNumLock);
m_iWaitTaskNum --;
//WELS_INFO_TRACE("Waiting Task Num: " << m_iWaitTaskNum);
if (m_iWaitTaskNum == 0) {
WelsEventSignal (&m_hTaskEvent);
//WELS_INFO_TRACE("Tasks over ");
}
OnTaskMinusOne();
return ENC_RETURN_SUCCESS;
}
WelsErrorType CWelsTaskManageBase::OnTaskCancelled (WelsCommon::IWelsTask* pTask) {
WelsCommon::CWelsAutoLock cAutoLock (m_cWaitTaskNumLock);
m_iWaitTaskNum --;
if (m_iWaitTaskNum == 0) {
WelsEventSignal (&m_hTaskEvent);
void CWelsTaskManageBase::InitFrame (const int32_t kiCurDid) {
m_iWaitTaskNum = m_pEncCtx->pSvcParam->sSpatialLayers[kiCurDid].sSliceCfg.sSliceArgument.uiSliceNum;
//printf("InitFrame m_iWaitTaskNum=%d, slice_mode=%d\n", m_iWaitTaskNum, m_pEncCtx->pSvcParam->sSpatialLayers[kiCurDid].sSliceCfg.uiSliceMode);
//TODO: update mbmap;
}
WelsErrorType CWelsTaskManageBase::ExecuteTasks() {
//printf("ExecuteTasks m_iWaitTaskNum=%d\n", m_iWaitTaskNum);
int32_t iCurrentTaskCount = m_iWaitTaskNum; //if directly use m_iWaitTaskNum in the loop make cause sync problem
int32_t iIdx = 0;
while (iIdx < iCurrentTaskCount) {
m_pThreadPool->QueueTask (m_cTaskList->GetIndexNode(iIdx));
iIdx ++;
}
WelsEventWait (&m_hTaskEvent);
return ENC_RETURN_SUCCESS;
}

View File

@ -3727,4 +3727,133 @@ TEST_F (EncodeDecodeTestAPI, SimulcastAVCDiffFps) {
#endif
}
TEST_F (EncodeDecodeTestAPI, DiffSlicingInDlayer) {
int iSpatialLayerNum = 3;
int iWidth = WelsClip3 ((((rand() % MAX_WIDTH) >> 1) + 1) << 1, (64 << 2), MAX_WIDTH);
int iHeight = WelsClip3 ((((rand() % MAX_HEIGHT) >> 1) + 1) << 1, (64 << 2), 2240);//TODO: use MAX_HEIGHT after the limit is removed
float fFrameRate = rand() + 0.5f;
int iEncFrameNum = WelsClip3 ((rand() % ENCODE_FRAME_NUM) + 1, 1, ENCODE_FRAME_NUM);
// prepare params
SEncParamExt sParam;
encoder_->GetDefaultParams (&sParam);
prepareParamDefault (iSpatialLayerNum, 1, iWidth, iHeight, fFrameRate, &sParam);
sParam.iMultipleThreadIdc = (rand() % 4) + 1;
sParam.bSimulcastAVC = 1;
sParam.sSpatialLayers[0].iVideoWidth = (iWidth >> 2);
sParam.sSpatialLayers[0].iVideoHeight = (iHeight >> 2);
sParam.sSpatialLayers[0].sSliceCfg.uiSliceMode = SM_ROWMB_SLICE;
sParam.sSpatialLayers[1].iVideoWidth = (iWidth >> 1);
sParam.sSpatialLayers[1].iVideoHeight = (iHeight >> 1);
sParam.sSpatialLayers[1].sSliceCfg.uiSliceMode = SM_RASTER_SLICE;
sParam.sSpatialLayers[1].sSliceCfg.sSliceArgument.uiSliceMbNum[0] = 30;
sParam.sSpatialLayers[1].sSliceCfg.sSliceArgument.uiSliceMbNum[1] = 32;
sParam.sSpatialLayers[2].iVideoWidth = iWidth;
sParam.sSpatialLayers[2].iVideoHeight = iHeight;
sParam.sSpatialLayers[2].sSliceCfg.uiSliceMode = SM_FIXEDSLCNUM_SLICE;
sParam.sSpatialLayers[2].sSliceCfg.sSliceArgument.uiSliceNum = (rand() % 30) + 1;
int rv = encoder_->InitializeExt (&sParam);
ASSERT_TRUE (rv == cmResultSuccess) << "Init Failed sParam: rv = " << rv;;
unsigned char* pBsBuf[MAX_SPATIAL_LAYER_NUM];
ISVCDecoder* decoder[MAX_SPATIAL_LAYER_NUM];
int iIdx = 0;
//create decoder
for (iIdx = 0; iIdx < iSpatialLayerNum; iIdx++) {
pBsBuf[iIdx] = static_cast<unsigned char*> (malloc (iWidth * iHeight * 3 * sizeof (unsigned char) / 2));
EXPECT_TRUE (pBsBuf[iIdx] != NULL);
long rv = WelsCreateDecoder (&decoder[iIdx]);
ASSERT_EQ (0, rv);
EXPECT_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);
}
TestOneSimulcastAVC (&sParam, decoder, pBsBuf, iSpatialLayerNum, iEncFrameNum, 0);
for (iIdx = 0; iIdx < iSpatialLayerNum; iIdx++) {
free (pBsBuf[iIdx]);
if (decoder[iIdx] != NULL) {
decoder[iIdx]->Uninitialize();
WelsDestroyDecoder (decoder[iIdx]);
}
}
}
TEST_F (EncodeDecodeTestAPI, ThreadNumAndSliceNum) {
int iSpatialLayerNum = 1;
int iWidth = WelsClip3 ((((rand() % MAX_WIDTH) >> 1) + 1) << 1, (64 << 2), MAX_WIDTH);
int iHeight = WelsClip3 ((((rand() % MAX_HEIGHT) >> 1) + 1) << 1, (64 << 2),
2240);//TODO: use MAX_HEIGHT after the limit is removed
float fFrameRate = rand() + 0.5f;
int iEncFrameNum = WelsClip3 ((rand() % ENCODE_FRAME_NUM) + 1, 1, ENCODE_FRAME_NUM);
// prepare params
SEncParamExt sParam;
encoder_->GetDefaultParams (&sParam);
prepareParamDefault (iSpatialLayerNum, 1, iWidth, iHeight, fFrameRate, &sParam);
sParam.iMultipleThreadIdc = (rand() % 3) + 2;
sParam.bSimulcastAVC = 1;
sParam.sSpatialLayers[0].iVideoWidth = iWidth;
sParam.sSpatialLayers[0].iVideoHeight = iHeight;
sParam.sSpatialLayers[0].sSliceCfg.uiSliceMode = SM_FIXEDSLCNUM_SLICE;
sParam.sSpatialLayers[0].sSliceCfg.sSliceArgument.uiSliceNum = (rand() % 2) ? (sParam.iMultipleThreadIdc + 1) :
(sParam.iMultipleThreadIdc - 1);
int rv = encoder_->InitializeExt (&sParam);
ASSERT_TRUE (rv == cmResultSuccess) << "Init Failed sParam: rv = " << rv;;
unsigned char* pBsBuf[MAX_SPATIAL_LAYER_NUM];
ISVCDecoder* decoder[MAX_SPATIAL_LAYER_NUM];
int iIdx = 0;
//create decoder
for (iIdx = 0; iIdx < iSpatialLayerNum; iIdx++) {
pBsBuf[iIdx] = static_cast<unsigned char*> (malloc (iWidth * iHeight * 3 * sizeof (unsigned char) / 2));
EXPECT_TRUE (pBsBuf[iIdx] != NULL);
long rv = WelsCreateDecoder (&decoder[iIdx]);
ASSERT_EQ (0, rv);
EXPECT_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);
}
TestOneSimulcastAVC (&sParam, decoder, pBsBuf, iSpatialLayerNum, iEncFrameNum, 0);
for (iIdx = 0; iIdx < iSpatialLayerNum; iIdx++) {
free (pBsBuf[iIdx]);
if (decoder[iIdx] != NULL) {
decoder[iIdx]->Uninitialize();
WelsDestroyDecoder (decoder[iIdx]);
}
}
}

View File

@ -866,6 +866,10 @@
/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\..\common\WelsThreadPoolTest.cpp"
>
</File>
</Filter>
</Files>
<Globals>

View File

@ -194,3 +194,50 @@ TEST (CWelsCircleQueue, CWelsCircleQueueOnThread) {
}
#endif
TEST (CWelsCircleQueue, CWelsCircleQueueReadWithIdx) {
CWelsCircleQueue<int32_t> cThreadQueue;
const int kiIncreaseNum = (rand() % 1000) + 1;
const int kiDecreaseNum = rand() % kiIncreaseNum;
int32_t* pInput = static_cast<int32_t*> (malloc (kiIncreaseNum * 10 * sizeof (int32_t)));
if (!pInput) {
return;
}
for (int32_t i = 0; i < kiIncreaseNum * 10; i++) {
pInput[i] = i;
}
for (int j = 0; j < 10; j++) {
const int iBias = j * (kiIncreaseNum - kiDecreaseNum);
for (int i = 0; i < kiIncreaseNum; i++) {
cThreadQueue.push_back (&pInput[i + kiIncreaseNum * j]);
}
EXPECT_TRUE (kiIncreaseNum + iBias == cThreadQueue.size()) << "after push size=" <<
cThreadQueue.size() ;
EXPECT_TRUE ((kiDecreaseNum * j) == * (cThreadQueue.begin()));
for (int i = 0; i < kiIncreaseNum; i++) {
EXPECT_TRUE ((i + kiIncreaseNum * j) == * (cThreadQueue.GetIndexNode (i + iBias)));
}
for (int i = 0; i < cThreadQueue.size(); i++) {
EXPECT_TRUE ((i + kiDecreaseNum * j) == * (cThreadQueue.GetIndexNode (i)));
}
for (int i = kiDecreaseNum; i > 0; i--) {
cThreadQueue.pop_front();
}
EXPECT_TRUE ((j + 1) * (kiIncreaseNum - kiDecreaseNum) == cThreadQueue.size()) << "after pop size=" <<
cThreadQueue.size() ;
EXPECT_TRUE ((kiDecreaseNum * (j + 1)) == * (cThreadQueue.begin()));
}
//clean-up
while (NULL != cThreadQueue.begin()) {
cThreadQueue.pop_front();
}
EXPECT_TRUE (0 == cThreadQueue.size());
free (pInput);
}

View File

@ -0,0 +1,54 @@
#include <gtest/gtest.h>
#include <string.h>
#include <string>
#include <list>
#include <map>
#include "typedefs.h"
#include "WelsThreadLib.h"
#include "WelsThreadPool.h"
#include "WelsTask.h"
#include "WelsThreadPoolTest.h"
#define TEST_TASK_NUM 20
class CSimpleTask : public IWelsTask {
public:
static uint32_t id;
CSimpleTask() {
m_uiID = id ++;
}
virtual ~CSimpleTask() {
}
virtual int32_t Execute() {
WelsSleep (300 - m_uiID);
//printf ("Task %d executing\n", m_uiID);
return cmResultSuccess;
}
private:
uint32_t m_uiID;
};
uint32_t CSimpleTask::id = 0;
TEST (CThreadPoolTest, CThreadPoolTest) {
CSimpleTask tasks[TEST_TASK_NUM];
CThreadPoolTest cThreadPoolTest;
CWelsThreadPool cThreadPool (&cThreadPoolTest);
int32_t i;
for (i = 0; i < TEST_TASK_NUM; i++) {
cThreadPool.QueueTask (&tasks[i]);
}
while (cThreadPoolTest.GetTaskCount() < TEST_TASK_NUM) {
WelsSleep (1);
}
}

View File

@ -0,0 +1,39 @@
#ifndef _WELS_THREAD_POOL_TEST_H_
#define _WELS_THREAD_POOL_TEST_H_
#include "WelsThreadPool.h"
using namespace WelsCommon;
class CThreadPoolTest : public IWelsThreadPoolSink {
public:
CThreadPoolTest() {
m_iTaskCount = 0;
}
~CThreadPoolTest() {}
virtual int32_t OnTaskExecuted (IWelsTask* pTask) {
m_iTaskCount ++;
//printf("Task execute over count is %d\n", m_iTaskCount);
return cmResultSuccess;
}
virtual int32_t OnTaskCancelled (IWelsTask* pTask) {
m_iTaskCount ++;
//printf("Task execute cancelled count is %d\n", m_iTaskCount);
return cmResultSuccess;
}
int32_t GetTaskCount() {
return m_iTaskCount;
}
private:
int32_t m_iTaskCount;
};
#endif

View File

@ -1,8 +1,9 @@
COMMON_UNITTEST_SRCDIR=test/common
COMMON_UNITTEST_CPP_SRCS=\
$(COMMON_UNITTEST_SRCDIR)/ExpandPicture.cpp\
$(COMMON_UNITTEST_SRCDIR)/CWelsCircleQueue.cpp\
$(COMMON_UNITTEST_SRCDIR)/CWelsListTest.cpp\
$(COMMON_UNITTEST_SRCDIR)/ExpandPicture.cpp\
$(COMMON_UNITTEST_SRCDIR)/WelsThreadPoolTest.cpp\
COMMON_UNITTEST_OBJS += $(COMMON_UNITTEST_CPP_SRCS:.cpp=.$(OBJ))