History

Mainly update DecodeCurrentAccessUnit and associated functions to do threaded parallel frame decodings.

Add additional function PrefetchLastPicForThread and variables for better control of threaded decoding in the case of multi-slice with one slice group contains one slice.

xiaotiansf committed 7 years ago

Commit b0f95c41 parent 8b881449 files · +279 −89Browse files

Unified · Split

9 files
  1. codec/decoder/core/inc/decoder_context.h +3 −0
  2. codec/decoder/core/inc/pic_queue.h +2 −0
  3. codec/decoder/core/inc/picture.h +1 −0
  4. codec/decoder/core/src/decode_slice.cpp +1 −2
  5. codec/decoder/core/src/decoder.cpp +31 −4
  6. codec/decoder/core/src/decoder_core.cpp +222 −82
  7. codec/decoder/core/src/manage_dec_ref.cpp +1 −1
  8. codec/decoder/core/src/pic_queue.cpp +12 −0
  9. codec/decoder/core/src/wels_decoder_thread.cpp +6 −0
codec/decoder/core/inc/decoder_context.h+3−0
@@ -277,6 +277,7 @@ typedef struct tagSWelsLastDecPicInfo { · 276 unmodified lines
277277 PPicture pPreviousDecodedPictureInDpb; //pointer to previously decoded picture in DPB for error concealment
278278 int32_t iPrevFrameNum;// frame number of previous frame well decoded for non-truncated mode yet
279279 bool bLastHasMmco5;
280+ uint32_t uiDecodingTimeStamp; //represent relative decoding time stamps
280281 } SWelsLastDecPicInfo, *PWelsLastDecPicInfo;
281282
282283 typedef struct tagPictInfo {
@@ -538,6 +539,8 @@ typedef struct tagSWelsDecThreadCtx { · 255 unmodified lines
538539 PPicture pDec;
539540 SWelsDecEvent sImageReady;
540541 SWelsDecEvent sSliceDecodeStart;
542+ SWelsDecEvent sSliceDecodeFinsh;
543+ int32_t iPicBuffIdx; //picBuff Index
541544 } SWelsDecoderThreadCTX, *PWelsDecoderThreadCTX;
542545
543546 static inline void ResetActiveSPSForEachLayer (PWelsDecoderContext pCtx) {
codec/decoder/core/inc/pic_queue.h+2−0
@@ -54,6 +54,8 @@ typedef struct TagPicBuff { · 53 unmodified lines
5454
5555 PPicture PrefetchPic (PPicBuff pPicBuff); // To get current node applicable
5656 PPicture PrefetchPicForThread (PPicBuff pPicBuff); // To get current node applicable in the case of threaded mode
57+PPicture PrefetchLastPicForThread (PPicBuff pPicBuff,
58+ const int32_t& iLast); // To get last node applicable in the case of threaded mode
5759
5860 } // namespace WelsDec
5961
codec/decoder/core/inc/picture.h+1−0
@@ -89,6 +89,7 @@ struct SPicture { · 88 unmodified lines
8989 uint32_t uiDecodingTimeStamp; //represent relative decoding time stamps
9090 int32_t iPicBuffIdx;
9191 EWelsSliceType eSliceType;
92+ bool bIsUngroupedMultiSlice; //multi-slice picture with each each slice group contains one slice.
9293 bool bNewSeqBegin;
9394 int32_t iMbEcedNum;
9495 int32_t iMbEcedPropNum;
codec/decoder/core/src/decode_slice.cpp+1−2
@@ -1736,9 +1736,8 @@ int32_t WelsDecodeAndConstructSlice (PWelsDecoderContext pCtx) { · 1735 unmodified lines
17361736 if (!pCurDqLayer->pMbCorrectlyDecodedFlag[iNextMbXyIndex]) { //already con-ed, overwrite
17371737 pCurDqLayer->pMbCorrectlyDecodedFlag[iNextMbXyIndex] = true;
17381738 pCtx->pDec->iMbEcedPropNum += (pCurDqLayer->pMbRefConcealedFlag[iNextMbXyIndex] ? 1 : 0);
1739− ++pCtx->iTotalNumMbRec;
17401739 }
1741−
1740+ ++pCtx->iTotalNumMbRec;
17421741 if (pCtx->iTotalNumMbRec > iTotalMbTargetLayer) {
17431742 WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING,
17441743 "WelsTargetSliceConstruction():::pCtx->iTotalNumMbRec:%d, iTotalMbTargetLayer:%d",
codec/decoder/core/src/decoder.cpp+31−4
@@ -393,6 +393,7 @@ void WelsDecoderLastDecPicInfoDefaults (SWelsLastDecPicInfo& sLastDecPicInfo) { · 392 unmodified lines
393393 sLastDecPicInfo.pPreviousDecodedPictureInDpb = NULL;
394394 sLastDecPicInfo.iPrevFrameNum = -1;
395395 sLastDecPicInfo.bLastHasMmco5 = false;
396+ sLastDecPicInfo.uiDecodingTimeStamp = 0;
396397 }
397398
398399 /*!
@@ -437,6 +438,9 @@ static inline int32_t GetTargetRefListSize (PWelsDecoderContext pCtx) { · 38 unmodified lines
437438 iNumRefFrames = MAX_REF_PIC_COUNT + 2;
438439 } else {
439440 iNumRefFrames = pCtx->pSps->iNumRefFrames + 2;
441+ if (pCtx->pThreadCtx != NULL) {
442+ iNumRefFrames = MAX_REF_PIC_COUNT + 1;
443+ }
440444 }
441445
442446 #ifdef LONG_TERM_REF
@@ -478,7 +482,9 @@ int32_t WelsRequestMem (PWelsDecoderContext pCtx, const int32_t kiMbWidth, const · 35 unmodified lines
478482 && kiPicHeight == pCtx->iImgHeightInPixel) && (!bNeedChangePicQueue)) // have same scaled buffer
479483
480484 // sync update pRefList
481− WelsResetRefPic (pCtx); // added to sync update ref list due to pictures are free
485+ if (pCtx->pThreadCtx == NULL) {
486+ WelsResetRefPic (pCtx); // added to sync update ref list due to pictures are free
487+ }
482488
483489 if (pCtx->bHaveGotMemory && (kiPicWidth == pCtx->iImgWidthInPixel && kiPicHeight == pCtx->iImgHeightInPixel)
484490 && pCtx->pPicBuff != NULL && pCtx->pPicBuff->iCapacity != iPicQueueSize) {
@@ -554,6 +560,17 @@ void WelsFreeDynamicMemory (PWelsDecoderContext pCtx) { · 69 unmodified lines
554560 if (NULL != pPicBuff && NULL != *pPicBuff) {
555561 DestroyPicBuff (pCtx, pPicBuff, pMa);
556562 }
563+ if (pCtx->pThreadCtx != NULL) {
564+ //prevent from double destruction of PPicBuff
565+ PWelsDecoderThreadCTX pThreadCtx = (PWelsDecoderThreadCTX) (pCtx->pThreadCtx);
566+ int32_t threadCount = pThreadCtx->sThreadInfo.uiThrMaxNum;
567+ int32_t id = pThreadCtx->sThreadInfo.uiThrNum;
568+ for (int32_t i = 0; i < threadCount; ++i) {
569+ if (pThreadCtx[i - id].pCtx != NULL) {
570+ pThreadCtx[i - id].pCtx->pPicBuff = NULL;
571+ }
572+ }
573+ }
557574
558575 if (pCtx->pTempDec) {
559576 FreePicture (pCtx->pTempDec, pCtx->pMemAlign);
@@ -796,7 +813,11 @@ int32_t WelsDecodeBs (PWelsDecoderContext pCtx, const uint8_t* kpBsBuf, const in · 236 unmodified lines
796813 }
797814 CheckAndFinishLastPic (pCtx, ppDst, pDstBufInfo);
798815 if (pCtx->bAuReadyFlag && pCtx->pAccessUnitList->uiAvailUnitsNum != 0) {
799− ConstructAccessUnit (pCtx, ppDst, pDstBufInfo);
816+ if (pCtx->pThreadCtx == NULL) {
817+ ConstructAccessUnit (pCtx, ppDst, pDstBufInfo);
818+ } else {
819+ pCtx->pAccessUnitList->uiAvailUnitsNum = 1;
820+ }
800821 }
801822 }
802823 DecodeFinishUpdate (pCtx);
@@ -852,9 +873,15 @@ int32_t WelsDecodeBs (PWelsDecoderContext pCtx, const uint8_t* kpBsBuf, const in · 49 unmodified lines
852873 if (IS_PARAM_SETS_NALS (pCtx->sCurNalHead.eNalUnitType)) {
853874 iRet = ParseNonVclNal (pCtx, pNalPayload, iDstIdx - iConsumedBytes, pSrcNal - 3, iSrcIdx + 3);
854875 }
855− CheckAndFinishLastPic (pCtx, ppDst, pDstBufInfo);
876+ if (pCtx->pThreadCtx == NULL) {
877+ CheckAndFinishLastPic (pCtx, ppDst, pDstBufInfo);
878+ }
856879 if (pCtx->bAuReadyFlag && pCtx->pAccessUnitList->uiAvailUnitsNum != 0) {
857− ConstructAccessUnit (pCtx, ppDst, pDstBufInfo);
880+ if (pCtx->pThreadCtx == NULL) {
881+ ConstructAccessUnit (pCtx, ppDst, pDstBufInfo);
882+ } else {
883+ pCtx->pAccessUnitList->uiAvailUnitsNum = 1;
884+ }
858885 }
859886 }
860887 DecodeFinishUpdate (pCtx);
codec/decoder/core/src/decoder_core.cpp+222−82
@@ -194,8 +194,9 @@ static inline int32_t DecodeFrameConstruction (PWelsDecoderContext pCtx, uint8_t · 193 unmodified lines
194194 "DecodeFrameConstruction(): iTotalNumMbRec:%d, total_num_mb_sps:%d, cur_layer_mb_width:%d, cur_layer_mb_height:%d ",
195195 pCtx->iTotalNumMbRec, kiTotalNumMbInCurLayer, pCurDq->iMbWidth, pCurDq->iMbHeight);
196196 bFrameCompleteFlag = false; //return later after output buffer is done
197− if (pCtx->bInstantDecFlag) //no-delay decoding, wait for new slice
197+ if (pCtx->bInstantDecFlag) { //no-delay decoding, wait for new slice
198198 return ERR_INFO_MB_NUM_INADEQUATE;
199+ }
199200 } else if (pCurDq->sLayerInfo.sNalHeaderExt.bIdrFlag
200201 && (pCtx->iErrorCode == dsErrorFree)) { //complete non-ECed IDR frame done
201202 pCtx->pDec->bIsComplete = true;
@@ -220,9 +221,26 @@ static inline int32_t DecodeFrameConstruction (PWelsDecoderContext pCtx, uint8_t · 18 unmodified lines
220221 ppDst[1] = ppDst[1] + pCtx->sFrameCrop.iTopOffset * pPic->iLinesize[1] + pCtx->sFrameCrop.iLeftOffset;
221222 ppDst[2] = ppDst[2] + pCtx->sFrameCrop.iTopOffset * pPic->iLinesize[1] + pCtx->sFrameCrop.iLeftOffset;
222223 pDstInfo->iBufferStatus = 1;
223−
224− bool bOutResChange = (pCtx->iLastImgWidthInPixel != pDstInfo->UsrData.sSystemBuffer.iWidth)
225− || (pCtx->iLastImgHeightInPixel != pDstInfo->UsrData.sSystemBuffer.iHeight);
224+ if (pCtx->pThreadCtx != NULL && pPic->bIsComplete == false) {
225+ pPic->bIsComplete = true;
226+ }
227+ if (pCtx->pThreadCtx != NULL) {
228+ uint32_t uiMbHeight = (pCtx->pDec->iHeightInPixel + 15) >> 4;
229+ for (uint32_t i = 0; i < uiMbHeight; ++i) {
230+ SET_EVENT (&pCtx->pDec->pReadyEvent[i]);
231+ }
232+ }
233+ bool bOutResChange = false;
234+ if (pCtx->pThreadCtx == NULL || pCtx->pLastThreadCtx == NULL) {
235+ bOutResChange = (pCtx->iLastImgWidthInPixel != pDstInfo->UsrData.sSystemBuffer.iWidth)
236+ || (pCtx->iLastImgHeightInPixel != pDstInfo->UsrData.sSystemBuffer.iHeight);
237+ } else {
238+ if (pCtx->pLastThreadCtx != NULL) {
239+ PWelsDecoderThreadCTX pLastThreadCtx = (PWelsDecoderThreadCTX) (pCtx->pLastThreadCtx);
240+ bOutResChange = (pLastThreadCtx->pCtx->iLastImgWidthInPixel != pDstInfo->UsrData.sSystemBuffer.iWidth)
241+ || (pLastThreadCtx->pCtx->iLastImgHeightInPixel != pDstInfo->UsrData.sSystemBuffer.iHeight);
242+ }
243+ }
226244 pCtx->iLastImgWidthInPixel = pDstInfo->UsrData.sSystemBuffer.iWidth;
227245 pCtx->iLastImgHeightInPixel = pDstInfo->UsrData.sSystemBuffer.iHeight;
228246 if (pCtx->pParam->eEcActiveIdc == ERROR_CON_DISABLE) //no buffer output if EC is disabled and frame incomplete
@@ -846,8 +864,9 @@ void UpdateDecoderStatisticsForActiveParaset (SDecoderStatistics* pDecoderStatis · 617 unmodified lines
846864 * Parse slice header of bitstream in avc for storing data structure
847865 */
848866 int32_t ParseSliceHeaderSyntaxs (PWelsDecoderContext pCtx, PBitStringAux pBs, const bool kbExtensionFlag) {
849− PNalUnit const kpCurNal = pCtx->pAccessUnitList->pNalUnitsList[pCtx->pAccessUnitList->uiAvailUnitsNum -
850− 1];
867+ PNalUnit const kpCurNal =
868+ pCtx->pAccessUnitList->pNalUnitsList[pCtx->pAccessUnitList->uiAvailUnitsNum -
869+ 1];
851870
852871 PNalUnitHeaderExt pNalHeaderExt = NULL;
853872 PSliceHeader pSliceHead = NULL;
@@ -1462,7 +1481,6 @@ int32_t UpdateAccessUnit (PWelsDecoderContext pCtx) { · 608 unmodified lines
14621481
14631482 int32_t InitialDqLayersContext (PWelsDecoderContext pCtx, const int32_t kiMaxWidth, const int32_t kiMaxHeight) {
14641483 int32_t i = 0;
1465−
14661484 WELS_VERIFY_RETURN_IF (ERR_INFO_INVALID_PARAM, (NULL == pCtx || kiMaxWidth <= 0 || kiMaxHeight <= 0))
14671485 pCtx->sMb.iMbWidth = (kiMaxWidth + 15) >> 4;
14681486 pCtx->sMb.iMbHeight = (kiMaxHeight + 15) >> 4;
@@ -1508,7 +1526,8 @@ int32_t InitialDqLayersContext (PWelsDecoderContext pCtx, const int32_t kiMaxWid · 39 unmodified lines
15081526 sizeof (
15091527 bool),
15101528 "pCtx->sMb.pNoSubMbPartSizeLessThan8x8Flag[]");
1511− pCtx->sMb.pTransformSize8x8Flag[i] = (bool*)pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (bool),
1529+ pCtx->sMb.pTransformSize8x8Flag[i] = (bool*)pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (
1530+ bool),
15121531 "pCtx->sMb.pTransformSize8x8Flag[]");
15131532 pCtx->sMb.pChromaQp[i] = (int8_t (*)[2])pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (
15141533 int8_t) * 2,
@@ -1519,9 +1538,11 @@ int32_t InitialDqLayersContext (PWelsDecoderContext pCtx, const int32_t kiMaxWid · 4 unmodified lines
15191538 int16_t) * MV_A * MB_BLOCK4x4_NUM, "pCtx->sMb.pMvd[][]");
15201539 pCtx->sMb.pCbfDc[i] = (uint16_t*)pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (uint16_t),
15211540 "pCtx->sMb.pCbfDc[]");
1522− pCtx->sMb.pNzc[i] = (int8_t (*)[24])pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (int8_t) * 24,
1541+ pCtx->sMb.pNzc[i] = (int8_t (*)[24])pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (
1542+ int8_t) * 24,
15231543 "pCtx->sMb.pNzc[]");
1524− pCtx->sMb.pNzcRs[i] = (int8_t (*)[24])pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (int8_t) * 24,
1544+ pCtx->sMb.pNzcRs[i] = (int8_t (*)[24])pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (
1545+ int8_t) * 24,
15251546 "pCtx->sMb.pNzcRs[]");
15261547 pCtx->sMb.pScaledTCoeff[i] = (int16_t (*)[MB_COEFF_LIST_SIZE])pMa->WelsMallocz (pCtx->sMb.iMbWidth *
15271548 pCtx->sMb.iMbHeight *
@@ -1539,20 +1560,24 @@ int32_t InitialDqLayersContext (PWelsDecoderContext pCtx, const int32_t kiMaxWid · 11 unmodified lines
15391560 "pCtx->sMb.pChromaPredMode[]");
15401561 pCtx->sMb.pCbp[i] = (int8_t*)pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (int8_t),
15411562 "pCtx->sMb.pCbp[]");
1542− pCtx->sMb.pSubMbType[i] = (uint32_t (*)[MB_PARTITION_SIZE])pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight *
1563+ pCtx->sMb.pSubMbType[i] = (uint32_t (*)[MB_PARTITION_SIZE])pMa->WelsMallocz (pCtx->sMb.iMbWidth *
1564+ pCtx->sMb.iMbHeight *
15431565 sizeof (
15441566 uint32_t) * MB_PARTITION_SIZE, "pCtx->sMb.pSubMbType[]");
15451567 pCtx->sMb.pSliceIdc[i] = (int32_t*) pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (int32_t),
15461568 "pCtx->sMb.pSliceIdc[]"); // using int32_t for slice_idc, 4/21/2010
1547− pCtx->sMb.pResidualPredFlag[i] = (int8_t*) pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (int8_t),
1569+ pCtx->sMb.pResidualPredFlag[i] = (int8_t*) pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (
1570+ int8_t),
15481571 "pCtx->sMb.pResidualPredFlag[]");
1549− pCtx->sMb.pInterPredictionDoneFlag[i] = (int8_t*) pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (
1550− int8_t), "pCtx->sMb.pInterPredictionDoneFlag[]");
1572+ pCtx->sMb.pInterPredictionDoneFlag[i] = (int8_t*) pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight *
1573+ sizeof (
1574+ int8_t), "pCtx->sMb.pInterPredictionDoneFlag[]");
15511575
15521576 pCtx->sMb.pMbCorrectlyDecodedFlag[i] = (bool*) pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (
15531577 bool),
15541578 "pCtx->sMb.pMbCorrectlyDecodedFlag[]");
1555− pCtx->sMb.pMbRefConcealedFlag[i] = (bool*) pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (bool),
1579+ pCtx->sMb.pMbRefConcealedFlag[i] = (bool*) pMa->WelsMallocz (pCtx->sMb.iMbWidth * pCtx->sMb.iMbHeight * sizeof (
1580+ bool),
15561581 "pCtx->pMbRefConcealedFlag[]");
15571582
15581583 // check memory block valid due above allocated..
@@ -1599,6 +1624,8 @@ int32_t InitialDqLayersContext (PWelsDecoderContext pCtx, const int32_t kiMaxWid · 40 unmodified lines
15991624 return ERR_NONE;
16001625 }
16011626
1627+
1628+
16021629 void UninitialDqLayersContext (PWelsDecoderContext pCtx) {
16031630 int32_t i = 0;
16041631 CMemoryAlign* pMa = pCtx->pMemAlign;
@@ -2307,39 +2334,18 @@ int32_t InitConstructAccessUnit (PWelsDecoderContext pCtx, SBufferInfo* pDstInfo · 702 unmodified lines
23072334 * 0 - success; otherwise returned error_no defined in error_no.h
23082335 */
23092336 int32_t ConstructAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBufferInfo* pDstInfo) {
2310− int32_t iErr;
2311− PAccessUnit pCurAu = pCtx->pAccessUnitList;
2312− pCtx->bAuReadyFlag = false;
2313− pCtx->pLastDecPicInfo->bLastHasMmco5 = false;
2314− bool bTmpNewSeqBegin = CheckNewSeqBeginAndUpdateActiveLayerSps (pCtx);
2315− pCtx->bNewSeqBegin = pCtx->bNewSeqBegin || bTmpNewSeqBegin;
2316− iErr = WelsDecodeAccessUnitStart (pCtx);
2317− GetVclNalTemporalId (pCtx);
2318−
2319− if (ERR_NONE != iErr) {
2320− ForceResetCurrentAccessUnit (pCtx->pAccessUnitList);
2321− if (!pCtx->pParam->bParseOnly)
2322− pDstInfo->iBufferStatus = 0;
2323− pCtx->bNewSeqBegin = pCtx->bNewSeqBegin || pCtx->bNextNewSeqBegin;
2324− pCtx->bNextNewSeqBegin = false; // reset it
2325− if (pCtx->bNewSeqBegin)
2326− ResetActiveSPSForEachLayer (pCtx);
2327− return iErr;
2328− }
2329−
2330− pCtx->pSps = pCurAu->pNalUnitsList[pCurAu->uiStartPos]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.pSps;
2331− pCtx->pPps = pCurAu->pNalUnitsList[pCurAu->uiStartPos]->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader.pPps;
2332−
2333− //try to allocate or relocate DPB memory only when new sequence is coming.
2334− if (pCtx->bNewSeqBegin) {
2335− WelsResetRefPic (pCtx); //clear ref pPic when IDR NAL
2336− iErr = SyncPictureResolutionExt (pCtx, pCtx->pSps->iMbWidth, pCtx->pSps->iMbHeight);
2337−
2337+ int32_t iErr = ERR_NONE;
2338+ if (pCtx->pThreadCtx == NULL) {
2339+ iErr = InitConstructAccessUnit (pCtx, pDstInfo);
23382340 if (ERR_NONE != iErr) {
2339− WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "sync picture resolution ext failed, the error is %d", iErr);
23402341 return iErr;
23412342 }
23422343 }
2344+ if (pCtx->pCabacDecEngine == NULL) {
2345+ pCtx->pCabacDecEngine = (SWelsCabacDecEngine*)pCtx->pMemAlign->WelsMallocz (sizeof (SWelsCabacDecEngine),
2346+ "pCtx->pCabacDecEngine");
2347+ WELS_VERIFY_RETURN_IF (ERR_INFO_OUT_OF_MEMORY, (NULL == pCtx->pCabacDecEngine))
2348+ }
23432349
23442350 iErr = DecodeCurrentAccessUnit (pCtx, ppDst, pDstInfo);
23452351
@@ -2412,6 +2418,9 @@ void WelsDqLayerDecodeStart (PWelsDecoderContext pCtx, PNalUnit pCurNal, PSps pS · 66 unmodified lines
24122418
24132419 int32_t InitRefPicList (PWelsDecoderContext pCtx, const uint8_t kuiNRi, int32_t iPoc) {
24142420 int32_t iRet = ERR_NONE;
2421+ if (pCtx->pThreadCtx != NULL && pCtx->bNewSeqBegin) {
2422+ WelsResetRefPic (pCtx);
2423+ }
24152424 if (pCtx->eSliceType == B_SLICE) {
24162425 iRet = WelsInitBSliceRefList (pCtx, iPoc);
24172426 CreateImplicitWeightTable (pCtx);
@@ -2466,13 +2475,26 @@ void InitCurDqLayerData (PWelsDecoderContext pCtx, PDqLayer pCurDq) { · 48 unmodified lines
24662475 * Decode current access unit when current AU is completed.
24672476 */
24682477 int32_t DecodeCurrentAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBufferInfo* pDstInfo) {
2469− int32_t iRefCount[LIST_A];
2470− PNalUnit pNalCur = NULL;
2478+ PNalUnit pNalCur = pCtx->pNalCur = NULL;
24712479 PAccessUnit pCurAu = pCtx->pAccessUnitList;
24722480
24732481 int32_t iIdx = pCurAu->uiStartPos;
24742482 int32_t iEndIdx = pCurAu->uiEndPos;
24752483
2484+ //get current thread ctx
2485+ PWelsDecoderThreadCTX pThreadCtx = NULL;
2486+ if (pCtx->pThreadCtx != NULL) {
2487+ pThreadCtx = (PWelsDecoderThreadCTX)pCtx->pThreadCtx;
2488+ }
2489+ //get last thread ctx
2490+ PWelsDecoderThreadCTX pLastThreadCtx = NULL;
2491+ if (pCtx->pLastThreadCtx != NULL) {
2492+ pLastThreadCtx = (PWelsDecoderThreadCTX) (pCtx->pLastThreadCtx);
2493+ if (pLastThreadCtx->pDec == NULL) {
2494+ pLastThreadCtx->pDec = PrefetchLastPicForThread (pCtx->pPicBuff,
2495+ pLastThreadCtx->iPicBuffIdx);
2496+ }
2497+ }
24762498 int32_t iPpsId = 0;
24772499 int32_t iRet = ERR_NONE;
24782500
@@ -2487,7 +2509,7 @@ int32_t DecodeCurrentAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBuf · 8 unmodified lines
24872509 true; // Another fresh slice comingup for given dq layer, for multiple slices in case of header parts of slices sometimes loss over error-prone channels, 8/14/2008
24882510
24892511 //update pCurDqLayer at the starting of AU decoding
2490− if (pCtx->bInitialDqLayersMem) {
2512+ if (pCtx->bInitialDqLayersMem || pCtx->pCurDqLayer == NULL) {
24912513 pCtx->pCurDqLayer = pCtx->pDqLayersList[0];
24922514 }
24932515
@@ -2500,8 +2522,71 @@ int32_t DecodeCurrentAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBuf · 6 unmodified lines
25002522 PSliceHeaderExt pShExt = NULL;
25012523 PSliceHeader pSh = NULL;
25022524
2525+ if (pLastThreadCtx != NULL) {
2526+ pSh = &pNalCur->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader;
2527+ if (pSh->iFirstMbInSlice == 0) {
2528+ if (pLastThreadCtx->pCtx->pDec != NULL && pLastThreadCtx->pCtx->pDec->bIsUngroupedMultiSlice) {
2529+ WAIT_EVENT (&pLastThreadCtx->sSliceDecodeFinsh, WELS_DEC_THREAD_WAIT_INFINITE);
2530+ }
2531+ pCtx->pDec = NULL;
2532+ pCtx->iTotalNumMbRec = 0;
2533+ } else if (pLastThreadCtx->pCtx->pDec != NULL) {
2534+ if (pSh->iFrameNum == pLastThreadCtx->pCtx->pDec->iFrameNum
2535+ && pSh->iPicOrderCntLsb == pLastThreadCtx->pCtx->pDec->iFramePoc) {
2536+ WAIT_EVENT (&pLastThreadCtx->sSliceDecodeFinsh, WELS_DEC_THREAD_WAIT_INFINITE);
2537+ pCtx->pDec = pLastThreadCtx->pCtx->pDec;
2538+ pCtx->pDec->bIsUngroupedMultiSlice = true;
2539+ pCtx->sRefPic = pLastThreadCtx->pCtx->sRefPic;
2540+ pCtx->iTotalNumMbRec = pLastThreadCtx->pCtx->iTotalNumMbRec;
2541+ }
2542+ }
2543+ }
2544+ bool isNewFrame = true;
2545+ if (pThreadCtx != NULL) {
2546+ isNewFrame = pCtx->pDec == NULL;
2547+ }
25032548 if (pCtx->pDec == NULL) {
2549+ if (pLastThreadCtx != NULL) {
2550+ pLastThreadCtx->pDec->bUsedAsRef = pLastThreadCtx->pCtx->uiNalRefIdc > 0;
2551+ if (pLastThreadCtx->pDec->bUsedAsRef) {
2552+ for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
2553+ uint32_t i = 0;
2554+ while (i < MAX_DPB_COUNT && pLastThreadCtx->pCtx->sRefPic.pRefList[listIdx][i]) {
2555+ pLastThreadCtx->pDec->pRefPic[listIdx][i] = pLastThreadCtx->pCtx->sRefPic.pRefList[listIdx][i];
2556+ pLastThreadCtx->pDec->pRefPic[listIdx][i]->bAvailableFlag = false;
2557+ ++i;
2558+ }
2559+ }
2560+ pLastThreadCtx->pCtx->sTmpRefPic = pLastThreadCtx->pCtx->sRefPic;
2561+ WelsMarkAsRef (pLastThreadCtx->pCtx, pLastThreadCtx->pDec);
2562+ pCtx->sRefPic = pLastThreadCtx->pCtx->sTmpRefPic;
2563+ } else {
2564+ pCtx->sRefPic = pLastThreadCtx->pCtx->sRefPic;
2565+ }
2566+ //printf ("last uiDecodingTimeStamp = %d\n", pLastThreadCtx->pCtx->uiDecodingTimeStamp);
2567+ for (int32_t i = 0; i < pCtx->sRefPic.uiRefCount[LIST_0]; ++i) {
2568+ if (pCtx->sRefPic.pRefList[LIST_0][i] != NULL) {
2569+ pCtx->sRefPic.pRefList[LIST_0][i]->bAvailableFlag = false;
2570+ }
2571+ }
2572+ for (int32_t i = 0; i < pCtx->sRefPic.uiRefCount[LIST_1]; ++i) {
2573+ if (pCtx->sRefPic.pRefList[LIST_1][i] != NULL) {
2574+ pCtx->sRefPic.pRefList[LIST_1][i]->bAvailableFlag = false;
2575+ }
2576+ }
2577+ }
25042578 pCtx->pDec = PrefetchPic (pCtx->pPicBuff);
2579+ if (pThreadCtx != NULL) {
2580+ if (pCtx->pDec != NULL) {
2581+ pCtx->pDec->bAvailableFlag = false;
2582+ pCtx->pDec->bIsUngroupedMultiSlice = false;
2583+ pThreadCtx->pDec = pCtx->pDec;
2584+ uint32_t uiMbHeight = (pCtx->pDec->iHeightInPixel + 15) >> 4;
2585+ for (uint32_t i = 0; i < uiMbHeight; ++i) {
2586+ RESET_EVENT (&pCtx->pDec->pReadyEvent[i]);
2587+ }
2588+ }
2589+ }
25052590 if (pCtx->iTotalNumMbRec != 0)
25062591 pCtx->iTotalNumMbRec = 0;
25072592
@@ -2519,6 +2604,9 @@ int32_t DecodeCurrentAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBuf · 11 unmodified lines
25192604 }
25202605 pCtx->pDec->uiTimeStamp = pNalCur->uiTimeStamp;
25212606 pCtx->pDec->uiDecodingTimeStamp = pCtx->uiDecodingTimeStamp;
2607+ if (pThreadCtx != NULL) {
2608+ pThreadCtx->iPicBuffIdx = pCtx->pDec->iPicBuffIdx;
2609+ }
25222610
25232611 if (pCtx->iTotalNumMbRec == 0) { //Picture start to decode
25242612 for (int32_t i = 0; i < LAYER_NUM_EXCHANGEABLE; ++ i)
@@ -2556,6 +2644,7 @@ int32_t DecodeCurrentAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBuf · 31 unmodified lines
25562644 pCtx->pDec->iFramePoc = pSh->iPicOrderCntLsb; // still can not obtain correct, because current do not support POCtype 2
25572645 pCtx->pDec->bIdrFlag = pNalCur->sNalHeaderExt.bIdrFlag;
25582646 pCtx->pDec->eSliceType = pSh->eSliceType;
2647+
25592648 memcpy (&pLayerInfo.sSliceInLayer.sSliceHeaderExt, pShExt, sizeof (SSliceHeaderExt)); //confirmed_safe_unsafe_usage
25602649 pLayerInfo.sSliceInLayer.bSliceHeaderExtFlag = pNalCur->sNalData.sVclNal.bSliceHeaderExtFlag;
25612650 pLayerInfo.sSliceInLayer.eSliceType = pSh->eSliceType;
@@ -2587,11 +2676,9 @@ int32_t DecodeCurrentAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBuf · 25 unmodified lines
25872676 bFreshSliceAvailable = (iCurrIdD != iLastIdD
25882677 || iCurrIdQ != iLastIdQ); // do not need condition of (first_mb == 0) due multiple slices might be disorder
25892678
2679+
25902680 WelsDqLayerDecodeStart (pCtx, pNalCur, pLayerInfo.pSps, pLayerInfo.pPps);
25912681
2592− if (iCurrIdQ == BASE_QUALITY_ID) {
2593− ST64 (iRefCount, LD64 (pLayerInfo.sSliceInLayer.sSliceHeaderExt.sSliceHeader.uiRefCount));
2594− }
25952682
25962683 if ((iLastIdD < 0) || //case 1: first layer
25972684 (iLastIdD == iCurrIdD)) { //case 2: same uiDId
@@ -2601,13 +2688,23 @@ int32_t DecodeCurrentAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBuf · 3 unmodified lines
26012688 const bool kbIdrFlag = dq_cur->sLayerInfo.sNalHeaderExt.bIdrFlag
26022689 || (dq_cur->sLayerInfo.sNalHeaderExt.sNalUnitHeader.eNalUnitType == NAL_UNIT_CODED_SLICE_IDR);
26032690 // Subclause 8.2.5.2 Decoding process for gaps in frame_num
2691+ int32_t iPrevFrameNum = pCtx->pLastDecPicInfo->iPrevFrameNum;
2692+ if (pLastThreadCtx != NULL) {
2693+ if (pCtx->bNewSeqBegin) {
2694+ iPrevFrameNum = 0;
2695+ } else if (pLastThreadCtx->pDec != NULL) {
2696+ iPrevFrameNum = pLastThreadCtx->pDec->iFrameNum;
2697+ } else {
2698+ iPrevFrameNum = pCtx->bNewSeqBegin ? 0 : pLastThreadCtx->pCtx->iFrameNum;
2699+ }
2700+ }
26042701 if (!kbIdrFlag &&
2605− pSh->iFrameNum != pCtx->pLastDecPicInfo->iPrevFrameNum &&
2606− pSh->iFrameNum != ((pCtx->pLastDecPicInfo->iPrevFrameNum + 1) & ((1 << dq_cur->sLayerInfo.pSps->uiLog2MaxFrameNum) -
2702+ pSh->iFrameNum != iPrevFrameNum &&
2703+ pSh->iFrameNum != ((iPrevFrameNum + 1) & ((1 << dq_cur->sLayerInfo.pSps->uiLog2MaxFrameNum) -
26072704 1))) {
26082705 WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING,
26092706 "referencing pictures lost due frame gaps exist, prev_frame_num: %d, curr_frame_num: %d",
2610− pCtx->pLastDecPicInfo->iPrevFrameNum,
2707+ iPrevFrameNum,
26112708 pSh->iFrameNum);
26122709
26132710 bAllRefComplete = false;
@@ -2623,7 +2720,7 @@ int32_t DecodeCurrentAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBuf · 9 unmodified lines
26232720 }
26242721 }
26252722
2626− if (iCurrIdD == kuiDependencyIdMax && iCurrIdQ == BASE_QUALITY_ID) {
2723+ if (iCurrIdD == kuiDependencyIdMax && iCurrIdQ == BASE_QUALITY_ID && isNewFrame) {
26272724 iRet = InitRefPicList (pCtx, pCtx->uiNalRefIdc, pSh->iPicOrderCntLsb);
26282725 if (iRet) {
26292726 pCtx->bRPLRError = true;
@@ -2643,7 +2740,13 @@ int32_t DecodeCurrentAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBuf · 13 unmodified lines
26432740 if (pSh->eSliceType == B_SLICE && !pSh->iDirectSpatialMvPredFlag)
26442741 ComputeColocatedTemporalScaling (pCtx);
26452742
2646− iRet = WelsDecodeSlice (pCtx, bFreshSliceAvailable, pNalCur);
2743+ if (pThreadCtx != NULL) {
2744+ memset (&pCtx->lastReadyHeightOffset[0][0], -1, LIST_A * MAX_REF_PIC_COUNT * sizeof (int16_t));
2745+ SET_EVENT (&pThreadCtx->sSliceDecodeStart);
2746+ iRet = WelsDecodeAndConstructSlice (pCtx);
2747+ } else {
2748+ iRet = WelsDecodeSlice (pCtx, bFreshSliceAvailable, pNalCur);
2749+ }
26472750
26482751 //Output good store_base reconstruction when enhancement quality layer occurred error for MGS key picture case
26492752 if (iRet != ERR_NONE) {
@@ -2659,17 +2762,19 @@ int32_t DecodeCurrentAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBuf · 9 unmodified lines
26592762 }
26602763 }
26612764
2662− if (bReconstructSlice) {
2765+ if (pThreadCtx == NULL && bReconstructSlice) {
26632766 if ((iRet = WelsDecodeConstructSlice (pCtx, pNalCur)) != ERR_NONE) {
26642767 pCtx->pDec->bIsComplete = false; // reconstruction error, directly set the flag false
26652768 return iRet;
26662769 }
26672770 }
26682771 if (bAllRefComplete && pCtx->eSliceType != I_SLICE) {
2669− if (pCtx->sRefPic.uiRefCount[LIST_0] > 0) {
2670− bAllRefComplete &= CheckRefPicturesComplete (pCtx);
2671− } else {
2672− bAllRefComplete = false;
2772+ if (pCtx->pThreadCtx == NULL) {
2773+ if (pCtx->sRefPic.uiRefCount[LIST_0] > 0) {
2774+ bAllRefComplete &= CheckRefPicturesComplete (pCtx);
2775+ } else {
2776+ bAllRefComplete = false;
2777+ }
26732778 }
26742779 }
26752780 }
@@ -2721,34 +2826,49 @@ int32_t DecodeCurrentAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBuf · 45 unmodified lines
27212826 }
27222827 }
27232828
2829+ if (pThreadCtx != NULL && pCtx->uiDecodingTimeStamp > 1 && pCtx->pLastDecPicInfo->uiDecodingTimeStamp > 0) {
2830+ while (pCtx->uiDecodingTimeStamp > pCtx->pLastDecPicInfo->uiDecodingTimeStamp + 1) {
2831+ WelsSleep (1);
2832+ }
2833+ }
2834+ if (pThreadCtx != NULL) {
2835+ pCtx->pLastDecPicInfo->uiDecodingTimeStamp = pCtx->uiDecodingTimeStamp;
2836+ }
27242837 iRet = DecodeFrameConstruction (pCtx, ppDst, pDstInfo);
2725− if (iRet)
2838+ if (iRet) {
2839+ if (pThreadCtx != NULL) {
2840+ SET_EVENT (&pThreadCtx->sSliceDecodeFinsh);
2841+ }
27262842 return iRet;
2843+ }
27272844
27282845 pCtx->pLastDecPicInfo->pPreviousDecodedPictureInDpb = pCtx->pDec; //store latest decoded picture for EC
2729− pCtx->bUsedAsRef = false;
2730− if (pCtx->uiNalRefIdc > 0) {
2731− pCtx->bUsedAsRef = true;
2732− for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
2733− uint32_t i = 0;
2734− while (i < MAX_DPB_COUNT && pCtx->sRefPic.pRefList[listIdx][i]) {
2735− pCtx->pDec->pRefPic[listIdx][i] = pCtx->sRefPic.pRefList[listIdx][i];
2736− ++i;
2846+ pCtx->bUsedAsRef = pCtx->uiNalRefIdc > 0;
2847+ if (pCtx->pThreadCtx == NULL) {
2848+ if (pCtx->bUsedAsRef) {
2849+ for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
2850+ uint32_t i = 0;
2851+ while (i < MAX_DPB_COUNT && pCtx->sRefPic.pRefList[listIdx][i]) {
2852+ pCtx->pDec->pRefPic[listIdx][i] = pCtx->sRefPic.pRefList[listIdx][i];
2853+ ++i;
2854+ }
27372855 }
2738− }
2739− iRet = WelsMarkAsRef (pCtx);
2740− if (iRet != ERR_NONE) {
2741− if (iRet == ERR_INFO_DUPLICATE_FRAME_NUM)
2742− pCtx->iErrorCode |= dsBitstreamError;
2743− if (pCtx->pParam->eEcActiveIdc == ERROR_CON_DISABLE) {
2744− pCtx->pDec = NULL;
2745− return iRet;
2856+ iRet = WelsMarkAsRef (pCtx);
2857+ if (iRet != ERR_NONE) {
2858+ if (iRet == ERR_INFO_DUPLICATE_FRAME_NUM)
2859+ pCtx->iErrorCode |= dsBitstreamError;
2860+ if (pCtx->pParam->eEcActiveIdc == ERROR_CON_DISABLE) {
2861+ pCtx->pDec = NULL;
2862+ return iRet;
2863+ }
27462864 }
2865+ if (!pCtx->pParam->bParseOnly)
2866+ ExpandReferencingPicture (pCtx->pDec->pData, pCtx->pDec->iWidthInPixel, pCtx->pDec->iHeightInPixel,
2867+ pCtx->pDec->iLinesize,
2868+ pCtx->sExpandPicFunc.pfExpandLumaPicture, pCtx->sExpandPicFunc.pfExpandChromaPicture);
27472869 }
2748− if (!pCtx->pParam->bParseOnly)
2749− ExpandReferencingPicture (pCtx->pDec->pData, pCtx->pDec->iWidthInPixel, pCtx->pDec->iHeightInPixel,
2750− pCtx->pDec->iLinesize,
2751− pCtx->sExpandPicFunc.pfExpandLumaPicture, pCtx->sExpandPicFunc.pfExpandChromaPicture);
2870+ } else {
2871+ SET_EVENT (&pThreadCtx->sImageReady);
27522872 }
27532873 pCtx->pDec = NULL; //after frame decoding, always set to NULL
27542874 }
@@ -2758,8 +2878,27 @@ int32_t DecodeCurrentAccessUnit (PWelsDecoderContext pCtx, uint8_t** ppDst, SBuf · 3 unmodified lines
27582878 pCtx->pLastDecPicInfo->iPrevFrameNum = pSh->iFrameNum;
27592879 if (pCtx->pLastDecPicInfo->bLastHasMmco5)
27602880 pCtx->pLastDecPicInfo->iPrevFrameNum = 0;
2881+ if (pThreadCtx != NULL) {
2882+ int32_t threadCount = pThreadCtx->sThreadInfo.uiThrMaxNum;
2883+ int32_t id = pThreadCtx->sThreadInfo.uiThrNum;
2884+ for (int32_t i = 0; i < threadCount; ++i) {
2885+ if (pThreadCtx[i - id].pCtx != NULL) {
2886+ unsigned long long uiTimeStamp = pThreadCtx[i - id].pCtx->uiTimeStamp;
2887+ if (uiTimeStamp > 0 && pThreadCtx[i - id].pCtx->sSpsPpsCtx.iSeqId > pCtx->sSpsPpsCtx.iSeqId) {
2888+ CopySpsPps (pThreadCtx[i - id].pCtx, pCtx);
2889+ if (pCtx->pPicBuff != pThreadCtx[i - id].pCtx->pPicBuff) {
2890+ pCtx->pPicBuff = pThreadCtx[i - id].pCtx->pPicBuff;
2891+ }
2892+ InitialDqLayersContext (pCtx, pCtx->pSps->iMbWidth << 4, pCtx->pSps->iMbHeight << 4);
2893+ break;
2894+ }
2895+ }
2896+ }
2897+ }
2898+ }
2899+ if (pThreadCtx != NULL) {
2900+ SET_EVENT (&pThreadCtx->sSliceDecodeFinsh);
27612901 }
2762−
27632902 return ERR_NONE;
27642903 }
27652904
@@ -2875,6 +3014,7 @@ bool CheckRefPicturesComplete (PWelsDecoderContext pCtx) { · 109 unmodified lines
28753014 if (iRealMbIdx == -1) //caused by abnormal return of FmoNextMb()
28763015 return false;
28773016 }
3017+
28783018 return bAllRefComplete;
28793019 }
28803020 } // namespace WelsDec
codec/decoder/core/src/manage_dec_ref.cpp+1−1
@@ -150,7 +150,7 @@ static int32_t WelsCheckAndRecoverForFutureDecoding (PWelsDecoderContext pCtx) { · 149 unmodified lines
150150 && pCtx->eSliceType != SI_SLICE)) {
151151 if (pCtx->pParam->eEcActiveIdc !=
152152 ERROR_CON_DISABLE) { //IDR lost!, recover it for future decoding with data all set to 0
153− PPicture pRef = pCtx->pThreadCtx != NULL ? PrefetchPicForThread (pCtx->pPicBuff) : PrefetchPic (pCtx->pPicBuff);
153+ PPicture pRef = PrefetchPic (pCtx->pPicBuff);
154154 if (pRef != NULL) {
155155 // IDR lost, set new
156156 pRef->bIsComplete = false; // Set complete flag to false for lost IDR ref picture
codec/decoder/core/src/pic_queue.cpp+12−0
@@ -217,4 +217,16 @@ PPicture PrefetchPicForThread (PPicBuff pPicBuf) { · 216 unmodified lines
217217 return pPic;
218218 }
219219
220+PPicture PrefetchLastPicForThread (PPicBuff pPicBuf, const int32_t& iLastPicBuffIdx) {
221+ PPicture pPic = NULL;
222+
223+ if (pPicBuf->iCapacity == 0) {
224+ return NULL;
225+ }
226+ if (iLastPicBuffIdx >= 0 && iLastPicBuffIdx < pPicBuf->iCapacity) {
227+ pPic = pPicBuf->ppPic[iLastPicBuffIdx];
228+ }
229+ return pPic;
230+}
231+
220232 } // namespace WelsDec
codec/decoder/core/src/wels_decoder_thread.cpp+6−0
@@ -57,6 +57,12 @@ · 56 unmodified lines
5757 #define HW_NCPU_NAME "hw.ncpu"
5858 #endif
5959 #endif
60+#ifdef ANDROID_NDK
61+#include <cpu-features.h>
62+#endif
63+#ifdef __ANDROID__
64+#include <android/api-level.h>
65+#endif
6066
6167 #include "wels_decoder_thread.h"
6268 #include <stdio.h>

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t