1157 lines · 46.8 KB · C++
RawDownload
/*! * \copy *     Copyright (c)  2010-2013, Cisco Systems *     All rights reserved. * *     Redistribution and use in source and binary forms, with or without *     modification, are permitted provided that the following conditions *     are met: * *        * Redistributions of source code must retain the above copyright *          notice, this list of conditions and the following disclaimer. * *        * Redistributions in binary form must reproduce the above copyright *          notice, this list of conditions and the following disclaimer in *          the documentation and/or other materials provided with the *          distribution. * *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *     COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, *     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN *     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE *     POSSIBILITY OF SUCH DAMAGE. * * * \file    slice_multi_threading.h * * \brief   pSlice based multiple threading * * \date    04/16/2010 Created * ************************************************************************************* */  #include <assert.h>#if !defined(_WIN32)#include <semaphore.h>#include <unistd.h>#endif//!_WIN32#ifndef SEM_NAME_MAX// length of semaphore name should be system constrained at least on mac 10.7#define  SEM_NAME_MAX 32#endif//SEM_NAME_MAX#include "slice_multi_threading.h"#include "mt_defs.h"#include "nal_encap.h"#include "utils.h"#include "encoder.h"#include "svc_encode_slice.h"#include "deblocking.h"#include "svc_enc_golomb.h"#include "crt_util_safe_x.h" // for safe crt like calls#include "rc.h" #include "cpu.h" #include "measure_time.h"#include "wels_task_management.h" #if defined(ENABLE_TRACE_MT)#define MT_TRACE_LOG(pLog, x, ...) WelsLog(pLog, x, __VA_ARGS__)#else#define MT_TRACE_LOG(x, ...)#endif #define WELS_THREAD_SIGNAL_AND_BREAK(CodedEventList, CodedMasterEvent, iEventIdx) {  \    WelsEventSignal(&CodedEventList[iEventIdx]);  \    WelsEventSignal (&CodedMasterEvent);  \    break;  \} namespace WelsEnc {void UpdateMbListNeighborParallel (SDqLayer* pCurDq,                                   SMB* pMbList,                                   const int32_t uiSliceIdc) {  SSliceCtx* pSliceCtx           = &pCurDq->sSliceEncCtx;  SSlice* pUpdateSlice           = &pCurDq->sLayerInfo.pSliceInLayer[uiSliceIdc];  const uint16_t* kpMbMap        = pSliceCtx->pOverallMbMap;  const int32_t kiMbWidth        = pSliceCtx->iMbWidth;  int32_t iIdx                   = pUpdateSlice->sSliceHeaderExt.sSliceHeader.iFirstMbInSlice;  const int32_t kiEndMbInSlice   = iIdx + pSliceCtx->pCountMbNumInSlice[uiSliceIdc] - 1;   do {    SMB* pMb                     = &pMbList[iIdx];    uint32_t uiNeighborAvailFlag = 0;    const int32_t kiMbXY         = pMb->iMbXY;    const int32_t kiMbX          = pMb->iMbX;    const int32_t kiMbY          = pMb->iMbY;    bool     bLeft;    bool     bTop;    bool     bLeftTop;    bool     bRightTop;    int32_t   iLeftXY, iTopXY, iLeftTopXY, iRightTopXY;     iLeftXY = kiMbXY - 1;    iTopXY = kiMbXY - kiMbWidth;    iLeftTopXY = iTopXY - 1;    iRightTopXY = iTopXY + 1;     bLeft = (kiMbX > 0) && (uiSliceIdc == kpMbMap[iLeftXY]);    bTop = (kiMbY > 0) && (uiSliceIdc == kpMbMap[iTopXY]);    bLeftTop = (kiMbX > 0) && (kiMbY > 0) && (uiSliceIdc == kpMbMap[iLeftTopXY]);    bRightTop = (kiMbX < (kiMbWidth - 1)) && (kiMbY > 0) && (uiSliceIdc == kpMbMap[iRightTopXY]);     if (bLeft) {      uiNeighborAvailFlag |= LEFT_MB_POS;    }    if (bTop) {      uiNeighborAvailFlag |= TOP_MB_POS;    }    if (bLeftTop) {      uiNeighborAvailFlag |= TOPLEFT_MB_POS;    }    if (bRightTop) {      uiNeighborAvailFlag |= TOPRIGHT_MB_POS;    }    pMb->uiNeighborAvail        = (uint8_t)uiNeighborAvailFlag;    pMb->uiSliceIdc             = uiSliceIdc;     ++ iIdx;  } while (iIdx <= kiEndMbInSlice);} void CalcSliceComplexRatio (SDqLayer* pCurDq) {  SSliceCtx* pSliceCtx          = &pCurDq->sSliceEncCtx;  SSlice*    pSliceInLayer      = pCurDq->sLayerInfo.pSliceInLayer;  int32_t iSumAv                = 0;  int32_t* pCountMbInSlice      = (int32_t*)pSliceCtx->pCountMbNumInSlice;  const int32_t kiSliceCount    = pSliceCtx->iSliceNumInFrame;  int32_t iSliceIdx             = 0;  int32_t iAvI[MAX_SLICES_NUM];   WelsEmms();   while (iSliceIdx < kiSliceCount) {    iAvI[iSliceIdx] = WELS_DIV_ROUND (INT_MULTIPLY * pCountMbInSlice[iSliceIdx], pSliceInLayer[iSliceIdx].uiSliceConsumeTime);    MT_TRACE_LOG (NULL, WELS_LOG_DEBUG, "[MT] CalcSliceComplexRatio(), uiSliceConsumeTime[%d]= %d us, slice_run= %d",                  iSliceIdx,                  pSliceInLayer[iSliceIdx].uiSliceConsumeTime, pCountMbInSlice[iSliceIdx]);    iSumAv += iAvI[iSliceIdx];     ++ iSliceIdx;  }  while (-- iSliceIdx >= 0) {    pSliceInLayer[iSliceIdx].iSliceComplexRatio = WELS_DIV_ROUND (INT_MULTIPLY * iAvI[iSliceIdx], iSumAv);  }} int32_t NeedDynamicAdjust (SSlice* pSliceInLayer, const int32_t iSliceNum) {  if ( NULL == pSliceInLayer )    return false;   uint32_t uiTotalConsume       = 0;  int32_t iSliceIdx             = 0;  int32_t iNeedAdj              = false;   WelsEmms();   while (iSliceIdx < iSliceNum) {    uiTotalConsume += pSliceInLayer[iSliceIdx].uiSliceConsumeTime;    iSliceIdx ++;  }  if (uiTotalConsume == 0) {    MT_TRACE_LOG (NULL, WELS_LOG_DEBUG,                  "[MT] NeedDynamicAdjust(), herein do no adjust due first picture, iCountSliceNum= %d",                  iSliceNum);    return false;  }   iSliceIdx = 0;  float fThr                    = EPSN; // threshold for various cores cases  float fRmse                   = .0f;  // root mean square error of pSlice consume ratios  const float kfMeanRatio       = 1.0f / iSliceNum;  do {    const float fRatio = 1.0f * pSliceInLayer[iSliceIdx].uiSliceConsumeTime / uiTotalConsume;    const float fDiffRatio = fRatio - kfMeanRatio;    fRmse += (fDiffRatio * fDiffRatio);    ++ iSliceIdx;  } while (iSliceIdx + 1 < iSliceNum);  fRmse = sqrtf (fRmse / iSliceNum);  if (iSliceNum >= 8) {    fThr += THRESHOLD_RMSE_CORE8;  } else if (iSliceNum >= 4) {    fThr += THRESHOLD_RMSE_CORE4;  } else if (iSliceNum >= 2) {    fThr += THRESHOLD_RMSE_CORE2;  } else    fThr = 1.0f;  if (fRmse > fThr)    iNeedAdj = true;  MT_TRACE_LOG (NULL, WELS_LOG_DEBUG,                "[MT] NeedDynamicAdjust(), herein adjustment decision is made (iNeedAdj= %d) by: fRmse of pSlice complexity ratios %.6f, the corresponding threshold %.6f, iCountSliceNum %d",                iNeedAdj, fRmse, fThr, iSliceNum);   return iNeedAdj;} void DynamicAdjustSlicing (sWelsEncCtx* pCtx,                           SDqLayer* pCurDqLayer,                           int32_t iCurDid) {  SSliceCtx* pSliceCtx          = &pCurDqLayer->sSliceEncCtx;  SSlice* pSliceInLayer         = pCurDqLayer->sLayerInfo.pSliceInLayer;  const int32_t kiCountSliceNum = pSliceCtx->iSliceNumInFrame;  const int32_t kiCountNumMb    = pSliceCtx->iMbNumInFrame;  int32_t iMinimalMbNum         =    pSliceCtx->iMbWidth;  // in theory we need only 1 SMB, here let it as one SMB row required  int32_t iMaximalMbNum         = 0;    // dynamically assign later  int32_t iMbNumLeft            = kiCountNumMb;  int32_t iRunLen[MAX_THREADS_NUM] = {0};  int32_t iSliceIdx             = 0;   int32_t iNumMbInEachGom = 0;  SWelsSvcRc* pWelsSvcRc = &pCtx->pWelsSvcRc[iCurDid];  if (pCtx->pSvcParam->iRCMode != RC_OFF_MODE) {    iNumMbInEachGom = pWelsSvcRc->iNumberMbGom;     if (iNumMbInEachGom <= 0) {      WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR,               "[MT] DynamicAdjustSlicing(), invalid iNumMbInEachGom= %d from RC, iDid= %d, iCountNumMb= %d", iNumMbInEachGom,               iCurDid, kiCountNumMb);      return;    }     // do not adjust in case no extra iNumMbInEachGom based left for slicing adjustment,    // extra MB of non integrated GOM assigned at the last pSlice in default, keep up on early initial result.    if (iNumMbInEachGom * kiCountSliceNum >= kiCountNumMb) {      return;    }    iMinimalMbNum = iNumMbInEachGom;  }   if (kiCountSliceNum < 2 || (kiCountSliceNum & 0x01)) // we need suppose uiSliceNum is even for multiple threading    return;   iMaximalMbNum = kiCountNumMb - (kiCountSliceNum - 1) * iMinimalMbNum;   WelsEmms();   MT_TRACE_LOG (pCtx, WELS_LOG_DEBUG, "[MT] DynamicAdjustSlicing(), iDid= %d, iCountNumMb= %d", iCurDid, kiCountNumMb);   iSliceIdx = 0;  while (iSliceIdx + 1 < kiCountSliceNum) {    int32_t iNumMbAssigning = WELS_DIV_ROUND (kiCountNumMb * pSliceInLayer[iSliceIdx].iSliceComplexRatio, INT_MULTIPLY);     // GOM boundary aligned    if (pCtx->pSvcParam->iRCMode != RC_OFF_MODE) {      iNumMbAssigning = iNumMbAssigning / iNumMbInEachGom * iNumMbInEachGom;    }     // make sure one GOM at least in each pSlice for safe    if (iNumMbAssigning < iMinimalMbNum)      iNumMbAssigning = iMinimalMbNum;    else if (iNumMbAssigning > iMaximalMbNum)      iNumMbAssigning = iMaximalMbNum;     assert (iNumMbAssigning > 0);     iMbNumLeft -= iNumMbAssigning;    if (iMbNumLeft <= 0) { // error due to we can not support slice_skip now yet, do not adjust this time      assert (0);      return;    }    iRunLen[iSliceIdx] = iNumMbAssigning;    MT_TRACE_LOG (pCtx, WELS_LOG_DEBUG,                  "[MT] DynamicAdjustSlicing(), uiSliceIdx= %d, iSliceComplexRatio= %.2f, slice_run_org= %d, slice_run_adj= %d",                  iSliceIdx, pSliceInLayer[iSliceIdx].iSliceComplexRatio * 1.0f / INT_MULTIPLY,                  pSliceCtx->pCountMbNumInSlice[iSliceIdx],                  iNumMbAssigning);    ++ iSliceIdx;    iMaximalMbNum = iMbNumLeft - (kiCountSliceNum - iSliceIdx - 1) * iMinimalMbNum; // get maximal num_mb in left parts  }  iRunLen[iSliceIdx] = iMbNumLeft;  MT_TRACE_LOG (pCtx, WELS_LOG_DEBUG,                "[MT] DynamicAdjustSlicing(), iSliceIdx= %d, iSliceComplexRatio= %.2f, slice_run_org= %d, slice_run_adj= %d",                iSliceIdx, pSliceInLayer[iSliceIdx].iSliceComplexRatio * 1.0f / INT_MULTIPLY,                pSliceCtx->pCountMbNumInSlice[iSliceIdx], iMbNumLeft);    if (DynamicAdjustSlicePEncCtxAll (pCurDqLayer, iRunLen) == 0) {    const int32_t kiThreadNum   = pCtx->pSvcParam->iCountThreadsNum;    int32_t iThreadIdx          = 0;    do {      WelsEventSignal (&pCtx->pSliceThreading->pUpdateMbListEvent[iThreadIdx]);      WelsEventSignal (&pCtx->pSliceThreading->pThreadMasterEvent[iThreadIdx]);      ++ iThreadIdx;    } while (iThreadIdx < kiThreadNum);     WelsMultipleEventsWaitAllBlocking (kiThreadNum, &pCtx->pSliceThreading->pFinUpdateMbListEvent[0]);  }} int32_t SetMultiSliceBuffer (sWelsEncCtx** ppCtx, CMemoryAlign* pMa, SSliceThreading* pSmt,                             int32_t iMaxSliceNum, int32_t iSlice1Len, int32_t iSlice0Len, bool bDynamicSlice) {  (*ppCtx)->pSliceBs = (SWelsSliceBs*)pMa->WelsMalloc (sizeof (SWelsSliceBs) * iMaxSliceNum, "pSliceBs");  if (NULL == (*ppCtx)->pSliceBs) {    return ENC_RETURN_MEMALLOCERR;  }   if (iSlice0Len <= 0) {    return ENC_RETURN_UNEXPECTED;  }  //slice 0  (*ppCtx)->pSliceBs[0].uiSize = iSlice0Len;  (*ppCtx)->pSliceBs[0].pBs    = (*ppCtx)->pFrameBs;  (*ppCtx)->pSliceBs[0].uiBsPos = 0;  (*ppCtx)->pSliceBs[0].pBsBuffer = pSmt->pThreadBsBuffer[0];  if ((iMaxSliceNum == 1) && (!bDynamicSlice)) {    return ENC_RETURN_SUCCESS;  }  //slice >0  if (iSlice1Len <= 0) {    return ENC_RETURN_UNEXPECTED;  }  if ((*ppCtx)->iFrameBsSize < (iSlice0Len + (iMaxSliceNum - 1)*iSlice1Len)) {    return ENC_RETURN_MEMALLOCERR;  }  for (int32_t k = 1; k < iMaxSliceNum; k++) {    (*ppCtx)->pSliceBs[k].uiSize = iSlice1Len;    (*ppCtx)->pSliceBs[k].pBs    = (*ppCtx)->pSliceBs[k - 1].pBs + (*ppCtx)->pSliceBs[k - 1].uiSize;  }  return ENC_RETURN_SUCCESS; } int32_t RequestMtResource (sWelsEncCtx** ppCtx, SWelsSvcCodingParam* pCodingParam, const int32_t iCountBsLen,                           const int32_t iMaxSliceBufferSize, bool bDynamicSlice) {  CMemoryAlign* pMa             = NULL;  SWelsSvcCodingParam* pPara = NULL;  SSliceThreading* pSmt         = NULL;  int32_t iNumSpatialLayers     = 0;  int32_t iThreadNum            = 0;  int32_t iIdx                  = 0;  int16_t iMaxSliceNum          = 1;  int32_t iReturn = ENC_RETURN_SUCCESS;  bool bWillUseTaskManage = false;   if (NULL == ppCtx || NULL == pCodingParam || NULL == *ppCtx || iCountBsLen <= 0)    return 1;   pMa = (*ppCtx)->pMemAlign;  pPara = pCodingParam;  iNumSpatialLayers = pPara->iSpatialLayerNum;  iThreadNum = pPara->iCountThreadsNum;  iMaxSliceNum = (*ppCtx)->iMaxSliceCount;   pSmt = (SSliceThreading*)pMa->WelsMalloc (sizeof (SSliceThreading), "SSliceThreading");  WELS_VERIFY_RETURN_PROC_IF (1, (NULL == pSmt), FreeMemorySvc (ppCtx))  (*ppCtx)->pSliceThreading = pSmt;  pSmt->pThreadPEncCtx = (SSliceThreadPrivateData*)pMa->WelsMalloc (sizeof (SSliceThreadPrivateData) * iThreadNum,                         "pThreadPEncCtx");  WELS_VERIFY_RETURN_PROC_IF (1, (NULL == pSmt->pThreadPEncCtx), FreeMemorySvc (ppCtx)) #ifdef _WIN32  // Dummy event namespace, the windows events don't actually use this  WelsSnprintf (pSmt->eventNamespace, sizeof (pSmt->eventNamespace), "%p", (void*) *ppCtx);#else  WelsSnprintf (pSmt->eventNamespace, sizeof (pSmt->eventNamespace), "%p%x", (void*) *ppCtx, getpid());#endif//!_WIN32   iIdx = 0;  while (iIdx < iNumSpatialLayers) {    SSliceArgument* pSliceArgument = &pPara->sSpatialLayers[iIdx].sSliceArgument;   if (pSliceArgument->uiSliceMode == SM_FIXEDSLCNUM_SLICE || pSliceArgument->uiSliceMode == SM_RASTER_SLICE) {      bWillUseTaskManage = true;    }    ++ iIdx;  } #ifdef MT_DEBUG  // file handle for MT debug  pSmt->pFSliceDiff = NULL;   if (pSmt->pFSliceDiff) {    fclose (pSmt->pFSliceDiff);    pSmt->pFSliceDiff = NULL;  }  pSmt->pFSliceDiff = fopen ("slice_time.txt", "wt+");#endif//MT_DEBUG   MT_TRACE_LOG (*ppCtx, WELS_LOG_INFO, "encpEncCtx= 0x%p", (void*) *ppCtx);   char name[SEM_NAME_MAX] = {0};  WELS_GCC_UNUSED WELS_THREAD_ERROR_CODE err = 0;   iIdx = 0;  while (iIdx < iThreadNum) {    pSmt->pThreadPEncCtx[iIdx].pWelsPEncCtx     = (void*) *ppCtx;    pSmt->pThreadPEncCtx[iIdx].iSliceIndex      = iIdx;    pSmt->pThreadPEncCtx[iIdx].iThreadIndex     = iIdx;    pSmt->pThreadHandles[iIdx]                  = 0;     WelsSnprintf (name, SEM_NAME_MAX, "ee%d%s", iIdx, pSmt->eventNamespace);    err = WelsEventOpen (&pSmt->pExitEncodeEvent[iIdx], name);    MT_TRACE_LOG (*ppCtx, WELS_LOG_INFO, "[MT] Open pExitEncodeEvent%d named(%s) ret%d err%d", iIdx, name, err, errno);    WelsSnprintf (name, SEM_NAME_MAX, "tm%d%s", iIdx, pSmt->eventNamespace);    err = WelsEventOpen (&pSmt->pThreadMasterEvent[iIdx], name);    MT_TRACE_LOG (*ppCtx, WELS_LOG_INFO, "[MT] Open pThreadMasterEvent%d named(%s) ret%d err%d", iIdx, name, err, errno);    // length of semaphore name should be system constrained at least on mac 10.7    WelsSnprintf (name, SEM_NAME_MAX, "ud%d%s", iIdx, pSmt->eventNamespace);    err = WelsEventOpen (&pSmt->pUpdateMbListEvent[iIdx], name);    MT_TRACE_LOG (*ppCtx, WELS_LOG_INFO, "[MT] Open pUpdateMbListEvent%d named(%s) ret%d err%d", iIdx, name, err, errno);    WelsSnprintf (name, SEM_NAME_MAX, "fu%d%s", iIdx, pSmt->eventNamespace);    err = WelsEventOpen (&pSmt->pFinUpdateMbListEvent[iIdx], name);    MT_TRACE_LOG (*ppCtx, WELS_LOG_INFO, "[MT] Open pFinUpdateMbListEvent%d named(%s) ret%d err%d", iIdx, name, err,                  errno);    WelsSnprintf (name, SEM_NAME_MAX, "sc%d%s", iIdx, pSmt->eventNamespace);    err = WelsEventOpen (&pSmt->pSliceCodedEvent[iIdx], name);    MT_TRACE_LOG (*ppCtx, WELS_LOG_INFO, "[MT] Open pSliceCodedEvent%d named(%s) ret%d err%d", iIdx, name, err, errno);    WelsSnprintf (name, SEM_NAME_MAX, "rc%d%s", iIdx, pSmt->eventNamespace);    err = WelsEventOpen (&pSmt->pReadySliceCodingEvent[iIdx], name);    MT_TRACE_LOG (*ppCtx, WELS_LOG_INFO, "[MT] Open pReadySliceCodingEvent%d = 0x%p named(%s) ret%d err%d", iIdx,                  (void*)pSmt->pReadySliceCodingEvent[iIdx], name, err, errno);     pSmt->pThreadBsBuffer[iIdx] = (uint8_t*)pMa->WelsMalloc (iCountBsLen, "pSmt->pThreadBsBuffer");    WELS_VERIFY_RETURN_PROC_IF (1, (NULL == pSmt->pThreadBsBuffer[iIdx]), FreeMemorySvc (ppCtx))     ++ iIdx;  }  for (; iIdx < MAX_THREADS_NUM; iIdx++) {    pSmt->pThreadBsBuffer[iIdx] = NULL;  }   //previous conflict  WelsSnprintf (name, SEM_NAME_MAX, "scm%s", pSmt->eventNamespace);  err = WelsEventOpen (&pSmt->pSliceCodedMasterEvent, name);  MT_TRACE_LOG (*ppCtx, WELS_LOG_INFO, "[MT] Open pSliceCodedMasterEvent named(%s) ret%d err%d", name, err, errno);  //previous conflict ends   iReturn = SetMultiSliceBuffer (ppCtx, pMa, pSmt, iMaxSliceNum,                                 iMaxSliceBufferSize,                                 iCountBsLen,                                 bDynamicSlice);  WELS_VERIFY_RETURN_PROC_IF (iReturn, (ENC_RETURN_SUCCESS != iReturn), FreeMemorySvc (ppCtx))   iReturn = WelsMutexInit (&pSmt->mutexSliceNumUpdate);  WELS_VERIFY_RETURN_PROC_IF (1, (WELS_THREAD_ERROR_OK != iReturn), FreeMemorySvc (ppCtx))   if (bWillUseTaskManage) {    (*ppCtx)->pTaskManage = IWelsTaskManage::CreateTaskManage (*ppCtx, iNumSpatialLayers, bDynamicSlice);    WELS_VERIFY_RETURN_PROC_IF (iReturn, (NULL == (*ppCtx)->pTaskManage), FreeMemorySvc (ppCtx))  }   memset (&pSmt->bThreadBsBufferUsage, 0, MAX_THREADS_NUM * sizeof (bool));  iReturn = WelsMutexInit (&pSmt->mutexThreadBsBufferUsage);  WELS_VERIFY_RETURN_PROC_IF (1, (WELS_THREAD_ERROR_OK != iReturn), FreeMemorySvc (ppCtx))   iReturn = WelsMutexInit (& (*ppCtx)->mutexEncoderError);  WELS_VERIFY_RETURN_PROC_IF (1, (WELS_THREAD_ERROR_OK != iReturn), FreeMemorySvc (ppCtx))   MT_TRACE_LOG (*ppCtx, WELS_LOG_INFO, "RequestMtResource(), iThreadNum=%d, iCountSliceNum= %d",                pPara->iCountThreadsNum,                iMaxSliceNum);   return 0;} void ReleaseMtResource (sWelsEncCtx** ppCtx) {  SWelsSliceBs* pSliceB                 = NULL;  SSliceThreading* pSmt                 = NULL;  CMemoryAlign* pMa                     = NULL;  int32_t iIdx                          = 0;  int32_t iThreadNum                    = 0;  int16_t uiSliceNum                    = 0;   if (NULL == ppCtx || NULL == *ppCtx)    return;   pMa           = (*ppCtx)->pMemAlign;  uiSliceNum    = (*ppCtx)->iMaxSliceCount;  iThreadNum    = (*ppCtx)->pSvcParam->iCountThreadsNum;  pSmt          = (*ppCtx)->pSliceThreading;   if (NULL == pSmt)    return;   char ename[SEM_NAME_MAX] = {0};  while (iIdx < iThreadNum) {    // length of semaphore name should be system constrained at least on mac 10.7    WelsSnprintf (ename, SEM_NAME_MAX, "ee%d%s", iIdx, pSmt->eventNamespace);    WelsEventClose (&pSmt->pExitEncodeEvent[iIdx], ename);    WelsSnprintf (ename, SEM_NAME_MAX, "tm%d%s", iIdx, pSmt->eventNamespace);    WelsEventClose (&pSmt->pThreadMasterEvent[iIdx], ename);    WelsSnprintf (ename, SEM_NAME_MAX, "sc%d%s", iIdx, pSmt->eventNamespace);    WelsEventClose (&pSmt->pSliceCodedEvent[iIdx], ename);    WelsSnprintf (ename, SEM_NAME_MAX, "rc%d%s", iIdx, pSmt->eventNamespace);    WelsEventClose (&pSmt->pReadySliceCodingEvent[iIdx], ename);    WelsSnprintf (ename, SEM_NAME_MAX, "ud%d%s", iIdx, pSmt->eventNamespace);    WelsEventClose (&pSmt->pUpdateMbListEvent[iIdx], ename);    WelsSnprintf (ename, SEM_NAME_MAX, "fu%d%s", iIdx, pSmt->eventNamespace);    WelsEventClose (&pSmt->pFinUpdateMbListEvent[iIdx], ename);     ++ iIdx;  }

Lines 1–500 of 1157.

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