FFMPEG:多线程解码死锁?

时间:2014-11-06 05:06:03

标签: c++ multithreading ffmpeg deadlock decode

我正在使用FFMPEG解码来自IP Camera的H264流。有很多相机,所以我使用多线程与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)

在连接到IP Camera的每个线程中,用于解码来自该IP Camera的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_close(rtpHeader.pCodecCtx);时程序死锁了我已修复并且可能是函数{ {1}}正常工作(不抛出异常)。

  • 但是现在,有时我在解码时遇到了死锁,但我不知道哪个函数导致了死锁。因为很难重现这个错误。

有人可以告诉我代码中是否存在任何潜在的死锁?

非常感谢!

1 个答案:

答案 0 :(得分:1)

This libav thread显示锁的实现略有不同。

此外,您似乎在解码函数中初始化ffmpeg。 This thread here似乎指出即使你正确地声明lockmgr,打开和关闭流也不是线程安全操作的结论。您应该考虑将它们移动到流开始的中央同步位置