简体   繁体   English

使用DirectShow捕获音频

[英]Capturing audio using DirectShow

I'm writing program which captures audio in C# using DirectShow library and writes it to ogg container. 我正在编写一个程序,该程序使用DirectShow库捕获C#中的音频并将其写入ogg容器。 I created a graph in GraphEditPlus. 我在GraphEditPlus中创建了一个图形。 It generates a GraphBuilder method code which I copied to my code. 它会生成一个GraphBuilder方法代码,并将其复制到我的代码中。 This code is: 这段代码是:

class AudioCapture
{
  public static void checkHR(int hr, string msg)
  {
    if (hr < 0)
    {
      MessageBox.Show(msg);
      DsError.ThrowExceptionForHR(hr);
    }
  }

  public static void BuildGraph (IGraphBuilder pGraph, string dstFile)
  {
    int hr = 0;

    //graph builder
    ICaptureGraphBuilder2 pBuilder = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
    hr = pBuilder.SetFiltergraph(pGraph);
    checkHR(hr, "Can't SetFiltergraph");

    Guid CLSID_XiphOrgVorbisEncoder = new Guid("{5C94FE86-B93B-467F-BFC3-BD6C91416F9B}");
    Guid CLSID_XiphOrgOggMuxer = new Guid("{1F3EFFE4-0E70-47C7-9C48-05EB99E20011}");

    //add microphone
    IBaseFilter pMicrophone = (IBaseFilter) new AudioRecord();
    hr = pGraph.AddFilter(pMicrophone, "Microphone");
    checkHR(hr, "Can't add microphone to graph");

    //add Vorbis Encoder
    IBaseFilter pVorbisEncoder = (IBaseFilter)Activator.CreateInstance(Type.GetTypeFromCLSID(CLSID_XiphOrgVorbisEncoder));
    checkHR(hr, "Can't add Vorbis Encoder to graph");

    //connect Microphone and Vorbis Encoder
    hr = pGraph.ConnectDirect(GetPin(pMicrophone, "Capture"), GetPin(pVorbisEncoder, "PCM In"), null);
    checkHR(hr, "Can't connect Microphone and Vorbis Encoder");

    //add Ogg Muxer
    IBaseFilter pOggMuxer = (IBaseFilter)Activator.CreateInstance(Type.GetTypeFromCLSID(CLSID_XiphOrgOggMuxer));
    checkHR(hr, "Can't add Ogg Muxer to graph");

    //set destination filename
    IFileSinkFilter pOggMuxer_sink = pOggMuxer as IFileSinkFilter;
    if (pOggMuxer_sink == null)
      checkHR(unchecked((int)0x80004002), "Can't get IFileSinkFilter");
    hr = pOggMuxer_sink.SetFileName(dstFile, null);
    checkHR(hr, "Can't set filename");

    //connect Vorbis Encoder and Ogg Muxer
    hr = pGraph.ConnectDirect(GetPin(pVorbisEncoder, "VorbisOut"), GetPin(pOggMuxer, "Ogg Packet In"), null);
    checkHR(hr, "Can't connect Vorbis Encoder and Ogg Muxer");
  }

  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;
  }
}

When I'm trying to execute this code program throws me a message "Pin can't found" after trying to connect microphone and vorbis encoder filters. 当我尝试执行此代码程序时,尝试连接麦克风和vorbis编码器滤波器后,提示“找不到引脚”。 After debugging I found out that it can't find the microphone pin. 调试后,我发现找不到麦克风引脚。 Does anybody knows where is my error? 有人知道我的错误在哪里吗?

Try do something like this when you looking for pins 寻找别针时,尝试做类似这样的事情

    pinout = FindPinByDirection( Source, PinDirection.Output);
    pinin = FindPinByDirection( Target, PinDirection.Input);

    Graph.Connect(pinout, pinin);

This is better way then depending on names. 然后根据名称,这是更好的方法。

You should not look for pins by their names, as this is not quite reliable. 您不应该按引脚名称查找引脚,因为这不太可靠。 Perhaps it might be still more or less acceptable if you are absolutely sure what filter/class you are dealing with, but it is definitely not the way to do with generic audio source filter (more specifically: noone gives a promise that capture pin is named "Capture", instead pins implement IKsPropertySet to indicate that). 如果您完全确定要处理的是哪个滤波器/类,也许或多或少都可以接受,但这绝对不是使用通用音频源滤波器的方法(更具体地说:没有人承诺将捕获引脚命名为改为使用“捕获”,大头针实现IKsPropertySet进行指示)。

Your best approach would be using ICaptureGraphBuilder::RenderStream with PIN_CATEGORY_CAPTURE argument so that it could pick up capture pin for you. 最好的方法是将ICaptureGraphBuilder::RenderStreamPIN_CATEGORY_CAPTURE参数一起使用,以便它可以为您选择捕获引脚。 See MSDN for details http://msdn.microsoft.com/en-us/library/dd311932%28v=vs.85%29.aspx and I am pretty sure you will easily find sample code for doing this too. 有关详细信息,请参见MSDN。http: //msdn.microsoft.com/zh-cn/library/dd311932%28v=vs.85%29.aspx ,我敢肯定,您也将很容易找到执行此操作的示例代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM