2012-10-16 19 views
5

Używam api z programem Windows Media Foundation do wyliczania zarówno moich mikrofonów, jak i dostępnych kamer, które działają.Nagrywanie dźwięku z programu Windows Media Foundation

Oto mój kod wyliczenie:

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

Aby pobrać urządzeń audio lub przechwytywania kamery, określić zarówno MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID lub MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID i że działa bez problemu, a ja mogę złapać nazwy urządzeń, a także IMFA zmodyfikuj. Mam kod do nagrywania kamery internetowej do wyjściowego pliku wideo, jednak mam trudny czas zastanawia się, jak nagrać audio do pliku. Mam wrażenie, że muszę użyć IMFSinkWriter, ale nie mogę znaleźć żadnych przykładów, które wykorzystują przechwytywanie dźwięku IMFActivate i IMFSinkWriter.

Nie jestem programistą Windows API, więc jestem pewien, że istnieje dość prosta odpowiedź, ale rzeczy COM są tylko trochę ponad moją głową. Jeśli chodzi o format audio, tak naprawdę nie obchodzi mnie, o ile dostanie się do pliku - może być wav, wma lub cokolwiek innego. Mimo że nagrywam wideo, potrzebuję osobnych plików wideo i audio, więc nie mogę po prostu dowiedzieć się, jak dodać dźwięk do mojego kodowania wideo.

Odpowiedz

7

Przepraszam za spóźnioną reakcję i mam nadzieję, że nadal możesz znaleźć to cenne. Niedawno ukończyłem projekt podobny do twojego (nagrywanie wideo z kamery internetowej wraz z wybranym mikrofonem do pojedynczego pliku wideo z dźwiękiem). Kluczem jest stworzenie zagregowanego źródła mediów.

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

Podczas konfiguracji nagrywarki zlewu dodasz 2 strumienie (jeden dla audio i jeden dla wideo). Oczywiście skonfigurujesz również program piszący poprawnie dla typów strumieni wejściowych.

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

Następnie podczas odczytu próbek, trzeba zwrócić szczególną uwagę na streamIndex czytnika i wysyłanie ich do pisarza odpowiednio. Będziesz także musiał zwracać szczególną uwagę na format oczekiwany przez kodek. Na przykład IEEE float vs PCM itd. Powodzenia i mam nadzieję, że nie jest za późno.

+0

Minęło dużo czasu, odkąd pracowałem nad tym projektem, i został on przejęty przez inne osoby, które przyjęły go w innym kierunku. Niezależnie od tego, dzięki za jasną odpowiedź z przykładowym kodem, jest to bardzo doceniane i być może ktoś inny uzna to za bardzo przydatne :) – OzBarry

0

Czy miałeś trudności z zarządzaniem przechwytywaniem audio DirectShow w Record directshow audio device to file?

Przechwytywanie za pomocą Media Foundation nie jest wcale prostsze. Nie wspominając nawet, że w ogóle istnieje wiele więcej zasobów na DirectShow tam ....

MSDN oferuje WavSink Sample który implementuje przechwytywanie audio do pliku:

pokazuje jak zaimplementować zlew zwyczaj mediów w Microsoft Media Foundation. Przykład implementuje ujście archiwum, które zapisuje nieskompresowany dźwięk PCM do pliku .wav.

Nie jestem pewien, dlaczego zdecydowali się nie tworzyć tego standardowego komponentu. Mając Medialną Fundację gorszą od DirectShow na wiele sposobów, mogliby przynajmniej uczynić tę małą rzecz jako zaletę. W każdym razie masz próbkę i wygląda na dobry początek.

+0

Tak, zauważyłem przykład WavSink, problem w rzeczywistości jest transkoderem; pobiera plik audio pcm i konwertuje go do pliku * .wav, więc nie mówi mi, jak faktycznie pobrać dane audio bezpośrednio z urządzenia. Używałem directshow, ale mój szef mocno mnie zachęcał (czytaj, jak mi powiedziałem) z wykorzystaniem fundacji medialnej. – OzBarry

+0

Daje ci najważniejszy kawałek.Tak, musisz uczynić topologię nie transkodować, ale używać prawdziwego urządzenia do przechwytywania dźwięku. –

Powiązane problemy