using DirectShow; using DirectShow.BaseClasses; using Sonic; using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Drawing.Text; using System.Linq; using System.Runtime.InteropServices; using System.Windows.Forms; namespace VideoPlayLib { public class VideoCapture : IDisposable { //[ComVisible(true)] //[Guid("8AF6F710-1AF5-4952-AAFF-ACCD0DB2C9BB")] [AMovieSetup(true)] //[PropPageSetup(typeof(AboutForm))] private abstract class OsdFilter : TransformFilter { #region Constructor protected OsdFilter() : base("OSD Filter") { } #endregion Constructor #region Overridden Methods public override int CheckInputType(AMMediaType pmt) { if (pmt.majorType != MediaType.Video) { return VFW_E_TYPE_NOT_ACCEPTED; } if (pmt.subType != MediaSubType.RGB32) { return VFW_E_TYPE_NOT_ACCEPTED; } if (pmt.formatType != FormatType.VideoInfo) { return VFW_E_TYPE_NOT_ACCEPTED; } if (pmt.formatPtr == IntPtr.Zero) { return VFW_E_TYPE_NOT_ACCEPTED; } return NOERROR; } [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)] private static extern void CopyMemory(IntPtr dest, IntPtr src, int count); public override int Transform(ref IMediaSampleImpl input, ref IMediaSampleImpl sample) { var lDataLength = input.GetActualDataLength(); sample.SetActualDataLength(lDataLength); IntPtr ptrIn; IntPtr ptrOut; input.GetPointer(out ptrIn); sample.GetPointer(out ptrOut); var bmiIn = (BitmapInfoHeader)Input.CurrentMediaType; var bmiOut = (BitmapInfoHeader)Output.CurrentMediaType; using (var bmpIn = new Bitmap(bmiIn.Width, bmiIn.Height, bmiIn.Width * 4, PixelFormat.Format32bppRgb, ptrIn)) { bmpIn.RotateFlip(RotateFlipType.RotateNoneFlipY); BurnOsd(bmpIn); bmpIn.RotateFlip(RotateFlipType.RotateNoneFlipY); var data = bmpIn.LockBits(new Rectangle(Point.Empty, bmpIn.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb); CopyMemory(ptrOut, data.Scan0, bmiIn.Width * bmiIn.Height * 4); bmpIn.UnlockBits(data); bmpIn.Dispose(); } return S_OK; } protected abstract void BurnOsd(Bitmap frame); public override int DecideBufferSize(ref IMemAllocatorImpl pAlloc, ref AllocatorProperties prop) { if (!Output.IsConnected) return VFW_E_NOT_CONNECTED; if (Output.CurrentMediaType.majorType != MediaType.Video) return VFW_E_INVALIDMEDIATYPE; var actual = new AllocatorProperties(); var bmi = (BitmapInfoHeader)Output.CurrentMediaType; if (bmi == null) return VFW_E_INVALIDMEDIATYPE; prop.cbBuffer = bmi.GetBitmapSize(); if (prop.cbBuffer < bmi.ImageSize) { prop.cbBuffer = bmi.ImageSize; } prop.cBuffers = 1; var hr = pAlloc.SetProperties(prop, actual); return hr; } public override int GetMediaType(int iPosition, ref AMMediaType pMediaType) { if (iPosition > 0) return VFW_S_NO_MORE_ITEMS; if (pMediaType == null) return E_INVALIDARG; if (!Input.IsConnected) return VFW_E_NOT_CONNECTED; AMMediaType.Copy(Input.CurrentMediaType, ref pMediaType); return NOERROR; } public override int CheckTransform(AMMediaType mtIn, AMMediaType mtOut) { return AMMediaType.AreEquals(mtIn, mtOut) ? NOERROR : VFW_E_INVALIDMEDIATYPE; } #endregion Overridden Methods } private class TimeOsdFilter : OsdFilter { private readonly int _channel; private const bool VideoOsdHighQuality = true; private static readonly Font VideoOsdFont = new Font("微软雅黑", 20); public TimeOsdFilter(int channel) { _channel = channel; } protected override void BurnOsd(Bitmap frame) { var osdText = string.Format("{0:yyyy年MM月dd日 dddd HH:mm:ss.ff}{1}CAM#{2} - {3}", DateTime.Now, Environment.NewLine, _channel + 1, ""); var loc = Point.Empty; var locT = new PointF(loc.X, loc.Y - 1); var locB = new PointF(loc.X, loc.Y + 1); var locL = new PointF(loc.X - 1, loc.Y); var locR = new PointF(loc.X + 1, loc.Y); using (Graphics dc = Graphics.FromImage(frame)) { if (VideoOsdHighQuality) { dc.CompositingQuality = CompositingQuality.HighQuality; dc.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; dc.SmoothingMode = SmoothingMode.HighQuality; dc.InterpolationMode = InterpolationMode.HighQualityBicubic; } else { dc.CompositingQuality = CompositingQuality.HighSpeed; dc.TextRenderingHint = TextRenderingHint.SingleBitPerPixel; dc.SmoothingMode = SmoothingMode.HighSpeed; dc.InterpolationMode = InterpolationMode.NearestNeighbor; } dc.DrawString(osdText, VideoOsdFont, Brushes.Black, locT); dc.DrawString(osdText, VideoOsdFont, Brushes.Black, locB); dc.DrawString(osdText, VideoOsdFont, Brushes.Black, locL); dc.DrawString(osdText, VideoOsdFont, Brushes.Black, locR); dc.DrawString(osdText, VideoOsdFont, Brushes.White, loc); } } } private readonly int _deviceIndex; private readonly Control[] _displayContainer; public VideoCapture(int deviceIndex, params Control[] displayContainer) { _deviceIndex = deviceIndex; _displayContainer = displayContainer; } public bool IsRuning { get; private set; } public void Run() { var devices = new DSVideoCaptureCategory().Objects.OrderBy(p => p.Name).ToArray(); var graph = new Graph(); var cd = graph.AddDeviceFilter(devices[_deviceIndex]); var av = graph.AddFilter(new DSFilter(KnownGuid.Misc.AviDecompressor), "av"); var to = graph.AddFilter(new DSFilter(new TimeOsdFilter(_deviceIndex)), "to"); var vr = graph.AddFilter(new DSFilter(KnownGuid.VideoRender.VideoMixingRenderer7), "vr"); graph.Connect(cd.OutputPin, av.InputPin); graph.Connect(av.OutputPin, to.InputPin); graph.Connect(to.OutputPin, vr.InputPin); _displayContainer.ToList().ForEach(p => new VideoInControl(graph, p)); graph.Run(); } public void Dispose() { throw new NotImplementedException(); } } }