如何使用 DirectShow.NET C# 访问音频流

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/857546/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 04:26:38  来源:igfitidea点击:

How to access an audio stream using DirectShow.NET C#

c#.net-3.5streamingdirectshowdirectshow.net

提问by Hauke

What I would like to do is to pass an arbitrary audio file to a DirectShow filtergraph and receive a (PCM audio) stream object in the end using .NET 3.5 C# and DirectShow.NET. I would like to reach the point that I can just say:

我想要做的是将任意音频文件传递给 DirectShow filtergraph 并最终使用 .NET 3.5 C# 和 DirectShow.NET 接收(PCM 音频)流对象。我想达到我只能说的一点:

 Stream OpenFile(string filename) {...}

and

stream.Read(...)

I have been reading up on DirectShow for a couple of days and think I have started to grasp the idea of filters and filtergraphs. I found examples (to file/ to device) how to play audio or write it to a file, but cannot seem to find the solution for a Stream object. Is this even possible? Could you point me in the right direction in case I missed something, please?

我已经在 DirectShow 上阅读了几天,并认为我已经开始掌握过滤器和过滤器图的概念。我找到了如何播放音频或将其写入文件的示例(到文件/到设备),但似乎找不到 Stream 对象的解决方案。这甚至可能吗?如果我错过了什么,你能指出我正确的方向吗?

Best,

最好的事物,

Hauke

豪克

采纳答案by Hauke

I would like to share my solution to my own problem with you (my focus was on the exotic bwf file format. hence the name.):

