2012-10-16 11 views
5

Sto usando Windows Media Foundation API per enumerare sia i miei microfoni che le telecamere disponibili, che funzionano entrambe.Windows Media Foundation registrazione audio

Ecco il mio codice di enumerazione:

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; 
} 

Per afferrare dispositivi audio o catturare macchina fotografica, ho specificare MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID o MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID e che funziona senza alcun problema, e posso afferrare i nomi dei dispositivi, così come l'IMFActivate. Ho il codice per registrare la webcam su un file video di output, tuttavia, mi sto divertendo a capire come registrare l'audio in un file. Ho l'impressione che ho bisogno di utilizzare un IMFSinkWriter, ma non riesco a trovare alcun esempio che utilizza un'acquisizione audio IMFActivate e IMFSinkWriter.

Non sono un programmatore di Windows Api, quindi sono sicuro che ci sia una risposta abbastanza semplice, ma la roba della COM è un po 'sopra la mia testa. Per quanto riguarda il formato audio, non mi interessa, a patto che entri in un file, possa essere wav, wma o altro. Anche se sto registrando video, ho bisogno di separare i file video e audio, quindi non riesco a capire come aggiungere l'audio alla mia codifica video.

risposta

7

Mi scuso per la risposta in ritardo, e spero che tu possa ancora trovare questo prezioso. Di recente ho completato un progetto simile al tuo (registrando video in webcam insieme a un microfono selezionato in un singolo file video con audio). La chiave è creare una fonte multimediale aggregata.

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

Quando si configura il sink writer, verranno aggiunti 2 flussi (uno per l'audio e uno per il video). Naturalmente, si configurerà anche il writer correttamente per i tipi di flusso di input.

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

Poi, quando la lettura dei campioni, è necessario prestare molta attenzione al streamIndex lettore, e inviarli allo scrittore in modo appropriato. Dovrai inoltre prestare molta attenzione al formato che il codec si aspetta. Ad esempio, IEEE float vs PCM, ecc. Buona fortuna, e spero che non sia troppo tardi.

+0

È passato molto tempo da quando ho lavorato a quel progetto e da allora è stato preso in carico da altre persone che lo hanno preso in una direzione diversa. Indipendentemente da ciò, grazie per la risposta chiara con il codice di esempio, è molto apprezzato, e forse qualcun altro lo troverà molto utile :) – OzBarry

0

Hai avuto difficoltà a gestire l'acquisizione audio di DirectShow in Record directshow audio device to file?

Catturare con Media Foundation non è affatto più semplice. Nemmeno menzionare che, in generale, ci sono molte più risorse su DirectShow là fuori ....

MSDN ti offre una WavSink Sample che implementa la cattura audio in file di:

mostra come implementare un sink di supporto personalizzato in Microsoft Media Foundation. L'esempio implementa un sink di archivio che scrive l'audio PCM non compresso in un file .wav.

Non sono sicuro del motivo per cui hanno deciso di non renderlo un componente standard. Avendo Media Foundation inferiore a DirectShow in molti modi, potrebbero almeno rendere questa piccola cosa un vantaggio. Ad ogni modo, hai il campione e sembra un buon inizio.

+0

Sì, ho notato l'esempio di WavSink, il problema è che in realtà è un transcodificatore; prende un file audio pcm e lo converte in un file * .wav, quindi in realtà non mi dice come ottenere effettivamente i dati audio direttamente da un dispositivo. Stavo usando directshow, ma il mio capo mi ha fortemente incoraggiato (leggi come mi è stato detto) di usare le fondamenta dei media. – OzBarry

+0

Ti dà comunque il pezzo più importante.Sì, è necessario rendere la topologia non transcodifica, ma utilizzare un dispositivo di acquisizione audio reale. –