Capture audio/vidéo dans Media Foundation
Microsoft Media Foundation prend en charge la capture audio et vidéo. Les appareils de capture vidéo sont pris en charge via le pilote de classe UVC et doivent être compatibles avec UVC 1.1. Les appareils de capture audio sont pris en charge via l’API de session audio Windows (WASAPI).
Un appareil de capture est représenté dans Media Foundation par un objet source multimédia, qui expose l’interface IMFMediaSource. Dans la plupart des cas, l’application n’utilise pas directement cette interface, mais une API de niveau supérieur telle que le lecteur source pour contrôler l’appareil de capture.
Énumérer les appareils de capture
Pour énumérer les appareils de capture sur le système, procédez comme suit :
Appelez la fonction MFCreateAttributes pour créer un magasin d’attributs.
Définissez l’attribut MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE sur l’une des valeurs suivantes :
Valeur Description MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID Énumérer les appareils de capture audio. MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID Énumérez les appareils de capture vidéo. Appelez la fonction MFEnumDeviceSources. Cette fonction alloue un tableau de pointeurs IMFActivate. Chaque pointeur représente un objet d’activation pour un appareil sur le système.
Appelez la méthode IMFActivate::ActivateObject pour créer une instance de la source multimédia à partir de l’un des objets d’activation.
L’exemple suivant crée une source multimédia pour le premier appareil de capture vidéo dans la liste d’énumérations :
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;
}
Vous pouvez interroger les objets d’activation pour différents attributs, notamment :
- L’attribut MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME contient le nom complet de l’appareil. Le nom complet convient à l’affichage de l’utilisateur, mais peut ne pas être unique.
- Pour les appareils vidéo, l’attribut MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK contient le lien symbolique vers l’appareil. Le lien symbolique identifie de manière unique l’appareil sur le système, mais n’est pas une chaîne lisible.
- Pour les appareils audio, l’attribut MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID contient l’ID de point de terminaison audio de l’appareil. L’ID de point de terminaison audio est similaire à un lien symbolique. Il identifie de manière unique l’appareil sur le système, mais n’est pas une chaîne lisible.
L’exemple suivant prend un tableau de pointeurs IMFActivate et affiche le nom complet de chaque appareil dans la fenêtre de débogage :
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);
}
}
Si vous connaissez déjà le lien symbolique d’un appareil vidéo, il existe une autre façon de créer la source multimédia pour cet appareil :
- Appelez MFCreateAttributes pour créer un magasin d’attributs.
- Définissez l’attribut MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE sur MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID.
- Définissez l’attribut MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK sur le lien symbolique.
- Appelez la fonction MFCreateDeviceSource ou MFCreateDeviceSourceActivate. La première renvoie un pointeur IMFMediaSource. La dernière renvoie un pointeur IMFActivate vers un objet d’activation. Vous pouvez utiliser l’objet d’activation pour créer la source. (Un objet d’activation peut être marshalé vers un autre processus. Il est donc utile de créer la source dans un autre processus. Pour plus d’informations, consultez Objets d’activation.)
L’exemple suivant prend le lien symbolique d’un appareil vidéo et crée une source multimédia.
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;
}
Il existe un moyen équivalent de créer un périphérique audio à partir de l’ID de point de terminaison audio :
- Appelez MFCreateAttributes pour créer un magasin d’attributs.
- Définissez l’attribut MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE sur MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID.
- Définissez l’attribut MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_ENDPOINT_ID sur l’ID de point de terminaison.
- Appelez la fonction MFCreateDeviceSource ou MFCreateDeviceSourceActivate.
L’exemple suivant prend un ID de point de terminaison audio et crée une source multimédia.
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;
}
Utiliser un appareil de capture
Après avoir créé la source multimédia d’un appareil de capture, utilisez le lecteur source pour extraire des données de cet appareil. Le lecteur source fournit des exemples multimédias qui contiennent les données audio de capture ou les images vidéo. L’étape suivante dépend de votre scénario d’application :
- Aperçu vidéo : utilisez Microsoft Direct3D ou Direct2D pour afficher la vidéo.
- Capture de fichier : utilisez l’enregistreur récepteur pour encoder le fichier.
- Aperçu audio : utilisez WASAPI.
Si vous souhaitez combiner la capture audio avec la capture vidéo, utilisez la source multimédia d’agrégation. La source multimédia d’agrégation contient une collection de sources multimédias et combine tous leurs flux dans un seul objet source multimédia. Pour créer une instance de la source multimédia d’agrégation, appelez la fonction MFCreateAggregateSource.
Arrêter l’appareil de capture
Lorsque l’appareil de capture n’est plus nécessaire, vous devez l'arrêter en appelant Arrêt sur l’objet IMFMediaSource que vous avez obtenu en appelant MFCreateDeviceSource ou IMFActivate::ActivateObject. L’échec de l’appel Arrêt peut entraîner des fuites de mémoire, car le système peut conserver une référence aux ressources IMFMediaSource jusqu’à ce que Arrêt soit appelé.
if (g_pSource)
{
g_pSource->Shutdown();
g_pSource->Release();
g_pSource = NULL;
}
Si vous avez alloué une chaîne contenant le lien symbolique à un appareil de capture, vous devez également libérer cet objet.
CoTaskMemFree(g_pwszSymbolicLink);
g_pwszSymbolicLink = NULL;
g_cchSymbolicLink = 0;
Rubriques connexes