C#调用FFmpeg推送RTSP流至YouTube直播无响应问题排查
解决FFmpeg无法识别RTSP摄像头流并推流到YouTube的问题
让我来帮你排查这个推流问题——从你给出的命令参数和debug日志来看,有几个关键错误直接导致了摄像头流无法被识别,甚至进程冻结的情况,咱们一步步来修正:
1. 先解决参数里的硬错误
你的命令里有几个明显的参数问题,这是核心原因:
-rtsp_transport udp放错位置了:这个参数是专门给RTSP输入流用的,必须放在摄像头RTSP地址的-i前面!你现在把它放在两个-i之间,FFmpeg会把它当成第一个输入(虚拟音频anullsrc)的参数,摄像头流根本没用到这个传输配置,这就是为什么日志里只成功加载了音频流,卡在RTSP连接那里。- 视频编码参数冲突:你同时写了
-vcodec libx264和-c:v copy,这俩是互斥的:-c:v copy是直接复制原始视频流,不做重新编码,只有当摄像头输出的是YouTube支持的H.264编码时才能用-vcodec libx264是强制用x264重新编码,适合摄像头输出非H.264流的情况
你得二选一,不能同时写。
- 无效的
-pix_fmt +:+不是有效的像素格式,YouTube要求输出必须是yuv420p,所以把这个改成-pix_fmt yuv420p,或者直接删掉这个错误参数。
2. 修正后的可用命令
根据你的需求,给你两个实用的命令版本:
版本1:直接复制视频流(仅摄像头输出H.264时用)
这个版本效率更高,不用重新编码:
ffmpeg -f lavfi -i anullsrc -rtsp_transport tcp -i rtsp://onvif:bridge@localhost:554/live/xxxxx-xxxguidtocameraxxx-xxxxx -tune zerolatency -c:v copy -c:a aac -strict experimental -pix_fmt yuv420p -f flv rtmp://x.rtmp.youtube.com/live2/{streamkey}
版本2:强制重新编码为H.264(兼容所有摄像头)
如果摄像头输出的不是H.264,用这个版本,加上-preset ultrafast保证低延迟,适合直播:
ffmpeg -f lavfi -i anullsrc -rtsp_transport tcp -i rtsp://onvif:bridge@localhost:554/live/xxxxx-xxxguidtocameraxxx-xxxxx -tune zerolatency -vcodec libx264 -preset ultrafast -pix_fmt yuv420p -c:a aac -strict experimental -f flv rtmp://x.rtmp.youtube.com/live2/{streamkey}
小提示:把UDP改成TCP是因为很多RTSP服务器在UDP模式下容易丢包或者连接超时,TCP模式更稳定,适合直播场景。
3. 先确认RTSP流本身可用
如果修正参数后还是不行,先单独测试你的摄像头RTSP流能不能正常播放,用ffplay试试:
ffplay -rtsp_transport tcp rtsp://onvif:bridge@localhost:554/live/xxxxx-xxxguidtocameraxxx-xxxxx
如果ffplay也播不了,那问题出在你的ONVIF桥接服务器上,得先确保它能正常输出RTSP流。
4. C#调用时的关键注意事项
你提到用C#启动FFmpeg,进程冻结还有一个常见原因:没有及时读取FFmpeg的输出缓冲区,缓冲区满了就会卡住进程。给你一段实用的C#代码片段,记得异步读取输出:
var ffmpegPath = @"C:\ffmpeg\bin\ffmpeg.exe"; // 换成你的FFmpeg绝对路径 var streamKey = "你的YouTube流密钥"; var cameraRtspUrl = "rtsp://onvif:bridge@localhost:554/live/xxxxx-xxxguidtocameraxxx-xxxxx"; var arguments = $"-f lavfi -i anullsrc -rtsp_transport tcp -i {cameraRtspUrl} -tune zerolatency -vcodec libx264 -preset ultrafast -pix_fmt yuv420p -c:a aac -strict experimental -f flv rtmp://x.rtmp.youtube.com/live2/{streamKey}"; var processStartInfo = new ProcessStartInfo(ffmpegPath, arguments) { RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; using (var process = Process.Start(processStartInfo)) { // 异步读取输出,防止缓冲区阻塞导致进程冻结 process.OutputDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) Console.WriteLine($"FFmpeg输出:{e.Data}"); }; process.ErrorDataReceived += (sender, e) => { if (!string.IsNullOrEmpty(e.Data)) Console.WriteLine($"FFmpeg错误:{e.Data}"); }; process.BeginOutputReadLine(); process.BeginErrorReadLine(); process.WaitForExit(); }
内容的提问来源于stack exchange,提问作者Felix




