2012-10-16 60 views
5

我使用Windows Media基礎API來枚舉我的兩個麥克風和攝像頭可用,這兩者的工作。Windows媒體基金會錄製的音頻

這裏是我的枚舉代碼:

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或其他。儘管我在錄製視頻,但我需要將視頻和音頻文件分開,所以我不能僅僅知道如何將音頻添加到我的視頻編碼中。

回答

7

我的反應遲到道歉,我希望你仍然可以找到這寶貴的。我最近完成了一個類似於您的項目(將攝像頭視頻連同選定的麥克風一起錄製到帶有音頻的單個視頻文件)。關鍵是創建一個聚合媒體源。

// http://msdn.microsoft.com/en-us/library/windows/desktop/dd388085(v=vs.85).aspx 
HRESULT CreateAggregateMediaSource(IMFMediaSource *videoSource, IMFMediaSource *audioSource, IMFMediaSource **aggregateSource) 
{ 
    *aggregateSource = NULL; 
    IMFCollection *pCollection = NULL; 

    HRESULT hr = MFCreateCollection(&pCollection); 

    if (SUCCEEDED(hr)) 
     hr = pCollection->AddElement(videoSource); 

    if (SUCCEEDED(hr)) 
     hr = pCollection->AddElement(audioSource); 

    if (SUCCEEDED(hr)) 
     hr = MFCreateAggregateSource(pCollection, aggregateSource); 

    SafeRelease(&pCollection); 
    return hr; 
} 

配置接收器時,您將添加2個流(一個用於音頻,一個用於視頻)。 當然,您還將正確配置輸入流類型的編寫器。

HRESULT  hr = S_OK; 
IMFMediaType *videoInputType = NULL; 
IMFMediaType *videoOutputType = NULL; 
DWORD   videoOutStreamIndex = 0; 
DWORD   audioOutStreamIndex = 0; 
IMFSinkWriter *writer = NULL; 

// [other create and configure writer] 

if (SUCCEEDED(hr)) 
    hr = writer->AddStream(videoOutputType, &videoOutStreamIndex);  

// [more configuration code] 

if (SUCCEEDED(hr)) 
    hr = writer->AddStream(audioOutputType, &audioOutStreamIndex); 

然後讀取樣本時,則需要密切關注讀者streamIndex,並適當地發送到作家。您還需要密切關注編解碼器預期的格式。例如,IEEE浮動與PCM等,祝你好運,我希望它不會遲到。

+0

我一直在研究這個項目已經很長時間了,而且這個項目已經被另外一些人採納了,而這些人則朝不同的方向發展。無論如何,感謝您使用示例代碼的明確答案,非常感謝,也許別人會發現它非常有用:) – OzBarry

0

難道你很難在Record directshow audio device to file管理DirectShow的音頻採集?

與媒體基金會捕獲幾乎沒有任何簡單。甚至不提的是,一般有DirectShow的在那裏有更多的資源....

MSDN爲您提供WavSink Sample實現音頻採集到的文件:

展示瞭如何實現一個自定義的媒體宿在Microsoft媒體基礎。該示例實現了將未壓縮PCM音頻寫入.wav文件的歸檔接收器。

我不知道他們爲什麼決定不把它作爲標準組件。媒體基金會在許多方面不如DirectShow,他們至少可以把這個小事看作是一個優勢。無論如何,你有樣品,它看起來像一個好的開始。

+0

是的,我注意到WavSink的例子,它的問題實際上是一個轉碼器;它需要一個pcm音頻文件,並將其轉換爲* .wav文件,因此它並不真正告訴我如何直接從設備獲取音頻數據。 我正在使用directshow,但我的老闆嚴重鼓勵我(閱讀告訴我)使用媒體基礎。 – OzBarry

+0

無論如何它給你最重要的一塊。是的,您需要使拓撲不進行代碼轉換,而是使用真正的音頻捕獲設備。 –