Cor*_*own 6 c# ffmpeg stream h.264 raspberry-pi
我有一个带有专用摄像头的Raspberry Pi板,只能在h264中录制视频.我正在寻找在c#windows forms app中实时流式传输和播放录制视频的最佳方法(例如,延迟不到1秒).附加要求是在显示之前可以容易地处理这样的流,例如用于搜索图像上的对象.
我试过的东西:
- 使用radi上的VLC服务器和c#中的VLC控制形成app < - 简单的解决方案,使用RTSP,但是有一个严重的缺陷,即显示的图像延迟约3秒.我无法用buffor size/options等修复它.
- 使用nc在raspi上创建套接字,在c#中接收原始h264数据并将其传递给mplayer前端 < - 如果我只是启动raspotion | nc和笔记本电脑上的nc | mplayer,我得到了我想要的结果,我得到的视频几乎是实时的,但是当我尝试在c#中创建mplayer前端并模拟nc.exe时出现问题.也许我正在传递h264数据错误(只是将它们写入stdin)或者其他东西.
- 使用https://github.com/cisco/openh264 < - 我编译了所有内容,但我甚至无法解码使用h264dec.exe在raspi上录制的样本vid.h264,更不用说在c#中使用它了.
h264dec.exe vid.h264 out.yuv
Run Code Online (Sandbox Code Playgroud)
这会产生0bytes out.yuv文件,而:
h264dec.exe vid.h264
Run Code Online (Sandbox Code Playgroud)
给我错误消息:"配置文件中没有指定输入文件."
- ffmpeg < - 我在c#app中实现了ffplay.exe播放,但缺少简单的方法来获取screencaps等,这使我无法进一步调查和开发.
我甚至不确定我是否正确地接近这个主题,所以我会非常感谢我能得到的每一条建议.
编辑 这是我试图在c#中实现的"工作"解决方案
raspivid --width 400 --height 300 -t 9999999 --framerate 25 --output - | nc -l 5884
nc ip_addr 5884 | mplayer -nosound -fps 100 -demuxer +h264es -cache 1024 -
Run Code Online (Sandbox Code Playgroud)
这里的关键是FPS 100,因为mplayer跳过滞后并以正常速度播放它立即收到的视频.这里的问题是我不知道如何通过c#将视频数据从socket传递到mplayer,因为我猜它不是通过stdin完成的(已经尝试过了).
好吧,实际上我设法解决了这个问题:
就像我之前所说的 -fps 120 选项可以让播放器跳过缓冲区中的内容并在收到流后立即播放。PanelId 是 mplayer 嵌套在其中的面板的句柄。
class Mplayer
{
Process mplayer;
public Mplayer(string path, string pipeName, int panelId)
{
String args = "";
mplayer = new Process();
mplayer.StartInfo.UseShellExecute = false;
mplayer.StartInfo.RedirectStandardInput = true;
mplayer.StartInfo.FileName = path;
args = @"\\.\pipe\" + pipeName + " -demuxer +h264es -fps 120 -nosound -cache 512";
args += " -nofs -noquiet -identify -slave ";
args += " -nomouseinput -sub-fuzziness 1 ";
args += " -vo direct3d, -ao dsound -wid ";
args += panelId;
mplayer.StartInfo.Arguments = args;
}
public void Start()
{
mplayer.Start();
}
public void End()
{
mplayer.Kill();
}
}
Run Code Online (Sandbox Code Playgroud)
后台工作者从套接字读取内容:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
pipeServ.WaitForConnection(); //opcjonalne?
StreamWriter sw = new StreamWriter(pipeServ);
sw.AutoFlush = true;
tcpCamera = new TcpClient();
tcpCamera.Connect(ipAddress, camPort);
NetworkStream camStream = tcpCamera.GetStream();
int read = 0;
byte[] bytes = new byte[tcpCamera.ReceiveBufferSize];
while (tcpCamera.Connected)
{
read = camStream.Read(bytes, 0, tcpCamera.ReceiveBufferSize);
if (read > 0)
pipeServ.Write(bytes, 0, read);
}
}
catch (IOException ex)
{
//Broken pipe - result of Mplayer exit
//MessageBox.Show(ex.Message);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Run Code Online (Sandbox Code Playgroud)
该脚本在 RaspberryPi 上运行。Portnumber是rasp正在监听的端口号。
#!/bin/bash
raspivid --width 1280 --height 720 -t 9999999 --framerate 25 --output - | nc -l PORTNUMBER
Run Code Online (Sandbox Code Playgroud)