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