Как я могу добавить образец граббер-фильтра к графику, который у меня есть, чтобы я мог сохранять изображения / видео из потокового предварительного просмотра, используя directshow?

Устройство в USB является легато захвата игры. Предварительный просмотр потокового видео в pictureBox1 показывает видео с устройства, но это не пиксели, которые я могу сохранить из pictureBox1 как изображения.

"Невозможно сделать снимок окна, которое на самом деле не отображается. Если окно не полностью видно, то эти пиксели просто не существуют".

Другая проблема заключается в том, что я не могу найти устройство захвата игры legato в графите. Я также попробовал Graphedit Plus. Но устройства legato там нет в списке.

Вот как я создаю предварительный просмотр и транслирую его в pictureBox1

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using DirectShowLib;
using DirectShowLib.BDA;
using DirectShowLib.DES;
using DirectShowLib.DMO;
using DirectShowLib.Dvd;
using DirectShowLib.MultimediaStreaming;
using DirectShowLib.SBE;
using System.Runtime.InteropServices;
using System.Management;
using System.IO;
using System.Drawing.Imaging;


namespace Youtube_Manager
{

    public partial class Elgato_Video_Capture : Form
    {


        IFileSinkFilter sink;

        IFilterGraph2 graph;
        ICaptureGraphBuilder2 captureGraph;
        System.Drawing.Size videoSize;

        string error = "";
        List<Object> devices = new List<Object>();
        IMediaControl mediaControl;

        public Elgato_Video_Capture()
        {
            InitializeComponent();



            if (comboBox1.Items.Count == 0)
            {
                for (int xx = 1; xx <= 8; xx++)
                {
                    comboBox1.Items.Add(xx);
                }
            }

            InitDevice();
            timer1.Start();
        }

        IBaseFilter smartTeeFilter;
        IPin outPin;
        IPin inPin;
        private void InitDevice()
        {
            try
            {
                //Set the video size to use for capture and recording
                videoSize = new Size(827, 505);//1280, 720);

                //Initialize filter graph and capture graph
                graph = (IFilterGraph2)new FilterGraph();
                captureGraph = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
                captureGraph.SetFiltergraph(graph);
                //Create filter for Elgato
                Guid elgatoGuid = new Guid("39F50F4C-99E1-464A-B6F9-D605B4FB5918");
                Type comType = Type.GetTypeFromCLSID(elgatoGuid);
                IBaseFilter  elgatoFilter = (IBaseFilter)Activator.CreateInstance(comType);
                graph.AddFilter(elgatoFilter, "Elgato Video Capture Filter");

                //Create smart tee filter, add to graph, connect Elgato's video out to smart tee in
                smartTeeFilter = (IBaseFilter)new SmartTee();

                graph.AddFilter(smartTeeFilter, "Smart Tee");
                outPin = GetPin(elgatoFilter, "Video");
                inPin = GetPin(smartTeeFilter, "Input");
                SetAndGetAllAvailableResolution(outPin);
                graph.Connect(outPin, inPin);


                //Create video renderer filter, add it to graph, connect smartTee Preview pin to video renderer's input pin
                IBaseFilter videoRendererFilter = (IBaseFilter)new VideoRenderer();

                graph.AddFilter(videoRendererFilter, "Video Renderer");
                outPin = GetPin(smartTeeFilter, "Preview");

                inPin = GetPin(videoRendererFilter, "Input");
                graph.Connect(outPin, inPin);

               // int hr = graph.Connect(outPin, inPin); ;
               // DsError.ThrowExceptionForHR(hr);

                captureGraph.SetOutputFileName(MediaSubType.Avi, @"e:\screenshots\test1.mp4", out smartTeeFilter, out sink);

                //Render stream from video renderer
                captureGraph.RenderStream(PinCategory.VideoPort, MediaType.Video, videoRendererFilter, null, null);
                //Set the video preview to be the videoFeed panel
                IVideoWindow vw = (IVideoWindow)graph;
                vw.put_Owner(pictureBox1.Handle);
                vw.put_MessageDrain(this.Handle);
                vw.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipSiblings | WindowStyle.ClipChildren);
                vw.SetWindowPosition(0, 0, 827, 505);

                //Start the preview
                mediaControl = graph as IMediaControl;
                mediaControl.Run();
            }
            catch (Exception err)
            {
                error = err.ToString();
            }
        }

         IPin GetPin(IBaseFilter filter, string pinname)
        {
            IEnumPins epins;
            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);
                bool found = (pinfo.name == pinname);
                DsUtils.FreePinInfo(pinfo);
                if (found)
                    return pins[0];
            }
            checkHR(-1, "Pin not found");
            return null;
        }

        public  void checkHR(int hr, string msg)
        {
            if (hr < 0)
            {
                MessageBox.Show(msg);
                DsError.ThrowExceptionForHR(hr);
            }



        }

        public void SetAndGetAllAvailableResolution(IPin VideoOutPin)
        {
            int hr = 0;
            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);
                if (i == 2)// 4
                {
                    CorectvidFormat = searchmedia;
                }
            }
            hr = streamConfig.SetFormat(CorectvidFormat);

            IntPtr pmt = IntPtr.Zero;
            AMMediaType mediaType = new AMMediaType();
            IAMStreamConfig streamConfig1 = (IAMStreamConfig)VideoOutPin;
            hr = streamConfig1.GetFormat(out mediaType);
            BitmapInfoHeader bmpih = new BitmapInfoHeader();
            Marshal.PtrToStructure(mediaType.formatPtr, bmpih);
        }
  }
} 

