Acquisizione audio/video in Media Foundation

Microsoft Media Foundation supporta l'acquisizione di audio e video. I dispositivi di acquisizione video sono supportati tramite il driver di classe UVC e devono essere compatibili con UVC 1.1. I dispositivi di acquisizione audio sono supportati tramite l'API sessione audio di Windows (WASAPI).

Un dispositivo di acquisizione è rappresentato in Media Foundation da un oggetto di origine multimediale, che espone l'interfaccia IMFMediaSource . Nella maggior parte dei casi, l'applicazione non userà direttamente questa interfaccia, ma userà un'API di livello superiore, ad esempio lettore di origine per controllare il dispositivo di acquisizione.

Enumerare i dispositivi di acquisizione

Per enumerare i dispositivi di acquisizione nel sistema, seguire questa procedura:

  1. Chiamare la funzione MFCreateAttributes per creare un archivio attributi.

  2. Impostare l'attributo MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE su uno dei valori seguenti:

    Valore Descrizione
    MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID Enumerare i dispositivi di acquisizione audio.
    MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID Enumerare i dispositivi di acquisizione video.

     

  3. Chiamare la funzione MFEnumDeviceSources. Questa funzione alloca una matrice di puntatori IMFActivate. Ogni puntatore rappresenta un oggetto di attivazione per un dispositivo nel sistema.

  4. Chiamare il metodo IMFActivate::ActivateObject per creare un'istanza dell'origine multimediale da uno degli oggetti di attivazione.

L'esempio seguente crea un'origine multimediale per il primo dispositivo di acquisizione video nell'elenco di enumerazione:

HRESULT CreateVideoCaptureDevice(IMFMediaSource **ppSource)
{
    *ppSource = NULL;

    UINT32 count = 0;

    IMFAttributes *pConfig = NULL;
    IMFActivate **ppDevices = NULL;

    // Create an attribute store to hold the search criteria.
    HRESULT hr = MFCreateAttributes(&pConfig, 1);

    // Request video capture devices.
    if (SUCCEEDED(hr))
    {
        hr = pConfig->SetGUID(
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, 
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
            );
    }

    // Enumerate the devices,
    if (SUCCEEDED(hr))
    {
        hr = MFEnumDeviceSources(pConfig, &ppDevices, &count);
    }

    // Create a media source for the first device in the list.
    if (SUCCEEDED(hr))
    {
        if (count > 0)
        {
            hr = ppDevices[0]->ActivateObject(IID_PPV_ARGS(ppSource));
        }
        else
        {
            hr = MF_E_NOT_FOUND;
        }
    }

    for (DWORD i = 0; i < count; i++)
    {
        ppDevices[i]->Release();
    }
    CoTaskMemFree(ppDevices);
    return hr;
}

È possibile eseguire query sugli oggetti di attivazione per vari attributi, tra cui:

  • L'attributo MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME contiene il nome visualizzato del dispositivo. Il nome visualizzato è adatto per mostrare all'utente, ma potrebbe non essere univoco.
  • Per i dispositivi video, l'attributo MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK contiene il collegamento simbolico al dispositivo. Il collegamento simbolico identifica in modo univoco il dispositivo nel sistema, ma non è una stringa leggibile.
  • Per i dispositivi audio, l'attributo MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID contiene l'ID endpoint audio del dispositivo. L'ID dell'endpoint audio è simile a un collegamento simbolico. Identifica in modo univoco il dispositivo nel sistema, ma non è una stringa leggibile.

L'esempio seguente accetta una matrice di puntatori IMFActivate e stampa il nome visualizzato di ogni dispositivo nella finestra di debug:

void DebugShowDeviceNames(IMFActivate **ppDevices, UINT count)
{
    for (DWORD i = 0; i < count; i++)
    {
        HRESULT hr = S_OK;
        WCHAR *szFriendlyName = NULL;
    
        // Try to get the display name.
        UINT32 cchName;
        hr = ppDevices[i]->GetAllocatedString(
            MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
            &szFriendlyName, &cchName);

        if (SUCCEEDED(hr))
        {
            OutputDebugString(szFriendlyName);
            OutputDebugString(L"\n");
        }
        CoTaskMemFree(szFriendlyName);
    }
}

