本地USB摄像头在使用中时,不支持另一个程序的并发访问,也就是所USB摄像头只能令第一个连接的程序“独享”。
在开发一个软件时,希望实现预览USB摄像头的同时,实现摄像头的推流。
推流要用的ffmpeg,经过资料查找,ffmpeg支持通过管道传输给ffplay实现本地预览,代码如下:
ffmpeg -f v4l2 -video_size 640x480 -i /dev/video0 -f alsa -i hw:0 -c:v libx264 -preset ultrafast -tune zerolatency -b:v 1000k -minrate 500k -maxrate 2000k -bufsize 2000k -c:a aac -strict experimental -f flv rtmp://server/live/stream | ffplay -
用这个方法弹出的界面不美观,而且对系统资源占用非常高,不建议使用。
经过查询ffmpeg源码,发现有个image2pipe参数,可以完美实现这个需求,具体实现步骤如下:
- 项目中安装AForge用于对摄像头操作
- 设计界面如下
- 窗体载入
// 获取摄像头设备 //获取内置、外接摄像头,非网络摄像头 videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice); if (videoDevices.Count != 0) { foreach (FilterInfo device in videoDevices) { cbo_camera.Items.Add(device.Name); } } else { cbo_camera.Items.Add("没有找到摄像头"); } cbo_camera.SelectedIndex = 0;
- 选择摄像头
private void cbo_camera_SelectedIndexChanged(object sender, EventArgs e) { if (videoDevices.Count != 0) { //获取每个摄像头支持的分辨率 videoDevice = new VideoCaptureDevice(videoDevices[cbo_camera.SelectedIndex].MonikerString); GetDeviceResolution(videoDevice); } }
- 获取分辨率
/// <summary> /// 获取每个摄像头支持的分辨率 /// </summary> /// <param name="videoCaptureDevice"></param> private void GetDeviceResolution(VideoCaptureDevice videoCaptureDevice) { cbo_rate.Items.Clear(); videoCapabilities = videoCaptureDevice.VideoCapabilities; foreach (VideoCapabilities capabilty in videoCapabilities) { cbo_rate.Items.Add($"{capabilty.FrameSize.Width} x {capabilty.FrameSize.Height}"); } cbo_rate.SelectedIndex = 0; }
- 摄像头有新帧进入的处理
currentFrame = image; pictureBox1.Image = currentFrame; PushToRtmpServer(currentFrame); Console.WriteLine("NewFrame");
- 为AForge控件添加事件
- PushToRtmpServer代码
private void PushToRtmpServer(Bitmap frame)
{
// 将摄像头视频推流到 RTMP 服务器
if (ffmpegProcess == null || ffmpegProcess.HasExited)
{
var outputSettings = $"rtmp://192.168.0.66/live/livestream?KeyCode=123";
var ffmpegArgs = $"-y -f image2pipe -pix_fmt bgr24 -s {frame.Width}x{frame.Height}" +
$" -r 25 -i - -c:v libx264 -preset fast -tune zerolatency -f flv {outputSettings}";
var processStartInfo = new ProcessStartInfo("ffmpeg.exe")
{
RedirectStandardInput = true,
UseShellExecute = false,
CreateNoWindow = true,
Arguments = ffmpegArgs,
WindowStyle = ProcessWindowStyle.Hidden
};
ffmpegProcess = Process.Start(processStartInfo);
}
using (var ms = new MemoryStream())
{
this.Invoke((EventHandler)delegate {
frame.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
ms.Seek(0, SeekOrigin.Begin);
ffmpegProcess.StandardInput.BaseStream.Write(ms.ToArray(), 0, ms.ToArray().Length);
});
}
}
运行结果:
代码下载: https://download.csdn.net/download/dgnankai/87767380