使用RTSPClientSharp接收RTSP流无帧且阻塞问题求助
问题分析与解决方案
核心问题点
- 事件订阅时机错误:你在调用
ReceiveAsync().Wait()之后才订阅FrameReceived事件,此时接收流程已启动,不仅会丢失前期帧,后续帧也无法触发事件。 ReceiveAsync阻塞主线程:ReceiveAsync是长期运行的异步方法,.Wait()会直接阻塞当前线程,导致后续的事件订阅代码根本无法执行。- 帧数据处理逻辑错误: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
相关产品推荐
相关产品推荐

