2014-11-06 107 views
0

我正在使用FFMPEG來解碼來自IP Camera的H264流。有很多相機,所以我用FFMPEG多線程。FFMPEG:多線程解碼死鎖?

我註冊多線程與FFMPEG通過下面的代碼

static int lockmgr(void **mtx, enum AVLockOp op) 
{ 
    switch (op) 
    { 
    case AV_LOCK_CREATE: 
     *mtx = malloc(sizeof(pthread_mutex_t)); 
     if (!*mtx) 
      return 1; 
     return !!pthread_mutex_init((pthread_mutex_t*)*mtx, NULL); 
    case AV_LOCK_OBTAIN: 
     return !!pthread_mutex_lock((pthread_mutex_t*)*mtx); 
    case AV_LOCK_RELEASE: 
     return !!pthread_mutex_unlock((pthread_mutex_t*)*mtx); 
    case AV_LOCK_DESTROY: 
     pthread_mutex_destroy((pthread_mutex_t*)*mtx); 
     free(*mtx); 
     return 0; 
    } 
    return 1; 
} 

av_lockmgr_register(lockmgr) 

在每個連接到網絡攝像機螺紋,用於從網絡攝像機解碼H264流的代碼是下面

int DecodeStream() 
{ 
    try 
    { 
     InitForH264Stream(); 

     int    bytesDecoded = 0; 
     int    frameFinished = 0; 
     while (commonGlobal->settings.iPCameraSettigs.isRunningThreadRequestVideo[rtpHeader->cameraInd]) 
     { 
      while (_packet->size > 0) 
      { 
       // Decode the next chunk of data 
       bytesDecoded = avcodec_decode_video2(rtpHeader->pCodecCtx, rtpHeader->pFrame, 
        &frameFinished, _packet); 
       // Was there an error? 
       if (bytesDecoded < 0) 
       { 
        if (rtpHeader->packetPointer != NULL) 
        { 
         _packet->data = rtpHeader->packetPointer; 
         rtpHeader->packetPointer = NULL; 
         av_free_packet(_packet); 
        } 
        return RS_NOT_OK; 
       } 

       _packet->size -= bytesDecoded; 
       _packet->data += bytesDecoded; 
       if (rtpHeader->packetPointer != NULL && _packet->size == 0) 
       { 
        _packet->data = rtpHeader->packetPointer; 
        rtpHeader->packetPointer = NULL; 
        av_free_packet(_packet); 
       } 
       if (frameFinished) 
       { 
        return RS_OK; 
       } 
       // Did we finish the current frame? Then we can return 
      } 
      do 
      { 
       try 
       { 
        av_init_packet(_packet); 
        rtpHeader->th->Reset(); 
        int ret = AVERROR(EAGAIN); 
        while (AVERROR(EAGAIN) == ret) 
         ret = av_read_frame(pFormatCtx, _packet); 
        if (ret < 0) 
        { 
         if (ret == AVERROR(AVERROR_EOF) || (pFormatCtx->pb && pFormatCtx->pb->eof_reached)) 
         { 
          sprintf(strErr, "Error end of file line %d", __LINE__); 
         } 
         if (pFormatCtx->pb && pFormatCtx->pb->error) 
         { 
          sprintf(strErr, "Error end of file line %d", __LINE__); 
         } 
         _packet->data = NULL; 
         return RS_NOT_OK; 
        } 
        if (_packet->stream_index != rtpHeader->videoStreamInd) 
         av_free_packet(_packet); 
        else 
         rtpHeader->packetPointer = _packet->data; 
       } 
       catch (...) 
       { 
        _packet->data = NULL; 
        return RS_NOT_OK; 
       } 
      } while (_packet->stream_index != rtpHeader->videoStreamInd); 
     } 
    } 
    catch (...) 
    { 
     _packet = NULL; 
     commonGlobal->WriteRuntimeLogs("ReceiveRTPBlock() threw an Exception"); 
     UnInitForH264Stream(); 
     return RS_NOT_OK; 
    } 
} 


VOID UnInitForH264Stream() 
{ 
    if (rtpHeader.pCodecCtx != NULL) 
     avcodec_close(rtpHeader.pCodecCtx); 

    if (pFormatCtx != NULL) 
     av_close_input_file(pFormatCtx); 

    if (rtpHeader.th != NULL) 
    { 
     delete rtpHeader.th; 
     rtpHeader.th = NULL; 
    }  

    if (rtpHeader.pFrame != NULL) 
     avcodec_free_frame(&rtpHeader.pFrame); 

    if (RGBFrame != NULL) 
    { 
     avcodec_free_frame(&RGBFrame); 
     RGBFrame = NULL;    
    } 

    if (ConversionContext != NULL) 
    { 
     sws_freeContext(ConversionContext); 
     ConversionContext = NULL; 
    } 

    if (rgbBuffer != NULL) 
    { 
     av_free(rgbBuffer); 
     rgbBuffer = NULL; 
    } 
} 
  • 當函數avcodec_decode_video2()拋出一個異常時,我遇到了一個死鎖,然後當調用UnInitForH264Stream()在線時程序被鎖死我已修好,也許功能avcodec_decode_video2()工作正確(不拋出異常)。

  • 但是現在有時我在解碼時遇到了死鎖,但是我不知道哪個函數導致了死鎖。因爲很難重現這個錯誤。

有人可以告訴我在我的代碼中是否存在潛在的死鎖?

非常感謝!

回答

1

This libav thread顯示一個稍微不同的鎖定實現。

此外,你似乎在你的解碼函數中初始化ffmpeg。 This thread here似乎指出,即使正確聲明lockmgr,打開和關閉流也不是線程安全的操作。你應該考慮把它們移到一箇中心,同步的地方,你的流開始

+0

謝謝!此代碼是摘要,主代碼按照您所說的「將它們移動到您的流開始的中央同步位置」來實現。你能解釋一下我的代碼和上面顯示的鎖的實現之間有什麼區別嗎? – TTGroup 2014-11-06 06:28:52

+0

我想刪除*這裏:if(!* mtx)。你也不需要!!在pthread函數前面。 !通常是C語言的「投擲指針」。我認爲它會返回1,如果pthread函數返回0將指示失敗。我不是100%關於這個 – Eric 2014-11-06 06:43:07

+0

nvm,!!應該沒問題,它會爲所有非0值返回1 – Eric 2014-11-06 06:49:23