您现在的位置是:首页 >技术交流 >C# 利用ffmpeg的image2pipe参数实现USB摄系头本地预览同时推流网站首页技术交流

C# 利用ffmpeg的image2pipe参数实现USB摄系头本地预览同时推流

beiger 2024-06-14 17:17:56
简介C# 利用ffmpeg的image2pipe参数实现USB摄系头本地预览同时推流

本地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参数,可以完美实现这个需求,具体实现步骤如下:

  1. 项目中安装AForge用于对摄像头操作
  2. 设计界面如下
  3. 窗体载入
    // 获取摄像头设备
    //获取内置、外接摄像头,非网络摄像头
    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;
  4. 选择摄像头
    private void cbo_camera_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (videoDevices.Count != 0)
        {
            //获取每个摄像头支持的分辨率
            videoDevice = new VideoCaptureDevice(videoDevices[cbo_camera.SelectedIndex].MonikerString);
            GetDeviceResolution(videoDevice);
        }
    }
  5. 获取分辨率
    /// <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;
    }
  6. 摄像头有新帧进入的处理
    currentFrame = image;
    pictureBox1.Image = currentFrame;
    PushToRtmpServer(currentFrame);
    Console.WriteLine("NewFrame");
  7. 为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

 

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。