使用 directshow 视频控件显示来自摄像机的实时视频,一切正常,但运动失真非常严重。它会在视频边缘产生锯齿状锯齿。从usb换成PCI采集卡,没有改善。相机供应商的应用程序显示了漂亮的全动态视频,所以看起来硬件还可以。有任何想法吗?
using System;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using DirectShowLib;
using System.Runtime.InteropServices.ComTypes;
namespace VideoDisplayControl
{
// [Guid("43878F19-1E0E-42d2-B72B-88A94418A302"), ComVisible(true)]
public partial class VideoDisplayControl : UserControl
{
public enum PlayState : int
{
Stopped,
Paused,
Running,
Error,
Init
}
private static int WM_GRAPHNOTIFY = Convert.ToInt32("0X8000", 16) + 1;
private PlayState _currentState = PlayState.Stopped;
private IVideoWindow _videoWindow = null;
private IMediaControl _mediaControl = null;
private IMediaEventEx _mediaEventEx = null;
private IGraphBuilder _graphBuilder = null;
private ICaptureGraphBuilder2 _captureGraphBuilder = null;
private float _imageAspectRatio = 0f;
private System.Windows.Forms.Label labelError;
public PlayState State
{
get { return _currentState; }
}
public VideoDisplayControl()
{
components = new System.ComponentModel.Container();
this.labelError = new System.Windows.Forms.Label();
this.SuspendLayout();
// Error label
this.labelError.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.labelError.ForeColor = Color.DimGray;
this.labelError.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.labelError.Location = new System.Drawing.Point(0, 0);
this.labelError.Name = "labelError";
this.labelError.Size = new System.Drawing.Size(50, 50);
this.labelError.TabIndex = 1;
this.labelError.Text = "Video Source Not Available";
this.labelError.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.labelError.Visible = false;
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
// System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(VideoDisplayControl));
this.Controls.Add(this.labelError);
this.ResumeLayout(false);
this.PerformLayout();
this.Load += new System.EventHandler(VideoDisplayControl_Load);
}
private void VideoDisplayControl_Load(object sender, System.EventArgs e)
{
this.Resize += new System.EventHandler(VideoDisplayControl_Resize);
CaptureVideo();
}
private void VideoDisplayControl_Resize(object sender, System.EventArgs e)
{
if (this._videoWindow == null)
return;
// Attempt to keep aspect ratio of source
if (_imageAspectRatio > 0)
{
int width = Math.Min(this.Width, (int)(this.ClientSize.Height * _imageAspectRatio));
int height = Math.Min(this.ClientSize.Height, (int)(this.Width / _imageAspectRatio));
int posX = (this.Width - width) / 2; // Center within control
int posY = (this.ClientSize.Height - height) / 2;
this._videoWindow.SetWindowPosition(posX, posY, width, height);
}
else // resize to size of control
this._videoWindow.SetWindowPosition(0, 0, this.Width, this.ClientSize.Height);
this.labelError.Size = new System.Drawing.Size(this.Width, this.ClientSize.Height);
}
private void CaptureVideo()
{
int hr = 0;
IBaseFilter sourceFilter = null;
try
{
GetInterfaces(); // Interface with DirectShow
hr = _captureGraphBuilder.SetFiltergraph(_graphBuilder);
DsError.ThrowExceptionForHR(hr);
sourceFilter = FindCaptureDevice();
hr = _graphBuilder.AddFilter(sourceFilter, "VideoDisplay Filter");
DsError.ThrowExceptionForHR(hr);
hr = _captureGraphBuilder.RenderStream(PinCategory.Preview, MediaType.Video, sourceFilter, null, null);
Debug.WriteLine(DsError.GetErrorText(hr));
DsError.ThrowExceptionForHR(hr);
Marshal.ReleaseComObject(sourceFilter);
SetupVideoWindow();
hr = _mediaControl.Run();
DsError.ThrowExceptionForHR(hr);
int width, height;
hr = _videoWindow.GetMaxIdealImageSize(out width, out height);
if ((hr == 0) && (width > 0) && (height > 0))
{
_imageAspectRatio = (float)width / (float)height;
VideoDisplayControl_Resize(this, null);
}
_currentState = PlayState.Running;
}
catch (Exception)
{
_currentState = PlayState.Error; // Set error state
this.labelError.Visible = true; // Display the "video not available" label
VideoDisplayControl_Resize(this, null); // resize control to center label
}
}
private IBaseFilter FindCaptureDevice()
{
IEnumMoniker classEnum = null;
IMoniker[] moniker = new IMoniker[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.");
}
System.IntPtr none = System.IntPtr.Zero;
if (classEnum.Next(moniker.Length, moniker, 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 GetInterfaces()
{
_graphBuilder = (IGraphBuilder)(new FilterGraph());
_captureGraphBuilder = (ICaptureGraphBuilder2)(new CaptureGraphBuilder2());
_mediaControl = (IMediaControl)_graphBuilder;
_videoWindow = (IVideoWindow)_graphBuilder;
_mediaEventEx = (IMediaEventEx)_graphBuilder;
// send notification messages to the control window
int hr = _mediaEventEx.SetNotifyWindow(this.Handle, WM_GRAPHNOTIFY, IntPtr.Zero);
DsError.ThrowExceptionForHR(hr);
}
private void HandleGraphEvent()
{
int hr = 0;
EventCode evCode = 0;
IntPtr evParam1;
IntPtr evParam2;
while (this._mediaEventEx != null && _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 = _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 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 = _videoWindow.put_Owner(this.Handle);
DsError.ThrowExceptionForHR(hr);
hr = _videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren);
DsError.ThrowExceptionForHR(hr);
//Use helper function to position video window in client rect of main application window
VideoDisplayControl_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 = _videoWindow.put_Visible(OABool.True);
DsError.ThrowExceptionForHR(hr);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_GRAPHNOTIFY)
{
HandleGraphEvent();
}
if (_videoWindow != null)
{
_videoWindow.NotifyOwnerMessage(m.HWnd, m.Msg, m.WParam, m.LParam);
}
base.WndProc(ref m);
}
}
}