我想与您分享我对自己问题的解决方案(我的重点是异国情调的 bwf 文件格式。因此得名。):

    using System;
    using System.Collections.Generic;
    using System.Text;
    using DirectShowLib;
    using System.Runtime.InteropServices;
    using System.IO;

    namespace ConvertBWF2WAV
    {
        public class BWF2WavConverter : ISampleGrabberCB
        {
            IFilterGraph2 gb = null;
            ICaptureGraphBuilder2 icgb = null;
            IBaseFilter ibfSrcFile = null;
            DsROTEntry m_rot = null;
            IMediaControl m_mediaCtrl = null;
            ISampleGrabber sg = null;


            public BWF2WavConverter() 
            { 
                // Initialize
                int hr;
                icgb = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
                gb = (IFilterGraph2) new FilterGraph();
                sg = (ISampleGrabber)new SampleGrabber();

    #if DEBUG
                m_rot = new DsROTEntry(gb);
    #endif
                hr = icgb.SetFiltergraph(gb);
                DsError.ThrowExceptionForHR(hr);
            }

            public void reset()
            {
                gb = null;
                icgb = null;
                ibfSrcFile = null;
                m_rot = null;
                m_mediaCtrl = null;
            }

            public void convert(object obj) 
            {
                string[] pair = obj as string[];
                string srcfile = pair[0];
                string targetfile = pair[1];

                int hr;

                ibfSrcFile = (IBaseFilter)new AsyncReader();
                hr = gb.AddFilter(ibfSrcFile, "Reader");
                DsError.ThrowExceptionForHR(hr);

                IFileSourceFilter ifileSource = (IFileSourceFilter)ibfSrcFile;
                hr = ifileSource.Load(srcfile, null);
                DsError.ThrowExceptionForHR(hr);

                // the guid is the one from ffdshow
                Type fftype = Type.GetTypeFromCLSID(new Guid("0F40E1E5-4F79-4988-B1A9-CC98794E6B55"));
                object ffdshow = Activator.CreateInstance(fftype);
                hr = gb.AddFilter((IBaseFilter)ffdshow, "ffdshow");
                DsError.ThrowExceptionForHR(hr);

                // the guid is the one from the WAV Dest sample in the SDK
                Type type = Type.GetTypeFromCLSID(new Guid("3C78B8E2-6C4D-11d1-ADE2-0000F8754B99"));
                object wavedest = Activator.CreateInstance(type);
                hr = gb.AddFilter((IBaseFilter)wavedest, "WAV Dest");
                DsError.ThrowExceptionForHR(hr);

                // manually tell the graph builder to try to hook up the pin that is left
                IPin pWaveDestOut = null;
                hr = icgb.FindPin(wavedest, PinDirection.Output, null, null, true, 0, out pWaveDestOut);
                DsError.ThrowExceptionForHR(hr);

                // render step 1
                hr = icgb.RenderStream(null, null, ibfSrcFile, (IBaseFilter)ffdshow, (IBaseFilter)wavedest);
                DsError.ThrowExceptionForHR(hr);

                 // Configure the sample grabber
                IBaseFilter baseGrabFlt = sg as IBaseFilter;
                ConfigSampleGrabber(sg);
                IPin pGrabberIn = DsFindPin.ByDirection(baseGrabFlt, PinDirection.Input, 0);
                IPin pGrabberOut = DsFindPin.ByDirection(baseGrabFlt, PinDirection.Output, 0);
                hr = gb.AddFilter((IBaseFilter)sg, "SampleGrabber");
                DsError.ThrowExceptionForHR(hr);
                AMMediaType mediatype = new AMMediaType();
                sg.GetConnectedMediaType(mediatype);

                hr = gb.Connect(pWaveDestOut, pGrabberIn);
                DsError.ThrowExceptionForHR(hr);

                // file writer
                FileWriter file_writer = new FileWriter();
                IFileSinkFilter fs = (IFileSinkFilter)file_writer;
                fs.SetFileName(targetfile, null);
                hr = gb.AddFilter((DirectShowLib.IBaseFilter)file_writer, "File Writer");
                DsError.ThrowExceptionForHR(hr);

                // render step 2
                AMMediaType mediatype2 = new AMMediaType();
                pWaveDestOut.ConnectionMediaType(mediatype2);
                gb.Render(pGrabberOut);

                // alternatively to the file writer use the NullRenderer() to just discard the rest

                // assign control
                m_mediaCtrl = gb as IMediaControl;

                // run
                hr = m_mediaCtrl.Run();
                DsError.ThrowExceptionForHR(hr);


            }


            //
            // configure the SampleGrabber filter of the graph
            //
            void ConfigSampleGrabber(ISampleGrabber sampGrabber)
            {
                AMMediaType media;

                // set the media type. works with "stream" somehow...
                media = new AMMediaType();
                media.majorType = MediaType.Stream;
                //media.subType = MediaSubType.WAVE;
                //media.formatType = FormatType.WaveEx;

                // that's the call to the ISampleGrabber interface
                sg.SetMediaType(media);

                DsUtils.FreeAMMediaType(media);
                media = null;

                // set BufferCB as the desired Callback function
                sg.SetCallback(this, 1);
            }

            public int SampleCB(double a, IMediaSample b)
            {
                return 0;
            }

            /// <summary>
            /// Called on each SampleGrabber hit.
            /// </summary>
            /// <param name="SampleTime">Starting time of the sample, in seconds.</param>
            /// <param name="pBuffer">Pointer to a buffer that contains the sample data.</param>
            /// <param name="BufferLen">Length of the buffer pointed to by pBuffer, in bytes.</param>
            /// <returns></returns>
            public int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)
            {
                byte[] buffer = new byte[BufferLen];
                Marshal.Copy(pBuffer, buffer, 0, BufferLen);
                using (BinaryWriter binWriter = new BinaryWriter(File.Open(@"C:\directshowoutput.pcm", FileMode.Append)))
                {
                    binWriter.Write(buffer);
                }
                return 0;
            }
        }
    }

回答by Lazarus

This (AVILibrary Wrapper) may lead you to a solution, it's not DirectSound based (which I get the feeling is very much biased to interfacing your code with the playback hardware) but could be the answer.

这(AVILibrary Wrapper)可能会引导您找到解决方案,它不是基于 DirectSound(我觉得它非常偏向于将您的代码与播放硬件接口),但可能是答案。

Another approach can be found here.

另一种方法可以在这里找到。

回答by Jesper Palm

How about NAudio ? http://www.codeplex.com/naudioIt has a stream implementation.

NAudio怎么样?http://www.codeplex.com/naudio它有一个流实现。