c++ - FFMPEG:多线程解码死锁?

标签 c++ multithreading ffmpeg deadlock decode

我正在使用 FFMPEG 解码来自网络摄像机的 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)

在每个连接到网络摄像机的线程中,解码来自该网络摄像机的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);我已经修复了,也许函数 avcodec_decode_video2() 可以正常工作(不会抛出异常)。

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

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

非常感谢!

最佳答案

This libav thread 显示了一个稍微不同的锁实现。

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

关于c++ - FFMPEG:多线程解码死锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26772104/

相关文章:

bash - youtube-dl 每 5 分钟下载一分钟(在 twitch 视频上,但如果更容易,我也保存了本地文件)

BASH 删除行中的第一个字母 (ffmpeg)

c++ - 防止破解——特别是使程序更难反编译的方法

c++ - 在 C++ 中使用 haru 库以 pdf 格式创建表

ruby-on-rails - Redis + ActionController::Live 线程不会死

java - Android Studio错误: "Method getText() must be called from the UI Thread,当前推断线程是worker

bash - 如何将文件名通过管道传输到 ffmpeg 命令中?

c++ - COLOR_ATTACHMENT's - 如何将多个纹理渲染为帧缓冲区对象内的颜色附件?

c++ set 输出的元素比它包含的元素多得多

java - 线程无法停止