我在VS 2012工作,我的项目是一个带有.NetFramework 4.0的C#WPF应用程序
我的目标 - 需要在用户控制中显示实时网络摄像头,并且每2秒处理一次当前帧(作为位图)。
我取得的成就 - 我可以初始化网络摄像头,并能够使用DirectShowLib流式传输实时视频。我使用了this示例。
我需要的东西 - 我无法获取框架(作为位图)。 是否有任何默认方法在DirectShow中获取当前帧?是否需要在我的用户控件中实现任何实现(如示例中所述的WebCamControl2)。我的需要有什么例子吗?
感谢。
更新
以下是我正在使用的代码:
using System;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using DirectShowLib;
using System.Runtime.InteropServices.ComTypes;
namespace WebCamControl2
{
[Guid("43878F19-1E0E-42d2-B72B-88A94418A302"),
ComVisible(true)]
public partial class WebCamControl2 : UserControl
{
public enum PlayState : int
{
Stopped,
Paused,
Running,
Init
}
private PlayState CurrentState = PlayState.Stopped;
private int WM_GRAPHNOTIFY = Convert.ToInt32("0X8000", 16) + 1;
private IVideoWindow videoWindow = null;
private IMediaControl mediaControl = null;
private IMediaEventEx mediaEventEx = null;
private IGraphBuilder graphBuilder = null;
private ICaptureGraphBuilder2 captureGraphBuilder = null;
public WebCamControl2()
{
InitializeComponent();
}
private void WebCamControl_Load(object sender, System.EventArgs e)
{
this.Resize += new System.EventHandler(WebCamControl_Resize);
CaptureVideo();
}
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(WebCamControl2));
this.Load += new System.EventHandler(WebCamControl_Load);
}
private void CaptureVideo()
{
int hr = 0;
IBaseFilter sourceFilter = null;
try
{
// create the necessary DirectShow interfaces
GetInterfaces();
hr = this.captureGraphBuilder.SetFiltergraph(this.graphBuilder);
DsError.ThrowExceptionForHR(hr);
sourceFilter = FindCaptureDevice();
hr = this.graphBuilder.AddFilter(sourceFilter, "WebCamControl Video");
DsError.ThrowExceptionForHR(hr);
hr = this.captureGraphBuilder.RenderStream(PinCategory.Preview, MediaType.Video, sourceFilter, null, null);
Debug.WriteLine(DsError.GetErrorText(hr));
DsError.ThrowExceptionForHR(hr);
Marshal.ReleaseComObject(sourceFilter);
SetupVideoWindow();
hr = this.mediaControl.Run();
DsError.ThrowExceptionForHR(hr);
this.CurrentState = PlayState.Running;
}
catch (Exception ex)
{
MessageBox.Show("An unrecoverable error has occurred.\r\n" + ex.ToString());
}
}
private void GetInterfaces()
{
this.graphBuilder = (IGraphBuilder)(new FilterGraph());
this.captureGraphBuilder = (ICaptureGraphBuilder2)(new CaptureGraphBuilder2());
this.mediaControl = (IMediaControl)this.graphBuilder;
this.videoWindow = (IVideoWindow)this.graphBuilder;
this.mediaEventEx = (IMediaEventEx)this.graphBuilder;
// send notification messages to the control window
int hr = this.mediaEventEx.SetNotifyWindow(this.Handle, WM_GRAPHNOTIFY, IntPtr.Zero);
DsError.ThrowExceptionForHR(hr);
}
private IBaseFilter FindCaptureDevice()
{
UCOMIEnumMoniker classEnum = null;
UCOMIMoniker[] moniker = new UCOMIMoniker[1];
object source = null;
ICreateDevEnum devEnum = (ICreateDevEnum)(new CreateDevEnum());
int hr = devEnum.CreateClassEnumerator(FilterCategory.VideoInputDevice, out classEnum, CDef.None);
DsError.ThrowExceptionForHR(hr);
Marshal.ReleaseComObject(devEnum);
if (classEnum == null)
{
throw new ApplicationException("No video capture device was detected.\\r\\n\\r\\n" + "This sample requires a video capture device, such as a USB WebCam,\\r\\nto be installed and working properly. The sample will now close.");
}
int none = 0;
if (classEnum.Next(moniker.Length, moniker, out none) == 0)
{
Guid iid = typeof(IBaseFilter).GUID;
moniker[0].BindToObject(null, null, ref iid, out source);
}
else
{
throw new ApplicationException("Unable to access video capture device!");
}
Marshal.ReleaseComObject(moniker[0]);
Marshal.ReleaseComObject(classEnum);
return (IBaseFilter)source;
}
private void SetupVideoWindow()
{
int hr = 0;
//set the video window to be a child of the main window
//putowner : Sets the owning parent window for the video playback window.
hr = this.videoWindow.put_Owner(this.Handle);
DsError.ThrowExceptionForHR(hr);
hr = this.videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren);
DsError.ThrowExceptionForHR(hr);
//Use helper function to position video window in client rect of main application window
WebCamControl_Resize(this, null);
//Make the video window visible, now that it is properly positioned
//put_visible : This method changes the visibility of the video window.
hr = this.videoWindow.put_Visible(OABool.True);
DsError.ThrowExceptionForHR(hr);
}
//protected override void WndProc(ref Message m)
//{
// if (m.Msg == WM_GRAPHNOTIFY)
// {
// HandleGraphEvent();
// }
// if (this.videoWindow != null)
// {
// this.videoWindow.NotifyOwnerMessage(m.HWnd, m.Msg, m.WParam.ToInt32(), m.LParam.ToInt32());
// }
// base.WndProc(ref m);
//}
private void HandleGraphEvent()
{
int hr = 0;
EventCode evCode = 0;
int evParam1 = 0;
int evParam2 = 0;
while (this.mediaEventEx != null && this.mediaEventEx.GetEvent(out evCode, out evParam1, out evParam2, 0) == 0)
{
// Free event parameters to prevent memory leaks associated with
// event parameter data. While this application is not interested
// in the received events, applications should always process them.
hr = this.mediaEventEx.FreeEventParams(evCode, evParam1, evParam2);
DsError.ThrowExceptionForHR(hr);
// Insert event processing code here, if desired (see http://msdn2.microsoft.com/en-us/library/ms783649.aspx)
}
}
private void ReleaseInterfaces()
{
if (this.mediaControl != null)
this.mediaControl.StopWhenReady();
this.CurrentState = PlayState.Stopped;
// stop notifications of events
if (this.mediaEventEx != null)
this.mediaEventEx.SetNotifyWindow(IntPtr.Zero, WM_GRAPHNOTIFY, IntPtr.Zero);
//// Relinquish ownership (IMPORTANT!) of the video window.
//// Failing to call put_Owner can lead to assert failures within
//// the video renderer, as it still assumes that it has a valid
//// parent window.
if (this.videoWindow != null)
{
this.videoWindow.put_Visible(OABool.False);
this.videoWindow.put_Owner(IntPtr.Zero);
}
// Release DirectShow interfaces
Marshal.ReleaseComObject(this.mediaControl);
this.mediaControl = null;
Marshal.ReleaseComObject(this.mediaEventEx);
this.mediaEventEx = null;
Marshal.ReleaseComObject(this.videoWindow);
this.videoWindow = null;
Marshal.ReleaseComObject(this.graphBuilder);
this.graphBuilder = null;
Marshal.ReleaseComObject(this.captureGraphBuilder);
this.captureGraphBuilder = null;
}
private void WebCamControl_Resize(object sender, System.EventArgs e)
{
//Resize the video preview window to match owner window size
if (this.videoWindow != null)
this.videoWindow.SetWindowPosition(0, 0, this.Width, this.ClientSize.Height);
}
}
}
答案 0 :(得分:1)
尝试使用EMGU或Opencv
http://www.emgu.com/wiki/index.php/Main_Page
这是一个如何从你的视频中捕获帧的示例(cam) http://www.emgu.com/wiki/index.php?title=Camera_Capture
1 - 将Emgu dll添加到您的应用程序中 2-这是一个例子
private Capture _capture;
Image<Gray, Byte> frame;
//0 is the default camera
_capture = new Capture(0);
//here how you can get the frames from your video
Image<Bgr, Byte> frame = _capture.QueryFrame();
答案 1 :(得分:0)
你会发现一些解决上述问题的问题,例如
有两种解决方案。您可以从可视化视频的组件(视频渲染器)中取回,或者将Sample Grabber或类似的过滤器添加到管道中并从其回调中获取。您可以使用两种方式获取数据,从而初始化.NET位图,但不完全是位图。也就是说,您要执行转换步骤(inspiring Q on this)。
你当然可以使用CV库,但这对于这样简单的任务来说是极大的过度杀伤,如果你需要添加别的东西,他们的视频捕获可能看起来不灵活。
答案 2 :(得分:0)
我通过截取屏幕截图而不是从渲染视频中取帧来克服这个问题。这是帮助我的代码
//Create a new bitmap.
var bmpScreenshot = new System.Drawing.Bitmap(Screen.PrimaryScreen.Bounds.Width,
Screen.PrimaryScreen.Bounds.Height,
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
// Create a graphics object from the bitmap.
var gfxScreenshot = System.Drawing.Graphics.FromImage(bmpScreenshot);
// Take the screenshot from the upper left corner to the right bottom corner.
gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X,
Screen.PrimaryScreen.Bounds.Y,
0,
0,
Screen.PrimaryScreen.Bounds.Size,
System.Drawing.CopyPixelOperation.SourceCopy);
我知道这不是正确的方法。但是,它为我提供了解决方案。我尝试使用SampleGrabber
和EMGU
,但我无法按预期获得解决方案。我觉得我的解决方案足够简单,可以满足我的需求并可以帮助别人。
感谢。