Se si conosce già il collegamento simbolico per un dispositivo video, è possibile creare l'origine multimediale per il dispositivo:

  1. Chiamare MFCreateAttributes per creare un archivio attributi.
  2. Impostare l'attributo MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE su MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID.
  3. Impostare l'attributo MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK sul collegamento simbolico.
  4. Chiamare la funzione MFCreateDeviceSource o MFCreateDeviceSourceActivate. Il primo restituisce un puntatore IMFMediaSource. Quest'ultimo restituisce un puntatore IMFActivate a un oggetto di attivazione. È possibile usare l'oggetto attivazione per creare l'origine. Un oggetto attivazione può essere sottoposto a marshalling in un altro processo, quindi è utile se si vuole creare l'origine in un altro processo. Per altre informazioni, vedere Oggetti attivazione.

L'esempio seguente accetta il collegamento simbolico di un dispositivo video e crea un'origine multimediale.

HRESULT CreateVideoCaptureDevice(PCWSTR *pszSymbolicLink, IMFMediaSource **ppSource)
{
    *ppSource = NULL;
    
    IMFAttributes *pAttributes = NULL;
    IMFMediaSource *pSource = NULL;

    HRESULT hr = MFCreateAttributes(&pAttributes, 2);

    // Set the device type to video.
    if (SUCCEEDED(hr))
    {
        hr = pAttributes->SetGUID(
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
            );
    }


    // Set the symbolic link.
    if (SUCCEEDED(hr))
    {
        hr = pAttributes->SetString(
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
            (LPCWSTR)pszSymbolicLink
            );            
    }

    if (SUCCEEDED(hr))
    {
        hr = MFCreateDeviceSource(pAttributes, ppSource);
    }

    SafeRelease(&pAttributes);
    return hr;    
}

Esiste un modo equivalente per creare un dispositivo audio dall'ID endpoint audio:

  1. Chiamare MFCreateAttributes per creare un archivio attributi.
  2. Impostare l'attributo MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE su MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID.
  3. Impostare l'attributo MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID sull'ID endpoint.
  4. Chiamare la funzione MFCreateDeviceSource o MFCreateDeviceSourceActivate.

L'esempio seguente accetta un ID endpoint audio e crea un'origine multimediale.

HRESULT CreateAudioCaptureDevice(PCWSTR *pszEndPointID, IMFMediaSource **ppSource)
{
    *ppSource = NULL;
    
    IMFAttributes *pAttributes = NULL;
    IMFMediaSource *pSource = NULL;

    HRESULT hr = MFCreateAttributes(&pAttributes, 2);

    // Set the device type to audio.
    if (SUCCEEDED(hr))
    {
        hr = pAttributes->SetGUID(
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID
            );
    }

    // Set the endpoint ID.
    if (SUCCEEDED(hr))
    {
        hr = pAttributes->SetString(
            MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID,
            (LPCWSTR)pszEndPointID
            ); 
    }

    if (SUCCEEDED(hr))
    {
        hr = MFCreateDeviceSource(pAttributes, ppSource);
    }

    SafeRelease(&pAttributes);
    return hr;    
}

Usare un dispositivo di acquisizione

Dopo aver creato l'origine multimediale per un dispositivo di acquisizione, usare lettore di origine per ottenere dati dal dispositivo. Il lettore di origine fornisce esempi multimediali che contengono i dati audio di acquisizione o i fotogrammi video. Il passaggio successivo dipende dallo scenario dell'applicazione:

  • Anteprima video: usare Microsoft Direct3D o Direct2D per visualizzare il video.
  • Acquisizione di file: usare il writer sink per codificare il file.
  • Anteprima audio: usare WASAPI.

Se si vuole combinare l'acquisizione audio con l'acquisizione video, usare l'origine multimediale di aggregazione. L'origine multimediale di aggregazione contiene una raccolta di origini multimediali e combina tutti i flussi in un singolo oggetto di origine multimediale. Per creare un'istanza dell'origine multimediale di aggregazione, chiamare la funzione MFCreateAggregateSource.

Arrestare il dispositivo di acquisizione

Quando il dispositivo di acquisizione non è più necessario, è necessario arrestare il dispositivo chiamando Shutdown sull'oggetto IMFMediaSource ottenuto chiamando MFCreateDeviceSource o IMFActivate::ActivateObject. L'impossibilità di chiamare Shutdown può causare perdite di memoria perché il sistema può mantenere un riferimento alle risorse IMFMediaSource fino a quando non viene chiamato Shutdown.

if (g_pSource)
{
    g_pSource->Shutdown();
    g_pSource->Release();
    g_pSource = NULL;
}

Se è stata allocata una stringa contenente il collegamento simbolico a un dispositivo di acquisizione, è necessario rilasciare anche questo oggetto.

    CoTaskMemFree(g_pwszSymbolicLink);
    g_pwszSymbolicLink = NULL;

    g_cchSymbolicLink = 0;

Acquisizione audio/video