c# - 如果落后则跳过帧渲染

标签 c# ffmpeg rtsp

我有下面的代码,它使用 ffmpeg 库(带有 Autogen 包装器的 v3.1.4)在我的应用程序中呈现 RTSP 视频。该代码通常运行良好。但是,receptical.Write方法不是特别有效。在慢速机器上,我的视频渲染开始落后。最终我的缓冲区填满,我开始看到视频损坏。当它开始落后时,如何更改下面的代码以跳过帧?如果有多个帧准备好了,我真的只关心显示最近可用的帧——毕竟这是实时视频。我相信 avcodec_send_packetavcodec_receive_frame方法大约是一对一的。

while (!token.IsCancellationRequested)
{
    if (ffmpeg.av_read_frame(pFormatContext, pPacket) != 0)
    {
        // end of the stream
        ffmpeg.av_packet_unref(pPacket);
        ffmpeg.av_frame_unref(pDecodedFrame);
        break;
    }

    if (pPacket->stream_index != pStream->index || (pPacket->flags & ffmpeg.AV_PKT_FLAG_CORRUPT) > 0)
    {
        // this should never happen; we only subscribe to one stream
        // and I believe corrupt packets are automatically discarded
        ffmpeg.av_packet_unref(pPacket);
        ffmpeg.av_frame_unref(pDecodedFrame);
        continue;
    }

    var sendResult = ffmpeg.avcodec_send_packet(pCodecContext, pPacket);
    if (sendResult < 0)
    {
        // one of the possible results is a "buffer full", but I don't think that should happen as long as we call 1-to-1 receive_frame
        ffmpeg.av_packet_unref(pPacket);
        ffmpeg.av_frame_unref(pDecodedFrame);
        _logger.Warn("Failure in FFmpeg avcodec_send_packet: " + sendResult);
        break;
    }

    while (ffmpeg.avcodec_receive_frame(pCodecContext, pDecodedFrame) == 0)
    {
        var src = &pDecodedFrame->data0;
        var dst = &pConvertedFrame->data0;
        var srcStride = pDecodedFrame->linesize;
        var dstStride = pConvertedFrame->linesize;
        ffmpeg.sws_scale(pConvertContext, src, srcStride, 0, height, dst, dstStride);

        sbyte* convertedFrameAddress = pConvertedFrame->data0;

        int linesize = dstStride[0];

        if (receptical == null)
        {
            receptical = writableBitampCreationCallback.Invoke(new DetectedImageDimensions {Width = width, Height = height, Format = DetectedPixelFormat.Bgr24, Linesize = linesize});
        }

        var imageBufferPtr = new IntPtr(convertedFrameAddress);
        receptical.Write(width, height, imageBufferPtr, linesize);

        ffmpeg.av_frame_unref(pDecodedFrame);
    }
    ffmpeg.av_packet_unref(pPacket);
}

最佳答案

  • 取决于您同步播放的方式,无论是针对系统时钟还是其他方式。您可以检查传入数据包的 PTS,如果它们开始落后于播放,则转储它们。即时实时解码是 CPU 密集型的。
  • 解码和使用 sws_scale 会吃掉你的 CPU。我不知道 'writableBitampCreationCallback' 是什么,但我也猜想这也会占用 CPU 时间。解决这个问题的最好方法是将您的解码分成单独的线程,每个线程用于音频和视频,也许还有字幕。这至少会释放cpu时间。数据包可以发送到每个线程。
  • 您没有显示视频最终是如何呈现的。使用 openGL 之类的东西,您可以使用 YUV 到 RGB 着色器直接渲染解码帧(YUV420),从而无需将帧转换为 RGB。这节省了大量的 CPU 时间。

  • 下面是一个片段着色器的示例,它从 YUV 数据中获取 3 个纹理。希望这将帮助您节省大量的 CPU 时间。
    precision mediump float;
    uniform sampler2D qt_TextureY;
    uniform sampler2D qt_TextureU;
    uniform sampler2D qt_TextureV;
    varying vec2 qt_TexCoord0;
    void main(void)
    {
        float y = texture2D(qt_TextureY, qt_TexCoord0).r;
        float u = texture2D(qt_TextureU, qt_TexCoord0).r - 0.5;
        float v = texture2D(qt_TextureV, qt_TexCoord0).r - 0.5;
        gl_FragColor = vec4( y + 1.403 * v,
                             y - 0.344 * u - 0.714 * v,
                             y + 1.770 * u, 1.0); \
    }
    

    关于c# - 如果落后则跳过帧渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40494973/

    相关文章:

    c# - 制作通用方法来更新 Entity Framework 多对多导航属性

    audio - 如何将 5.1 .flac 音轨添加到已经有 3 个音轨的 .ts 文件中?

    streaming - 将 RTSP 流转换为 RTMP 流

    Android bindProcessToNetwork 和 RTSP 流通过 MediaPlayer

    c# - 如何更深入地浏览 XML 并在其中 append 数据

    c# - DP 更改值后启用并聚焦已禁用的控件

    c# - 如何获得枚举标志值的最短表示?

    video - 来自 HDD 上(已记录的)原始 RTSP 流的 Demux H264

    FFMpeg 视频剪辑

    python - 以低延迟从 IP Camera 获取帧