Теперь я попытался добавить эти методы для использования с образцом граббер:

private void AddSampleGrabber(int hr, Guid elgatoguid, IFilterGraph2 pGraph)
        {
            //add SampleGrabber
            IBaseFilter pSampleGrabber = (IBaseFilter)Activator.CreateInstance(Type.GetTypeFromCLSID(elgatoguid));
            hr = pGraph.AddFilter(pSampleGrabber, "SampleGrabber");
            checkHR(hr, "Can't add SampleGrabber to graph");
            //set callback
            hr = ((ISampleGrabber)pSampleGrabber).SetCallback(new SampleGrabberCallback(), 0);
            checkHR(hr, "Can't set callback.");

            AMMediaType pmt = new AMMediaType();
            pmt.majorType = MediaType.Video;
            pmt.subType = MediaSubType.YUY2;
            pmt.formatType = FormatType.VideoInfo;
            pmt.fixedSizeSamples = true;
            pmt.formatSize = 88;
            pmt.sampleSize = 614400;
            pmt.temporalCompression = false;
            VideoInfoHeader format = new VideoInfoHeader();
            format.SrcRect = new DsRect();
            format.TargetRect = new DsRect();
            format.BmiHeader = new BitmapInfoHeader();
            format.BmiHeader.Size = 40;
            format.BmiHeader.Width = 640;
            format.BmiHeader.Height = 480;
            format.BmiHeader.Planes = 1;
            format.BmiHeader.BitCount = 16;
            format.BmiHeader.Compression = 844715353;
            format.BmiHeader.ImageSize = 614400;
            pmt.formatPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(format));
            Marshal.StructureToPtr(format, pmt.formatPtr, false);
            hr = ((IAMStreamConfig)GetPin(smartTeeFilter, "Capture")).SetFormat(pmt);
            DsUtils.FreeAMMediaType(pmt);
            checkHR(hr, "Can't set format");

            //connect USB2.0 Camera and SampleGrabber
            hr = pGraph.ConnectDirect(GetPin(smartTeeFilter, "Capture"), GetPin(pSampleGrabber, "Input"), null);
            checkHR(hr, "Can't connect USB2.0 Camera and SampleGrabber");

            //render the video
            hr = captureGraph.RenderStream(null, null, pSampleGrabber, null, null);
            checkHR(hr, "Can't render video from grabber");

        }

        class SampleGrabberCallback : ISampleGrabberCB
        {
            public SampleGrabberCallback()
            {
            }

            public int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)
            {
                return 0;
            }

            public int SampleCB(double SampleTime, IMediaSample pSample)
            {
                if (pSample == null) return -1;
                int len = pSample.GetActualDataLength();
                IntPtr pbuf;
                if (pSample.GetPointer(out pbuf) == 0 && len > 0)
                {
                    byte[] buf = new byte[len];
                    Marshal.Copy(pbuf, buf, 0, len);
                    for (int i = 0; i < len; i += 2)
                        buf[i] = (byte)(255 - buf[i]);
                    Marshal.Copy(buf, 0, pbuf, len);
                }
                return 0;
            }
        }

Но я получаю исключение на линии:

hr = ((ISampleGrabber)pSampleGrabber).SetCallback(new SampleGrabberCallback(), 0);

Невозможно привести объект COM типа "System.__ComObject" к типу интерфейса "DirectShowLib.ISampleGrabber". Эта операция завершилась неудачно, поскольку вызов QueryInterface для компонента COM для интерфейса с IID '{6B652FFF-11FE-4FCE-92AD-0266B5D7C78F}' завершился ошибкой из-за следующей ошибки: такой интерфейс не поддерживается (Исключение из HRESULT: 0x80004002 (E_NOINTERFACE))

Я предполагаю, что я не использую это правильно вообще. А также я не знаю, как использовать его позже, чтобы захватить (сохранить на жесткий диск) изображение / видео потоковой передачи.

1 ответ

Код вокруг pSampleGrabber не имеет смысла. Он ожидает COM-указатель на экземпляр Sample Grabber Filter. Ожидается, что другие фильтры не будут реализованы ISampleGrabber, Однако вы пытаетесь привести фильтр захвата видео к тому, чем он не должен быть (E_NOINTERFACE скажу тебе именно это!)

IBaseFilter pSampleGrabber = 
    (IBaseFilter)Activator.CreateInstance(Type.GetTypeFromCLSID(elgatoguid));

Вам нужно добавить фильтр захвата видео, затем создать экземпляр Sample Grabber и затем соединить их. Затем визуализируйте вывод граббера. Затем свяжите ваш обратный вызов с экземпляром граббера.

Другие вопросы по тегам