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