使用 FFmpeg API 播放 RTSP 期间的伪影

问题描述 投票:0回答:1

我需要从 IP 摄像机播放 RTSP 视频。 如果我使用 ffplay 或 VLC,一切都很好。 但如果我使用 FFmpeg API(C#、FFmpeg.AutoGen),则帧上会出现伪像。使用 FFmpeg API 可能会出现什么问题?

更新

根据 Christoph 的建议,我尝试将 ffplay 的 UDP 替换为 TCP。

  1. TCP 和 UDP 都给出了 3-4 秒的延迟(我的应用程序给出了不到一秒的延迟)。

  2. TCP 和 UDP 都可以正常工作。

  3. 使用UDP时,开头有错误信息:

max delay reached. need to consume packet
RTP: missed 436 packets
Invalid level prefix
error while decoding MB 17 28

这些错误才刚刚开始。那么就没有错误了。 当使用TCP时,根本不会报告任何错误。

  1. 我的应用程序中的

    discardcorrupt
    标志无法修复工件。

  2. 如果我在应用程序中使用 TCP(

    rtsp_transport=tcp
    标志),工件就会消失。这很好。但我不想因为 TCP 而在网络上产生额外的负载。另外,可能会有视频延迟。

ffplay 和 VLC 如何在 UDP 上运行而不会出现伪影?为什么 API 不能做到这一点?

RTSP FFmpeg artifacts

AVFormatContext* pFormatContext = ffmpeg.avformat_alloc_context();

int error;

error = ffmpeg.avformat_open_input(&pFormatContext, rtspUrl, null, null);

if (error != 0)
    throw new ApplicationException(Helpers.GetErrorMessage(error));

error = ffmpeg.avformat_find_stream_info(pFormatContext, null);

if (error != 0)
    throw new ApplicationException(Helpers.GetErrorMessage(error));

AVStream* pStream = null;

for (var i = 0; i < pFormatContext->nb_streams; i++)
{
    if (pFormatContext->streams[i]->codec->codec_type == AVMediaType.AVMEDIA_TYPE_VIDEO)
    {
        pStream = pFormatContext->streams[i];
    }
}

if (pStream == null)
    throw new ApplicationException(@"Could not found video stream.");

AVCodecContext codecContext = *pStream->codec;

int width = codecContext.width;
int height = codecContext.height;
AVPixelFormat sourcePixFmt = codecContext.pix_fmt;
AVCodecID codecId = codecContext.codec_id;

AVPixelFormat destinationPixFmt = AVPixelFormat.AV_PIX_FMT_BGR24;

if (sourcePixFmt == AVPixelFormat.AV_PIX_FMT_NONE && codecId == AVCodecID.AV_CODEC_ID_H264)
{
    sourcePixFmt = AVPixelFormat.AV_PIX_FMT_YUV420P;
}

SwsContext* pConvertContext = ffmpeg.sws_getContext(width, height, sourcePixFmt, width, height, destinationPixFmt, ffmpeg.SWS_FAST_BILINEAR, null, null, null);

if (pConvertContext == null)
    throw new ApplicationException(@"Could not initialize the conversion context.");

AVFrame* pConvertedFrame = ffmpeg.av_frame_alloc();

int convertedFrameBufferSize = ffmpeg.av_image_get_buffer_size(destinationPixFmt, width, height, 1);

IntPtr convertedFrameBufferPtr = Marshal.AllocHGlobal(convertedFrameBufferSize);

byte_ptrArray4 dstData = new byte_ptrArray4();
int_array4 dstLinesize = new int_array4();

ffmpeg.av_image_fill_arrays(ref dstData, ref dstLinesize, (byte*)convertedFrameBufferPtr, destinationPixFmt, width, height, 1);



WorkEnabled = true;

AVCodec* pCodec = ffmpeg.avcodec_find_decoder(codecId);

if (pCodec == null)
    throw new ApplicationException(@"Unsupported codec.");

AVCodecContext* pCodecContext = &codecContext;

if ((pCodec->capabilities & ffmpeg.AV_CODEC_CAP_TRUNCATED) == ffmpeg.AV_CODEC_CAP_TRUNCATED)
{
    pCodecContext->flags |= ffmpeg.AV_CODEC_FLAG_TRUNCATED;
}

error = ffmpeg.avcodec_open2(pCodecContext, pCodec, null);

if (error < 0)
    throw new ApplicationException(Helpers.GetErrorMessage(error));

AVFrame* pDecodedFrame = ffmpeg.av_frame_alloc();

AVPacket packet = new AVPacket();
AVPacket* pPacket = &packet;
ffmpeg.av_init_packet(pPacket);


Bitmap bitmap = null;
Bitmap previousbBitmap = null;

while (WorkEnabled)
{
    try
    {
        do
        {
            error = ffmpeg.av_read_frame(pFormatContext, pPacket);

            if (error == ffmpeg.AVERROR_EOF)
            {
                Thread.Sleep(1000);
                break;
            }
            if (error < 0)
                throw new ApplicationException(Helpers.GetErrorMessage(error));

            if (pPacket->stream_index != pStream->index) continue;

            error = ffmpeg.avcodec_send_packet(pCodecContext, pPacket);

            if (error < 0)
                throw new ApplicationException(Helpers.GetErrorMessage(error));

            error = ffmpeg.avcodec_receive_frame(pCodecContext, pDecodedFrame);


        } while (error == ffmpeg.AVERROR(ffmpeg.EAGAIN) && WorkEnabled);

        if (error == ffmpeg.AVERROR_EOF)
        {
            Thread.Sleep(1000);
            continue;
        }
        if (error < 0)
            throw new ApplicationException(Helpers.GetErrorMessage(error));

        if (pPacket->stream_index != pStream->index) continue;

        // YUV->RGB
        ffmpeg.sws_scale(pConvertContext, pDecodedFrame->data, pDecodedFrame->linesize, 0, height, dstData, dstLinesize);
    }
    catch (Exception)
    {}
    finally
    {
        ffmpeg.av_packet_unref(pPacket);
        ffmpeg.av_frame_unref(pDecodedFrame);
    }

    bitmap = new Bitmap(width, height, dstLinesize[0], PixelFormat.Format24bppRgb, convertedFrameBufferPtr);

    previousbBitmap = bitmap;

    System.Windows.Application.Current.Dispatcher.Invoke(() => _pictureBox.Image = bitmap);

}
c# ffmpeg rtsp ip-camera
1个回答
0
投票

这里这里讨论了类似的问题。事实证明,对于 UDP,有必要增加缓冲区大小。

ffmpeg.av_dict_set(&formatOpts, "rtsp_transport", "udp", 0);
ffmpeg.av_dict_set(&formatOpts, "buffer_size", "200000", 0);
ffmpeg.avformat_open_input(&pFormatContext, url, null, &formatOpts);

文物消失了!

© www.soinside.com 2019 - 2024. All rights reserved.