shithub: openh264

Download patch

ref: 006d982fde9ae972c83ca816755be667b4c114a5
parent: f02cf48cae01ac087b41a5a125b3bc4f2c71f6a0
author: xiaotianshi2 <xiaotianshimail2@gmail.com>
date: Mon Sep 7 11:47:37 EDT 2020

1. fix readPicture in h264dec.cpp for multi-slice parser and add support for nal_deliminator.
2. Fix thread-decoding hanging due to incorrect call order of PrefetchPic and reference list update.
3. call WelsResetRefPic in right place to fix artifacts existing in a thread unit test case
4. add GetPrevFrameNum function to get correct iPrevFrameNum in thread-decoding mode.

--- a/codec/console/dec/src/h264dec.cpp
+++ b/codec/console/dec/src/h264dec.cpp
@@ -114,6 +114,7 @@
   int32_t pps_count = 0;
   int32_t non_idr_pict_count = 0;
   int32_t idr_pict_count = 0;
+  int32_t nal_deliminator = 0;
   pSpsBuf = NULL;
   sps_byte_count = 0;
   while (read_bytes < bytes_available - 4) {
@@ -143,12 +144,22 @@
         }
       } else if (nal_unit_type == 7) {
         pSpsBuf = ptr + (has4ByteStartCode ? 4 : 3);
-        if ((++sps_count == 1) && (non_idr_pict_count == 1 || idr_pict_count == 1)) {
+        if ((++sps_count >= 1) && (non_idr_pict_count >= 1 || idr_pict_count >= 1)) {
           return read_bytes;
         }
+        if (sps_count == 2) {
+          return read_bytes;
+        }
       } else if (nal_unit_type == 8) {
         if (++pps_count == 1 && sps_count == 1) {
           sps_byte_count = int32_t (ptr - pSpsBuf);
+        }
+        if (pps_count >= 1 && (non_idr_pict_count >= 1 || idr_pict_count >= 1)) {
+          return read_bytes;
+        }
+      } else if (nal_unit_type == 9) {
+        if (++nal_deliminator == 2) {
+          return read_bytes;
         }
       }
       if (read_bytes >= bytes_available - 4) {
--- a/codec/decoder/core/inc/decoder_context.h
+++ b/codec/decoder/core/inc/decoder_context.h
@@ -557,6 +557,25 @@
   }
   return iThreadCount;
 }
+//GetPrevFrameNum only applies when thread count >= 2
+static inline int32_t GetPrevFrameNum (PWelsDecoderContext pCtx) {
+  if (pCtx->uiDecodingTimeStamp > 0) {
+    PWelsDecoderThreadCTX pThreadCtx = (PWelsDecoderThreadCTX)pCtx->pThreadCtx;
+    int32_t iThreadCount = int32_t (pThreadCtx->sThreadInfo.uiThrMaxNum);
+    int32_t  uiThrNum = int32_t (pThreadCtx->sThreadInfo.uiThrNum);
+    for (int32_t i = 0; i < iThreadCount; ++i) {
+      int32_t id = i - uiThrNum;
+      if (id != 0 && pThreadCtx[id].pCtx->uiDecodingTimeStamp == pCtx->uiDecodingTimeStamp - 1) {
+        if (pThreadCtx[id].pCtx->pDec != NULL) {
+          int32_t iFrameNum = pThreadCtx[id].pCtx->pDec->iFrameNum;
+          if (iFrameNum >= 0) return iFrameNum;
+        }
+        return pThreadCtx[id].pCtx->iFrameNum;
+      }
+    }
+  }
+  return pCtx->pLastDecPicInfo->iPrevFrameNum;
+}
 //#ifdef __cplusplus
 //}
 //#endif//__cplusplus
