我正在使用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 float vs PCM等。祝您好运,我希望还不晚。

10-08 08:22
查看更多