如何在WinForms中使用C#连接IP Camera并在pictureBox1显示画面
实现方案(按摄像头支持程度分两种路径)
路径1:先确认摄像头是否存在未公开的标准流地址
大部分民用IP摄像头哪怕官方不对外公开接口,本质也会输出标准流媒体协议的流地址,可以通过抓包获取:
- 运行抓包工具后打开官方配套应用播放摄像头画面,过滤出摄像头IP对应的流量包,查找RTSP/HTTP-FLV/HLS协议的请求地址
- 拿到有效流地址后,即可通过第三方库解码拉流,直接渲染到
pictureBox1控件
用FFmpeg.AutoGen库拉流渲染的实现步骤
- 先通过NuGet安装
FFmpeg.AutoGen包,同时把对应平台的FFmpeg动态库放到项目输出目录 - 核心代码逻辑示例:
// 初始化FFmpeg ffmpeg.av_register_all(); ffmpeg.avformat_network_init(); // 打开流地址 AVFormatContext* pFormatCtx = null; if (ffmpeg.avformat_open_input(&pFormatCtx, "你抓到的摄像头流地址", null, null) != 0) return; // 查找视频流索引 int videoStreamIndex = -1; for (int i = 0; i < pFormatCtx->nb_streams; i++) { if (pFormatCtx->streams[i]->codecpar->codec_type == AVMediaType.AVMEDIA_TYPE_VIDEO) { videoStreamIndex = i; break; } } // 后续解码循环中,将解码后的YUV帧转成Bitmap,赋值给pictureBox1.Image即可 // 注意:拉流解码逻辑要放在后台线程执行,转成Bitmap后用Invoke方法更新UI控件
- 不想自行封装FFmpeg逻辑的话,也可以用
Vlc.DotNet库直接绑定输出:
var libDirectory = new DirectoryInfo(@"你的VLC本地库路径"); vlcControl1.BeginInit(); vlcControl1.VlcLibDirectory = libDirectory; vlcControl1.EndInit(); // 绑定输出到pictureBox控件 vlcControl1.VideoHostControl = pictureBox1; vlcControl1.Play(new Uri("你抓到的摄像头流地址"));
路径2:抓不到标准流地址时用窗口捕获方案
如果摄像头传输逻辑完全加密,只能在官方APP播放,就捕获官方APP播放窗口的画面再渲染到pictureBox1:
- 先用Windows API找到官方APP播放窗口的句柄,调用
PrintWindowAPI捕获窗口内容 - 捕获到的HBITMAP转成.NET Bitmap对象后直接赋值给
pictureBox1.Image即可
窗口捕获核心代码示例:
[DllImport("user32.dll")] static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll")] static extern bool PrintWindow(IntPtr hWnd, IntPtr hdcBlt, uint nFlags); [DllImport("user32.dll")] static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); // 按窗口标题找到官方APP播放窗口 IntPtr hwnd = FindWindow(null, "官方APP播放窗口的标题"); if (hwnd != IntPtr.Zero) { RECT rect; GetWindowRect(hwnd, out rect); int width = rect.Right - rect.Left; int height = rect.Bottom - rect.Top; Bitmap bmp = new Bitmap(width, height); using (Graphics g = Graphics.FromImage(bmp)) { IntPtr hdc = g.GetHdc(); PrintWindow(hwnd, hdc, 0); g.ReleaseHdc(hdc); } pictureBox1.Image = bmp; }
- 该方案仅要求官方APP不被完全遮挡,可将其移到屏幕外区域不影响正常操作,实时性取决于你设置的捕获帧率
注意事项
- 所有拉流、捕获操作都要放在后台线程执行,不要阻塞UI线程,更新
pictureBox1.Image属性时必须用Control.Invoke方法封送到UI线程执行 - 路径2如果出现捕获画面黑屏的情况,可以替换为
BitBltAPI从屏幕DC直接截取对应窗口区域的内容
内容的提问来源于stack exchange,提问作者Ezgi
相关产品推荐
相关产品推荐

