You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用RTSPClientSharp接收RTSP流无帧且阻塞问题求助

问题分析与解决方案

核心问题点

  1. 事件订阅时机错误:你在调用ReceiveAsync().Wait()之后才订阅FrameReceived事件,此时接收流程已启动,不仅会丢失前期帧,后续帧也无法触发事件。
  2. ReceiveAsync阻塞主线程:ReceiveAsync是长期运行的异步方法,.Wait()会直接阻塞当前线程,导致后续的事件订阅代码根本无法执行。
  3. 帧数据处理逻辑错误:RTSP流的帧是编码后的媒体数据(比如H.264格式),无法直接用Bitmap从内存流创建,必须先解码。

修正后的代码示例

using RtspClientSharp;
using RtspClientSharp.MediaParsers;
using System;
using System.Drawing;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        Uri RTSPURL = new Uri("rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4");
        var credentials = new NetworkCredential("", "");
        var connectionParameters = new ConnectionParameters(RTSPURL, credentials);
        connectionParameters.RtpTransport = RtpTransportProtocol.TCP;

        // 初始化H.264解码器(需根据流的实际编码调整)
        var videoDecoder = new H264Decoder();
        videoDecoder.FrameDecoded += OnVideoFrameDecoded;

        using (var rtspClient = new RtspClient(connectionParameters))
        {
            // 先订阅事件,再启动连接和接收流程
            rtspClient.FrameReceived += (sender, frame) =>
            {
                Console.WriteLine("收到编码帧");
                if (frame.MediaType == MediaType.Video)
                    videoDecoder.Parse(frame.FrameSegment);
            };

            try
            {
                // 用await替代Wait(),避免线程阻塞
                await rtspClient.ConnectAsync(CancellationToken.None);
                Console.WriteLine("已连接RTSP服务器");
                
                // 用取消令牌控制接收时长,示例为10秒后停止
                var cts = new CancellationTokenSource();
                cts.CancelAfter(TimeSpan.FromSeconds(10));
                
                await rtspClient.ReceiveAsync(cts.Token);
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine("接收已停止");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"错误信息:{ex.Message}");
            }
        }
    }

    private static void OnVideoFrameDecoded(object sender, DecodedVideoFrame frame)
    {
        Console.WriteLine("收到解码帧");
        // 将YUV格式的解码帧转换为Bitmap(需补充YUV转RGB的逻辑)
        using (var bmp = new Bitmap(frame.Width, frame.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb))
        {
            var bitmapData = bmp.LockBits(new Rectangle(0, 0, frame.Width, frame.Height), 
                                          System.Drawing.Imaging.ImageLockMode.WriteOnly, 
                                          bmp.PixelFormat);
            // 此处省略YUV转RGB的具体实现,可使用ImageSharp等第三方库简化开发
            bmp.UnlockBits(bitmapData);
            
            // 后续对Bitmap进行业务处理
        }
    }
}

关键优化说明

  • 事件订阅前置:必须在ConnectAsync和ReceiveAsync调用前完成事件订阅,保证能捕获所有帧数据。
  • 异步方法正确调用:使用await替代.Wait(),避免主线程阻塞,确保事件订阅和后续逻辑正常执行。
  • 添加解码流程:RTSP原始帧为编码格式,需通过对应解码器处理后才能转换为可显示的位图,示例使用库内置的H264Decoder,需根据流编码类型调整。
  • 优雅控制接收流程:通过CancellationTokenSource可以灵活停止ReceiveAsync的运行,避免程序无限阻塞。

额外排查建议

  • 确认项目已正确引用RtspClientSharp的全部依赖包,保证解码组件正常加载。
  • 尝试切换RtpTransportProtocol为UDP,部分服务器对TCP传输的兼容性较差。

内容的提问来源于stack exchange,提问作者Pychro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 01:10:28