1

我有一个最初为 Windows 窗体编写的 DLL。它创建了 2 个窗口形式,一个用于查看来自 BlackMagics 卡的实时视频源,一个用于从视频捕获的静态图像。

DLL 都是静态类,通过包含对 dll 的引用(VideoCapture.dll)来调用,并且在程序中我通过调用来启动捕获屏幕

VideoCapture.RSVideoControler.Start();

在 Windows 窗体测试程序中,我有一个仅调用此命令的按钮。视频窗口打开,并让主窗口正常运行。CPU 使用率约为(任务管理器 50)并按预期显示视频源。关闭主程序可以顺利关闭所有内容。

现在启动相同的 DLL 和代码,但放入 WPF 应用程序。在按下按钮之前,应用程序以 0 CPU(任务管理器)运行,您可以正常移动窗口。但在运行启动命令后,应用程序以 99 CPU(任务管理器)运行并且变得无响应。

WPF 在启动此线程时与 Windows 窗体有何不同?

预计到达时间:RSVidoControler

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using VideoCapture.Classes;

namespace VideoCapture
{
    public class RSVideoControler
    {
        public static Bitmap LastImage = new Bitmap(1920, 1080,     PixelFormat.Format16bppRgb565);
        private static VidCardGlobal VideoInterface;
    private static IntPtr m_ip = IntPtr.Zero;
    //[STAThread]
    public static void Start() {VideoInterface = new VidCardGlobal();}
    public static Bitmap GrabFrame()
    {
        if (m_ip != IntPtr.Zero)
        {
            Marshal.FreeCoTaskMem(m_ip);
            m_ip = IntPtr.Zero;
        }
        m_ip = VideoInterface.Click();
        using (Bitmap b = new Bitmap(VideoInterface.Width, VideoInterface.Height, VideoInterface.Stride, PixelFormat.Format16bppRgb565, m_ip))
        {
            if (b != null)
            {
                b.RotateFlip(RotateFlipType.RotateNoneFlipY);
                LastImage.Dispose();
                LastImage = new Bitmap(b);
                b.Dispose();
            }
        }
        return LastImage;
    }
    public static void VideoVisable(bool Visibility)
    {
        VidCardGlobal.VideoViewer.Visible = Visibility;
    }
    public static void ShutDownVideo()
    {
        VideoInterface.Dispose();       // Shuts down Image Capturing interface
        VidCardGlobal.MediaControl.Stop(); // Shuts down Video Viewing Screen
    }
}
}

VidCard全球

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Threading;
using System.Windows.Forms;
using DirectShowLib;
using VideoCapture.Forms;

namespace VideoCapture.Classes
{
internal class VidCardGlobal : ISampleGrabberCB, IDisposable
{
    //private object syncLock = new object();
    #region Varables for SingleFrameCapture
    private ManualResetEvent m_PictureReady = null;
    private bool m_WantOne = false;
    private int m_videoWidth;
    private int m_videoHeight;
    private int m_stride;
    private IntPtr m_ipBuffer = IntPtr.Zero;
    private IAMVideoControl m_VidControl = null;
    private IPin m_pinStill = null;
    #endregion
    public int Width { get { return m_videoWidth; } }
    public int Height { get { return m_videoHeight; } }
    public int Stride { get { return m_stride; } }
    public static VideoFeed VideoViewer = new VideoFeed();
    #region DirectShow Stuff
    public MemoryStream stream { get; private set; }
    public static IGraphBuilder graph;
    public static IVMRWindowlessControl9 WindowlessControl = null;
    public static IBaseFilter pinfilter;
    public static bool VideoHandlersAdded = false;
    public static IMediaControl MediaControl;
    public static ISampleGrabber SampleGrabberFilter;

