2009-05-13 8 views
4

Was ich tun möchte, ist eine beliebige Audiodatei an eine DirectShow Filtergraph übergeben und ein Streaming-Objekt (PCM-Audio) am Ende mit .NET 3.5 C# und DirectShow erhalten .NETZ. Ich möchte den Punkt erreichen, dass ich einfach sagen:Zugriff auf einen Audio-Stream mit DirectShow.NET C#

Stream OpenFile(string filename) {...} 

und

stream.Read(...) 

Ich habe für ein paar Tage auf Directshow Lesen worden und denke, ich habe begonnen, die Idee zu erfassen von Filter und Filtergraphs. Ich fand Beispiele (to file/to device), wie man Audio spielt oder es in eine Datei schreibt, aber scheint nicht die Lösung für ein Stream-Objekt zu finden. Ist das überhaupt möglich? Können Sie mir bitte in die richtige Richtung zeigen, falls ich etwas verpasst habe?

Best,

Hauke ​​

+0

Welche Art von Dateien (mp3, wav, wma) Möchtest du? –

+0

Es sollte alles verschlingen, was DirectShow kann; mp3, mp2, wma. DirectShow kann alle tun, ich habe gerade nicht die Schnittstelle gefunden, um einen Strom anzuzapfen. – Hauke

Antwort

5

ich mit Ihnen möchte meine Lösung für mein eigenes Problem teilen (mein Fokus auf der exotischen bwf Dateiformat war daher der 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; 
      } 
     } 
    } 
+1

danke für die gemeinsame Nutzung - das ist eine benutzerunfreundliche API! –

1

Diese (AVILibrary Wrapper) können Sie zu einer Lösung führen, ist es nicht auf Basis DirectSound- (was ich das Gefühl, sehr voreingenommen ist Ihr Code mit der Wiedergabe-Hardware Schnittstelle), aber könnte die Antwort sein.

Ein anderer Ansatz kann here gefunden werden.

1

Wie wäre es mit NAudio? http://www.codeplex.com/naudio Es hat eine Stream-Implementierung.

+0

Ich fand NAudio zu restriktiv auf Dateitypen. – Hauke

+0

NAudio kann derzeit Zugriff auf alle installierten ACM-Codecs und DirectX Media Objects (DMOs) gewähren. DirectShow-Filter möchte ich in Zukunft hinzufügen. –