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
相关产品推荐
相关产品推荐

