How to play video file from Memory Stream using DirectShowLib in C#

1

I am working on a project in which the video file has non standard header, it is using H264 algorithm and the file is in .avi format. The problem is that file doesn't contain .avi standard header, the header is custom and i want to do the following

  1. Load the video in memory stream as bytes array (e.g. IO.Stream or DirectShow.IStream)
  2. Remove the header from each frame (bytes array) of video
  3. Get rest of the frame data (raw video data) and give it to DirectShowLib
  4. Play the raw video data using DirectShowLib

Please guide how can i create graph in GraphEditPlus in such scenario, sample image attached

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;
    }
}
arrays
byte
memorystream
asked on Stack Overflow Dec 23, 2019 by Muhammad Mohsin • edited Dec 23, 2019 by Muhammad Mohsin

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0