1 /*!
2  * \copy
3  *     Copyright (c)  2009-2015, Cisco Systems
4  *     All rights reserved.
5  *
6  *     Redistribution and use in source and binary forms, with or without
7  *     modification, are permitted provided that the following conditions
8  *     are met:
9  *
10  *        * Redistributions of source code must retain the above copyright
11  *          notice, this list of conditions and the following disclaimer.
12  *
13  *        * Redistributions in binary form must reproduce the above copyright
14  *          notice, this list of conditions and the following disclaimer in
15  *          the documentation and/or other materials provided with the
16  *          distribution.
17  *
18  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  *     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  *     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  *     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  *     COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  *     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26  *     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  *     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28  *     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  *     POSSIBILITY OF SUCH DAMAGE.
30  *
31  *
32  * \file    wels_task_management.cpp
33  *
34  * \brief   function for task management
35  *
36  * \date    5/14/2012 Created
37  *
38  *************************************************************************************
39  */
40 #include <string.h>
41 #include <assert.h>
42 
43 #include "typedefs.h"
44 #include "utils.h"
45 #include "WelsLock.h"
46 #include "memory_align.h"
47 
48 #include "wels_common_basis.h"
49 #include "encoder_context.h"
50 #include "wels_task_base.h"
51 #include "wels_task_encoder.h"
52 #include "wels_task_management.h"
53 
54 namespace WelsEnc {
55 
56 
57 
CreateTaskManage(sWelsEncCtx * pCtx,const int32_t iSpatialLayer,const bool bNeedLock)58 IWelsTaskManage*   IWelsTaskManage::CreateTaskManage (sWelsEncCtx* pCtx, const int32_t iSpatialLayer,
59     const bool bNeedLock) {
60   if (NULL == pCtx) {
61     return NULL;
62   }
63 
64   IWelsTaskManage* pTaskManage;
65   pTaskManage = WELS_NEW_OP (CWelsTaskManageBase(), CWelsTaskManageBase);
66   WELS_VERIFY_RETURN_IF (NULL, NULL == pTaskManage)
67 
68   if (ENC_RETURN_SUCCESS != pTaskManage->Init (pCtx)) {
69     pTaskManage->Uninit();
70     WELS_DELETE_OP (pTaskManage);
71   }
72   return pTaskManage;
73 }
74 
75 
CWelsTaskManageBase()76 CWelsTaskManageBase::CWelsTaskManageBase()
77   : m_pEncCtx (NULL),
78     m_pThreadPool (NULL),
79     m_iWaitTaskNum (0) {
80 
81   for (int32_t iDid = 0; iDid < MAX_DEPENDENCY_LAYER; iDid++) {
82     m_iTaskNum[iDid] = 0;
83     m_cEncodingTaskList[iDid] = new TASKLIST_TYPE();
84     m_cPreEncodingTaskList[iDid] = new TASKLIST_TYPE();
85   }
86 
87   WelsEventOpen (&m_hTaskEvent);
88   WelsMutexInit (&m_hEventMutex);
89 }
90 
~CWelsTaskManageBase()91 CWelsTaskManageBase::~CWelsTaskManageBase() {
92   //fprintf(stdout, "~CWelsTaskManageBase\n");
93   Uninit();
94 }
95 
Init(sWelsEncCtx * pEncCtx)96 WelsErrorType CWelsTaskManageBase::Init (sWelsEncCtx* pEncCtx) {
97   m_pEncCtx = pEncCtx;
98   m_iThreadNum = m_pEncCtx->pSvcParam->iMultipleThreadIdc;
99 
100   int32_t iReturn = ENC_RETURN_SUCCESS;
101   //fprintf(stdout, "m_pThreadPool = &(CWelsThreadPool::GetInstance, this=%x\n", this);
102   iReturn = CWelsThreadPool::SetThreadNum (m_iThreadNum);
103   m_pThreadPool = (CWelsThreadPool::AddReference());
104   if ((iReturn != ENC_RETURN_SUCCESS) && pEncCtx) {
105     WelsLog (& (pEncCtx->sLogCtx), WELS_LOG_WARNING, "Set Thread Num to %d did not succeed, current thread num in use: %d",
106              m_iThreadNum, m_pThreadPool->GetThreadNum());
107   }
108   WELS_VERIFY_RETURN_IF (ENC_RETURN_MEMALLOCERR, NULL == m_pThreadPool)
109   //fprintf(stdout, "m_pThreadPool = &(CWelsThreadPool::GetInstance3\n");
110 
111   iReturn = ENC_RETURN_SUCCESS;
112   for (int32_t iDid = 0; iDid < MAX_DEPENDENCY_LAYER; iDid++) {
113     m_pcAllTaskList[CWelsBaseTask::WELS_ENC_TASK_ENCODING][iDid] = m_cEncodingTaskList[iDid];
114     m_pcAllTaskList[CWelsBaseTask::WELS_ENC_TASK_UPDATEMBMAP][iDid] = m_cPreEncodingTaskList[iDid];
115     iReturn |= CreateTasks (pEncCtx, iDid);
116   }
117 
118   //fprintf(stdout, "CWelsTaskManageBase Init m_iThreadNum %d m_iCurrentTaskNum %d pEncCtx->iMaxSliceCount %d\n", m_iThreadNum, m_iCurrentTaskNum, pEncCtx->iMaxSliceCount);
119   return iReturn;
120 }
121 
Uninit()122 void   CWelsTaskManageBase::Uninit() {
123   DestroyTasks();
124   //fprintf(stdout, "m_pThreadPool = m_pThreadPool->RemoveInstance\n");
125   if (m_pThreadPool)
126     m_pThreadPool->RemoveInstance();
127   //WELS_DELETE_OP (m_pThreadPool);
128 
129   //fprintf(stdout, "m_pThreadPool = m_pThreadPool->RemoveInstance2\n");
130 
131   for (int32_t iDid = 0; iDid < MAX_DEPENDENCY_LAYER; iDid++) {
132     WELS_DELETE_OP (m_cEncodingTaskList[iDid]);
133     WELS_DELETE_OP (m_cPreEncodingTaskList[iDid]);
134   }
135   WelsEventClose (&m_hTaskEvent);
136   WelsMutexDestroy (&m_hEventMutex);
137 }
138 
CreateTasks(sWelsEncCtx * pEncCtx,const int32_t kiCurDid)139 WelsErrorType CWelsTaskManageBase::CreateTasks (sWelsEncCtx* pEncCtx, const int32_t kiCurDid) {
140   CWelsBaseTask* pTask = NULL;
141   int32_t kiTaskCount;
142   uint32_t uiSliceMode = pEncCtx->pSvcParam->sSpatialLayers[kiCurDid].sSliceArgument.uiSliceMode;
143 
144   if (uiSliceMode != SM_SIZELIMITED_SLICE) {
145     kiTaskCount = m_iTaskNum[kiCurDid] = pEncCtx->pSvcParam->sSpatialLayers[kiCurDid].sSliceArgument.uiSliceNum;
146   } else {
147     kiTaskCount = m_iTaskNum[kiCurDid] = pEncCtx->iActiveThreadsNum;
148   }
149 
150   for (int idx = 0; idx < kiTaskCount; idx++) {
151     pTask = WELS_NEW_OP (CWelsUpdateMbMapTask (this, pEncCtx, idx), CWelsUpdateMbMapTask);
152     WELS_VERIFY_RETURN_IF (ENC_RETURN_MEMALLOCERR, NULL == pTask)
153     WELS_VERIFY_RETURN_IF (ENC_RETURN_MEMALLOCERR, true != m_cPreEncodingTaskList[kiCurDid]->push_back (pTask));
154   }
155 
156   for (int idx = 0; idx < kiTaskCount; idx++) {
157     if (uiSliceMode == SM_SIZELIMITED_SLICE) {
158       pTask = WELS_NEW_OP (CWelsConstrainedSizeSlicingEncodingTask (this, pEncCtx, idx),
159                            CWelsConstrainedSizeSlicingEncodingTask);
160     } else {
161       if (pEncCtx->pSvcParam->bUseLoadBalancing) {
162         pTask = WELS_NEW_OP (CWelsLoadBalancingSlicingEncodingTask (this, pEncCtx, idx), CWelsLoadBalancingSlicingEncodingTask);
163       } else {
164         pTask = WELS_NEW_OP (CWelsSliceEncodingTask (this, pEncCtx, idx), CWelsSliceEncodingTask);
165       }
166     }
167     WELS_VERIFY_RETURN_IF (ENC_RETURN_MEMALLOCERR, NULL == pTask)
168     WELS_VERIFY_RETURN_IF (ENC_RETURN_MEMALLOCERR, true != m_cEncodingTaskList[kiCurDid]->push_back (pTask));
169   }
170 
171   //fprintf(stdout, "CWelsTaskManageBase CreateTasks m_iThreadNum %d kiTaskCount=%d\n", m_iThreadNum, kiTaskCount);
172   return ENC_RETURN_SUCCESS;
173 }
174 
DestroyTaskList(TASKLIST_TYPE * pTargetTaskList)175 void CWelsTaskManageBase::DestroyTaskList (TASKLIST_TYPE* pTargetTaskList) {
176   //fprintf(stdout, "CWelsTaskManageBase: pTargetTaskList size=%d m_iTotalTaskNum=%d\n", static_cast<int32_t> (pTargetTaskList->size()), m_iTotalTaskNum);
177   while (NULL != pTargetTaskList->begin()) {
178     CWelsBaseTask* pTask = pTargetTaskList->begin();
179     WELS_DELETE_OP (pTask);
180     pTargetTaskList->pop_front();
181   }
182   pTargetTaskList = NULL;
183 }
184 
DestroyTasks()185 void CWelsTaskManageBase::DestroyTasks() {
186   for (int32_t iDid = 0; iDid < MAX_DEPENDENCY_LAYER; iDid++)  {
187     if (m_iTaskNum[iDid] > 0) {
188       DestroyTaskList (m_cEncodingTaskList[iDid]);
189       DestroyTaskList (m_cPreEncodingTaskList[iDid]);
190       m_iTaskNum[iDid] = 0;
191       m_pcAllTaskList[CWelsBaseTask::WELS_ENC_TASK_ENCODING][iDid] = NULL;
192     }
193   }
194   //fprintf(stdout, "[MT] CWelsTaskManageBase() DestroyTasks, cleaned %d tasks\n", m_iTotalTaskNum);
195 }
196 
OnTaskMinusOne()197 void  CWelsTaskManageBase::OnTaskMinusOne() {
198   //fprintf(stdout, "OnTaskMinusOne event %x m_iWaitTaskNum=%d\n", &m_hEventMutex, m_iWaitTaskNum);
199   WelsCommon::CWelsAutoLock cAutoLock (m_cWaitTaskNumLock);
200   WelsEventSignal (&m_hTaskEvent, &m_hEventMutex, &m_iWaitTaskNum);
201   /*WelsMutexLock(&m_hEventMutex);
202   m_iWaitTaskNum --;
203   WelsMutexUnlock(&m_hEventMutex);
204 
205   if (m_iWaitTaskNum <= 0) {
206     WelsEventSignal (&m_hTaskEvent);
207     fprintf(stdout, "OnTaskMinusOne WelsEventSignal m_iWaitTaskNum=%d\n", m_iWaitTaskNum);
208   }*/
209   //fprintf(stdout, "OnTaskMinusOne m_iWaitTaskNum=%d\n", m_iWaitTaskNum);
210 }
211 
OnTaskCancelled()212 WelsErrorType  CWelsTaskManageBase::OnTaskCancelled() {
213   OnTaskMinusOne();
214   return ENC_RETURN_SUCCESS;
215 }
216 
OnTaskExecuted()217 WelsErrorType  CWelsTaskManageBase::OnTaskExecuted() {
218   OnTaskMinusOne();
219   return ENC_RETURN_SUCCESS;
220 }
221 
ExecuteTaskList(TASKLIST_TYPE ** pTaskList)222 WelsErrorType  CWelsTaskManageBase::ExecuteTaskList (TASKLIST_TYPE** pTaskList) {
223   m_iWaitTaskNum = m_iTaskNum[m_iCurDid];
224   TASKLIST_TYPE* pTargetTaskList = (pTaskList[m_iCurDid]);
225   //fprintf(stdout, "ExecuteTaskList m_iWaitTaskNum=%d\n", m_iWaitTaskNum);
226   if (0 == m_iWaitTaskNum) {
227     return ENC_RETURN_SUCCESS;
228   }
229 
230   int32_t iCurrentTaskCount = m_iWaitTaskNum; //if directly use m_iWaitTaskNum in the loop make cause sync problem
231   int32_t iIdx = 0;
232   while (iIdx < iCurrentTaskCount) {
233     m_pThreadPool->QueueTask (pTargetTaskList->getNode (iIdx));
234     iIdx ++;
235   }
236 
237   WelsEventWait (&m_hTaskEvent, &m_hEventMutex, m_iWaitTaskNum);
238 
239   return ENC_RETURN_SUCCESS;
240 }
241 
InitFrame(const int32_t kiCurDid)242 void CWelsTaskManageBase::InitFrame (const int32_t kiCurDid) {
243   m_iCurDid = kiCurDid;
244   if (m_pEncCtx->pCurDqLayer->bNeedAdjustingSlicing) {
245     ExecuteTaskList (m_pcAllTaskList[CWelsBaseTask::WELS_ENC_TASK_UPDATEMBMAP]);
246   }
247 }
248 
ExecuteTasks(const CWelsBaseTask::ETaskType iTaskType)249 WelsErrorType  CWelsTaskManageBase::ExecuteTasks (const CWelsBaseTask::ETaskType iTaskType) {
250   return ExecuteTaskList (m_pcAllTaskList[iTaskType]);
251 }
252 
GetThreadPoolThreadNum()253 int32_t  CWelsTaskManageBase::GetThreadPoolThreadNum() {
254   return m_pThreadPool->GetThreadNum();
255 }
256 
257 // CWelsTaskManageOne is for test
Init(sWelsEncCtx * pEncCtx)258 WelsErrorType CWelsTaskManageOne::Init (sWelsEncCtx* pEncCtx) {
259   m_pEncCtx = pEncCtx;
260 
261   return CreateTasks (pEncCtx, pEncCtx->iMaxSliceCount);
262 }
263 
ExecuteTasks(const CWelsBaseTask::ETaskType iTaskType)264 WelsErrorType  CWelsTaskManageOne::ExecuteTasks (const CWelsBaseTask::ETaskType iTaskType) {
265   while (NULL != m_cEncodingTaskList[0]->begin()) {
266     (m_cEncodingTaskList[0]->begin())->Execute();
267     m_cEncodingTaskList[0]->pop_front();
268   }
269   return ENC_RETURN_SUCCESS;
270 }
271 // CWelsTaskManageOne is for test
272 
273 }
274 
275 
276 
277 
278