如何在C#中使用DirectShowLib从Memory Stream播放视频文件

时间:2019-12-23 13:42:54

标签: arrays byte memorystream

我正在一个视频文件具有非标准标题,使用H264算法且该文件为.avi格式的项目中。问题是文件不包含.avi标准标题,标题是自定义的,我想执行以下操作

  1. 将视频作为字节数组(例如IO.Stream或DirectShow.IStream)加载到内存流中
  2. 从视频的每个帧(字节数组)中删除标题
  3. 获取其余的帧数据(原始视频数据)并将其提供给DirectShowLib
  4. 使用DirectShowLib播放原始视频数据

请指导如何在这种情况下在GraphEditPlus中创建图形,并附带示例图像

DirectShow Graph Image Sample

using DirectShowLib;

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    //[STAThread]
    //static void Main(string[] args)
    //{
    //    Application.EnableVisualStyles();
    //    Application.SetCompatibleTextRenderingDefault(false);
    //    Application.Run(new Form1());
    //}




    static void checkHR(int hr, string msg)
    {
        if (hr < 0)
        {
            Console.WriteLine(msg);
            DsError.ThrowExceptionForHR(hr);
        }
    }

    static void BuildGraph(IGraphBuilder pGraph, string srcFile1)
    {
        int hr = 0;

        //graph builder
        ICaptureGraphBuilder2 pBuilder = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
        hr = pBuilder.SetFiltergraph(pGraph);
        checkHR(hr, "Can't SetFiltergraph");

        Guid CLSID_Mpeg4sDecoderDMO = new Guid("{2A11BAE2-FE6E-4249-864B-9E9ED6E8DBC2}"); //DMO
        Guid CLSID_Mpeg4sDecoderDMO_cat = new Guid("{4A69B442-28BE-4991-969C-B500ADF5D8A8}"); //DMO category
        Guid CLSID_MP3DecoderDMO = new Guid("{BBEEA841-0A63-4F52-A7AB-A9B3A84ED38A}"); //DMO
        Guid CLSID_MP3DecoderDMO_cat = new Guid("{57F2DB8B-E6BB-4513-9D43-DCD2A6593125}"); //DMO category
        Guid CLSID_VideoRenderer = new Guid("{B87BEB7B-8D29-423F-AE4D-6582C10175AC}"); //quartz.dll
        Guid CLSID_SampleGrabber = new Guid("{C1F400A0-3F08-11D3-9F0B-006008039E37}"); //qedit.dll

        Guid CLSID_Filestreamrenderer = new Guid("{D51BD5A5-7548-11CF-A520-0080C77EF58A}"); //quartz.dll

        //add File stream renderer
        IBaseFilter pFilestreamrenderer = (IBaseFilter)Activator.CreateInstance(Type.GetTypeFromCLSID(CLSID_Filestreamrenderer));
        hr = pGraph.AddFilter(pFilestreamrenderer, "File stream renderer");
        checkHR(hr, "Can't add File stream renderer to graph");



        //add File Source (Async.)
        IBaseFilter pFileSourceAsync = (IBaseFilter)new AsyncReader();
        hr = pGraph.AddFilter(pFileSourceAsync, "File Source (Async.)");
        checkHR(hr, "Can't add File Source (Async.) to graph");



        //set source filename
        IFileSourceFilter pFileSourceAsync_src = pFileSourceAsync as IFileSourceFilter;
        if (pFileSourceAsync_src == null)
            checkHR(unchecked((int)0x80004002), "Can't get IFileSourceFilter");
        hr = pFileSourceAsync_src.Load(srcFile1, null);
        checkHR(hr, "Can't load file");

        //add AVI Splitter
        IBaseFilter pAVISplitter = (IBaseFilter)new AviSplitter();
        hr = pGraph.AddFilter(pAVISplitter, "AVI Splitter");
        checkHR(hr, "Can't add AVI Splitter to graph");

        //connect File Source (Async.) and AVI Splitter
        hr = pGraph.ConnectDirect(GetPin(pFileSourceAsync, "Output"), GetPin(pAVISplitter, "input pin"), null);
        checkHR(hr, "Can't connect File Source (Async.) and AVI Splitter");

        //add Mpeg4s Decoder DMO
        IBaseFilter pMpeg4sDecoderDMO = (IBaseFilter)new DMOWrapperFilter();
        var pMpeg4sDecoderDMO_wrapper = pMpeg4sDecoderDMO as IDMOWrapperFilter;
        if (pMpeg4sDecoderDMO_wrapper == null)
            checkHR(unchecked((int)0x80004002), "Can't get IDMOWrapperFilter");
        hr = pMpeg4sDecoderDMO_wrapper.Init(CLSID_Mpeg4sDecoderDMO, CLSID_Mpeg4sDecoderDMO_cat);
        checkHR(hr, "DMO Wrapper Init failed");
        hr = pGraph.AddFilter(pMpeg4sDecoderDMO, "Mpeg4s Decoder DMO");
        checkHR(hr, "Can't add Mpeg4s Decoder DMO to graph");

        //add MP3 Decoder DMO
        IBaseFilter pMP3DecoderDMO = (IBaseFilter)new DMOWrapperFilter();
        var pMP3DecoderDMO_wrapper = pMP3DecoderDMO as IDMOWrapperFilter;
        if (pMP3DecoderDMO_wrapper == null)
            checkHR(unchecked((int)0x80004002), "Can't get IDMOWrapperFilter");
        hr = pMP3DecoderDMO_wrapper.Init(CLSID_MP3DecoderDMO, CLSID_MP3DecoderDMO_cat);
        checkHR(hr, "DMO Wrapper Init failed");
        hr = pGraph.AddFilter(pMP3DecoderDMO, "MP3 Decoder DMO");
        checkHR(hr, "Can't add MP3 Decoder DMO to graph");

        //connect AVI Splitter and MP3 Decoder DMO
        hr = pGraph.ConnectDirect(GetPin(pAVISplitter, "Stream 01"), GetPin(pMP3DecoderDMO, "in0"), null);
        checkHR(hr, "Can't connect AVI Splitter and MP3 Decoder DMO");

        //add Video Renderer
        IBaseFilter pVideoRenderer = (IBaseFilter)Activator.CreateInstance(Type.GetTypeFromCLSID(CLSID_VideoRenderer));
        hr = pGraph.AddFilter(pVideoRenderer, "Video Renderer");
        checkHR(hr, "Can't add Video Renderer to graph");

        //add Default DirectSound Device
        IBaseFilter pDefaultDirectSoundDevice = (IBaseFilter)new DSoundRender();
        hr = pGraph.AddFilter(pDefaultDirectSoundDevice, "Default DirectSound Device");
        checkHR(hr, "Can't add Default DirectSound Device to graph");

        //connect MP3 Decoder DMO and Default DirectSound Device
        hr = pGraph.ConnectDirect(GetPin(pMP3DecoderDMO, "out0"), GetPin(pDefaultDirectSoundDevice, "Audio Input pin (rendered)"), null);
        checkHR(hr, "Can't connect MP3 Decoder DMO and Default DirectSound Device");

        //add SampleGrabber
        IBaseFilter pSampleGrabber = (IBaseFilter)Activator.CreateInstance(Type.GetTypeFromCLSID(CLSID_SampleGrabber));
        hr = pGraph.AddFilter(pSampleGrabber, "SampleGrabber");
        checkHR(hr, "Can't add SampleGrabber to graph");

        ISampleGrabber _sampleGrabber = ((ISampleGrabber)pSampleGrabber);
        _sampleGrabber.SetOneShot(false);
        _sampleGrabber.SetBufferSamples(false);
        SampleGrabberCallback _sampleGrabberCallback = new SampleGrabberCallback();

        //hr = ((ISampleGrabber)pSampleGrabber).SetBufferSamples(false);
        //if (hr == 0)
        //{
        //    hr = ((ISampleGrabber)pSampleGrabber).SetOneShot(false);
        //}
        //if (hr == 0)
        //{
        //    hr = ((ISampleGrabber)pSampleGrabber).SetCallback(_sampleGrabberCallback, 0);
        //}
        //if (hr < 0)
        //{
        //    Marshal.ThrowExceptionForHR(hr);
        //}

        //set callback
        hr = _sampleGrabber.SetCallback(new SampleGrabberCallback(), 0);
        checkHR(hr, "Can't set callback.");

        AMMediaType pSampleGrabber_pmt = new AMMediaType();
        pSampleGrabber_pmt.majorType = MediaType.Video;
        pSampleGrabber_pmt.subType = MediaSubType.YUY2;
        pSampleGrabber_pmt.formatType = FormatType.VideoInfo;
        pSampleGrabber_pmt.fixedSizeSamples = true;
        pSampleGrabber_pmt.formatSize = 88;
        pSampleGrabber_pmt.sampleSize = 4147200;
        pSampleGrabber_pmt.temporalCompression = false;
        VideoInfoHeader pSampleGrabber_format = new VideoInfoHeader();
        pSampleGrabber_format.SrcRect = new DsRect();
        pSampleGrabber_format.TargetRect = new DsRect();
        pSampleGrabber_format.AvgTimePerFrame = 400000;
        pSampleGrabber_format.BmiHeader = new BitmapInfoHeader();
        pSampleGrabber_format.BmiHeader.Size = 40;
        pSampleGrabber_format.BmiHeader.Width = 1920;
        pSampleGrabber_format.BmiHeader.Height = 1080;
        pSampleGrabber_format.BmiHeader.Planes = 1;
        pSampleGrabber_format.BmiHeader.BitCount = 16;
        pSampleGrabber_format.BmiHeader.Compression = 844715353;
        pSampleGrabber_format.BmiHeader.ImageSize = 4147200;
        pSampleGrabber_pmt.formatPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(pSampleGrabber_format));
        Marshal.StructureToPtr(pSampleGrabber_format, pSampleGrabber_pmt.formatPtr, false);
        hr = ((ISampleGrabber)pSampleGrabber).SetMediaType(pSampleGrabber_pmt);
        DsUtils.FreeAMMediaType(pSampleGrabber_pmt);
        checkHR(hr, "Can't set media type to sample grabber");


        //connect AVI Splitter and Mpeg4s Decoder DMO
        hr = pGraph.ConnectDirect(GetPin(pAVISplitter, "Stream 00"), GetPin(pMpeg4sDecoderDMO, "in0"), null);
        checkHR(hr, "Can't connect AVI Splitter and Mpeg4s Decoder DMO");

        //connect Mpeg4s Decoder DMO and SampleGrabber
        hr = pGraph.ConnectDirect(GetPin(pMpeg4sDecoderDMO, "out0"), GetPin(pSampleGrabber, "Input"), null);
        checkHR(hr, "Can't connect Mpeg4s Decoder DMO and SampleGrabber");

        //add AVI Decompressor
        IBaseFilter pAVIDecompressor = (IBaseFilter)new AVIDec();
        hr = pGraph.AddFilter(pAVIDecompressor, "AVI Decompressor");
        checkHR(hr, "Can't add AVI Decompressor to graph");

        //connect SampleGrabber and AVI Decompressor
        hr = pGraph.ConnectDirect(GetPin(pSampleGrabber, "Output"), GetPin(pAVIDecompressor, "XForm In"), null);
        checkHR(hr, "Can't connect SampleGrabber and AVI Decompressor");

        //connect AVI Decompressor and Video Renderer
        hr = pGraph.ConnectDirect(GetPin(pAVIDecompressor, "XForm Out"), GetPin(pVideoRenderer, "VMR Input0"), null);
        checkHR(hr, "Can't connect AVI Decompressor and Video Renderer");

    }

    static void Main(string[] args)
    {
        try
        {
            IGraphBuilder graph = (IGraphBuilder)new FilterGraph();
            Console.WriteLine("Building graph...");
            BuildGraph(graph, @"Panasonic_HDC_TM_700_P_50i.avi");
            Console.WriteLine("Running...");
            IMediaControl mediaControl = (IMediaControl)graph;
            IMediaEvent mediaEvent = (IMediaEvent)graph;
            int hr = mediaControl.Run();
            checkHR(hr, "Can't run the graph");
            bool stop = false;
            while (!stop)
            {
                System.Threading.Thread.Sleep(500);
                Console.Write(".");
                EventCode ev;
                IntPtr p1, p2;
                System.Windows.Forms.Application.DoEvents();
                while (mediaEvent.GetEvent(out ev, out p1, out p2, 0) == 0)
                {
                    if (ev == EventCode.Complete || ev == EventCode.UserAbort)
                    {
                        Console.WriteLine("Done!");
                        stop = true;
                    }
                    else
                    if (ev == EventCode.ErrorAbort)
                    {
                        Console.WriteLine("An error occured: HRESULT={0:X}", p1);
                        mediaControl.Stop();
                        stop = true;
                    }
                    mediaEvent.FreeEventParams(ev, p1, p2);
                }
            }
        }
        catch (COMException ex)
        {
            Console.WriteLine("COM error: " + ex.ToString());
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error: " + ex.ToString());
        }
    }
    static 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;
    }

}

class SampleGrabberCallback : ISampleGrabberCB
{
    public int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)
    {
        //Console.WriteLine("Time : " + SampleTime + " " + BufferLen);
        return 0;
    }

    public int SampleCB(double SampleTime, IMediaSample pSample)
    {

        Console.WriteLine("Time : " + SampleTime + " " + pSample.GetActualDataLength().ToString());
        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);
        }
        Marshal.ReleaseComObject(pSample);
        return 0;
    }
}

0 个答案:

没有答案