2014-11-06 68 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