在 C# 应用程序中显示 tcp 视频流(来自 FFPLAY / FFMPEG)

Posted

技术标签:

【中文标题】在 C# 应用程序中显示 tcp 视频流(来自 FFPLAY / FFMPEG)【英文标题】:Show a tcp video stream (from FFPLAY / FFMPEG) in an C# application 【发布时间】:2012-12-21 12:47:47 【问题描述】:

我正在尝试让我的 Parrot AR Drone 2.0 与 Windows 机器配合使用。

我有一个简单的 C# 应用程序来控制它 - 但现在我想要在我的应用程序中播放视频流。

如果我执行ffplay tcp://192.168.1.1:5555,它会连接到视频流并显示一个包含视频的窗口。

如何在我的应用程序中获取此视频?比如,一个简单的“框架”或“图像”填充了该内容?

我从来没有这么多地使用 C#,所以任何帮助都会很棒。

【问题讨论】:

到目前为止你有什么代码可以做到这一点..? 查看此链接并查看可能有帮助或无帮助的文档。gstreamer.freedesktop.org dronecontroller.codeplex.com 这里是存储库 - github.com/RobQuistNL/ARDrone-Control-.NET- 我已经编辑了一些代码,但还没有推送。今晚会做:) 编辑:那里有一个视频流代码,但那个是无人机的 1.0 版本。不适用于 2.0 版本。我相信它是一个 H.687(或类似的)流 请输入一些您尝试过的代码,以帮助您解决问题 【参考方案1】:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Drawing.Text;
using System.Text.RegularExpressions;
using System.Configuration;
using Microsoft.Win32;
using System.Windows.Forms.VisualStyles;


namespace FfplayTest

    public partial class Form1 : Form
    
        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

        [DllImport("user32.dll")]
        private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
        public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);


        public Form1()
        
            InitializeComponent();
            Application.EnableVisualStyles();
            this.DoubleBuffered = true;
        

        private void Form1_Load(object sender, EventArgs e)
        

        

        public Process ffplay = new Process();
        private void xxxFFplay()
        


            ffplay.StartInfo.FileName = "ffplay.exe";

            string _argString = "-fflags nobuffer \"rtsp://admin:admin@192.168.0.163/live0.264\" -x 640 -y 480";
            string _newArgString = _argString.Replace("\",\"", ";");
            ffplay.StartInfo.Arguments = _newArgString;

            ffplay.StartInfo.CreateNoWindow = true;
            ffplay.StartInfo.RedirectStandardOutput = true;
            ffplay.StartInfo.UseShellExecute = false;

            ffplay.EnableRaisingEvents = true;
            ffplay.OutputDataReceived += (o, e) => Debug.WriteLine(e.Data ?? "NULL", "ffplay");
            ffplay.ErrorDataReceived += (o, e) => Debug.WriteLine(e.Data ?? "NULL", "ffplay");
            ffplay.Exited += (o, e) => Debug.WriteLine("Exited", "ffplay");
            ffplay.Start();
            IntPtr intPtr = ffplay.MainWindowHandle;
            Thread.Sleep(200); // you need to wait/check the process started, then...

            // child, new parent
            // make 'this' the parent of ffmpeg (presuming you are in scope of a Form or Control)
            SetParent(ffplay.MainWindowHandle, this.Handle);

            // window, x, y, width, height, repaint
            // move the ffplayer window to the top-left corner and set the size to 320x280
            MoveWindow(ffplay.MainWindowHandle, 0, 0, 320, 280, true);


        

        private void button1_Click(object sender, EventArgs e)
        
            xxxFFplay();
        

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        
            try  ffplay.Kill(); 
            catch  
        
    

我的代码是这样的,它是如何加载 ffplay 但不要移动到面板或不将其定位到给定的

【讨论】:

【参考方案2】:

您可以启动ffplay 进程,然后PInvoke SetParent 将播放器窗口放置在您的表单中,然后MoveWindow 将其定位。

为此,您需要定义以下内容。

[DllImport("user32.dll", SetLastError = true)]
private static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

[DllImport("user32.dll")]
private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

那么你就可以像这样使用这两种原生方法了。

// start ffplay 
var ffplay = new Process
    
        StartInfo =
            
                FileName = "ffplay",
                Arguments = "tcp://192.168.1.1:5555",
                // hides the command window
                CreateNoWindow = true, 
                // redirect input, output, and error streams..
                RedirectStandardError = true,
                RedirectStandardOutput = true,
                UseShellExecute = false    
            
    ;

ffplay.EnableRaisingEvents = true;
ffplay.OutputDataReceived += (o, e) => Debug.WriteLine(e.Data ?? "NULL", "ffplay");
ffplay.ErrorDataReceived += (o, e) => Debug.WriteLine(e.Data ?? "NULL", "ffplay");
ffplay.Exited += (o, e) => Debug.WriteLine("Exited", "ffplay");
ffplay.Start();

Thread.Sleep(200); // you need to wait/check the process started, then...

// child, new parent
// make 'this' the parent of ffmpeg (presuming you are in scope of a Form or Control)
SetParent(ffplay.MainWindowHandle, this.Handle);

// window, x, y, width, height, repaint
// move the ffplayer window to the top-left corner and set the size to 320x280
MoveWindow(ffplay.MainWindowHandle, 0, 0, 320, 280, true);

ffplay 进程的标准输出,通常在命令窗口中看到的文本是通过ErrorDataReceived 处理的。在传递给 ffplay 的参数中将 -loglevel 设置为 fatal 可以减少引发的事件数量并允许您只处理真正的故障。

【讨论】:

明天试试这两种方法! 别担心,我还添加了如何将输出文本从进程捕获到托管代码中,从而允许您处理错误等。 非常好!谢谢 :) 如果这很好用,很多 ARDrone 传单都会感谢你! 完全不用担心。如果您accept the answer,人们将来也更有可能帮助您。 我还是要试试看:P 然后我会选择一个答案。谢谢!【参考方案3】:

您是否尝试过使用媒体播放器进行流式传输?只需在表单上添加工具箱中的控件,然后将以下代码添加到您的 form.cs

 private void Form1_Load(object sender, EventArgs e)
    
        axWindowsMediaPlayer1.URL = "your URL";
    

详情见以下链接

http://msdn.microsoft.com/en-us/library/bb383953%28v=vs.90%29.aspx

【讨论】:

好吧,这可能会奏效。我今晚会试试。但我想这不是真正的直接流,这样我会有更多的延迟。今晚我会回复你的! 视频有什么好运气吗? 媒体播放器不适用于 ffmpeg 托管流

以上是关于在 C# 应用程序中显示 tcp 视频流(来自 FFPLAY / FFMPEG)的主要内容,如果未能解决你的问题,请参考以下文章

试图通过 TCP 流式传输 2 路音频?

在 C# 中将音频流添加到视频流

如何在消息框中显示来自 C# 的带有 WCHAR* 的 C 函数

从 C# 调用 F# 代码

在 C# 中使用 FFMPEG 合并音频和视频文件

来自回调 c# 的未处理异常错误