简体   繁体   中英

FFMPEG: Multithread decoding deadlock?

I'm using FFMPEG to decode H264 stream from IP Camera. There are many cameras so I used multithread with FFMPEG.

I registered multithread with FFMPEG by the below code

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)

In each thread that connect to IP Camera, the code for decoding H264 stream from that IP Camera is below

 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;
    }   
}
  • I encountered a deadlock when the function avcodec_decode_video2() throw an exception, and then the program was deadlocked when call UnInitForH264Stream() at line avcodec_close(rtpHeader.pCodecCtx); I have fixed and maybe the funtion avcodec_decode_video2() work right (not throw exception).

  • But now, sometime I encountered a deadlock when decoding, but I don't know which function that caused the deadlock. Because It's hard to reproduce this bug.

Someone can tell me is there any potential deadlock in my code?

Thank you very much!

This libav thread Shows a slightly different implementation of the lock.

Furthermore, you seem to init ffmpeg within your decode function. This thread here seems to point to the conclusion that opening and closing streams is not a thread safe operation even if you declare the lockmgr properly. You should consider moving them to a central, synchronized place where your stream start

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM