代码之家  ›  专栏  ›  技术社区  ›  Hauke

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

  •  4
  • Hauke  · 技术社区  · 17 年前

     Stream OpenFile(string filename) {...}
    

    stream.Read(...)
    

    我已经在DirectShow上读了几天了,我想我已经开始掌握过滤器和过滤器图的概念了。我找到了一些例子( to file / to device )如何播放音频或将其写入文件,但似乎无法找到流对象的解决方案。这可能吗?你能给我指一下正确的方向吗,以防我漏掉了什么?

    最好的

    豪克

    3 回复  |  直到 15 年前
        1
  •  5
  •   Hauke    17 年前

    我想与您分享我对自己问题的解决方案(我的重点是外来的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;
                }
            }
        }
    
        2
  •  1
  •   Lazarus    17 年前

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

    here .

        3
  •  1
  •   Jesper Palm    17 年前