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_encoder.h
33 *
34 * \brief interface for encoder tasks
35 *
36 * \date 07/06/2015 Created
37 *
38 *************************************************************************************
39 */
40
41 #include <string.h>
42 #include <assert.h>
43
44 #include "typedefs.h"
45 #include "utils.h"
46 #include "measure_time.h"
47 #include "WelsTask.h"
48
49 #include "wels_task_base.h"
50 #include "wels_task_encoder.h"
51
52 #include "svc_enc_golomb.h"
53 #include "svc_encode_slice.h"
54 #include "slice_multi_threading.h"
55
56 namespace WelsEnc {
57
CWelsSliceEncodingTask(WelsCommon::IWelsTaskSink * pSink,sWelsEncCtx * pCtx,const int32_t iSliceIdx)58 CWelsSliceEncodingTask::CWelsSliceEncodingTask (WelsCommon::IWelsTaskSink* pSink, sWelsEncCtx* pCtx,
59 const int32_t iSliceIdx) : CWelsBaseTask (pSink), m_eTaskResult (ENC_RETURN_SUCCESS) {
60 m_pCtx = pCtx;
61 m_iSliceIdx = iSliceIdx;
62 }
63
~CWelsSliceEncodingTask()64 CWelsSliceEncodingTask::~CWelsSliceEncodingTask() {
65 }
66
Execute()67 WelsErrorType CWelsSliceEncodingTask::Execute() {
68 //fprintf(stdout, "OpenH264Enc_CWelsSliceEncodingTask_Execute, %x, sink=%x\n", this, m_pSink);
69
70 m_eTaskResult = InitTask();
71 WELS_VERIFY_RETURN_IFNEQ (m_eTaskResult, ENC_RETURN_SUCCESS)
72
73 m_eTaskResult = ExecuteTask();
74
75 FinishTask();
76
77 //fprintf(stdout, "OpenH264Enc_CWelsSliceEncodingTask_Execute Ends\n");
78 return m_eTaskResult;
79 }
80
SetBoundary(int32_t iStartIdx,int32_t iEndIdx)81 WelsErrorType CWelsSliceEncodingTask::SetBoundary (int32_t iStartIdx, int32_t iEndIdx) {
82 m_iStartMbIdx = iStartIdx;
83 m_iEndMbIdx = iEndIdx;
84 return ENC_RETURN_SUCCESS;
85 }
86
QueryEmptyThread(bool * pThreadBsBufferUsage)87 int32_t CWelsSliceEncodingTask::QueryEmptyThread (bool* pThreadBsBufferUsage) {
88 for (int32_t k = 0; k < MAX_THREADS_NUM; k++) {
89 if (pThreadBsBufferUsage[k] == false) {
90 pThreadBsBufferUsage[k] = true;
91 return k;
92 }
93 }
94 return -1;
95 }
96
InitTask()97 WelsErrorType CWelsSliceEncodingTask::InitTask() {
98 m_eNalType = m_pCtx->eNalType;
99 m_eNalRefIdc = m_pCtx->eNalPriority;
100 m_bNeedPrefix = m_pCtx->bNeedPrefixNalFlag;
101
102 WelsMutexLock (&m_pCtx->pSliceThreading->mutexThreadBsBufferUsage);
103 m_iThreadIdx = QueryEmptyThread (m_pCtx->pSliceThreading->bThreadBsBufferUsage);
104 WelsMutexUnlock (&m_pCtx->pSliceThreading->mutexThreadBsBufferUsage);
105
106 WelsLog (&m_pCtx->sLogCtx, WELS_LOG_DEBUG,
107 "[MT] CWelsSliceEncodingTask()InitTask for m_iSliceIdx %d, lock thread %d",
108 m_iSliceIdx, m_iThreadIdx);
109 if (m_iThreadIdx < 0) {
110 WelsLog (&m_pCtx->sLogCtx, WELS_LOG_WARNING,
111 "[MT] CWelsSliceEncodingTask InitTask(), Cannot find available thread for m_iSliceIdx = %d", m_iSliceIdx);
112 return ENC_RETURN_UNEXPECTED;
113 }
114
115 int32_t iReturn = InitOneSliceInThread (m_pCtx, m_pSlice, m_iThreadIdx, m_pCtx->uiDependencyId, m_iSliceIdx);
116 WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
117 m_pSliceBs = &m_pSlice->sSliceBs;
118
119 iReturn = SetSliceBoundaryInfo (m_pCtx->pCurDqLayer, m_pSlice, m_iSliceIdx);
120 WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
121
122 SetOneSliceBsBufferUnderMultithread (m_pCtx, m_iThreadIdx, m_pSlice);
123
124 assert ((void*) (&m_pSliceBs->sBsWrite) == (void*)m_pSlice->pSliceBsa);
125 InitBits (&m_pSliceBs->sBsWrite, m_pSliceBs->pBsBuffer, m_pSliceBs->uiSize);
126 //printf ("CWelsSliceEncodingTask_InitTask slice %d\n", m_iSliceIdx);
127
128 return ENC_RETURN_SUCCESS;
129 }
130
FinishTask()131 void CWelsSliceEncodingTask::FinishTask() {
132 WelsMutexLock (&m_pCtx->pSliceThreading->mutexThreadBsBufferUsage);
133 m_pCtx->pSliceThreading->bThreadBsBufferUsage[m_iThreadIdx] = false;
134 WelsMutexUnlock (&m_pCtx->pSliceThreading->mutexThreadBsBufferUsage);
135
136 WelsLog (&m_pCtx->sLogCtx, WELS_LOG_DEBUG,
137 "[MT] CWelsSliceEncodingTask()FinishTask for m_iSliceIdx %d, unlock thread %d",
138 m_iSliceIdx, m_iThreadIdx);
139
140 //sync multi-threading error
141 WelsMutexLock (&m_pCtx->mutexEncoderError);
142 if (ENC_RETURN_SUCCESS != m_eTaskResult) {
143 m_pCtx->iEncoderError |= m_eTaskResult;
144 }
145 WelsMutexUnlock (&m_pCtx->mutexEncoderError);
146 }
147
ExecuteTask()148 WelsErrorType CWelsSliceEncodingTask::ExecuteTask() {
149
150 #if MT_DEBUG_BS_WR
151 m_pSliceBs->bSliceCodedFlag = false;
152 #endif//MT_DEBUG_BS_WR
153 SSpatialLayerInternal* pParamInternal = &m_pCtx->pSvcParam->sDependencyLayers[m_pCtx->uiDependencyId];
154 if (m_bNeedPrefix) {
155 if (m_eNalRefIdc != NRI_PRI_LOWEST) {
156 WelsLoadNalForSlice (m_pSliceBs, NAL_UNIT_PREFIX, m_eNalRefIdc);
157 WelsWriteSVCPrefixNal (&m_pSliceBs->sBsWrite, m_eNalRefIdc, (NAL_UNIT_CODED_SLICE_IDR == m_eNalType));
158 WelsUnloadNalForSlice (m_pSliceBs);
159 } else { // No Prefix NAL Unit RBSP syntax here, but need add NAL Unit Header extension
160 WelsLoadNalForSlice (m_pSliceBs, NAL_UNIT_PREFIX, m_eNalRefIdc);
161 // No need write any syntax of prefix NAL Unit RBSP here
162 WelsUnloadNalForSlice (m_pSliceBs);
163 }
164 }
165
166 WelsLoadNalForSlice (m_pSliceBs, m_eNalType, m_eNalRefIdc);
167 assert (m_iSliceIdx == (int) m_pSlice->iSliceIdx);
168 int32_t iReturn = WelsCodeOneSlice (m_pCtx, m_pSlice, m_eNalType);
169 if (ENC_RETURN_SUCCESS != iReturn) {
170 return iReturn;
171 }
172 WelsUnloadNalForSlice (m_pSliceBs);
173
174 m_iSliceSize = 0;
175 iReturn = WriteSliceBs (m_pCtx, m_pSliceBs, m_iSliceIdx, m_iSliceSize);
176 if (ENC_RETURN_SUCCESS != iReturn) {
177 WelsLog (&m_pCtx->sLogCtx, WELS_LOG_WARNING,
178 "[MT] CWelsSliceEncodingTask ExecuteTask(), WriteSliceBs not successful: coding_idx %d, um_iSliceIdx %d",
179 pParamInternal->iCodingIndex,
180 m_iSliceIdx);
181 return iReturn;
182 }
183
184 m_pCtx->pFuncList->pfDeblocking.pfDeblockingFilterSlice (m_pCtx->pCurDqLayer, m_pCtx->pFuncList, m_pSlice);
185
186 WelsLog (&m_pCtx->sLogCtx, WELS_LOG_DETAIL,
187 "@pSlice=%-6d sliceType:%c idc:%d size:%-6d", m_iSliceIdx,
188 (m_pCtx->eSliceType == P_SLICE ? 'P' : 'I'),
189 m_eNalRefIdc,
190 m_iSliceSize);
191
192 #if MT_DEBUG_BS_WR
193 m_pSliceBs->bSliceCodedFlag = true;
194 #endif//MT_DEBUG_BS_WR
195
196 return ENC_RETURN_SUCCESS;
197 }
198
199
200 // CWelsLoadBalancingSlicingEncodingTask
InitTask()201 WelsErrorType CWelsLoadBalancingSlicingEncodingTask::InitTask() {
202 WelsErrorType iReturn = CWelsSliceEncodingTask::InitTask();
203 if (ENC_RETURN_SUCCESS != iReturn) {
204 return iReturn;
205 }
206
207 m_iSliceStart = WelsTime();
208 WelsLog (&m_pCtx->sLogCtx, WELS_LOG_DEBUG,
209 "[MT] CWelsLoadBalancingSlicingEncodingTask()InitTask for m_iSliceIdx %d at time=%" PRId64,
210 m_iSliceIdx, m_iSliceStart);
211
212 return ENC_RETURN_SUCCESS;
213 }
214
FinishTask()215 void CWelsLoadBalancingSlicingEncodingTask::FinishTask() {
216 CWelsSliceEncodingTask::FinishTask();
217 SSpatialLayerInternal* pParamInternal = &m_pCtx->pSvcParam->sDependencyLayers[m_pCtx->uiDependencyId];
218 m_pSlice->uiSliceConsumeTime = (uint32_t) (WelsTime() - m_iSliceStart);
219 WelsLog (&m_pCtx->sLogCtx, WELS_LOG_DEBUG,
220 "[MT] CWelsLoadBalancingSlicingEncodingTask()FinishTask, coding_idx %d, um_iSliceIdx %d, uiSliceConsumeTime %d, m_iSliceSize %d, iFirstMbInSlice %d, count_num_mb_in_slice %d at time=%"
221 PRId64,
222 pParamInternal->iCodingIndex,
223 m_iSliceIdx,
224 m_pSlice->uiSliceConsumeTime,
225 m_iSliceSize,
226 m_pSlice->sSliceHeaderExt.sSliceHeader.iFirstMbInSlice,
227 m_pSlice->iCountMbNumInSlice,
228 (m_pSlice->uiSliceConsumeTime + m_iSliceStart));
229 }
230
231 //CWelsConstrainedSizeSlicingEncodingTask
ExecuteTask()232 WelsErrorType CWelsConstrainedSizeSlicingEncodingTask::ExecuteTask() {
233
234 SDqLayer* pCurDq = m_pCtx->pCurDqLayer;
235 const int32_t kiSliceIdxStep = m_pCtx->iActiveThreadsNum;
236 SSpatialLayerInternal* pParamInternal = &m_pCtx->pSvcParam->sDependencyLayers[m_pCtx->uiDependencyId];
237 const int32_t kiPartitionId = m_iSliceIdx % kiSliceIdxStep;
238 const int32_t kiFirstMbInPartition = pCurDq->FirstMbIdxOfPartition[kiPartitionId];
239 const int32_t kiEndMbIdxInPartition = pCurDq->EndMbIdxOfPartition[kiPartitionId];
240 const int32_t kiCodedSliceNumByThread = pCurDq->sSliceBufferInfo[m_iThreadIdx].iCodedSliceNum;
241 m_pSlice = &pCurDq->sSliceBufferInfo[m_iThreadIdx].pSliceBuffer[kiCodedSliceNumByThread];
242 m_pSlice->sSliceHeaderExt.sSliceHeader.iFirstMbInSlice = kiFirstMbInPartition;
243 int32_t iReturn = 0;
244 bool bNeedReallocate = false;
245
246 int32_t iDiffMbIdx = kiEndMbIdxInPartition - kiFirstMbInPartition;
247 if (0 == iDiffMbIdx) {
248 m_pSlice->iSliceIdx = -1;
249 return ENC_RETURN_SUCCESS;
250 }
251
252 int32_t iAnyMbLeftInPartition = iDiffMbIdx + 1;
253 int32_t iLocalSliceIdx = m_iSliceIdx;
254 while (iAnyMbLeftInPartition > 0) {
255 bNeedReallocate = (pCurDq->sSliceBufferInfo[m_iThreadIdx].iCodedSliceNum
256 >= pCurDq->sSliceBufferInfo[m_iThreadIdx].iMaxSliceNum - 1) ? true : false;
257 if (bNeedReallocate) {
258 WelsMutexLock (&m_pCtx->pSliceThreading->mutexThreadSlcBuffReallocate);
259 //for memory statistic variable
260 iReturn = ReallocateSliceInThread (m_pCtx, pCurDq, m_pCtx->uiDependencyId, m_iThreadIdx);
261 WelsMutexUnlock (&m_pCtx->pSliceThreading->mutexThreadSlcBuffReallocate);
262 if (ENC_RETURN_SUCCESS != iReturn) {
263 return iReturn;
264 }
265 }
266
267 iReturn = InitOneSliceInThread (m_pCtx, m_pSlice, m_iThreadIdx, m_pCtx->uiDependencyId, iLocalSliceIdx);
268 WELS_VERIFY_RETURN_IFNEQ (iReturn, ENC_RETURN_SUCCESS)
269 m_pSliceBs = &m_pSlice->sSliceBs;
270 InitBits (&m_pSliceBs->sBsWrite, m_pSliceBs->pBsBuffer, m_pSliceBs->uiSize);
271
272 if (m_bNeedPrefix) {
273 if (m_eNalRefIdc != NRI_PRI_LOWEST) {
274 WelsLoadNalForSlice (m_pSliceBs, NAL_UNIT_PREFIX, m_eNalRefIdc);
275 WelsWriteSVCPrefixNal (&m_pSliceBs->sBsWrite, m_eNalRefIdc, (NAL_UNIT_CODED_SLICE_IDR == m_eNalType));
276 WelsUnloadNalForSlice (m_pSliceBs);
277 } else { // No Prefix NAL Unit RBSP syntax here, but need add NAL Unit Header extension
278 WelsLoadNalForSlice (m_pSliceBs, NAL_UNIT_PREFIX, m_eNalRefIdc);
279 // No need write any syntax of prefix NAL Unit RBSP here
280 WelsUnloadNalForSlice (m_pSliceBs);
281 }
282 }
283
284 WelsLoadNalForSlice (m_pSliceBs, m_eNalType, m_eNalRefIdc);
285
286 assert (iLocalSliceIdx == (int) m_pSlice->iSliceIdx);
287 int32_t iReturn = WelsCodeOneSlice (m_pCtx, m_pSlice, m_eNalType);
288 if (ENC_RETURN_SUCCESS != iReturn) {
289 return iReturn;
290 }
291 WelsUnloadNalForSlice (m_pSliceBs);
292
293 iReturn = WriteSliceBs (m_pCtx, m_pSliceBs, iLocalSliceIdx, m_iSliceSize);
294 if (ENC_RETURN_SUCCESS != iReturn) {
295 WelsLog (&m_pCtx->sLogCtx, WELS_LOG_WARNING,
296 "[MT] CWelsConstrainedSizeSlicingEncodingTask ExecuteTask(), WriteSliceBs not successful: coding_idx %d, uiLocalSliceIdx %d, BufferSize %d, m_iSliceSize %d, iPayloadSize %d",
297 pParamInternal->iCodingIndex,
298 iLocalSliceIdx, m_pSliceBs->uiSize, m_iSliceSize, m_pSliceBs->sNalList[0].iPayloadSize);
299 return iReturn;
300 }
301 m_pCtx->pFuncList->pfDeblocking.pfDeblockingFilterSlice (pCurDq, m_pCtx->pFuncList, m_pSlice);
302
303 WelsLog (&m_pCtx->sLogCtx, WELS_LOG_DETAIL,
304 "@pSlice=%-6d sliceType:%c idc:%d size:%-6d\n",
305 iLocalSliceIdx,
306 (m_pCtx->eSliceType == P_SLICE ? 'P' : 'I'),
307 m_eNalRefIdc,
308 m_iSliceSize
309 );
310
311 WelsLog (&m_pCtx->sLogCtx, WELS_LOG_DEBUG,
312 "[MT] CWelsConstrainedSizeSlicingEncodingTask(), coding_idx %d, iPartitionId %d, m_iThreadIdx %d, iLocalSliceIdx %d, m_iSliceSize %d, ParamValidationExt(), invalid uiMaxNalSizeiEndMbInPartition %d, pCurDq->LastCodedMbIdxOfPartition[%d] %d\n",
313 pParamInternal->iCodingIndex, kiPartitionId, m_iThreadIdx, iLocalSliceIdx, m_iSliceSize,
314 kiEndMbIdxInPartition, kiPartitionId, pCurDq->LastCodedMbIdxOfPartition[kiPartitionId]);
315
316 iAnyMbLeftInPartition = kiEndMbIdxInPartition - pCurDq->LastCodedMbIdxOfPartition[kiPartitionId];
317 iLocalSliceIdx += kiSliceIdxStep;
318 m_pCtx->pCurDqLayer->sSliceBufferInfo[m_iThreadIdx].iCodedSliceNum ++;
319 }
320
321 return ENC_RETURN_SUCCESS;
322 }
323
324
CWelsUpdateMbMapTask(WelsCommon::IWelsTaskSink * pSink,sWelsEncCtx * pCtx,const int32_t iSliceIdx)325 CWelsUpdateMbMapTask::CWelsUpdateMbMapTask (WelsCommon::IWelsTaskSink* pSink, sWelsEncCtx* pCtx,
326 const int32_t iSliceIdx): CWelsBaseTask (pSink) {
327 m_pCtx = pCtx;
328 m_iSliceIdx = iSliceIdx;
329 }
330
~CWelsUpdateMbMapTask()331 CWelsUpdateMbMapTask::~CWelsUpdateMbMapTask() {
332 }
333
Execute()334 WelsErrorType CWelsUpdateMbMapTask::Execute() {
335 UpdateMbListNeighborParallel (m_pCtx->pCurDqLayer, m_pCtx->pCurDqLayer->sMbDataP, m_iSliceIdx);
336 return ENC_RETURN_SUCCESS;
337 }
338
339 }
340
341
342