You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DirectShow技术问题:如何从Avi MUX filter获取音频缓存而非写入文件

解决DirectShow音频录制与数据提取问题

一、整体流程改造方案

你需要在现有滤镜图中插入拦截组件,同时保留本地写入分支,最终滤镜图结构应为:

  • 麦克风 → Avi MUX Filter → 数据拦截组件 → [分支1:File Writer(本地写Avi);分支2:数据缓存→发送服务器]

二、从Avi MUX获取数据的具体实现

1. 使用Sample Grabber Filter(快速原型方案)

Sample Grabber是DirectShow内置滤镜,可快速捕获媒体样本:

  • 初始化Sample Grabber,通过ISampleGrabber接口设置回调函数,在回调中获取样本数据。
  • 将其插入Avi MUX与File Writer之间,确保媒体类型匹配。
  • 关键代码片段:
    // 创建Sample Grabber
    ISampleGrabber* pGrabber = nullptr;
    CoCreateInstance(CLSID_SampleGrabber, nullptr, CLSCTX_INPROC_SERVER, IID_ISampleGrabber, (void**)&pGrabber);
    
    // 设置回调类
    pGrabber->SetCallback(new CSampleGrabberCallback(), 1);
    
    // 匹配Avi MUX输出的媒体类型
    AM_MEDIA_TYPE mt;
    ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
    mt.majortype = MEDIATYPE_Stream;
    mt.subtype = MEDIASUBTYPE_Avi;
    pGrabber->SetMediaType(&mt);
    
    // 加入滤镜图并连接
    pGraph->AddFilter(pGrabber, L"Sample Grabber");
    pGraph->ConnectDirect(pAviMuxOutputPin, pGrabberInputPin, nullptr);
    pGraph->ConnectDirect(pGrabberOutputPin, pFileWriterInputPin, nullptr);
    
  • 回调类核心实现:
    class CSampleGrabberCallback : public ISampleGrabberCB {
    public:
      STDMETHODIMP SampleCB(double SampleTime, IMediaSample* pSample) {
        BYTE* pBuffer = nullptr;
        pSample->GetPointer(&pBuffer);
        long lBufferSize = pSample->GetSize();
        
        // 将数据存入线程安全队列,由单独线程处理服务器发送
        m_dataQueue.Push(pBuffer, lBufferSize);
        
        return S_OK;
      }
    
      // 实现IUnknown接口方法
      STDMETHODIMP_(ULONG) AddRef() { return 1; }
      STDMETHODIMP_(ULONG) Release() { return 0; }
      STDMETHODIMP QueryInterface(REFIID riid, void** ppv) {
        if (riid == IID_ISampleGrabberCB || riid == IID_IUnknown) {
          *ppv = this;
          return S_OK;
        }
        return E_NOINTERFACE;
      }
    };
    

2. 自定义Transform Filter(生产环境方案)

若需更灵活的控制,可实现自定义Transform Filter:

  • 继承CTransformFilter类,重写Transform方法,在该方法中拷贝输入样本数据到缓存,再传递给下一个滤镜。
  • 核心逻辑:
    HRESULT CMyGrabberFilter::Transform(IMediaSample* pIn, IMediaSample* pOut) {
      BYTE* pInBuf = nullptr;
      BYTE* pOutBuf = nullptr;
      pIn->GetPointer(&pInBuf);
      pOut->GetPointer(&pOutBuf);
      long lSize = pIn->GetSize();
      
      // 拷贝数据保证File Writer正常接收
      memcpy(pOutBuf, pInBuf, lSize);
      // 存入缓存队列
      m_dataCache.Enqueue(pInBuf, lSize);
      
      return S_OK;
    }
    

三、关键注意事项

  • 线程安全:回调或Transform方法运行在DirectShow工作线程中,禁止执行阻塞操作(如网络发送),需用线程安全队列异步处理。
  • 媒体类型匹配:通过IPin::ConnectionMediaType获取Avi MUX输出的媒体类型,确保拦截组件输入类型完全匹配,否则连接失败。
  • 数据类型选择:Avi MUX输出的是封装后的Avi流,若需原始PCM音频,应在麦克风与Avi MUX之间拦截数据,再分两路处理(发送服务器+送入Avi MUX封装)。

内容的提问来源于stack exchange,提问作者TomP

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 02:15:35