Windows Media Foundation正在录制音频

Windows Media Foundation recording audio

本文关键字:音频 Media Foundation Windows      更新时间:2023-10-16

我正在使用windows media foundation api来枚举我的麦克风和可用的相机,它们都可以工作。

这是我的枚举代码:

class deviceInput {
public:
deviceInput( REFGUID source );
~deviceInput();
int listDevices(bool refresh = false);
IMFActivate *getDevice(unsigned int deviceId);
const WCHAR *getDeviceName(unsigned int deviceId);
private:
void Clear();
HRESULT EnumerateDevices();
UINT32      m_count;
IMFActivate **m_devices;
REFGUID     m_source;
};
deviceInput::deviceInput( REFGUID source )
: m_devices( NULL )
, m_count( 0 )
, m_source( source )
{   }
deviceInput::~deviceInput()
{
Clear();
}
int deviceInput::listDevices(bool refresh)
{
if ( refresh || !m_devices ) {
if ( FAILED(this->EnumerateDevices()) ) return -1;
}
return m_count;
}
IMFActivate *deviceInput::getDevice(unsigned int deviceId)
{
if ( deviceId >= m_count ) return NULL;
IMFActivate *device = m_devices[deviceId];
device->AddRef();
return device;
}
const WCHAR *deviceInput::getDeviceName(unsigned int deviceId)
{
if ( deviceId >= m_count ) return NULL;
HRESULT hr = S_OK;
WCHAR *devName = NULL;
UINT32 length;
hr = m_devices[deviceId]->GetAllocatedString( MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &devName, &length );
if ( FAILED(hr) ) return NULL;
return devName;
}
void deviceInput::Clear()
{
if ( m_devices ) {
for (UINT32 i = 0; i < m_count; i++) SafeRelease( &m_devices[i] );
CoTaskMemFree( m_devices );
}
m_devices = NULL;
m_count = 0;
}
HRESULT deviceInput::EnumerateDevices()
{
HRESULT hr = S_OK;
IMFAttributes *pAttributes = NULL;
Clear();
hr = MFCreateAttributes(&pAttributes, 1);
if ( SUCCEEDED(hr) ) hr = pAttributes->SetGUID( MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, m_source );
if ( SUCCEEDED(hr) ) hr = MFEnumDeviceSources( pAttributes, &m_devices, &m_count );
SafeRelease( &pAttributes );
return hr;
}

要获取音频或相机捕获设备,我指定MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUIDMF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID,这没有问题,而且我可以获取设备的名称以及IMFActivate。我有将网络摄像头录制到输出视频文件的代码,但是,我很难弄清楚如何将音频录制到文件中。我觉得我需要使用IMFSinkWriter,但我找不到任何使用音频捕获IMFActivate和IMFSinkWriter的示例。

我不是一个windows api程序员,所以我相信有一个相当直接的答案,但COM的东西有点让我难以理解。至于音频格式,我真的不在乎,只要它进入一个文件——可以是wav、wma或其他什么。即使我在录制视频,我也需要将视频和音频文件分开,所以我无法直接找出如何将音频添加到视频编码中。

我对延迟回复表示歉意,我希望您仍然能发现这一点很有价值。我最近完成了一个类似于你的项目(将网络摄像头视频和选定的麦克风录制到一个带音频的视频文件中)。关键是要创建一个聚合媒体源。

// http://msdn.microsoft.com/en-us/library/windows/desktop/dd388085(v=vs.85).aspx
HRESULT CreateAggregateMediaSource(IMFMediaSource *videoSource,
IMFMediaSource *audioSource,
IMFMediaSource **aggregateSource)
{
*aggregateSource = nullptr;
IMFCollection *pCollection = nullptr;
HRESULT hr = ::MFCreateCollection(&pCollection);
if (S_OK == hr)
hr = pCollection->AddElement(videoSource);
if (S_OK == hr)
hr = pCollection->AddElement(audioSource);
if (S_OK == hr)
hr = ::MFCreateAggregateSource(pCollection, aggregateSource);
SafeRelease(&pCollection);
return hr;
}

配置接收器写入程序时,您将添加2个流(一个用于音频,一个用于视频)。当然,您还将为输入流类型正确配置编写器。

HRESULT        hr                  = S_OK;
IMFMediaType  *videoInputType      = nullptr;
IMFMediaType  *videoOutputType     = nullptr;
DWORD          videoOutStreamIndex = 0u;
DWORD          audioOutStreamIndex = 0u;
IMFSinkWriter *writer              = nullptr;
// [other create and configure writer]
if (S_OK == hr))
hr = writer->AddStream(videoOutputType, &videoOutStreamIndex);    
// [more configuration code]
if (S_OK == hr)
hr = writer->AddStream(audioOutputType, &audioOutStreamIndex);

然后,在阅读示例时,您需要密切关注阅读器streamIndex,并将其适当地发送给作者。您还需要密切关注编解码器所期望的格式。例如,IEEE浮动与PCM等。祝你好运,我希望现在还为时不晚。

在将DirectShow音频设备录制到文件中管理DirectShow音频捕获时遇到困难吗?

用媒体基金会捕捉并不是一件简单的事。甚至没有提到,一般来说,DirectShow上有更多的资源。。。。

MSDN为您提供了一个WavSink示例,它可以将音频捕获到文件中:

显示如何在Microsoft media Foundation中实现自定义媒体接收器。该示例实现了一个将未压缩的PCM音频写入.wav文件的存档接收器。

我不知道他们为什么决定不将其作为标准组件。媒体基金会在很多方面都不如DirectShow,他们至少可以把这件小事作为优势。不管怎样,你有样品,看起来是一个良好的开端。