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

发布于 2024-07-20 16:48:16 字数 645 浏览 7 评论 0原文

我想做的是将任意音频文件传递到 DirectShow 过滤器,并最终使用 .NET 3.5 C# 和 DirectShow.NET 接收(PCM 音频)流对象。 我想说的是:

 Stream OpenFile(string filename) {...}

stream.Read(...)

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

最好的,

豪克

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:

 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?

Best,

Hauke

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

东走西顾 2024-07-27 16:48:16

我想与您分享我对自己问题的解决方案(我的重点是异国情调的 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;
            }
        }
    }

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.):

    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;
            }
        }
    }
离去的眼神 2024-07-27 16:48:16

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

另一种方法可以在此处找到。

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.

Another approach can be found here.

梦回旧景 2024-07-27 16:48:16

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文