6

我正在使用 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_GUIDorMF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID和,这没有问题,我可以获取设备的名称以及 IMFActivate。我有将网络摄像头录制到输出视频文件的代码,但是,我很难弄清楚如何将音频录制到文件中。我的印象是我需要使用 IMFSinkWriter,但我找不到任何使用音频捕获 IMFActivate 和 IMFSinkWriter 的示例。

我不是一个 Windows api 程序员,所以我确信有一个相当直截了当的答案,但 COM 的东西只是有点过头了。至于音频格式,我真的不在乎,只要它进入一个文件 - 可以是 wav、wma 或其他。即使我正在录制视频,我也需要将视频和音频文件分开,所以我无法弄清楚如何将音频添加到我的视频编码中。

4

2 回答 2

7

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

// 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);

然后在阅读示例时,您需要密切注意阅读器的流索引,并将它们适当地发送给编写器。您还需要密切注意编解码器期望的格式。例如,IEEE float vs PCM 等。祝你好运,我希望还为时不晚。

于 2014-04-02T18:22:14.703 回答
0

您是否很难在将 DirectShow 音频设备录制到文件中管理 DirectShow 音频捕获?

使用 Media Foundation 进行捕获几乎没有任何简单。更不用说一般来说 DirectShow 上有更多的资源......

MSDN 为您提供了一个将音频捕获到文件中的WavSink 示例

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

我不确定他们为什么决定不将其作为标准组件。Media Foundation 在很多方面不如 DirectShow,他们至少可以把这个小东西当成优势。无论如何,你有样本,它看起来是一个好的开始。

于 2012-10-16T14:58:59.893 回答