/work/openh264/codec/decoder/plus/src/welsDecoderExt.cpp
Line | Count | Source |
1 | | /*! |
2 | | * \copy |
3 | | * Copyright (c) 2009-2013, 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 | | * welsDecoderExt.cpp |
33 | | * |
34 | | * Abstract |
35 | | * Cisco OpenH264 decoder extension utilization |
36 | | * |
37 | | * History |
38 | | * 3/12/2009 Created |
39 | | * |
40 | | * |
41 | | ************************************************************************/ |
42 | | //#include <assert.h> |
43 | | #include "welsDecoderExt.h" |
44 | | #include "welsCodecTrace.h" |
45 | | #include "codec_def.h" |
46 | | #include "typedefs.h" |
47 | | #include "memory_align.h" |
48 | | #include "utils.h" |
49 | | #include "version.h" |
50 | | |
51 | | //#include "macros.h" |
52 | | #include "decoder.h" |
53 | | #include "decoder_core.h" |
54 | | #include "manage_dec_ref.h" |
55 | | #include "error_concealment.h" |
56 | | |
57 | | #include "measure_time.h" |
58 | | extern "C" { |
59 | | #include "decoder_core.h" |
60 | | #include "manage_dec_ref.h" |
61 | | } |
62 | | #include "error_code.h" |
63 | | #include "crt_util_safe_x.h" // Safe CRT routines like util for cross platforms |
64 | | #include <time.h> |
65 | | #if defined(_WIN32) /*&& defined(_DEBUG)*/ |
66 | | |
67 | | #include <windows.h> |
68 | | #include <stdio.h> |
69 | | #include <stdarg.h> |
70 | | #include <sys/types.h> |
71 | | #include <malloc.h> |
72 | | #else |
73 | | #include <sys/time.h> |
74 | | #endif |
75 | | |
76 | | namespace WelsDec { |
77 | | |
78 | | ////////////////////////////////////////////////////////////////////// |
79 | | // Construction/Destruction |
80 | | ////////////////////////////////////////////////////////////////////// |
81 | | |
82 | | /*************************************************************************** |
83 | | * Description: |
84 | | * class CWelsDecoder constructor function, do initialization and |
85 | | * alloc memory required |
86 | | * |
87 | | * Input parameters: none |
88 | | * |
89 | | * return: none |
90 | | ***************************************************************************/ |
91 | 0 | DECLARE_PROCTHREAD (pThrProcInit, p) { |
92 | 0 | SWelsDecThreadInfo* sThreadInfo = (SWelsDecThreadInfo*)p; |
93 | | #if defined(WIN32) |
94 | | _alloca (WELS_DEC_MAX_THREAD_STACK_SIZE * (sThreadInfo->uiThrNum + 1)); |
95 | | #endif |
96 | 0 | return sThreadInfo->pThrProcMain (p); |
97 | 0 | } |
98 | | |
99 | 0 | static DECODING_STATE ConstructAccessUnit (CWelsDecoder* pWelsDecoder, PWelsDecoderThreadCTX pThrCtx) { |
100 | 0 | int iRet = dsErrorFree; |
101 | | //WelsMutexLock (&pWelsDecoder->m_csDecoder); |
102 | 0 | if (pThrCtx->pCtx->pLastThreadCtx != NULL) { |
103 | 0 | PWelsDecoderThreadCTX pLastThreadCtx = (PWelsDecoderThreadCTX) (pThrCtx->pCtx->pLastThreadCtx); |
104 | 0 | if (WAIT_EVENT (&pLastThreadCtx->sSliceDecodeStart, WELS_DEC_THREAD_WAIT_TIMEOUT_MS) != WELS_DEC_THREAD_WAIT_SIGNALED) { |
105 | 0 | pThrCtx->pCtx->iErrorCode |= dsRefLost; |
106 | 0 | return (DECODING_STATE)GENERATE_ERROR_NO (ERR_LEVEL_SLICE_DATA, ERR_INFO_REFERENCE_PIC_LOST); |
107 | 0 | } |
108 | 0 | RESET_EVENT (&pLastThreadCtx->sSliceDecodeStart); |
109 | 0 | } |
110 | 0 | pThrCtx->pDec = NULL; |
111 | 0 | if (GetThreadCount (pThrCtx->pCtx) > 1) { |
112 | 0 | RESET_EVENT (&pThrCtx->sSliceDecodeFinish); |
113 | 0 | } |
114 | 0 | iRet |= pWelsDecoder->DecodeFrame2WithCtx (pThrCtx->pCtx, NULL, 0, pThrCtx->ppDst, &pThrCtx->sDstInfo); |
115 | | |
116 | | //WelsMutexUnlock (&pWelsDecoder->m_csDecoder); |
117 | 0 | return (DECODING_STATE)iRet; |
118 | 0 | } |
119 | | |
120 | 0 | DECLARE_PROCTHREAD (pThrProcFrame, p) { |
121 | 0 | SWelsDecoderThreadCTX* pThrCtx = (SWelsDecoderThreadCTX*)p; |
122 | 0 | while (1) { |
123 | 0 | RELEASE_SEMAPHORE (pThrCtx->sThreadInfo.sIsBusy); |
124 | 0 | RELEASE_SEMAPHORE (&pThrCtx->sThreadInfo.sIsIdle); |
125 | 0 | WAIT_SEMAPHORE (&pThrCtx->sThreadInfo.sIsActivated, WELS_DEC_THREAD_WAIT_INFINITE); |
126 | 0 | if (pThrCtx->sThreadInfo.uiCommand == WELS_DEC_THREAD_COMMAND_RUN) { |
127 | 0 | CWelsDecoder* pWelsDecoder = (CWelsDecoder*)pThrCtx->threadCtxOwner; |
128 | 0 | ConstructAccessUnit (pWelsDecoder, pThrCtx); |
129 | 0 | } else if (pThrCtx->sThreadInfo.uiCommand == WELS_DEC_THREAD_COMMAND_ABORT) { |
130 | 0 | break; |
131 | 0 | } |
132 | 0 | } |
133 | 0 | return 0; |
134 | 0 | } |
135 | | |
136 | | CWelsDecoder::CWelsDecoder (void) |
137 | 1.15k | : m_pWelsTrace (NULL), |
138 | 1.15k | m_uiDecodeTimeStamp (0), |
139 | 1.15k | m_bIsBaseline (false), |
140 | 1.15k | m_iCpuCount (1), |
141 | 1.15k | m_iThreadCount (0), |
142 | 1.15k | m_iCtxCount (1), |
143 | 1.15k | m_pPicBuff (NULL), |
144 | 1.15k | m_bParamSetsLostFlag (false), |
145 | 1.15k | m_bFreezeOutput (false), |
146 | 1.15k | m_DecCtxActiveCount (0), |
147 | 1.15k | m_pDecThrCtx (NULL), |
148 | 1.15k | m_pLastDecThrCtx (NULL), |
149 | 1.15k | m_iLastBufferedIdx (0), |
150 | 1.15k | m_iStreamSeqNum (0) { |
151 | | #ifdef OUTPUT_BIT_STREAM |
152 | | char chFileName[1024] = { 0 }; //for .264 |
153 | | int iBufUsed = 0; |
154 | | int iBufLeft = 1023; |
155 | | int iCurUsed; |
156 | | |
157 | | char chFileNameSize[1024] = { 0 }; //for .len |
158 | | int iBufUsedSize = 0; |
159 | | int iBufLeftSize = 1023; |
160 | | int iCurUsedSize; |
161 | | #endif//OUTPUT_BIT_STREAM |
162 | | |
163 | | |
164 | 1.15k | m_pWelsTrace = new welsCodecTrace(); |
165 | 1.15k | if (m_pWelsTrace != NULL) { |
166 | 1.15k | m_pWelsTrace->SetCodecInstance (this); |
167 | 1.15k | m_pWelsTrace->SetTraceLevel (WELS_LOG_ERROR); |
168 | | |
169 | 1.15k | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::CWelsDecoder() entry"); |
170 | 1.15k | } |
171 | | |
172 | 1.15k | ResetReorderingPictureBuffers (&m_sReoderingStatus, m_sPictInfoList, true); |
173 | | |
174 | 1.15k | m_iCpuCount = GetCPUCount(); |
175 | 1.15k | if (m_iCpuCount > WELS_DEC_MAX_NUM_CPU) { |
176 | 1.15k | m_iCpuCount = WELS_DEC_MAX_NUM_CPU; |
177 | 1.15k | } |
178 | | |
179 | 1.15k | m_pDecThrCtx = new SWelsDecoderThreadCTX[m_iCtxCount]; |
180 | 1.15k | memset (m_pDecThrCtx, 0, sizeof (SWelsDecoderThreadCTX)*m_iCtxCount); |
181 | 19.7k | for (int32_t i = 0; i < WELS_DEC_MAX_NUM_CPU; ++i) { |
182 | 18.5k | m_pDecThrCtxActive[i] = NULL; |
183 | 18.5k | } |
184 | | #ifdef OUTPUT_BIT_STREAM |
185 | | SWelsTime sCurTime; |
186 | | |
187 | | WelsGetTimeOfDay (&sCurTime); |
188 | | |
189 | | iCurUsed = WelsSnprintf (chFileName, iBufLeft, "bs_0x%p_", (void*)this); |
190 | | iCurUsedSize = WelsSnprintf (chFileNameSize, iBufLeftSize, "size_0x%p_", (void*)this); |
191 | | |
192 | | iBufUsed += iCurUsed; |
193 | | iBufLeft -= iCurUsed; |
194 | | if (iBufLeft > 0) { |
195 | | iCurUsed = WelsStrftime (&chFileName[iBufUsed], iBufLeft, "%y%m%d%H%M%S", &sCurTime); |
196 | | iBufUsed += iCurUsed; |
197 | | iBufLeft -= iCurUsed; |
198 | | } |
199 | | |
200 | | iBufUsedSize += iCurUsedSize; |
201 | | iBufLeftSize -= iCurUsedSize; |
202 | | if (iBufLeftSize > 0) { |
203 | | iCurUsedSize = WelsStrftime (&chFileNameSize[iBufUsedSize], iBufLeftSize, "%y%m%d%H%M%S", &sCurTime); |
204 | | iBufUsedSize += iCurUsedSize; |
205 | | iBufLeftSize -= iCurUsedSize; |
206 | | } |
207 | | |
208 | | if (iBufLeft > 0) { |
209 | | iCurUsed = WelsSnprintf (&chFileName[iBufUsed], iBufLeft, ".%03.3u.264", WelsGetMillisecond (&sCurTime)); |
210 | | iBufUsed += iCurUsed; |
211 | | iBufLeft -= iCurUsed; |
212 | | } |
213 | | |
214 | | if (iBufLeftSize > 0) { |
215 | | iCurUsedSize = WelsSnprintf (&chFileNameSize[iBufUsedSize], iBufLeftSize, ".%03.3u.len", |
216 | | WelsGetMillisecond (&sCurTime)); |
217 | | iBufUsedSize += iCurUsedSize; |
218 | | iBufLeftSize -= iCurUsedSize; |
219 | | } |
220 | | |
221 | | |
222 | | m_pFBS = WelsFopen (chFileName, "wb"); |
223 | | m_pFBSSize = WelsFopen (chFileNameSize, "wb"); |
224 | | #endif//OUTPUT_BIT_STREAM |
225 | 1.15k | } |
226 | | |
227 | | /*************************************************************************** |
228 | | * Description: |
229 | | * class CWelsDecoder destructor function, destroy allocced memory |
230 | | * |
231 | | * Input parameters: none |
232 | | * |
233 | | * return: none |
234 | | ***************************************************************************/ |
235 | 1.15k | CWelsDecoder::~CWelsDecoder() { |
236 | 1.15k | if (m_pWelsTrace != NULL) { |
237 | 1.15k | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::~CWelsDecoder()"); |
238 | 1.15k | } |
239 | 1.15k | CloseDecoderThreads(); |
240 | 1.15k | UninitDecoder(); |
241 | | |
242 | | #ifdef OUTPUT_BIT_STREAM |
243 | | if (m_pFBS) { |
244 | | WelsFclose (m_pFBS); |
245 | | m_pFBS = NULL; |
246 | | } |
247 | | if (m_pFBSSize) { |
248 | | WelsFclose (m_pFBSSize); |
249 | | m_pFBSSize = NULL; |
250 | | } |
251 | | #endif//OUTPUT_BIT_STREAM |
252 | | |
253 | 1.15k | if (m_pWelsTrace != NULL) { |
254 | 1.15k | delete m_pWelsTrace; |
255 | 1.15k | m_pWelsTrace = NULL; |
256 | 1.15k | } |
257 | 1.15k | if (m_pDecThrCtx != NULL) { |
258 | 1.15k | delete[] m_pDecThrCtx; |
259 | 1.15k | m_pDecThrCtx = NULL; |
260 | 1.15k | } |
261 | 1.15k | } |
262 | | |
263 | 1.15k | long CWelsDecoder::Initialize (const SDecodingParam* pParam) { |
264 | 1.15k | int iRet = ERR_NONE; |
265 | 1.15k | if (m_pWelsTrace == NULL) { |
266 | 0 | return cmMallocMemeError; |
267 | 0 | } |
268 | | |
269 | 1.15k | if (pParam == NULL) { |
270 | 0 | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "CWelsDecoder::Initialize(), invalid input argument."); |
271 | 0 | return cmInitParaError; |
272 | 0 | } |
273 | | |
274 | | // H.264 decoder initialization,including memory allocation,then open it ready to decode |
275 | 1.15k | iRet = InitDecoder (pParam); |
276 | 1.15k | if (iRet) |
277 | 0 | return iRet; |
278 | | |
279 | 1.15k | return cmResultSuccess; |
280 | 1.15k | } |
281 | | |
282 | 1.15k | long CWelsDecoder::Uninitialize() { |
283 | 1.15k | UninitDecoder(); |
284 | | |
285 | 1.15k | return ERR_NONE; |
286 | 1.15k | } |
287 | | |
288 | 3.47k | void CWelsDecoder::UninitDecoder (void) { |
289 | 6.95k | for (int32_t i = 0; i < m_iCtxCount; ++i) { |
290 | 3.47k | if (m_pDecThrCtx[i].pCtx != NULL) { |
291 | 1.15k | if (i > 0) { |
292 | 0 | WelsResetRefPicWithoutUnRef (m_pDecThrCtx[i].pCtx); |
293 | 0 | } |
294 | 1.15k | UninitDecoderCtx (m_pDecThrCtx[i].pCtx); |
295 | 1.15k | } |
296 | 3.47k | } |
297 | 3.47k | } |
298 | | |
299 | 1.15k | void CWelsDecoder::OpenDecoderThreads() { |
300 | 1.15k | if (m_iThreadCount >= 1) { |
301 | 0 | m_uiDecodeTimeStamp = 0; |
302 | 0 | CREATE_SEMAPHORE (&m_sIsBusy, m_iThreadCount, m_iThreadCount, NULL); |
303 | 0 | WelsMutexInit (&m_csDecoder); |
304 | 0 | CREATE_EVENT (&m_sBufferingEvent, 1, 0, NULL); |
305 | 0 | SET_EVENT (&m_sBufferingEvent); |
306 | 0 | CREATE_EVENT (&m_sReleaseBufferEvent, 1, 0, NULL); |
307 | 0 | SET_EVENT (&m_sReleaseBufferEvent); |
308 | 0 | for (int32_t i = 0; i < m_iThreadCount; ++i) { |
309 | 0 | m_pDecThrCtx[i].sThreadInfo.uiThrMaxNum = m_iThreadCount; |
310 | 0 | m_pDecThrCtx[i].sThreadInfo.uiThrNum = i; |
311 | 0 | m_pDecThrCtx[i].sThreadInfo.uiThrStackSize = WELS_DEC_MAX_THREAD_STACK_SIZE; |
312 | 0 | m_pDecThrCtx[i].sThreadInfo.pThrProcMain = pThrProcFrame; |
313 | 0 | m_pDecThrCtx[i].sThreadInfo.sIsBusy = &m_sIsBusy; |
314 | 0 | m_pDecThrCtx[i].sThreadInfo.uiCommand = WELS_DEC_THREAD_COMMAND_RUN; |
315 | 0 | m_pDecThrCtx[i].threadCtxOwner = this; |
316 | 0 | m_pDecThrCtx[i].kpSrc = NULL; |
317 | 0 | m_pDecThrCtx[i].kiSrcLen = 0; |
318 | 0 | m_pDecThrCtx[i].ppDst = NULL; |
319 | 0 | m_pDecThrCtx[i].pDec = NULL; |
320 | 0 | CREATE_EVENT (&m_pDecThrCtx[i].sImageReady, 1, 0, NULL); |
321 | 0 | CREATE_EVENT (&m_pDecThrCtx[i].sSliceDecodeStart, 1, 0, NULL); |
322 | 0 | CREATE_EVENT (&m_pDecThrCtx[i].sSliceDecodeFinish, 1, 0, NULL); |
323 | 0 | CREATE_SEMAPHORE (&m_pDecThrCtx[i].sThreadInfo.sIsIdle, 0, 1, NULL); |
324 | 0 | CREATE_SEMAPHORE (&m_pDecThrCtx[i].sThreadInfo.sIsActivated, 0, 1, NULL); |
325 | 0 | CREATE_THREAD (&m_pDecThrCtx[i].sThreadInfo.sThrHandle, pThrProcInit, (void*) (& (m_pDecThrCtx[i]))); |
326 | 0 | } |
327 | 0 | } |
328 | 1.15k | } |
329 | 1.15k | void CWelsDecoder::CloseDecoderThreads() { |
330 | 1.15k | if (m_iThreadCount >= 1) { |
331 | 0 | SET_EVENT (&m_sReleaseBufferEvent); |
332 | 0 | for (int32_t i = 0; i < m_iThreadCount; i++) { //waiting the completion begun slices |
333 | 0 | WAIT_SEMAPHORE (&m_pDecThrCtx[i].sThreadInfo.sIsIdle, WELS_DEC_THREAD_WAIT_INFINITE); |
334 | 0 | m_pDecThrCtx[i].sThreadInfo.uiCommand = WELS_DEC_THREAD_COMMAND_ABORT; |
335 | 0 | RELEASE_SEMAPHORE (&m_pDecThrCtx[i].sThreadInfo.sIsActivated); |
336 | 0 | WAIT_THREAD (&m_pDecThrCtx[i].sThreadInfo.sThrHandle); |
337 | 0 | CLOSE_EVENT (&m_pDecThrCtx[i].sImageReady); |
338 | 0 | CLOSE_EVENT (&m_pDecThrCtx[i].sSliceDecodeStart); |
339 | 0 | CLOSE_EVENT (&m_pDecThrCtx[i].sSliceDecodeFinish); |
340 | 0 | CLOSE_SEMAPHORE (&m_pDecThrCtx[i].sThreadInfo.sIsIdle); |
341 | 0 | CLOSE_SEMAPHORE (&m_pDecThrCtx[i].sThreadInfo.sIsActivated); |
342 | 0 | } |
343 | 0 | WelsMutexDestroy (&m_csDecoder); |
344 | 0 | CLOSE_EVENT (&m_sBufferingEvent); |
345 | 0 | CLOSE_EVENT (&m_sReleaseBufferEvent); |
346 | 0 | CLOSE_SEMAPHORE (&m_sIsBusy); |
347 | 0 | } |
348 | 1.15k | } |
349 | | |
350 | 2.31k | void CWelsDecoder::UninitDecoderCtx (PWelsDecoderContext& pCtx) { |
351 | 2.31k | if (pCtx != NULL) { |
352 | | |
353 | 1.15k | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "CWelsDecoder::UninitDecoderCtx(), openh264 codec version = %s.", |
354 | 1.15k | VERSION_NUMBER); |
355 | | |
356 | 1.15k | WelsEndDecoder (pCtx); |
357 | | |
358 | 1.15k | if (pCtx->pMemAlign != NULL) { |
359 | 1.15k | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, |
360 | 1.15k | "CWelsDecoder::UninitDecoder(), verify memory usage (%d bytes) after free..", |
361 | 1.15k | pCtx->pMemAlign->WelsGetMemoryUsage()); |
362 | 1.15k | delete pCtx->pMemAlign; |
363 | 1.15k | pCtx->pMemAlign = NULL; |
364 | 1.15k | } |
365 | | |
366 | 1.15k | if (NULL != pCtx) { |
367 | 1.15k | WelsFree (pCtx, "m_pDecContext"); |
368 | | |
369 | 1.15k | pCtx = NULL; |
370 | 1.15k | } |
371 | 1.15k | if (m_iCtxCount <= 1) m_pDecThrCtx[0].pCtx = NULL; |
372 | 1.15k | } |
373 | 2.31k | } |
374 | | |
375 | | // the return value of this function is not suitable, it need report failure info to upper layer. |
376 | 1.15k | int32_t CWelsDecoder::InitDecoder (const SDecodingParam* pParam) { |
377 | | |
378 | 1.15k | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, |
379 | 1.15k | "CWelsDecoder::init_decoder(), openh264 codec version = %s, ParseOnly = %d", |
380 | 1.15k | VERSION_NUMBER, (int32_t)pParam->bParseOnly); |
381 | 1.15k | if (m_iThreadCount >= 1 && pParam->bParseOnly) { |
382 | 0 | m_iThreadCount = 0; |
383 | 0 | } |
384 | 1.15k | OpenDecoderThreads(); |
385 | | //reset decoder context |
386 | 1.15k | memset (&m_sDecoderStatistics, 0, sizeof (SDecoderStatistics)); |
387 | 1.15k | memset (&m_sLastDecPicInfo, 0, sizeof (SWelsLastDecPicInfo)); |
388 | 1.15k | memset (&m_sVlcTable, 0, sizeof (SVlcTable)); |
389 | 1.15k | UninitDecoder(); |
390 | 1.15k | WelsDecoderLastDecPicInfoDefaults (m_sLastDecPicInfo); |
391 | 2.31k | for (int32_t i = 0; i < m_iCtxCount; ++i) { |
392 | 1.15k | InitDecoderCtx (m_pDecThrCtx[i].pCtx, pParam); |
393 | 1.15k | if (m_iThreadCount >= 1) { |
394 | 0 | m_pDecThrCtx[i].pCtx->pThreadCtx = &m_pDecThrCtx[i]; |
395 | 0 | } |
396 | 1.15k | } |
397 | 1.15k | m_bParamSetsLostFlag = false; |
398 | 1.15k | m_bFreezeOutput = false; |
399 | 1.15k | return cmResultSuccess; |
400 | 1.15k | } |
401 | | |
402 | | // the return value of this function is not suitable, it need report failure info to upper layer. |
403 | 1.15k | int32_t CWelsDecoder::InitDecoderCtx (PWelsDecoderContext& pCtx, const SDecodingParam* pParam) { |
404 | | |
405 | 1.15k | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, |
406 | 1.15k | "CWelsDecoder::init_decoder(), openh264 codec version = %s, ParseOnly = %d", |
407 | 1.15k | VERSION_NUMBER, (int32_t)pParam->bParseOnly); |
408 | | |
409 | | //reset decoder context |
410 | 1.15k | UninitDecoderCtx (pCtx); |
411 | 1.15k | pCtx = (PWelsDecoderContext)WelsMallocz (sizeof (SWelsDecoderContext), "m_pDecContext"); |
412 | 1.15k | if (NULL == pCtx) |
413 | 0 | return cmMallocMemeError; |
414 | 1.15k | int32_t iCacheLineSize = 16; // on chip cache line size in byte |
415 | 1.15k | pCtx->pMemAlign = new CMemoryAlign (iCacheLineSize); |
416 | 1.15k | WELS_VERIFY_RETURN_PROC_IF (cmMallocMemeError, (NULL == pCtx->pMemAlign), UninitDecoderCtx (pCtx)) |
417 | 1.15k | if (m_iCtxCount <= 1) m_pDecThrCtx[0].pCtx = pCtx; |
418 | | //fill in default value into context |
419 | 1.15k | pCtx->pLastDecPicInfo = &m_sLastDecPicInfo; |
420 | 1.15k | pCtx->pDecoderStatistics = &m_sDecoderStatistics; |
421 | 1.15k | pCtx->pVlcTable = &m_sVlcTable; |
422 | 1.15k | pCtx->pPictInfoList = m_sPictInfoList; |
423 | 1.15k | pCtx->pPictReoderingStatus = &m_sReoderingStatus; |
424 | 1.15k | pCtx->pCsDecoder = &m_csDecoder; |
425 | 1.15k | pCtx->pStreamSeqNum = &m_iStreamSeqNum; |
426 | 1.15k | WelsDecoderDefaults (pCtx, &m_pWelsTrace->m_sLogCtx); |
427 | 1.15k | WelsDecoderSpsPpsDefaults (pCtx->sSpsPpsCtx); |
428 | | //check param and update decoder context |
429 | 1.15k | pCtx->pParam = (SDecodingParam*)pCtx->pMemAlign->WelsMallocz (sizeof (SDecodingParam), |
430 | 1.15k | "SDecodingParam"); |
431 | 1.15k | WELS_VERIFY_RETURN_PROC_IF (cmMallocMemeError, (NULL == pCtx->pParam), UninitDecoderCtx (pCtx)); |
432 | 1.15k | int32_t iRet = DecoderConfigParam (pCtx, pParam); |
433 | 1.15k | WELS_VERIFY_RETURN_IFNEQ (iRet, cmResultSuccess); |
434 | | |
435 | | //init decoder |
436 | 1.15k | WELS_VERIFY_RETURN_PROC_IF (cmMallocMemeError, WelsInitDecoder (pCtx, &m_pWelsTrace->m_sLogCtx), |
437 | 1.15k | UninitDecoderCtx (pCtx)) |
438 | 1.15k | pCtx->pPicBuff = NULL; |
439 | 1.15k | return cmResultSuccess; |
440 | 1.15k | } |
441 | | |
442 | 0 | int32_t CWelsDecoder::ResetDecoder (PWelsDecoderContext& pCtx) { |
443 | | // TBC: need to be modified when context and trace point are null |
444 | 0 | if (m_iThreadCount >= 1) { |
445 | 0 | ThreadResetDecoder (pCtx); |
446 | 0 | } else { |
447 | 0 | if (pCtx != NULL && m_pWelsTrace != NULL) { |
448 | 0 | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "ResetDecoder(), context error code is %d", |
449 | 0 | pCtx->iErrorCode); |
450 | 0 | SDecodingParam sPrevParam; |
451 | 0 | memcpy (&sPrevParam, pCtx->pParam, sizeof (SDecodingParam)); |
452 | |
|
453 | 0 | WELS_VERIFY_RETURN_PROC_IF (cmInitParaError, InitDecoderCtx (pCtx, &sPrevParam), |
454 | 0 | UninitDecoderCtx (pCtx)); |
455 | 0 | } else if (m_pWelsTrace != NULL) { |
456 | 0 | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "ResetDecoder() failed as decoder context null"); |
457 | 0 | } |
458 | 0 | ResetReorderingPictureBuffers (&m_sReoderingStatus, m_sPictInfoList, false); |
459 | 0 | } |
460 | 0 | return ERR_INFO_UNINIT; |
461 | 0 | } |
462 | | |
463 | 0 | int32_t CWelsDecoder::ThreadResetDecoder (PWelsDecoderContext& pCtx) { |
464 | | // TBC: need to be modified when context and trace point are null |
465 | 0 | SDecodingParam sPrevParam; |
466 | 0 | if (pCtx != NULL && m_pWelsTrace != NULL) { |
467 | 0 | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "ResetDecoder(), context error code is %d", pCtx->iErrorCode); |
468 | 0 | memcpy (&sPrevParam, pCtx->pParam, sizeof (SDecodingParam)); |
469 | 0 | ResetReorderingPictureBuffers (&m_sReoderingStatus, m_sPictInfoList, true); |
470 | 0 | CloseDecoderThreads(); |
471 | 0 | UninitDecoder(); |
472 | 0 | InitDecoder (&sPrevParam); |
473 | 0 | } else if (m_pWelsTrace != NULL) { |
474 | 0 | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "ResetDecoder() failed as decoder context null"); |
475 | 0 | } |
476 | 0 | return ERR_INFO_UNINIT; |
477 | 0 | } |
478 | | |
479 | | /* |
480 | | * Set Option |
481 | | */ |
482 | 0 | long CWelsDecoder::SetOption (DECODER_OPTION eOptID, void* pOption) { |
483 | 0 | int iVal = 0; |
484 | 0 | if (eOptID == DECODER_OPTION_NUM_OF_THREADS) { |
485 | 0 | if (pOption != NULL) { |
486 | 0 | int32_t threadCount = * ((int32_t*)pOption); |
487 | 0 | if (threadCount < 0) threadCount = 0; |
488 | 0 | if (threadCount > m_iCpuCount) { |
489 | 0 | threadCount = m_iCpuCount; |
490 | 0 | } |
491 | 0 | if (threadCount > 3) { |
492 | 0 | threadCount = 3; |
493 | 0 | } |
494 | 0 | if (threadCount != m_iThreadCount) { |
495 | 0 | m_iThreadCount = threadCount; |
496 | 0 | if (m_pDecThrCtx != NULL) { |
497 | 0 | delete [] m_pDecThrCtx; |
498 | 0 | m_iCtxCount = m_iThreadCount == 0 ? 1 : m_iThreadCount; |
499 | 0 | m_pDecThrCtx = new SWelsDecoderThreadCTX[m_iCtxCount]; |
500 | 0 | memset (m_pDecThrCtx, 0, sizeof (SWelsDecoderThreadCTX)*m_iCtxCount); |
501 | 0 | } |
502 | 0 | } |
503 | 0 | } |
504 | 0 | return cmResultSuccess; |
505 | 0 | } |
506 | 0 | for (int32_t i = 0; i < m_iCtxCount; ++i) { |
507 | 0 | PWelsDecoderContext pDecContext = m_pDecThrCtx[i].pCtx; |
508 | 0 | if (pDecContext == NULL && eOptID != DECODER_OPTION_TRACE_LEVEL && |
509 | 0 | eOptID != DECODER_OPTION_TRACE_CALLBACK && eOptID != DECODER_OPTION_TRACE_CALLBACK_CONTEXT) |
510 | 0 | return dsInitialOptExpected; |
511 | 0 | if (eOptID == DECODER_OPTION_END_OF_STREAM) { // Indicate bit-stream of the final frame to be decoded |
512 | 0 | if (pOption == NULL) |
513 | 0 | return cmInitParaError; |
514 | | |
515 | 0 | iVal = * ((int*)pOption); // boolean value for whether enabled End Of Stream flag |
516 | |
|
517 | 0 | if (pDecContext == NULL) return dsInitialOptExpected; |
518 | | |
519 | 0 | pDecContext->bEndOfStreamFlag = iVal ? true : false; |
520 | 0 | if (iVal && m_iThreadCount >= 1) |
521 | 0 | SET_EVENT (&m_sReleaseBufferEvent); |
522 | |
|
523 | 0 | return cmResultSuccess; |
524 | 0 | } else if (eOptID == DECODER_OPTION_ERROR_CON_IDC) { // Indicate error concealment status |
525 | 0 | if (pOption == NULL) |
526 | 0 | return cmInitParaError; |
527 | | |
528 | 0 | if (pDecContext == NULL) return dsInitialOptExpected; |
529 | | |
530 | 0 | iVal = * ((int*)pOption); // int value for error concealment idc |
531 | 0 | iVal = WELS_CLIP3 (iVal, (int32_t)ERROR_CON_DISABLE, (int32_t)ERROR_CON_SLICE_MV_COPY_CROSS_IDR_FREEZE_RES_CHANGE); |
532 | 0 | if ((pDecContext->pParam->bParseOnly) && (iVal != (int32_t)ERROR_CON_DISABLE)) { |
533 | 0 | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, |
534 | 0 | "CWelsDecoder::SetOption for ERROR_CON_IDC = %d not allowd for parse only!.", iVal); |
535 | 0 | return cmInitParaError; |
536 | 0 | } |
537 | | |
538 | 0 | pDecContext->pParam->eEcActiveIdc = (ERROR_CON_IDC)iVal; |
539 | 0 | InitErrorCon (pDecContext); |
540 | 0 | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, |
541 | 0 | "CWelsDecoder::SetOption for ERROR_CON_IDC = %d.", iVal); |
542 | |
|
543 | 0 | return cmResultSuccess; |
544 | 0 | } else if (eOptID == DECODER_OPTION_TRACE_LEVEL) { |
545 | 0 | if (m_pWelsTrace) { |
546 | 0 | uint32_t level = * ((uint32_t*)pOption); |
547 | 0 | m_pWelsTrace->SetTraceLevel (level); |
548 | 0 | } |
549 | 0 | return cmResultSuccess; |
550 | 0 | } else if (eOptID == DECODER_OPTION_TRACE_CALLBACK) { |
551 | 0 | if (m_pWelsTrace) { |
552 | 0 | WelsTraceCallback callback = * ((WelsTraceCallback*)pOption); |
553 | 0 | m_pWelsTrace->SetTraceCallback (callback); |
554 | 0 | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, |
555 | 0 | "CWelsDecoder::SetOption():DECODER_OPTION_TRACE_CALLBACK callback = %p.", |
556 | 0 | callback); |
557 | 0 | } |
558 | 0 | return cmResultSuccess; |
559 | 0 | } else if (eOptID == DECODER_OPTION_TRACE_CALLBACK_CONTEXT) { |
560 | 0 | if (m_pWelsTrace) { |
561 | 0 | void* ctx = * ((void**)pOption); |
562 | 0 | m_pWelsTrace->SetTraceCallbackContext (ctx); |
563 | 0 | } |
564 | 0 | return cmResultSuccess; |
565 | 0 | } else if (eOptID == DECODER_OPTION_GET_STATISTICS) { |
566 | 0 | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING, |
567 | 0 | "CWelsDecoder::SetOption():DECODER_OPTION_GET_STATISTICS: this option is get-only!"); |
568 | 0 | return cmInitParaError; |
569 | 0 | } else if (eOptID == DECODER_OPTION_STATISTICS_LOG_INTERVAL) { |
570 | 0 | if (pOption) { |
571 | 0 | if (pDecContext == NULL) return dsInitialOptExpected; |
572 | 0 | pDecContext->pDecoderStatistics->iStatisticsLogInterval = (* ((unsigned int*)pOption)); |
573 | 0 | return cmResultSuccess; |
574 | 0 | } |
575 | 0 | } else if (eOptID == DECODER_OPTION_GET_SAR_INFO) { |
576 | 0 | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING, |
577 | 0 | "CWelsDecoder::SetOption():DECODER_OPTION_GET_SAR_INFO: this option is get-only!"); |
578 | 0 | return cmInitParaError; |
579 | 0 | } |
580 | 0 | } |
581 | 0 | return cmInitParaError; |
582 | 0 | } |
583 | | |
584 | | /* |
585 | | * Get Option |
586 | | */ |
587 | 0 | long CWelsDecoder::GetOption (DECODER_OPTION eOptID, void* pOption) { |
588 | 0 | int iVal = 0; |
589 | 0 | if (DECODER_OPTION_NUM_OF_THREADS == eOptID) { |
590 | 0 | * ((int*)pOption) = m_iThreadCount; |
591 | 0 | return cmResultSuccess; |
592 | 0 | } |
593 | 0 | PWelsDecoderContext pDecContext = m_pDecThrCtx[0].pCtx; |
594 | 0 | if (pDecContext == NULL) |
595 | 0 | return cmInitExpected; |
596 | | |
597 | 0 | if (pOption == NULL) |
598 | 0 | return cmInitParaError; |
599 | | |
600 | 0 | if (DECODER_OPTION_END_OF_STREAM == eOptID) { |
601 | 0 | iVal = pDecContext->bEndOfStreamFlag; |
602 | 0 | * ((int*)pOption) = iVal; |
603 | 0 | return cmResultSuccess; |
604 | 0 | } |
605 | 0 | #ifdef LONG_TERM_REF |
606 | 0 | else if (DECODER_OPTION_IDR_PIC_ID == eOptID) { |
607 | 0 | iVal = pDecContext->uiCurIdrPicId; |
608 | 0 | * ((int*)pOption) = iVal; |
609 | 0 | return cmResultSuccess; |
610 | 0 | } else if (DECODER_OPTION_FRAME_NUM == eOptID) { |
611 | 0 | iVal = pDecContext->iFrameNum; |
612 | 0 | * ((int*)pOption) = iVal; |
613 | 0 | return cmResultSuccess; |
614 | 0 | } else if (DECODER_OPTION_LTR_MARKING_FLAG == eOptID) { |
615 | 0 | iVal = pDecContext->bCurAuContainLtrMarkSeFlag; |
616 | 0 | * ((int*)pOption) = iVal; |
617 | 0 | return cmResultSuccess; |
618 | 0 | } else if (DECODER_OPTION_LTR_MARKED_FRAME_NUM == eOptID) { |
619 | 0 | iVal = pDecContext->iFrameNumOfAuMarkedLtr; |
620 | 0 | * ((int*)pOption) = iVal; |
621 | 0 | return cmResultSuccess; |
622 | 0 | } |
623 | 0 | #endif |
624 | 0 | else if (DECODER_OPTION_VCL_NAL == eOptID) { //feedback whether or not have VCL NAL in current AU |
625 | 0 | iVal = pDecContext->iFeedbackVclNalInAu; |
626 | 0 | * ((int*)pOption) = iVal; |
627 | 0 | return cmResultSuccess; |
628 | 0 | } else if (DECODER_OPTION_TEMPORAL_ID == eOptID) { //if have VCL NAL in current AU, then feedback the temporal ID |
629 | 0 | iVal = pDecContext->iFeedbackTidInAu; |
630 | 0 | * ((int*)pOption) = iVal; |
631 | 0 | return cmResultSuccess; |
632 | 0 | } else if (DECODER_OPTION_IS_REF_PIC == eOptID) { |
633 | 0 | iVal = pDecContext->iFeedbackNalRefIdc; |
634 | 0 | if (iVal > 0) |
635 | 0 | iVal = 1; |
636 | 0 | * ((int*)pOption) = iVal; |
637 | 0 | return cmResultSuccess; |
638 | 0 | } else if (DECODER_OPTION_ERROR_CON_IDC == eOptID) { |
639 | 0 | iVal = (int)pDecContext->pParam->eEcActiveIdc; |
640 | 0 | * ((int*)pOption) = iVal; |
641 | 0 | return cmResultSuccess; |
642 | 0 | } else if (DECODER_OPTION_GET_STATISTICS == eOptID) { // get decoder statistics info for real time debugging |
643 | 0 | SDecoderStatistics* pDecoderStatistics = (static_cast<SDecoderStatistics*> (pOption)); |
644 | |
|
645 | 0 | memcpy (pDecoderStatistics, pDecContext->pDecoderStatistics, sizeof (SDecoderStatistics)); |
646 | |
|
647 | 0 | if (pDecContext->pDecoderStatistics->uiDecodedFrameCount != 0) { //not original status |
648 | 0 | pDecoderStatistics->fAverageFrameSpeedInMs = (float) (pDecContext->dDecTime) / |
649 | 0 | (pDecContext->pDecoderStatistics->uiDecodedFrameCount); |
650 | 0 | pDecoderStatistics->fActualAverageFrameSpeedInMs = (float) (pDecContext->dDecTime) / |
651 | 0 | (pDecContext->pDecoderStatistics->uiDecodedFrameCount + pDecContext->pDecoderStatistics->uiFreezingIDRNum + |
652 | 0 | pDecContext->pDecoderStatistics->uiFreezingNonIDRNum); |
653 | 0 | } |
654 | 0 | return cmResultSuccess; |
655 | 0 | } else if (eOptID == DECODER_OPTION_STATISTICS_LOG_INTERVAL) { |
656 | 0 | if (pOption) { |
657 | 0 | iVal = pDecContext->pDecoderStatistics->iStatisticsLogInterval; |
658 | 0 | * ((unsigned int*)pOption) = iVal; |
659 | 0 | return cmResultSuccess; |
660 | 0 | } |
661 | 0 | } else if (DECODER_OPTION_GET_SAR_INFO == eOptID) { //get decoder SAR info in VUI |
662 | 0 | PVuiSarInfo pVuiSarInfo = (static_cast<PVuiSarInfo> (pOption)); |
663 | 0 | memset (pVuiSarInfo, 0, sizeof (SVuiSarInfo)); |
664 | 0 | if (!pDecContext->pSps) { |
665 | 0 | return cmInitExpected; |
666 | 0 | } else { |
667 | 0 | pVuiSarInfo->uiSarWidth = pDecContext->pSps->sVui.uiSarWidth; |
668 | 0 | pVuiSarInfo->uiSarHeight = pDecContext->pSps->sVui.uiSarHeight; |
669 | 0 | pVuiSarInfo->bOverscanAppropriateFlag = pDecContext->pSps->sVui.bOverscanAppropriateFlag; |
670 | 0 | return cmResultSuccess; |
671 | 0 | } |
672 | 0 | } else if (DECODER_OPTION_PROFILE == eOptID) { |
673 | 0 | if (!pDecContext->pSps) { |
674 | 0 | return cmInitExpected; |
675 | 0 | } |
676 | 0 | iVal = (int)pDecContext->pSps->uiProfileIdc; |
677 | 0 | * ((int*)pOption) = iVal; |
678 | 0 | return cmResultSuccess; |
679 | 0 | } else if (DECODER_OPTION_LEVEL == eOptID) { |
680 | 0 | if (!pDecContext->pSps) { |
681 | 0 | return cmInitExpected; |
682 | 0 | } |
683 | 0 | iVal = (int)pDecContext->pSps->uiLevelIdc; |
684 | 0 | * ((int*)pOption) = iVal; |
685 | 0 | return cmResultSuccess; |
686 | 0 | } else if (DECODER_OPTION_NUM_OF_FRAMES_REMAINING_IN_BUFFER == eOptID) { |
687 | 0 | for (int32_t activeThread = 0; activeThread < m_DecCtxActiveCount; ++activeThread) { |
688 | 0 | WAIT_SEMAPHORE (&m_pDecThrCtxActive[activeThread]->sThreadInfo.sIsIdle, WELS_DEC_THREAD_WAIT_INFINITE); |
689 | 0 | RELEASE_SEMAPHORE (&m_pDecThrCtxActive[activeThread]->sThreadInfo.sIsIdle); |
690 | 0 | } |
691 | 0 | * ((int*)pOption) = m_sReoderingStatus.iNumOfPicts; |
692 | 0 | return cmResultSuccess; |
693 | 0 | } |
694 | | |
695 | 0 | return cmInitParaError; |
696 | 0 | } |
697 | | |
698 | | DECODING_STATE CWelsDecoder::DecodeFrameNoDelay (const unsigned char* kpSrc, |
699 | | const int kiSrcLen, |
700 | | unsigned char** ppDst, |
701 | 1.04k | SBufferInfo* pDstInfo) { |
702 | 1.04k | int iRet = dsErrorFree; |
703 | 1.04k | if (m_iThreadCount >= 1) { |
704 | 0 | SET_EVENT (&m_sReleaseBufferEvent); |
705 | 0 | iRet = ThreadDecodeFrameInternal (kpSrc, kiSrcLen, ppDst, pDstInfo); |
706 | 0 | if (m_sReoderingStatus.iNumOfPicts) { |
707 | 0 | WAIT_EVENT (&m_sBufferingEvent, WELS_DEC_THREAD_WAIT_INFINITE); |
708 | 0 | RESET_EVENT (&m_sBufferingEvent); |
709 | 0 | RESET_EVENT (&m_sReleaseBufferEvent); |
710 | 0 | if (!m_sReoderingStatus.bHasBSlice) { |
711 | 0 | if (m_sReoderingStatus.iNumOfPicts > 1) { |
712 | 0 | ReleaseBufferedReadyPictureNoReorder (NULL, ppDst, pDstInfo); |
713 | 0 | } |
714 | 0 | } |
715 | 0 | else { |
716 | 0 | ReleaseBufferedReadyPictureReorder (NULL, ppDst, pDstInfo); |
717 | 0 | } |
718 | 0 | } |
719 | 0 | return (DECODING_STATE)iRet; |
720 | 0 | } |
721 | | //SBufferInfo sTmpBufferInfo; |
722 | | //unsigned char* ppTmpDst[3] = {NULL, NULL, NULL}; |
723 | 1.04k | iRet = (int)DecodeFrame2 (kpSrc, kiSrcLen, ppDst, pDstInfo); |
724 | | //memcpy (&sTmpBufferInfo, pDstInfo, sizeof (SBufferInfo)); |
725 | | //ppTmpDst[0] = ppDst[0]; |
726 | | //ppTmpDst[1] = ppDst[1]; |
727 | | //ppTmpDst[2] = ppDst[2]; |
728 | 1.04k | iRet |= DecodeFrame2 (NULL, 0, ppDst, pDstInfo); |
729 | | //if ((pDstInfo->iBufferStatus == 0) && (sTmpBufferInfo.iBufferStatus == 1)) { |
730 | | //memcpy (pDstInfo, &sTmpBufferInfo, sizeof (SBufferInfo)); |
731 | | //ppDst[0] = ppTmpDst[0]; |
732 | | //ppDst[1] = ppTmpDst[1]; |
733 | | //ppDst[2] = ppTmpDst[2]; |
734 | | //} |
735 | 1.04k | return (DECODING_STATE)iRet; |
736 | 1.04k | } |
737 | | |
738 | | DECODING_STATE CWelsDecoder::DecodeFrame2WithCtx (PWelsDecoderContext pDecContext, const unsigned char* kpSrc, |
739 | | const int kiSrcLen, |
740 | | unsigned char** ppDst, |
741 | 2.08k | SBufferInfo* pDstInfo) { |
742 | 2.08k | if (pDecContext == NULL || pDecContext->pParam == NULL) { |
743 | 0 | if (m_pWelsTrace != NULL) { |
744 | 0 | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "Call DecodeFrame2 without Initialize.\n"); |
745 | 0 | } |
746 | 0 | return dsInitialOptExpected; |
747 | 0 | } |
748 | | |
749 | 2.08k | if (pDecContext->pParam->bParseOnly) { |
750 | 0 | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "bParseOnly should be false for this API calling! \n"); |
751 | 0 | pDecContext->iErrorCode |= dsInvalidArgument; |
752 | 0 | return dsInvalidArgument; |
753 | 0 | } |
754 | 2.08k | if (CheckBsBuffer (pDecContext, kiSrcLen)) { |
755 | 0 | if (ResetDecoder(pDecContext)) { |
756 | 0 | if (pDstInfo) pDstInfo->iBufferStatus = 0; |
757 | 0 | return dsOutOfMemory; |
758 | 0 | } |
759 | 0 | return dsErrorFree; |
760 | 0 | } |
761 | 2.08k | if (kiSrcLen > 0 && kpSrc != NULL) { |
762 | | #ifdef OUTPUT_BIT_STREAM |
763 | | if (m_pFBS) { |
764 | | WelsFwrite (kpSrc, sizeof (unsigned char), kiSrcLen, m_pFBS); |
765 | | WelsFflush (m_pFBS); |
766 | | } |
767 | | if (m_pFBSSize) { |
768 | | WelsFwrite (&kiSrcLen, sizeof (int), 1, m_pFBSSize); |
769 | | WelsFflush (m_pFBSSize); |
770 | | } |
771 | | #endif//OUTPUT_BIT_STREAM |
772 | 1.04k | pDecContext->bEndOfStreamFlag = false; |
773 | 1.04k | if (GetThreadCount (pDecContext) <= 0) { |
774 | 1.04k | pDecContext->uiDecodingTimeStamp = ++m_uiDecodeTimeStamp; |
775 | 1.04k | } |
776 | 1.04k | } else { |
777 | | //For application MODE, the error detection should be added for safe. |
778 | | //But for CONSOLE MODE, when decoding LAST AU, kiSrcLen==0 && kpSrc==NULL. |
779 | 1.04k | pDecContext->bEndOfStreamFlag = true; |
780 | 1.04k | pDecContext->bInstantDecFlag = true; |
781 | 1.04k | } |
782 | | |
783 | 2.08k | int64_t iStart, iEnd; |
784 | 2.08k | iStart = WelsTime(); |
785 | | |
786 | 2.08k | if (GetThreadCount (pDecContext) <= 1) { |
787 | 2.08k | ppDst[0] = ppDst[1] = ppDst[2] = NULL; |
788 | 2.08k | } |
789 | 2.08k | pDecContext->iErrorCode = dsErrorFree; //initialize at the starting of AU decoding. |
790 | 2.08k | pDecContext->iFeedbackVclNalInAu = FEEDBACK_UNKNOWN_NAL; //initialize |
791 | 2.08k | unsigned long long uiInBsTimeStamp = pDstInfo->uiInBsTimeStamp; |
792 | 2.08k | if (GetThreadCount (pDecContext) <= 1) { |
793 | 2.08k | memset (pDstInfo, 0, sizeof (SBufferInfo)); |
794 | 2.08k | } |
795 | 2.08k | pDstInfo->uiInBsTimeStamp = uiInBsTimeStamp; |
796 | 2.08k | #ifdef LONG_TERM_REF |
797 | 2.08k | pDecContext->bReferenceLostAtT0Flag = false; //initialize for LTR |
798 | 2.08k | pDecContext->bCurAuContainLtrMarkSeFlag = false; |
799 | 2.08k | pDecContext->iFrameNumOfAuMarkedLtr = 0; |
800 | 2.08k | pDecContext->iFrameNum = -1; //initialize |
801 | 2.08k | #endif |
802 | | |
803 | 2.08k | if (GetThreadCount (pDecContext) >= 1) { |
804 | 0 | WAIT_EVENT (&m_sReleaseBufferEvent, WELS_DEC_THREAD_WAIT_INFINITE); |
805 | 0 | } |
806 | | |
807 | 2.08k | pDecContext->iFeedbackTidInAu = -1; //initialize |
808 | 2.08k | pDecContext->iFeedbackNalRefIdc = -1; //initialize |
809 | 2.08k | if (pDstInfo) { |
810 | 2.08k | pDstInfo->uiOutYuvTimeStamp = 0; |
811 | 2.08k | pDecContext->uiTimeStamp = pDstInfo->uiInBsTimeStamp; |
812 | 2.08k | } else { |
813 | 0 | pDecContext->uiTimeStamp = 0; |
814 | 0 | } |
815 | 2.08k | WelsDecodeBs (pDecContext, kpSrc, kiSrcLen, ppDst, |
816 | 2.08k | pDstInfo, NULL); //iErrorCode has been modified in this function |
817 | 2.08k | pDecContext->bInstantDecFlag = false; //reset no-delay flag |
818 | 2.08k | if (pDecContext->iErrorCode) { |
819 | 1.00k | EWelsNalUnitType eNalType = |
820 | 1.00k | NAL_UNIT_UNSPEC_0; //for NBR, IDR frames are expected to decode as followed if error decoding an IDR currently |
821 | | |
822 | 1.00k | eNalType = pDecContext->sCurNalHead.eNalUnitType; |
823 | 1.00k | if (pDecContext->iErrorCode & dsOutOfMemory) { |
824 | 0 | if (ResetDecoder (pDecContext)) { |
825 | 0 | if (pDstInfo) pDstInfo->iBufferStatus = 0; |
826 | 0 | return dsOutOfMemory; |
827 | 0 | } |
828 | 0 | return dsErrorFree; |
829 | 0 | } |
830 | 1.00k | if (pDecContext->iErrorCode & dsRefListNullPtrs) { |
831 | 0 | if (ResetDecoder (pDecContext)) { |
832 | 0 | if (pDstInfo) pDstInfo->iBufferStatus = 0; |
833 | 0 | return dsRefListNullPtrs; |
834 | 0 | } |
835 | 0 | return dsErrorFree; |
836 | 0 | } |
837 | | //for AVC bitstream (excluding AVC with temporal scalability, including TP), as long as error occur, SHOULD notify upper layer key frame loss. |
838 | 1.00k | if ((IS_PARAM_SETS_NALS (eNalType) || NAL_UNIT_CODED_SLICE_IDR == eNalType) || |
839 | 1.00k | (VIDEO_BITSTREAM_AVC == pDecContext->eVideoType)) { |
840 | 1.00k | if (pDecContext->pParam->eEcActiveIdc == ERROR_CON_DISABLE) { |
841 | 1.00k | #ifdef LONG_TERM_REF |
842 | 1.00k | pDecContext->bParamSetsLostFlag = true; |
843 | | #else |
844 | | pDecContext->bReferenceLostAtT0Flag = true; |
845 | | #endif |
846 | 1.00k | } |
847 | 1.00k | } |
848 | | |
849 | 1.00k | if (pDecContext->bPrintFrameErrorTraceFlag) { |
850 | 985 | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "decode failed, failure type:%d \n", |
851 | 985 | pDecContext->iErrorCode); |
852 | 985 | pDecContext->bPrintFrameErrorTraceFlag = false; |
853 | 985 | } else { |
854 | 23 | pDecContext->iIgnoredErrorInfoPacketCount++; |
855 | 23 | if (pDecContext->iIgnoredErrorInfoPacketCount == INT_MAX) { |
856 | 0 | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_WARNING, "continuous error reached INT_MAX! Restart as 0."); |
857 | 0 | pDecContext->iIgnoredErrorInfoPacketCount = 0; |
858 | 0 | } |
859 | 23 | } |
860 | 1.00k | if ((pDecContext->pParam->eEcActiveIdc != ERROR_CON_DISABLE) && (pDstInfo->iBufferStatus == 1)) { |
861 | | //TODO after dec status updated |
862 | 0 | pDecContext->iErrorCode |= dsDataErrorConcealed; |
863 | |
|
864 | 0 | pDecContext->pDecoderStatistics->uiDecodedFrameCount++; |
865 | 0 | if (pDecContext->pDecoderStatistics->uiDecodedFrameCount == 0) { //exceed max value of uint32_t |
866 | 0 | ResetDecStatNums (pDecContext->pDecoderStatistics); |
867 | 0 | pDecContext->pDecoderStatistics->uiDecodedFrameCount++; |
868 | 0 | } |
869 | 0 | int32_t iMbConcealedNum = pDecContext->iMbEcedNum + pDecContext->iMbEcedPropNum; |
870 | 0 | pDecContext->pDecoderStatistics->uiAvgEcRatio = pDecContext->iMbNum == 0 ? |
871 | 0 | (pDecContext->pDecoderStatistics->uiAvgEcRatio * pDecContext->pDecoderStatistics->uiEcFrameNum) : (( |
872 | 0 | pDecContext->pDecoderStatistics->uiAvgEcRatio * pDecContext->pDecoderStatistics->uiEcFrameNum) + (( |
873 | 0 | iMbConcealedNum * 100) / pDecContext->iMbNum)); |
874 | 0 | pDecContext->pDecoderStatistics->uiAvgEcPropRatio = pDecContext->iMbNum == 0 ? |
875 | 0 | (pDecContext->pDecoderStatistics->uiAvgEcPropRatio * pDecContext->pDecoderStatistics->uiEcFrameNum) : (( |
876 | 0 | pDecContext->pDecoderStatistics->uiAvgEcPropRatio * pDecContext->pDecoderStatistics->uiEcFrameNum) + (( |
877 | 0 | pDecContext->iMbEcedPropNum * 100) / pDecContext->iMbNum)); |
878 | 0 | pDecContext->pDecoderStatistics->uiEcFrameNum += (iMbConcealedNum == 0 ? 0 : 1); |
879 | 0 | pDecContext->pDecoderStatistics->uiAvgEcRatio = pDecContext->pDecoderStatistics->uiEcFrameNum == 0 ? 0 : |
880 | 0 | pDecContext->pDecoderStatistics->uiAvgEcRatio / pDecContext->pDecoderStatistics->uiEcFrameNum; |
881 | 0 | pDecContext->pDecoderStatistics->uiAvgEcPropRatio = pDecContext->pDecoderStatistics->uiEcFrameNum == 0 ? 0 : |
882 | 0 | pDecContext->pDecoderStatistics->uiAvgEcPropRatio / pDecContext->pDecoderStatistics->uiEcFrameNum; |
883 | 0 | } |
884 | 1.00k | iEnd = WelsTime(); |
885 | 1.00k | pDecContext->dDecTime += (iEnd - iStart) / 1e3; |
886 | | |
887 | 1.00k | OutputStatisticsLog (*pDecContext->pDecoderStatistics); |
888 | 1.00k | if (GetThreadCount (pDecContext) >= 1) { |
889 | 0 | BufferingReadyPicture (pDecContext, ppDst, pDstInfo); |
890 | 0 | SET_EVENT (&m_sBufferingEvent); |
891 | 1.00k | } else { |
892 | 1.00k | ReorderPicturesInDisplay (pDecContext, ppDst, pDstInfo); |
893 | 1.00k | } |
894 | | |
895 | 1.00k | return (DECODING_STATE)pDecContext->iErrorCode; |
896 | 1.00k | } |
897 | | // else Error free, the current codec works well |
898 | | |
899 | 1.07k | if (pDstInfo->iBufferStatus == 1) { |
900 | |
|
901 | 0 | pDecContext->pDecoderStatistics->uiDecodedFrameCount++; |
902 | 0 | if (pDecContext->pDecoderStatistics->uiDecodedFrameCount == 0) { //exceed max value of uint32_t |
903 | 0 | ResetDecStatNums (pDecContext->pDecoderStatistics); |
904 | 0 | pDecContext->pDecoderStatistics->uiDecodedFrameCount++; |
905 | 0 | } |
906 | |
|
907 | 0 | OutputStatisticsLog (*pDecContext->pDecoderStatistics); |
908 | 0 | } |
909 | 1.07k | iEnd = WelsTime(); |
910 | 1.07k | pDecContext->dDecTime += (iEnd - iStart) / 1e3; |
911 | | |
912 | 1.07k | if (GetThreadCount (pDecContext) >= 1) { |
913 | 0 | BufferingReadyPicture (pDecContext, ppDst, pDstInfo); |
914 | 0 | SET_EVENT (&m_sBufferingEvent); |
915 | 1.07k | } else { |
916 | 1.07k | ReorderPicturesInDisplay (pDecContext, ppDst, pDstInfo); |
917 | 1.07k | } |
918 | 1.07k | return dsErrorFree; |
919 | 2.08k | } |
920 | | |
921 | | DECODING_STATE CWelsDecoder::DecodeFrame2 (const unsigned char* kpSrc, |
922 | | const int kiSrcLen, |
923 | | unsigned char** ppDst, |
924 | 2.08k | SBufferInfo* pDstInfo) { |
925 | 2.08k | PWelsDecoderContext pDecContext = m_pDecThrCtx[0].pCtx; |
926 | 2.08k | return DecodeFrame2WithCtx (pDecContext, kpSrc, kiSrcLen, ppDst, pDstInfo); |
927 | 2.08k | } |
928 | | |
929 | | DECODING_STATE CWelsDecoder::FlushFrame (unsigned char** ppDst, |
930 | 2.74k | SBufferInfo* pDstInfo) { |
931 | 2.74k | bool bEndOfStreamFlag = true; |
932 | 2.74k | if (m_iThreadCount <= 1) { |
933 | 5.48k | for (int32_t j = 0; j < m_iCtxCount; ++j) { |
934 | 2.74k | if (!m_pDecThrCtx[j].pCtx->bEndOfStreamFlag) { |
935 | 0 | bEndOfStreamFlag = false; |
936 | 0 | } |
937 | 2.74k | } |
938 | 2.74k | } |
939 | 2.74k | if (bEndOfStreamFlag && m_sReoderingStatus.iNumOfPicts > 0) { |
940 | 0 | if (!m_sReoderingStatus.bHasBSlice) { |
941 | 0 | ReleaseBufferedReadyPictureNoReorder (NULL, ppDst, pDstInfo); |
942 | 0 | } |
943 | 0 | else { |
944 | 0 | ReleaseBufferedReadyPictureReorder (NULL, ppDst, pDstInfo, true); |
945 | 0 | } |
946 | 0 | } |
947 | 2.74k | return dsErrorFree; |
948 | 2.74k | } |
949 | | |
950 | 1.00k | void CWelsDecoder::OutputStatisticsLog (SDecoderStatistics& sDecoderStatistics) { |
951 | 1.00k | if ((sDecoderStatistics.uiDecodedFrameCount > 0) && (sDecoderStatistics.iStatisticsLogInterval > 0) |
952 | 0 | && ((sDecoderStatistics.uiDecodedFrameCount % sDecoderStatistics.iStatisticsLogInterval) == 0)) { |
953 | 0 | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, |
954 | 0 | "DecoderStatistics: uiWidth=%d, uiHeight=%d, fAverageFrameSpeedInMs=%.1f, fActualAverageFrameSpeedInMs=%.1f, \ |
955 | 0 | uiDecodedFrameCount=%d, uiResolutionChangeTimes=%d, uiIDRCorrectNum=%d, \ |
956 | 0 | uiAvgEcRatio=%d, uiAvgEcPropRatio=%d, uiEcIDRNum=%d, uiEcFrameNum=%d, \ |
957 | 0 | uiIDRLostNum=%d, uiFreezingIDRNum=%d, uiFreezingNonIDRNum=%d, iAvgLumaQp=%d, \ |
958 | 0 | iSpsReportErrorNum=%d, iSubSpsReportErrorNum=%d, iPpsReportErrorNum=%d, iSpsNoExistNalNum=%d, iSubSpsNoExistNalNum=%d, iPpsNoExistNalNum=%d, \ |
959 | 0 | uiProfile=%d, uiLevel=%d, \ |
960 | 0 | iCurrentActiveSpsId=%d, iCurrentActivePpsId=%d,", |
961 | 0 | sDecoderStatistics.uiWidth, |
962 | 0 | sDecoderStatistics.uiHeight, |
963 | 0 | sDecoderStatistics.fAverageFrameSpeedInMs, |
964 | 0 | sDecoderStatistics.fActualAverageFrameSpeedInMs, |
965 | |
|
966 | 0 | sDecoderStatistics.uiDecodedFrameCount, |
967 | 0 | sDecoderStatistics.uiResolutionChangeTimes, |
968 | 0 | sDecoderStatistics.uiIDRCorrectNum, |
969 | |
|
970 | 0 | sDecoderStatistics.uiAvgEcRatio, |
971 | 0 | sDecoderStatistics.uiAvgEcPropRatio, |
972 | 0 | sDecoderStatistics.uiEcIDRNum, |
973 | 0 | sDecoderStatistics.uiEcFrameNum, |
974 | |
|
975 | 0 | sDecoderStatistics.uiIDRLostNum, |
976 | 0 | sDecoderStatistics.uiFreezingIDRNum, |
977 | 0 | sDecoderStatistics.uiFreezingNonIDRNum, |
978 | 0 | sDecoderStatistics.iAvgLumaQp, |
979 | |
|
980 | 0 | sDecoderStatistics.iSpsReportErrorNum, |
981 | 0 | sDecoderStatistics.iSubSpsReportErrorNum, |
982 | 0 | sDecoderStatistics.iPpsReportErrorNum, |
983 | 0 | sDecoderStatistics.iSpsNoExistNalNum, |
984 | 0 | sDecoderStatistics.iSubSpsNoExistNalNum, |
985 | 0 | sDecoderStatistics.iPpsNoExistNalNum, |
986 | |
|
987 | 0 | sDecoderStatistics.uiProfile, |
988 | 0 | sDecoderStatistics.uiLevel, |
989 | |
|
990 | 0 | sDecoderStatistics.iCurrentActiveSpsId, |
991 | 0 | sDecoderStatistics.iCurrentActivePpsId); |
992 | 0 | } |
993 | 1.00k | } |
994 | | |
995 | | void CWelsDecoder::BufferingReadyPicture (PWelsDecoderContext pCtx, unsigned char** ppDst, |
996 | 0 | SBufferInfo* pDstInfo) { |
997 | 0 | if (pDstInfo->iBufferStatus == 0) { |
998 | 0 | return; |
999 | 0 | } |
1000 | 0 | m_bIsBaseline = pCtx->pSps->uiProfileIdc == 66 || pCtx->pSps->uiProfileIdc == 83; |
1001 | 0 | if (!m_bIsBaseline) { |
1002 | 0 | if (pCtx->pSliceHeader->eSliceType == B_SLICE) { |
1003 | 0 | m_sReoderingStatus.bHasBSlice = true; |
1004 | 0 | } |
1005 | 0 | } |
1006 | 0 | for (int32_t i = 0; i < 16; ++i) { |
1007 | 0 | if (m_sPictInfoList[i].iPOC == IMinInt32) { |
1008 | 0 | memcpy (&m_sPictInfoList[i].sBufferInfo, pDstInfo, sizeof (SBufferInfo)); |
1009 | 0 | m_sPictInfoList[i].iPOC = pCtx->pSliceHeader->iPicOrderCntLsb; |
1010 | 0 | m_sPictInfoList[i].iSeqNum = pCtx->iSeqNum; |
1011 | 0 | m_sPictInfoList[i].uiDecodingTimeStamp = pCtx->uiDecodingTimeStamp; |
1012 | 0 | if (pCtx->pLastDecPicInfo->pPreviousDecodedPictureInDpb != NULL) { |
1013 | 0 | m_sPictInfoList[i].iPicBuffIdx = pCtx->pLastDecPicInfo->pPreviousDecodedPictureInDpb->iPicBuffIdx; |
1014 | 0 | if (GetThreadCount (pCtx) <= 1) ++pCtx->pLastDecPicInfo->pPreviousDecodedPictureInDpb->iRefCount; |
1015 | 0 | } |
1016 | 0 | m_iLastBufferedIdx = i; |
1017 | 0 | pDstInfo->iBufferStatus = 0; |
1018 | 0 | ++m_sReoderingStatus.iNumOfPicts; |
1019 | 0 | if (i > m_sReoderingStatus.iLargestBufferedPicIndex) { |
1020 | 0 | m_sReoderingStatus.iLargestBufferedPicIndex = i; |
1021 | 0 | } |
1022 | 0 | break; |
1023 | 0 | } |
1024 | 0 | } |
1025 | 0 | } |
1026 | | |
1027 | | void CWelsDecoder::ReleaseBufferedReadyPictureReorder (PWelsDecoderContext pCtx, unsigned char** ppDst, |
1028 | 0 | SBufferInfo* pDstInfo, bool isFlush) { |
1029 | 0 | PPicBuff pPicBuff = pCtx ? pCtx->pPicBuff : m_pPicBuff; |
1030 | 0 | if (pCtx == NULL && m_iThreadCount <= 1) { |
1031 | 0 | pCtx = m_pDecThrCtx[0].pCtx; |
1032 | 0 | } |
1033 | 0 | if (m_sReoderingStatus.iNumOfPicts > 0) { |
1034 | 0 | m_sReoderingStatus.iMinPOC = IMinInt32; |
1035 | 0 | int32_t firstValidIdx = -1; |
1036 | 0 | for (int32_t i = 0; i <= m_sReoderingStatus.iLargestBufferedPicIndex; ++i) { |
1037 | 0 | if (m_sReoderingStatus.iMinPOC == IMinInt32 && m_sPictInfoList[i].iPOC > IMinInt32) { |
1038 | 0 | m_sReoderingStatus.iMinPOC = m_sPictInfoList[i].iPOC; |
1039 | 0 | m_sReoderingStatus.iMinSeqNum = m_sPictInfoList[i].iSeqNum; |
1040 | 0 | m_sReoderingStatus.iPictInfoIndex = i; |
1041 | 0 | firstValidIdx = i; |
1042 | 0 | break; |
1043 | 0 | } |
1044 | 0 | } |
1045 | 0 | for (int32_t i = 0; i <= m_sReoderingStatus.iLargestBufferedPicIndex; ++i) { |
1046 | 0 | if (i == firstValidIdx) continue; |
1047 | 0 | if (m_sPictInfoList[i].iPOC > IMinInt32 |
1048 | 0 | && ((m_sPictInfoList[i].iSeqNum == m_sReoderingStatus.iMinSeqNum) ? (m_sPictInfoList[i].iPOC < m_sReoderingStatus.iMinPOC) : (m_sPictInfoList[i].iSeqNum - m_sReoderingStatus.iMinSeqNum < 0))) { |
1049 | 0 | m_sReoderingStatus.iMinPOC = m_sPictInfoList[i].iPOC; |
1050 | 0 | m_sReoderingStatus.iMinSeqNum = m_sPictInfoList[i].iSeqNum; |
1051 | 0 | m_sReoderingStatus.iPictInfoIndex = i; |
1052 | 0 | } |
1053 | 0 | } |
1054 | 0 | } |
1055 | 0 | if (m_sReoderingStatus.iMinPOC > IMinInt32) { |
1056 | 0 | bool isReady = true; |
1057 | 0 | if (!isFlush) { |
1058 | 0 | int32_t iLastPOC = pCtx != NULL ? pCtx->pSliceHeader->iPicOrderCntLsb : m_sPictInfoList[m_iLastBufferedIdx].iPOC; |
1059 | 0 | int32_t iLastSeqNum = pCtx != NULL ? pCtx->iSeqNum : m_sPictInfoList[m_iLastBufferedIdx].iSeqNum; |
1060 | 0 | isReady = (m_sReoderingStatus.iLastWrittenPOC > IMinInt32 |
1061 | 0 | && m_sReoderingStatus.iMinPOC - m_sReoderingStatus.iLastWrittenPOC <= 1) |
1062 | 0 | || m_sReoderingStatus.iMinPOC < iLastPOC |
1063 | 0 | || m_sReoderingStatus.iMinSeqNum - iLastSeqNum < 0; |
1064 | 0 | } |
1065 | 0 | if (isReady) { |
1066 | 0 | m_sReoderingStatus.iLastWrittenPOC = m_sReoderingStatus.iMinPOC; |
1067 | 0 | m_sReoderingStatus.iLastWrittenSeqNum = m_sReoderingStatus.iMinSeqNum; |
1068 | | #if defined (_DEBUG) |
1069 | | #ifdef _MOTION_VECTOR_DUMP_ |
1070 | | fprintf (stderr, "Output POC: #%d uiDecodingTimeStamp=%d\n", m_sReoderingStatus.iLastWrittenPOC, |
1071 | | m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].uiDecodingTimeStamp); |
1072 | | #endif |
1073 | | #endif |
1074 | 0 | memcpy (pDstInfo, &m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].sBufferInfo, sizeof (SBufferInfo)); |
1075 | 0 | ppDst[0] = pDstInfo->pDst[0]; |
1076 | 0 | ppDst[1] = pDstInfo->pDst[1]; |
1077 | 0 | ppDst[2] = pDstInfo->pDst[2]; |
1078 | 0 | m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].iPOC = IMinInt32; |
1079 | 0 | int32_t iPicBuffIdx = m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].iPicBuffIdx; |
1080 | 0 | if (pPicBuff != NULL) { |
1081 | 0 | if (iPicBuffIdx >= 0 && iPicBuffIdx < pPicBuff->iCapacity) |
1082 | 0 | { |
1083 | 0 | PPicture pPic = pPicBuff->ppPic[iPicBuffIdx]; |
1084 | 0 | --pPic->iRefCount; |
1085 | 0 | if (pPic->iRefCount <= 0 && pPic->pSetUnRef) |
1086 | 0 | pPic->pSetUnRef(pPic); |
1087 | 0 | } |
1088 | 0 | } |
1089 | 0 | m_sReoderingStatus.iMinPOC = IMinInt32; |
1090 | 0 | --m_sReoderingStatus.iNumOfPicts; |
1091 | 0 | } |
1092 | 0 | } |
1093 | 0 | } |
1094 | | |
1095 | | //if there is no b-frame, no ordering based on values of POCs is necessary. |
1096 | | //The function is added to force to avoid picture reordering because some h.264 streams do not follow H.264 POC specifications. |
1097 | | void CWelsDecoder::ReleaseBufferedReadyPictureNoReorder(PWelsDecoderContext pCtx, unsigned char** ppDst, SBufferInfo* pDstInfo) |
1098 | 0 | { |
1099 | 0 | int32_t firstValidIdx = -1; |
1100 | 0 | uint32_t uiDecodingTimeStamp = 0; |
1101 | 0 | for (int32_t i = 0; i <= m_sReoderingStatus.iLargestBufferedPicIndex; ++i) { |
1102 | 0 | if (m_sPictInfoList[i].iPOC != IMinInt32) { |
1103 | 0 | uiDecodingTimeStamp = m_sPictInfoList[i].uiDecodingTimeStamp; |
1104 | 0 | m_sReoderingStatus.iPictInfoIndex = i; |
1105 | 0 | firstValidIdx = i; |
1106 | 0 | break; |
1107 | 0 | } |
1108 | 0 | } |
1109 | 0 | for (int32_t i = 0; i <= m_sReoderingStatus.iLargestBufferedPicIndex; ++i) { |
1110 | 0 | if (i == firstValidIdx) continue; |
1111 | 0 | if (m_sPictInfoList[i].iPOC != IMinInt32 && m_sPictInfoList[i].uiDecodingTimeStamp < uiDecodingTimeStamp) { |
1112 | 0 | uiDecodingTimeStamp = m_sPictInfoList[i].uiDecodingTimeStamp; |
1113 | 0 | m_sReoderingStatus.iPictInfoIndex = i; |
1114 | 0 | } |
1115 | 0 | } |
1116 | 0 | if (uiDecodingTimeStamp > 0) { |
1117 | | #if defined (_DEBUG) |
1118 | | #ifdef _MOTION_VECTOR_DUMP_ |
1119 | | fprintf(stderr, "Output POC: #%d uiDecodingTimeStamp=%d\n", m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].iPOC, |
1120 | | uiDecodingTimeStamp); |
1121 | | #endif |
1122 | | #endif |
1123 | 0 | m_sReoderingStatus.iLastWrittenPOC = m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].iPOC; |
1124 | 0 | m_sReoderingStatus.iLastWrittenSeqNum = m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].iSeqNum; |
1125 | 0 | memcpy(pDstInfo, &m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].sBufferInfo, sizeof(SBufferInfo)); |
1126 | 0 | ppDst[0] = pDstInfo->pDst[0]; |
1127 | 0 | ppDst[1] = pDstInfo->pDst[1]; |
1128 | 0 | ppDst[2] = pDstInfo->pDst[2]; |
1129 | 0 | m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].iPOC = IMinInt32; |
1130 | 0 | if (pCtx || m_pPicBuff) { |
1131 | 0 | PPicBuff pPicBuff = pCtx ? pCtx->pPicBuff : m_pPicBuff; |
1132 | 0 | int32_t iPicBuffIdx = m_sPictInfoList[m_sReoderingStatus.iPictInfoIndex].iPicBuffIdx; |
1133 | 0 | if (pPicBuff != NULL && iPicBuffIdx >= 0 && iPicBuffIdx < pPicBuff->iCapacity) { |
1134 | 0 | PPicture pPic = pPicBuff->ppPic[iPicBuffIdx]; |
1135 | 0 | --pPic->iRefCount; |
1136 | 0 | if (pPic->iRefCount <= 0 && pPic->pSetUnRef) |
1137 | 0 | pPic->pSetUnRef(pPic); |
1138 | 0 | } |
1139 | 0 | } |
1140 | 0 | --m_sReoderingStatus.iNumOfPicts; |
1141 | 0 | } |
1142 | 0 | return; |
1143 | 0 | } |
1144 | | |
1145 | | DECODING_STATE CWelsDecoder::ReorderPicturesInDisplay(PWelsDecoderContext pDecContext, unsigned char** ppDst, |
1146 | 2.08k | SBufferInfo* pDstInfo) { |
1147 | 2.08k | DECODING_STATE iRet = dsErrorFree; |
1148 | 2.08k | if (pDecContext->pSps != NULL) { |
1149 | 0 | m_bIsBaseline = pDecContext->pSps->uiProfileIdc == 66 || pDecContext->pSps->uiProfileIdc == 83; |
1150 | 0 | if (!m_bIsBaseline) { |
1151 | 0 | if (pDstInfo->iBufferStatus == 1) { |
1152 | 0 | if (pDecContext->pSliceHeader->eSliceType == B_SLICE && |
1153 | 0 | ((pDecContext->iSeqNum == m_sReoderingStatus.iLastWrittenSeqNum) ? |
1154 | 0 | (pDecContext->pSliceHeader->iPicOrderCntLsb <= m_sReoderingStatus.iLastWrittenPOC + 2) : |
1155 | 0 | (pDecContext->iSeqNum - m_sReoderingStatus.iLastWrittenSeqNum == 1 && pDecContext->pSliceHeader->iPicOrderCntLsb == 0))) { |
1156 | 0 | m_sReoderingStatus.iLastWrittenPOC = pDecContext->pSliceHeader->iPicOrderCntLsb; |
1157 | 0 | m_sReoderingStatus.iLastWrittenSeqNum = pDecContext->iSeqNum; |
1158 | | //issue #3478, use b-slice type to determine correct picture order as the first priority as POC order is not as reliable as based on b-slice |
1159 | 0 | ppDst[0] = pDstInfo->pDst[0]; |
1160 | 0 | ppDst[1] = pDstInfo->pDst[1]; |
1161 | 0 | ppDst[2] = pDstInfo->pDst[2]; |
1162 | | #if defined (_DEBUG) |
1163 | | #ifdef _MOTION_VECTOR_DUMP_ |
1164 | | fprintf (stderr, "Output POC: #%d uiDecodingTimeStamp=%d\n", pDecContext->pSliceHeader->iPicOrderCntLsb, |
1165 | | pDecContext->uiDecodingTimeStamp); |
1166 | | #endif |
1167 | | #endif |
1168 | 0 | return iRet; |
1169 | 0 | } |
1170 | 0 | BufferingReadyPicture(pDecContext, ppDst, pDstInfo); |
1171 | 0 | if (!m_sReoderingStatus.bHasBSlice && m_sReoderingStatus.iNumOfPicts > 1) { |
1172 | 0 | ReleaseBufferedReadyPictureNoReorder (pDecContext, ppDst, pDstInfo); |
1173 | 0 | } |
1174 | 0 | else { |
1175 | 0 | ReleaseBufferedReadyPictureReorder (pDecContext, ppDst, pDstInfo); |
1176 | 0 | } |
1177 | 0 | } |
1178 | 0 | } |
1179 | 0 | } |
1180 | 2.08k | return iRet; |
1181 | 2.08k | } |
1182 | | |
1183 | 0 | DECODING_STATE CWelsDecoder::DecodeParser (const unsigned char* kpSrc, const int kiSrcLen, SParserBsInfo* pDstInfo) { |
1184 | 0 | PWelsDecoderContext pDecContext = m_pDecThrCtx[0].pCtx; |
1185 | |
|
1186 | 0 | if (pDecContext == NULL || pDecContext->pParam == NULL) { |
1187 | 0 | if (m_pWelsTrace != NULL) { |
1188 | 0 | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "Call DecodeParser without Initialize.\n"); |
1189 | 0 | } |
1190 | 0 | return dsInitialOptExpected; |
1191 | 0 | } |
1192 | | |
1193 | 0 | if (!pDecContext->pParam->bParseOnly) { |
1194 | 0 | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_ERROR, "bParseOnly should be true for this API calling! \n"); |
1195 | 0 | pDecContext->iErrorCode |= dsInvalidArgument; |
1196 | 0 | return dsInvalidArgument; |
1197 | 0 | } |
1198 | 0 | int64_t iEnd, iStart = WelsTime(); |
1199 | 0 | if (CheckBsBuffer (pDecContext, kiSrcLen)) { |
1200 | 0 | if (ResetDecoder (pDecContext)) |
1201 | 0 | return dsOutOfMemory; |
1202 | | |
1203 | 0 | return dsErrorFree; |
1204 | 0 | } |
1205 | 0 | if (kiSrcLen > 0 && kpSrc != NULL) { |
1206 | | #ifdef OUTPUT_BITSTREAM |
1207 | | if (m_pFBS) { |
1208 | | WelsFwrite (kpSrc, sizeof (unsigned char), kiSrcLen, m_pFBS); |
1209 | | WelsFflush (m_pFBS); |
1210 | | } |
1211 | | #endif//OUTPUT_BIT_STREAM |
1212 | 0 | pDecContext->bEndOfStreamFlag = false; |
1213 | 0 | } else { |
1214 | | //For application MODE, the error detection should be added for safe. |
1215 | | //But for CONSOLE MODE, when decoding LAST AU, kiSrcLen==0 && kpSrc==NULL. |
1216 | 0 | pDecContext->bEndOfStreamFlag = true; |
1217 | 0 | pDecContext->bInstantDecFlag = true; |
1218 | 0 | } |
1219 | |
|
1220 | 0 | pDecContext->iErrorCode = dsErrorFree; //initialize at the starting of AU decoding. |
1221 | 0 | pDecContext->pParam->eEcActiveIdc = ERROR_CON_DISABLE; //add protection to disable EC here. |
1222 | 0 | pDecContext->iFeedbackNalRefIdc = -1; //initialize |
1223 | 0 | if (!pDecContext->bFramePending) { //frame complete |
1224 | 0 | pDecContext->pParserBsInfo->iNalNum = 0; |
1225 | 0 | memset (pDecContext->pParserBsInfo->pNalLenInByte, 0, MAX_NAL_UNITS_IN_LAYER); |
1226 | 0 | } |
1227 | 0 | pDstInfo->iNalNum = 0; |
1228 | 0 | pDstInfo->iSpsWidthInPixel = pDstInfo->iSpsHeightInPixel = 0; |
1229 | 0 | if (pDstInfo) { |
1230 | 0 | pDecContext->uiTimeStamp = pDstInfo->uiInBsTimeStamp; |
1231 | 0 | pDstInfo->uiOutBsTimeStamp = 0; |
1232 | 0 | } else { |
1233 | 0 | pDecContext->uiTimeStamp = 0; |
1234 | 0 | } |
1235 | 0 | WelsDecodeBs (pDecContext, kpSrc, kiSrcLen, NULL, NULL, pDstInfo); |
1236 | 0 | if (pDecContext->iErrorCode & dsOutOfMemory) { |
1237 | 0 | if (ResetDecoder (pDecContext)) |
1238 | 0 | return dsOutOfMemory; |
1239 | 0 | return dsErrorFree; |
1240 | 0 | } |
1241 | | |
1242 | 0 | if (!pDecContext->bFramePending && pDecContext->pParserBsInfo->iNalNum) { |
1243 | 0 | memcpy (pDstInfo, pDecContext->pParserBsInfo, sizeof (SParserBsInfo)); |
1244 | |
|
1245 | 0 | if (pDecContext->iErrorCode == ERR_NONE) { //update statistics: decoding frame count |
1246 | 0 | pDecContext->pDecoderStatistics->uiDecodedFrameCount++; |
1247 | 0 | if (pDecContext->pDecoderStatistics->uiDecodedFrameCount == 0) { //exceed max value of uint32_t |
1248 | 0 | ResetDecStatNums (pDecContext->pDecoderStatistics); |
1249 | 0 | pDecContext->pDecoderStatistics->uiDecodedFrameCount++; |
1250 | 0 | } |
1251 | 0 | } |
1252 | 0 | } |
1253 | |
|
1254 | 0 | pDecContext->bInstantDecFlag = false; //reset no-delay flag |
1255 | |
|
1256 | 0 | if (pDecContext->iErrorCode && pDecContext->bPrintFrameErrorTraceFlag) { |
1257 | 0 | WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO, "decode failed, failure type:%d \n", pDecContext->iErrorCode); |
1258 | 0 | pDecContext->bPrintFrameErrorTraceFlag = false; |
1259 | 0 | } |
1260 | 0 | iEnd = WelsTime(); |
1261 | 0 | pDecContext->dDecTime += (iEnd - iStart) / 1e3; |
1262 | 0 | return (DECODING_STATE)pDecContext->iErrorCode; |
1263 | 0 | } |
1264 | | |
1265 | | DECODING_STATE CWelsDecoder::DecodeFrame (const unsigned char* kpSrc, |
1266 | | const int kiSrcLen, |
1267 | | unsigned char** ppDst, |
1268 | | int* pStride, |
1269 | | int& iWidth, |
1270 | 0 | int& iHeight) { |
1271 | 0 | DECODING_STATE eDecState = dsErrorFree; |
1272 | 0 | SBufferInfo DstInfo; |
1273 | |
|
1274 | 0 | memset (&DstInfo, 0, sizeof (SBufferInfo)); |
1275 | 0 | DstInfo.UsrData.sSystemBuffer.iStride[0] = pStride[0]; |
1276 | 0 | DstInfo.UsrData.sSystemBuffer.iStride[1] = pStride[1]; |
1277 | 0 | DstInfo.UsrData.sSystemBuffer.iWidth = iWidth; |
1278 | 0 | DstInfo.UsrData.sSystemBuffer.iHeight = iHeight; |
1279 | |
|
1280 | 0 | eDecState = DecodeFrame2 (kpSrc, kiSrcLen, ppDst, &DstInfo); |
1281 | 0 | if (eDecState == dsErrorFree) { |
1282 | 0 | pStride[0] = DstInfo.UsrData.sSystemBuffer.iStride[0]; |
1283 | 0 | pStride[1] = DstInfo.UsrData.sSystemBuffer.iStride[1]; |
1284 | 0 | iWidth = DstInfo.UsrData.sSystemBuffer.iWidth; |
1285 | 0 | iHeight = DstInfo.UsrData.sSystemBuffer.iHeight; |
1286 | 0 | } |
1287 | |
|
1288 | 0 | return eDecState; |
1289 | 0 | } |
1290 | | |
1291 | | DECODING_STATE CWelsDecoder::DecodeFrameEx (const unsigned char* kpSrc, |
1292 | | const int kiSrcLen, |
1293 | | unsigned char* pDst, |
1294 | | int iDstStride, |
1295 | | int& iDstLen, |
1296 | | int& iWidth, |
1297 | | int& iHeight, |
1298 | 0 | int& iColorFormat) { |
1299 | 0 | DECODING_STATE state = dsErrorFree; |
1300 | |
|
1301 | 0 | return state; |
1302 | 0 | } |
1303 | | |
1304 | 0 | DECODING_STATE CWelsDecoder::ParseAccessUnit (SWelsDecoderThreadCTX& sThreadCtx) { |
1305 | 0 | sThreadCtx.pCtx->bHasNewSps = false; |
1306 | 0 | sThreadCtx.pCtx->bParamSetsLostFlag = m_bParamSetsLostFlag; |
1307 | 0 | sThreadCtx.pCtx->bFreezeOutput = m_bFreezeOutput; |
1308 | 0 | sThreadCtx.pCtx->uiDecodingTimeStamp = ++m_uiDecodeTimeStamp; |
1309 | 0 | bool bPicBuffChanged = false; |
1310 | 0 | if (m_pLastDecThrCtx != NULL && sThreadCtx.pCtx->sSpsPpsCtx.iSeqId < m_pLastDecThrCtx->pCtx->sSpsPpsCtx.iSeqId) { |
1311 | 0 | CopySpsPps (m_pLastDecThrCtx->pCtx, sThreadCtx.pCtx); |
1312 | 0 | sThreadCtx.pCtx->iPicQueueNumber = m_pLastDecThrCtx->pCtx->iPicQueueNumber; |
1313 | 0 | if (sThreadCtx.pCtx->pPicBuff != m_pPicBuff) { |
1314 | 0 | bPicBuffChanged = true; |
1315 | 0 | sThreadCtx.pCtx->pPicBuff = m_pPicBuff; |
1316 | 0 | sThreadCtx.pCtx->bHaveGotMemory = m_pPicBuff != NULL; |
1317 | 0 | sThreadCtx.pCtx->iImgWidthInPixel = m_pLastDecThrCtx->pCtx->iImgWidthInPixel; |
1318 | 0 | sThreadCtx.pCtx->iImgHeightInPixel = m_pLastDecThrCtx->pCtx->iImgHeightInPixel; |
1319 | 0 | } |
1320 | 0 | } |
1321 | | |
1322 | | //if threadCount > 1, then each thread must contain exact one complete frame. |
1323 | 0 | if (GetThreadCount (sThreadCtx.pCtx) > 1) { |
1324 | 0 | sThreadCtx.pCtx->pAccessUnitList->uiAvailUnitsNum = 0; |
1325 | 0 | sThreadCtx.pCtx->pAccessUnitList->uiActualUnitsNum = 0; |
1326 | 0 | } |
1327 | |
|
1328 | 0 | int32_t iRet = DecodeFrame2WithCtx (sThreadCtx.pCtx, sThreadCtx.kpSrc, sThreadCtx.kiSrcLen, sThreadCtx.ppDst, |
1329 | 0 | &sThreadCtx.sDstInfo); |
1330 | |
|
1331 | 0 | int32_t iErr = InitConstructAccessUnit (sThreadCtx.pCtx, &sThreadCtx.sDstInfo); |
1332 | 0 | if (ERR_NONE != iErr) { |
1333 | 0 | return (DECODING_STATE) (iRet | iErr); |
1334 | 0 | } |
1335 | 0 | if (sThreadCtx.pCtx->bNewSeqBegin) { |
1336 | 0 | m_pPicBuff = sThreadCtx.pCtx->pPicBuff; |
1337 | 0 | } else if (bPicBuffChanged) { |
1338 | 0 | InitialDqLayersContext (sThreadCtx.pCtx, sThreadCtx.pCtx->pSps->iMbWidth << 4, sThreadCtx.pCtx->pSps->iMbHeight << 4); |
1339 | 0 | } |
1340 | 0 | if (!sThreadCtx.pCtx->bNewSeqBegin && m_pLastDecThrCtx != NULL) { |
1341 | 0 | sThreadCtx.pCtx->sFrameCrop = m_pLastDecThrCtx->pCtx->pSps->sFrameCrop; |
1342 | 0 | } |
1343 | 0 | m_bParamSetsLostFlag = sThreadCtx.pCtx->bNewSeqBegin ? false : sThreadCtx.pCtx->bParamSetsLostFlag; |
1344 | 0 | m_bFreezeOutput = sThreadCtx.pCtx->bNewSeqBegin ? false : sThreadCtx.pCtx->bFreezeOutput; |
1345 | 0 | return (DECODING_STATE) (iRet | iErr); |
1346 | 0 | } |
1347 | | /* |
1348 | | * Run decoding picture in separate thread. |
1349 | | */ |
1350 | | |
1351 | | int CWelsDecoder::ThreadDecodeFrameInternal (const unsigned char* kpSrc, const int kiSrcLen, unsigned char** ppDst, |
1352 | 0 | SBufferInfo* pDstInfo) { |
1353 | 0 | int state = dsErrorFree; |
1354 | 0 | int32_t i, j; |
1355 | 0 | int32_t signal = 0; |
1356 | | |
1357 | | //serial using of threads |
1358 | 0 | if (m_DecCtxActiveCount < m_iThreadCount) { |
1359 | 0 | signal = m_DecCtxActiveCount; |
1360 | 0 | } else { |
1361 | 0 | signal = m_pDecThrCtxActive[0]->sThreadInfo.uiThrNum; |
1362 | 0 | } |
1363 | |
|
1364 | 0 | WAIT_SEMAPHORE (&m_pDecThrCtx[signal].sThreadInfo.sIsIdle, WELS_DEC_THREAD_WAIT_INFINITE); |
1365 | |
|
1366 | 0 | for (i = 0; i < m_DecCtxActiveCount; ++i) { |
1367 | 0 | if (m_pDecThrCtxActive[i] == &m_pDecThrCtx[signal]) { |
1368 | 0 | m_pDecThrCtxActive[i] = NULL; |
1369 | 0 | for (j = i; j < m_DecCtxActiveCount - 1; j++) { |
1370 | 0 | m_pDecThrCtxActive[j] = m_pDecThrCtxActive[j + 1]; |
1371 | 0 | m_pDecThrCtxActive[j + 1] = NULL; |
1372 | 0 | } |
1373 | 0 | --m_DecCtxActiveCount; |
1374 | 0 | break; |
1375 | 0 | } |
1376 | 0 | } |
1377 | |
|
1378 | 0 | if (m_pLastDecThrCtx != NULL) { |
1379 | 0 | m_pDecThrCtx[signal].pCtx->pLastThreadCtx = m_pLastDecThrCtx; |
1380 | 0 | } |
1381 | 0 | m_pDecThrCtx[signal].kpSrc = const_cast<uint8_t*> (kpSrc); |
1382 | 0 | m_pDecThrCtx[signal].kiSrcLen = kiSrcLen; |
1383 | 0 | m_pDecThrCtx[signal].ppDst = ppDst; |
1384 | 0 | memcpy (&m_pDecThrCtx[signal].sDstInfo, pDstInfo, sizeof (SBufferInfo)); |
1385 | |
|
1386 | 0 | state = ParseAccessUnit (m_pDecThrCtx[signal]); |
1387 | 0 | if (state != dsErrorFree) { |
1388 | 0 | RELEASE_SEMAPHORE (&m_pDecThrCtx[signal].sThreadInfo.sIsIdle); |
1389 | 0 | return state; |
1390 | 0 | } |
1391 | | |
1392 | 0 | if (m_iThreadCount > 1 && m_pDecThrCtx[signal].pCtx->pAccessUnitList->uiAvailUnitsNum == 0) { |
1393 | 0 | RELEASE_SEMAPHORE (&m_pDecThrCtx[signal].sThreadInfo.sIsIdle); |
1394 | 0 | return state; |
1395 | 0 | } |
1396 | | |
1397 | 0 | m_pDecThrCtxActive[m_DecCtxActiveCount++] = &m_pDecThrCtx[signal]; |
1398 | 0 | if (m_iThreadCount > 1) { |
1399 | 0 | m_pLastDecThrCtx = &m_pDecThrCtx[signal]; |
1400 | 0 | } |
1401 | 0 | m_pDecThrCtx[signal].sThreadInfo.uiCommand = WELS_DEC_THREAD_COMMAND_RUN; |
1402 | 0 | RELEASE_SEMAPHORE (&m_pDecThrCtx[signal].sThreadInfo.sIsActivated); |
1403 | | |
1404 | | // wait early picture |
1405 | 0 | if (m_DecCtxActiveCount >= m_iThreadCount) { |
1406 | 0 | WAIT_SEMAPHORE (&m_pDecThrCtxActive[0]->sThreadInfo.sIsIdle, WELS_DEC_THREAD_WAIT_INFINITE); |
1407 | 0 | RELEASE_SEMAPHORE (&m_pDecThrCtxActive[0]->sThreadInfo.sIsIdle); |
1408 | 0 | } |
1409 | 0 | return state; |
1410 | 0 | } |
1411 | | |
1412 | | } // namespace WelsDec |
1413 | | |
1414 | | |
1415 | | using namespace WelsDec; |
1416 | | /* |
1417 | | * WelsGetDecoderCapability |
1418 | | * @return: DecCapability information |
1419 | | */ |
1420 | 0 | int WelsGetDecoderCapability (SDecoderCapability* pDecCapability) { |
1421 | 0 | memset (pDecCapability, 0, sizeof (SDecoderCapability)); |
1422 | 0 | pDecCapability->iProfileIdc = 66; //Baseline |
1423 | 0 | pDecCapability->iProfileIop = 0xE0; //11100000b |
1424 | 0 | pDecCapability->iLevelIdc = 32; //level_idc = 3.2 |
1425 | 0 | pDecCapability->iMaxMbps = 216000; //from level_idc = 3.2 |
1426 | 0 | pDecCapability->iMaxFs = 5120; //from level_idc = 3.2 |
1427 | 0 | pDecCapability->iMaxCpb = 20000; //from level_idc = 3.2 |
1428 | 0 | pDecCapability->iMaxDpb = 20480; //from level_idc = 3.2 |
1429 | 0 | pDecCapability->iMaxBr = 20000; //from level_idc = 3.2 |
1430 | 0 | pDecCapability->bRedPicCap = 0; //not support redundant pic |
1431 | |
|
1432 | 0 | return ERR_NONE; |
1433 | 0 | } |
1434 | | /* WINAPI is indeed in prefix due to sync to application layer callings!! */ |
1435 | | |
1436 | | /* |
1437 | | * WelsCreateDecoder |
1438 | | * @return: success in return 0, otherwise failed. |
1439 | | */ |
1440 | 1.15k | long WelsCreateDecoder (ISVCDecoder** ppDecoder) { |
1441 | | |
1442 | 1.15k | if (NULL == ppDecoder) { |
1443 | 0 | return ERR_INVALID_PARAMETERS; |
1444 | 0 | } |
1445 | | |
1446 | 1.15k | *ppDecoder = new CWelsDecoder(); |
1447 | | |
1448 | 1.15k | if (NULL == *ppDecoder) { |
1449 | 0 | return ERR_MALLOC_FAILED; |
1450 | 0 | } |
1451 | | |
1452 | 1.15k | return ERR_NONE; |
1453 | 1.15k | } |
1454 | | |
1455 | | /* |
1456 | | * WelsDestroyDecoder |
1457 | | */ |
1458 | 1.15k | void WelsDestroyDecoder (ISVCDecoder* pDecoder) { |
1459 | 1.15k | if (NULL != pDecoder) { |
1460 | 1.15k | delete (CWelsDecoder*)pDecoder; |
1461 | 1.15k | } |
1462 | 1.15k | } |