    //public static AMMediaType DefaultMediaType = new AMMediaType();
    //private static IMediaControl mediaControl = null;
    public int SampleCB(double Unknown1, IMediaSample MySample) { return 0; }
    public int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)
    {
        Debug.Assert(BufferLen == Math.Abs(m_stride) * m_videoHeight, "Incorrect buffer length");
        if (m_WantOne)
        {
            m_WantOne = false;
            Debug.Assert(m_ipBuffer != IntPtr.Zero, "Unitialized buffer");
            CopyMemory(m_ipBuffer, pBuffer, BufferLen);
            m_PictureReady.Set();
        }

        return 0;
    }
    #region IDisposable
    public void Dispose(bool disposing)
    {
        if (disposing)
        {
            //if (stream != null)
            {
                //stream.Dispose();
                //stream = null;
            }
        }
    }
    public void Dispose()
    {
        Dispose(true);
    }
    #endregion
    public static IBaseFilter CreateFilterbyName(string filterName, Guid category)
    {
        int hr = 0;
        DsDevice[] Devices = DsDevice.GetDevicesOfCat(category);
        foreach (DsDevice dev in Devices)
            if (dev.Name == filterName)
            {
                IBaseFilter filter = null;
                IBindCtx bindCtx = null;
                try
                {
                    hr = CreateBindCtx(0, out bindCtx);
                    DsError.ThrowExceptionForHR(hr);
                    Guid guid = typeof(IBaseFilter).GUID;
                    object obj;
                    dev.Mon.BindToObject(bindCtx, null, ref guid, out obj);
                    filter = (IBaseFilter)obj;
                }
                finally
                {
                    if (bindCtx != null) Marshal.ReleaseComObject(bindCtx);
                }
                return filter;
            }
        return null;
    }
    [DllImport("ole32.dll")]
    public static extern int CreateBindCtx(int reserved, out IBindCtx ppcb);
    [DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory")]
    private static extern void CopyMemory(IntPtr Destination, IntPtr Source, [MarshalAs(UnmanagedType.U4)] int Length);

    private static IPin GetPin(IBaseFilter filter, string pinname)
    {
        IEnumPins epins;
        bool FoundPin = false;
        IPin ValidPin = null;
        int hr = filter.EnumPins(out epins);
        checkHR(hr, "Can't enumerate pins");
        IntPtr Fetched = Marshal.AllocCoTaskMem(4);
        IPin[] Pins = new IPin[1];
        while (epins.Next(1, Pins, Fetched) == 0)
        {
            PinInfo pinfo;
            Pins[0].QueryPinInfo(out pinfo);
            pinfilter = pinfo.filter;
            bool found = (pinfo.name == pinname);
            DsUtils.FreePinInfo(pinfo);
            if (found)
            {
                ValidPin = Pins[0];
                FoundPin = true;
            }
            //return Pins[0];
        }
        if (!FoundPin) checkHR(-1, "Pin not found");
        return ValidPin;
    }
    private static IPin GetVPin(IBaseFilter filter, string pinname)
    {
        IEnumPins epins;
        bool FoundPin = false;
        IPin ValidPin = null;
        int hr = filter.EnumPins(out epins);
        checkHR(hr, "Can't enumerate pins");
        IntPtr Fetched = Marshal.AllocCoTaskMem(4);
        IPin[] Pins = new IPin[1];
        while (epins.Next(1, Pins, Fetched) == 0)
        {
            PinInfo pinfo;
            Pins[0].QueryPinInfo(out pinfo);
            pinfilter = pinfo.filter;
            bool found = (pinfo.name == pinname);
            DsUtils.FreePinInfo(pinfo);
            if (found)
            {
                ValidPin = Pins[0];
                FoundPin = true;
            }
            //return Pins[0];
        }
        if (!FoundPin) checkHR(-1, "Pin not found");

        return ValidPin;
    }
    private static IPin FindPinIterface(IBaseFilter filter, Guid pFormat, PinDirection PinDir, IIPDVDec riid)
    {
        IPin FoundPin = null;
        //hr = GetPin(pFilter, pFormat, PinDir, &FoundPin);
        return FoundPin;
    }
    #endregion
    public VidCardGlobal()
    {

        graph = (IGraphBuilder)new FilterGraph();
        SampleGrabberFilter = (ISampleGrabber)new SampleGrabber();
        MediaControl = (IMediaControl)graph;
        BuildGraph(graph);  //Builds Graph And Connects camera, ect to graph
        m_PictureReady = new ManualResetEvent(false);
        MediaControl.Run();
        VideoViewer.VideoFeed_ResizeMove(null, null);
    }
    ~VidCardGlobal()
    {
        Dispose();
    }
    private static void checkHR(int HR, string ErrorMessage)
    {
        if (HR < 0)
        {
            MessageBox.Show(ErrorMessage, "CheckER Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            try
            {
                DsError.ThrowExceptionForHR(HR);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
                //DsError.ThrowExceptionForHR(HR);
            }

        }
    }
    public void BuildGraph(IGraphBuilder pGraph)
    {

        int hr = 0;
        int DVC = 0;
        int DVCi = 0;
        #region Find Video Capture Card
        DsDevice[] CardFinder = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
        foreach (DsDevice Check in CardFinder)
        {
            if (Check.Name == "Decklink Video Capture") DVC = DVCi;
            DVCi++;
        }
        // Magics Card should be CardFinder[0]
        // graph builder
        ICaptureGraphBuilder2 pBuilder = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
        hr = pBuilder.SetFiltergraph(pGraph);
        checkHR(hr, "Can't SetFiltergraph");
        #endregion
        #region Create Connection to Capture Card
        //Guid HDYC = new Guid(0x43594448, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);

        IBaseFilter pDecklinkVideoCature;// = CreateFilterbyName(@"Decklink Video Capture", CLSID_VideoCaptureSource);
        IFilterGraph2 TempFilter = (IFilterGraph2)new FilterGraph();
        hr = TempFilter.AddSourceFilterForMoniker(CardFinder[DVC].Mon, null, CardFinder[DVC].Name, out pDecklinkVideoCature);
        checkHR(hr, "Can't Find Camera");
        hr = pGraph.AddFilter(pDecklinkVideoCature, "Decklink Video Capture");
        checkHR(hr, "Can't add Decklink video Capture to graph");
        // Configure pDecklinkVideoCature for 1080i @ 59.94fps somehow
        IPin VideoOutPin = GetVPin(pDecklinkVideoCature, "Capture");
        //AMMediaType VidMed = new AMMediaType();
        //VidMed.majorType = MediaType.Video;
        //VidMed.formatType = FormatType.VideoInfo;
        //VidMed.subType = MediaSubType.RGB24;
        //hr = VideoOutPin.ConnectionMediaType(VidMed);
        IAMStreamConfig streamConfig = (IAMStreamConfig)VideoOutPin;
        AMMediaType searchmedia;
        AMMediaType CorectvidFormat = new AMMediaType();
        IntPtr ptr;

        int piCount, piSize;
        hr = streamConfig.GetNumberOfCapabilities(out piCount, out piSize);
        ptr = Marshal.AllocCoTaskMem(piSize);
        for (int i = 0; i < piCount; i++)
        {
            hr = streamConfig.GetStreamCaps(i, out searchmedia, ptr);
            VideoInfoHeader v = new VideoInfoHeader();
            Marshal.PtrToStructure(searchmedia.formatPtr, v);
            VideoInfoHeader TestInfoHeader = (VideoInfoHeader)Marshal.PtrToStructure(searchmedia.formatPtr, typeof(VideoInfoHeader));
            int TestWidth = TestInfoHeader.BmiHeader.Width;
            int TestHeight = TestInfoHeader.BmiHeader.Height;
            int TestCompression = TestInfoHeader.BmiHeader.Compression;
            long TestTime = TestInfoHeader.AvgTimePerFrame;
            int TestError = TestInfoHeader.BitErrorRate;
            if ((TestWidth == 1920) & (TestHeight == 1080) & (TestTime == 333667))
            {
                CorectvidFormat = searchmedia;
            }
        }
        VideoInfoHeader videoInfoHeader = (VideoInfoHeader)Marshal.PtrToStructure(CorectvidFormat.formatPtr, typeof(VideoInfoHeader));
        m_videoWidth = videoInfoHeader.BmiHeader.Width;
        m_videoHeight = videoInfoHeader.BmiHeader.Height;
        m_stride = m_videoWidth * (videoInfoHeader.BmiHeader.BitCount / 8);

        hr = streamConfig.SetFormat(CorectvidFormat);
        checkHR(hr, "Can't Get Pin Query");
        #endregion
        #region Create Color Space Converter filter for Sample Grabber (I Hope)
        IBaseFilter pAVIDecompressor2 = (IBaseFilter)new AVIDec();
        hr = pGraph.AddFilter(pAVIDecompressor2, "AVI Decompressor");
        checkHR(hr, "Can't add AVI Decompressor to graph");
        // No Configuration needed for the AVI Decompresser that I know of
        IPin AVIDecompressor2OutPin = GetPin(pAVIDecompressor2, "XForm Out");
        IPin AVIDecompressor2InPin = GetPin(pAVIDecompressor2, "XForm In");

        //IBaseFilter ColorSpaceConverterFilter = new IBaseFilter;
        //hr = pGraph.AddFilter(ColorSpaceConverterFilter, "Color Space Converter");
        //checkHR(hr, "Can't Create Color Space Converter");
        //IPin CSCFIn = GetPin(ColorSpaceConverterFilter, "Input0");
        #endregion

        #region Create Sample Grabber
        AMMediaType SampleMediaType = new AMMediaType();
        SampleMediaType.majorType = MediaType.Video;
        SampleMediaType.subType = MediaSubType.RGB565;
        //SampleMediaType.subType = MediaSubType.UYVY;
        SampleMediaType.formatType = FormatType.VideoInfo;

        //hr = SampleGrabberFilter.SetMediaType(CorectvidFormat);
        hr = SampleGrabberFilter.SetMediaType(SampleMediaType);
        checkHR(hr, "Can't Set Sample Grabber Media Type");
        //ISampleGrabberCB pcallback;
        SampleGrabberFilter.SetCallback(this, 1);
        hr = SampleGrabberFilter.SetBufferSamples(false);
        hr = SampleGrabberFilter.SetOneShot(false);
        hr = pGraph.AddFilter((IBaseFilter)SampleGrabberFilter, "Sample Grabber");
        checkHR(hr, "Can't Add Sample Grabber");
        IPin SGFIn = GetPin((IBaseFilter)SampleGrabberFilter, "Input");
        IPin SGFOut = GetPin((IBaseFilter)SampleGrabberFilter, "Output");
        #endregion
        #region Create Null Renderer
        IBaseFilter VideoNullRenderer = (IBaseFilter)new NullRenderer();
        hr = pGraph.AddFilter(VideoNullRenderer, "Null Renderer");
        checkHR(hr, "Can't Create Null Renderer");
        IPin NullIn = GetPin(VideoNullRenderer, "In");
        #endregion
        #region Create Infinite Pin Tree Filter
        IBaseFilter InfinitePinTreeFilter = (IBaseFilter)new InfTee();
        hr = pGraph.AddFilter(InfinitePinTreeFilter, "Infinite Pin Tee");
        checkHR(hr, "Can't Add Pin Tee");
        IPin IPTIn = GetPin(InfinitePinTreeFilter, "Input");
        IPin IPTOut1 = GetPin(InfinitePinTreeFilter, "Output1");
        #region Connect IPTOut -> Sample Grabber -> Null renderer
        //hr = pGraph.ConnectDirect(VideoOutPin, IPTIn, CorectvidFormat);
        hr = pGraph.Connect(VideoOutPin, IPTIn);
        checkHR(hr, "Can't Connect Camera to Infinite Pin Tee");
        //hr = pGraph.ConnectDirect(IPTOut1, AVIDecompressor2InPin, CorectvidFormat);
        //checkHR(hr, "Can't IPT1 to AVIDecompressor 2");
        //hr = pGraph.ConnectDirect(AVIDecompressor2OutPin, SGFIn, SampleMediaType);
        //checkHR(hr, "Can't AVIDecompressor 2 to Sample In");
        hr = pGraph.Connect(IPTOut1, SGFIn);
        checkHR(hr, "Can't IPTOut1 to Sample In");
        hr = pGraph.Connect(SGFOut, NullIn);
        checkHR(hr, "Can't Sample Out To Null In");
        #endregion
        IPin IPTOut2 = GetPin(InfinitePinTreeFilter, "Output2");
        #endregion
        #region Add Video Mixing Renderer9
        //IBaseFilter pVideoMixingRenderer9 = (IBaseFilter)Activator.CreateInstance(Type.GetTypeFromCLSID(CLSID_VideoMixingRenderer9));
        IBaseFilter pVideoMixingRenderer9 = (IBaseFilter)new VideoMixingRenderer9();
        // Setup Video Renderer to go to Windows Form at this Point??
        #region Setup WindowlessMode
        IVMRFilterConfig9 MixingRendererFilterConfig = (IVMRFilterConfig9)pVideoMixingRenderer9;
        hr = MixingRendererFilterConfig.SetNumberOfStreams(1);
        checkHR(hr, "Problem Setting Streams to 1");

        hr = MixingRendererFilterConfig.SetRenderingMode(VMR9Mode.Windowless);
        checkHR(hr, "Can't Set Mode to Windowed"); // Doesn't work Windowless?

        WindowlessControl = (IVMRWindowlessControl9)pVideoMixingRenderer9;
        hr = WindowlessControl.SetVideoClippingWindow(VideoViewer.VideoPanel.Handle);
        checkHR(hr, "Problem Setting Clipping Window to VideoPanel");

        hr = WindowlessControl.SetAspectRatioMode(VMR9AspectRatioMode.LetterBox);
        checkHR(hr, "Problem Setting Aspect Ration");
        VideoViewer.AddHandlers();
        VideoViewer.Visible = true;

        #endregion
        hr = pGraph.AddFilter(pVideoMixingRenderer9, "Video Mixing Renderer 9");
        checkHR(hr, "Can't Create Video Mixing Renderer 9");
        IPin VideoFormPin = GetPin(pVideoMixingRenderer9, "VMR Input0");
        #endregion
        #region Create AVI Decompressor
        IBaseFilter pAVIDecompressor = (IBaseFilter)new AVIDec();
        AMMediaType AVIInMedia = new AMMediaType();
        AMMediaType AVIOutMedia = new AMMediaType();
        AVIOutMedia.majorType = MediaType.Video;
        AVIOutMedia.subType = MediaSubType.UYVY;
        hr = pGraph.AddFilter(pAVIDecompressor, "AVI Decompressor");
        checkHR(hr, "Can't add AVI Decompressor to graph");
        // No Configuration needed for the AVI Decompresser that I know of
        IPin AVIDecompressorOutPin = GetPin(pAVIDecompressor, "XForm Out");
        IPin AVIDecompressorInPin = GetPin(pAVIDecompressor, "XForm In");
        #endregion
        #region Connect Infinite Pin Out2 to Input of AVI Decompressor
        //hr = pGraph.ConnectDirect(IPTOut2, AVIDecompressorInPin, null);
        hr = pGraph.Connect(IPTOut2, AVIDecompressorInPin);
        checkHR(hr, "Can't Connect Infinite Pin 2 to AVI Decompressor");
        #endregion
        #region Connect Output of AVI Decompressor to Video Mixing Renderer9
        //hr = pGraph.ConnectDirect(AVIDecompressorOutPin, VideoFormPin, null);
        hr = pGraph.Connect(AVIDecompressorOutPin, VideoFormPin);
        checkHR(hr, "Can't Connect AVI Out to Renderer");
        #endregion
        DsUtils.FreeAMMediaType(SampleMediaType);
        DsUtils.FreeAMMediaType(CorectvidFormat);
        SampleMediaType = null;
        CorectvidFormat = null;
        VideoViewer.Activate();
    }
    public IntPtr Click()
    {
        int hr;
        // get ready to wait for new image
        m_PictureReady.Reset();
        m_ipBuffer = Marshal.AllocCoTaskMem(Math.Abs(m_stride) * m_videoHeight);
        try
        {
            m_WantOne = true;
            // If we are using a still pin, ask for a picture
            if (m_VidControl != null)
            {
                // Tell the camera to send an image
                hr = m_VidControl.SetMode(m_pinStill, VideoControlFlags.Trigger);
                checkHR(hr, "Can't SetMode");
                DsError.ThrowExceptionForHR(hr);
            }

            // Start waiting
            if (!m_PictureReady.WaitOne(9000, false))
            {
                throw new Exception("Timeout waiting to get picture");
            }
        }
        catch
        {
            Marshal.FreeCoTaskMem(m_ipBuffer);
            m_ipBuffer = IntPtr.Zero;
            throw;
        }

        // Got one
        return m_ipBuffer;
    }
}
}

VideoFeed(Windows 窗体)

using System;
using System.Windows.Forms;
using DirectShowLib;
using Microsoft.Win32;
using VideoCapture.Classes;

namespace VideoCapture.Forms
{
public partial class VideoFeed : Form
{
    public VideoFeed()
    {
        InitializeComponent();
        this.Visible = true;
    }
    public void AddHandlers()
    {
        this.Paint += new PaintEventHandler(VideoFeed_Paint);
        this.Resize += new EventHandler(VideoFeed_ResizeMove);
        this.Move += new EventHandler(VideoFeed_ResizeMove);
        SystemEvents.DisplaySettingsChanged += new EventHandler(SystemEvents_DisplaySettingsChanged);
        VidCardGlobal.VideoHandlersAdded = true;
    }
    public void RemoveHandlers()
    {
        this.Paint -= new PaintEventHandler(VideoFeed_Paint);
        this.Resize -= new EventHandler(VideoFeed_ResizeMove);
        this.Move -= new EventHandler(VideoFeed_ResizeMove);
        SystemEvents.DisplaySettingsChanged -= new EventHandler(SystemEvents_DisplaySettingsChanged);
        VidCardGlobal.VideoHandlersAdded = false;
    }
    public void VideoFeed_ResizeMove(object sender, EventArgs e)
    {
        if (VidCardGlobal.WindowlessControl != null)
        {
            int hr = VidCardGlobal.WindowlessControl.SetVideoPosition(null, DsRect.FromRectangle(this.VideoPanel.ClientRectangle));
        }
    }
    private void VideoFeed_Paint(object sender, PaintEventArgs e)
    {
        if (VidCardGlobal.WindowlessControl != null)
        {
            IntPtr hdc = e.Graphics.GetHdc();
            int hr = VidCardGlobal.WindowlessControl.RepaintVideo(this.VideoPanel.Handle, hdc);
            e.Graphics.ReleaseHdc(hdc);
        }
    }
    private void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
    {
        if (VidCardGlobal.WindowlessControl != null)
        {
            int hr = VidCardGlobal.WindowlessControl.DisplayModeChanged();
        }
    }
}
}

ETA:FilterGraph 定义

using System;
using System.Runtime.InteropServices;

namespace DirectShowLib
{
// CODE SNIPPED
#region COM Class Objects
/// <summary>
/// CLSID_FilterGraph
/// </summary>
[ComImport, Guid("e436ebb3-524f-11ce-9f53-0020af0ba770")]
public class FilterGraph
{
}
}
4

0 回答 0