--- a/codec/decoder/core/src/decoder.cpp
+++ b/codec/decoder/core/src/decoder.cpp
@@ -438,8 +438,9 @@
     iNumRefFrames = MAX_REF_PIC_COUNT + 2;
   } else {
     iNumRefFrames = pCtx->pSps->iNumRefFrames + 2;
-    if (GetThreadCount (pCtx) > 1) {
-      iNumRefFrames = MAX_REF_PIC_COUNT + 1;
+    int32_t  iThreadCount = GetThreadCount (pCtx);
+    if (iThreadCount > 1) {
+      iNumRefFrames = MAX_REF_PIC_COUNT;
     }
   }
 
--- a/codec/decoder/core/src/decoder_core.cpp
+++ b/codec/decoder/core/src/decoder_core.cpp
@@ -2421,9 +2421,6 @@
 
 int32_t InitRefPicList (PWelsDecoderContext pCtx, const uint8_t kuiNRi, int32_t iPoc) {
   int32_t iRet = ERR_NONE;
-  if (GetThreadCount (pCtx) > 1 && pCtx->bNewSeqBegin) {
-    WelsResetRefPic (pCtx);
-  }
   if (pCtx->eSliceType == B_SLICE) {
     iRet = WelsInitBSliceRefList (pCtx, iPoc);
     CreateImplicitWeightTable (pCtx);
@@ -2525,37 +2522,20 @@
     SLayerInfo pLayerInfo;
     PSliceHeaderExt pShExt = NULL;
     PSliceHeader pSh = NULL;
-
-    if (pLastThreadCtx != NULL) {
-      pSh = &pNalCur->sNalData.sVclNal.sSliceHeaderExt.sSliceHeader;
-      if (pSh->iFirstMbInSlice == 0) {
-        if (pLastThreadCtx->pCtx->pDec != NULL && pLastThreadCtx->pCtx->pDec->bIsUngroupedMultiSlice) {
-          WAIT_EVENT (&pLastThreadCtx->sSliceDecodeFinish, WELS_DEC_THREAD_WAIT_INFINITE);
-        }
-        pCtx->pDec = NULL;
-        pCtx->iTotalNumMbRec = 0;
-      } else if (pLastThreadCtx->pCtx->pDec != NULL) {
-        if (pSh->iFrameNum == pLastThreadCtx->pCtx->pDec->iFrameNum
-            && pSh->iPicOrderCntLsb == pLastThreadCtx->pCtx->pDec->iFramePoc) {
-          WAIT_EVENT (&pLastThreadCtx->sSliceDecodeFinish, WELS_DEC_THREAD_WAIT_INFINITE);
-          pCtx->pDec = pLastThreadCtx->pCtx->pDec;
-          pCtx->pDec->bIsUngroupedMultiSlice = true;
-          pCtx->sRefPic = pLastThreadCtx->pCtx->sRefPic;
-          pCtx->iTotalNumMbRec = pLastThreadCtx->pCtx->iTotalNumMbRec;
-        }
-      }
-    }
     bool isNewFrame = true;
     if (iThreadCount > 1) {
       isNewFrame = pCtx->pDec == NULL;
     }
     if (pCtx->pDec == NULL) {
-      if (pLastThreadCtx != NULL && iIdx == 0) {
+      //make call PrefetchPic first before updating reference lists in threaded mode
+      //this prevents from possible thread-decoding hanging
+      pCtx->pDec = PrefetchPic (pCtx->pPicBuff);
+      if (pLastThreadCtx != NULL) {
         pLastThreadCtx->pDec->bUsedAsRef = pLastThreadCtx->pCtx->uiNalRefIdc > 0;
         if (pLastThreadCtx->pDec->bUsedAsRef) {
           for (int32_t listIdx = LIST_0; listIdx < LIST_A; ++listIdx) {
             uint32_t i = 0;
-            while (i < MAX_DPB_COUNT && pLastThreadCtx->pCtx->sRefPic.pRefList[listIdx][i]) {
+            while (i < MAX_REF_PIC_COUNT && pLastThreadCtx->pCtx->sRefPic.pRefList[listIdx][i]) {
               pLastThreadCtx->pDec->pRefPic[listIdx][i] = pLastThreadCtx->pCtx->sRefPic.pRefList[listIdx][i];
               ++i;
             }
@@ -2567,7 +2547,11 @@
           pCtx->sRefPic = pLastThreadCtx->pCtx->sRefPic;
         }
       }
-      pCtx->pDec = PrefetchPic (pCtx->pPicBuff);
+      //WelsResetRefPic needs to be called when a new sequence is encountered
+      //Otherwise artifacts is observed in decoded yuv in couple of unit tests with multiple-slice frame
+      if (GetThreadCount (pCtx) > 1 && pCtx->bNewSeqBegin) {
+        WelsResetRefPic (pCtx);
+      }
       if (pCtx->iTotalNumMbRec != 0)
         pCtx->iTotalNumMbRec = 0;
 
@@ -2580,7 +2564,6 @@
         return ERR_INFO_REF_COUNT_OVERFLOW;
       }
       if (pThreadCtx != NULL) {
-        pCtx->pDec->bIsUngroupedMultiSlice = false;
         pThreadCtx->pDec = pCtx->pDec;
         if (iThreadCount > 1) ++pCtx->pDec->iRefCount;
         uint32_t uiMbHeight = (pCtx->pDec->iHeightInPixel + 15) >> 4;
@@ -2683,25 +2666,8 @@
           // Subclause 8.2.5.2 Decoding process for gaps in frame_num
           int32_t iPrevFrameNum = pCtx->pLastDecPicInfo->iPrevFrameNum;
           if (pLastThreadCtx != NULL) {
-            if (pCtx->bNewSeqBegin) {
-              iPrevFrameNum = 0;
-            } else if (pLastThreadCtx->pDec != NULL) {
-              if (pLastThreadCtx->pDec->uiTimeStamp == pCtx->uiTimeStamp - 1) {
-                iPrevFrameNum = pLastThreadCtx->pDec->iFrameNum;
-                if (iPrevFrameNum == -1) iPrevFrameNum = pLastThreadCtx->pCtx->iFrameNum;
-              } else {
-                int32_t  id = pThreadCtx->sThreadInfo.uiThrNum;
-                for (int32_t i = 0; i < iThreadCount; ++i) {
-                  if (pThreadCtx[i - id].pCtx->uiTimeStamp == pCtx->uiTimeStamp - 1) {
-                    if (pThreadCtx[i - id].pDec != NULL) iPrevFrameNum = pThreadCtx[i - id].pDec->iFrameNum;
-                    if (iPrevFrameNum == -1) iPrevFrameNum = pThreadCtx[i - id].pCtx->iFrameNum;
-                    break;
-                  }
-                }
-              }
-            } else {
-              iPrevFrameNum = pCtx->bNewSeqBegin ? 0 : pLastThreadCtx->pCtx->iFrameNum;
-            }
+            //call GetPrevFrameNum() to get correct iPrevFrameNum to prevent frame gap warning
+            iPrevFrameNum = pCtx->bNewSeqBegin ? 0 : GetPrevFrameNum (pCtx);
           }
           if (!kbIdrFlag  &&
               pSh->iFrameNum != iPrevFrameNum &&
@@ -2727,6 +2693,7 @@
 
         if (iCurrIdD == kuiDependencyIdMax && iCurrIdQ == BASE_QUALITY_ID && isNewFrame) {
           iRet = InitRefPicList (pCtx, pCtx->uiNalRefIdc, pSh->iPicOrderCntLsb);
+          if (iThreadCount > 1) isNewFrame = false;
           if (iRet) {
             pCtx->bRPLRError = true;
             bAllRefComplete = false; // RPLR error, set ref pictures complete flag false