Introduction à Media Foundation - Comprendre l'API à travers le prisme COM
· Mis à jour le: · Go Komura · Media Foundation, COM, C++, Développement Windows
Quand on commence à utiliser Media Foundation, on a facilement l’impression que « je pensais utiliser les API vidéo et audio de Windows, et voilà que tout devient soudain une histoire de COM ». CoInitializeEx, MFStartup, IMFSourceReader, IMFMediaType, IMFTransform, IMFActivate, HRESULT, les GUID, etc. arrivent tous en même temps, l’atmosphère prend brusquement des allures de Win32/COM, et ce qu’est réellement Media Foundation devient difficile à percevoir.
Plutôt que de couvrir l’ensemble de Media Foundation comme un dictionnaire, cet article se concentre sur trois points.
- Pourquoi les notions COM apparaissent-elles naturellement lorsqu’on utilise Media Foundation ?
- À quels endroits la teinte COM s’intensifie-t-elle ?
- Par où commencer au départ - Source Reader / Sink Writer / Media Session / MFT ?
Les exemples de code sont basés sur le C++, mais la façon de penser reste globalement la même lorsqu’on y accède via un wrapper depuis .NET ou un autre langage.
Table des matières
- La conclusion d’abord (en une phrase)
- Les tableaux de repère à consulter en premier
- 2.1. Que toucher selon ce que l’on veut faire
- 2.2. Où l’API prend-elle un visage COM
- 2.3. Les termes à connaître avant tout
- Vue d’ensemble de Media Foundation (schéma)
- Les points où Media Foundation prend un visage COM
- 4.1.
CoInitializeExetMFStartupcôte à côte à l’initialisation - 4.2. Les échanges d’objets sont centrés sur les interfaces
- 4.3. L’apparition des Activation Objects
- 4.4. Les paramètres et les informations de type centrés sur
IMFAttributeset les GUID - 4.5. L’asynchrone, les callbacks et les threads gérés à la manière COM
- 4.6. Mais Media Foundation ≠ COM
- 4.1.
- Guide rapide pour choisir
- 5.1. Commencer par le Source Reader
- 5.2. Écrire dans un fichier avec le Sink Writer
- 5.3. Gérer la lecture et la synchronisation avec la Media Session
- 5.4. Insérer des composants personnalisés avec un MFT
- Liste de vérification pour la pratique
- Extraits de code
- 7.1. Initialisation
- 7.2. Créer un Source Reader en mode synchrone
- 7.3. Créer un Source Reader en mode asynchrone
- 7.4. Énumérer et instancier des MFT avec
MFTEnumEx
- Conclusion
- Références
1. La conclusion d’abord (en une phrase)
- Media Foundation est une plateforme destinée à traiter la vidéo et l’audio ; l’API dans son ensemble n’est pas, en tant que telle, purement du COM
- Cependant, les frontières entre source, transform, sink, activation, attributes et callback sont exprimées via des interfaces COM, si bien que les notions d’
IUnknown,HRESULT, GUID et apartment apparaissent naturellement lorsqu’on l’utilise - Il est plus simple de commencer par le Source Reader / Sink Writer, de passer à la Media Session lorsque le contrôle de la lecture devient nécessaire, puis au MFT lorsqu’un convertisseur personnalisé est requis
En somme, Media Foundation est une plateforme de traitement multimédia dont les frontières sont profondément imprégnées de COM.
En gardant cela à l’esprit dès le départ, la question « pourquoi cela prend-il soudain un visage COM ? » devient beaucoup plus claire.
2. Les tableaux de repère à consulter en premier
2.1. Que toucher selon ce que l’on veut faire
Consulter d’abord ce tableau facilite le choix du point d’entrée.
| Ce que vous voulez faire | À toucher en premier | Intensité COM | Remarque |
|---|---|---|---|
| Récupérer des trames / échantillons depuis un fichier ou une caméra | Source Reader | Moyenne | Prend en charge le decoder si nécessaire |
| Écrire l’audio / la vidéo généré(e) dans un fichier | Sink Writer | Moyenne | Peut regrouper l’encoder et le media sink si nécessaire |
| Gérer la lecture, l’arrêt, le seek, la synchronisation A/V et le contrôle de qualité | Media Session | Élevée | Nécessite de comprendre la topology et la session |
| Insérer un convertisseur personnalisé ou un composant de type codec | MFT | Élevée | Raisonner autour d’IMFTransform |
| Examiner les candidats énumérés avant d’instancier uniquement ceux dont vous avez besoin | IMFActivate |
Élevée | Ce qui est renvoyé peut être un activation object plutôt que l’objet réel |
2.2. Où l’API prend-elle un visage COM
| Point | Ce qui apparaît | À comprendre en premier |
|---|---|---|
| Initialisation | CoInitializeEx, MFStartup |
L’initialisation COM et l’initialisation Media Foundation sont distinctes |
| Création et transmission d’objets | IMFSourceReader, IMFMediaType, IMFTransform |
La plupart sont des pointeurs d’interface + HRESULT |
| Paramètres | IMFAttributes, GUID |
Les valeurs de configuration et les informations de type sont exprimées en paires clé/valeur + GUID |
| Énumération et création différée | IMFActivate, ActivateObject |
Le résultat de l’énumération n’est pas toujours l’objet réel |
| Asynchrone | IMFSourceReaderCallback, work queue |
Il faut être attentif aux callbacks et aux apartments |
| Contrôle de la lecture | topology, Media Session | Le flux global du pipeline est un concept propre à Media Foundation |
2.3. Les termes à connaître avant tout
| Terme | Signification ici |
|---|---|
| Media Source | Le point d’entrée qui alimente le pipeline en données multimédias : fichiers, réseau, périphériques de capture, etc. |
| MFT | Media Foundation Transform. Le modèle commun pour les décodeurs, encodeurs, convertisseurs vidéo, etc. |
| Media Sink | La destination des données multimédias : affichage à l’écran, sortie audio, écriture de fichier, etc. |
| Media Session | Le mécanisme qui gère le flux de l’ensemble du pipeline ; responsable de la lecture et de la synchronisation |
| Topology | Le schéma de connexion décrivant comment relier source, transform et sink |
| Activation Object | Un objet auxiliaire permettant de créer l’objet réel ultérieurement ; représenté par IMFActivate |
| Attributes | Un magasin clé/valeur indexé par des GUID ; largement utilisé dans l’ensemble de Media Foundation |
Avoir déjà ce vocabulaire en tête réduit considérablement les points d’achoppement lors de la lecture de la documentation.
3. Vue d’ensemble de Media Foundation (schéma)
Vu dans son ensemble, Media Foundation est avant tout une histoire de pipeline multimédia. L’aspect COM est important, mais il est plus facile de s’organiser en regardant d’abord la vue d’ensemble.
flowchart TB
subgraph Pipeline["Modèle utilisant le pipeline complet"]
Source1["Media Source"] --> Transform1["MFT"]
Transform1 --> Sink1["Media Sink"]
Session["Media Session"] --- Source1
Session --- Transform1
Session --- Sink1
end
subgraph Direct["Modèle où l'application gère les données directement"]
Source2["Media Source"] --> Reader["Source Reader (+ decoder)"]
App["Application"] --> Writer["Sink Writer (+ encoder)"]
Writer --> Sink2["Media Sink"]
end
Media Foundation propose globalement deux modes d’utilisation.
- Le modèle utilisant le pipeline complet
- Vous connectez source, transform et sink, et la Media Session gère le flux de données et la synchronisation A/V
- Le modèle où l’application gère les données directement
- Vous extrayez les données d’une source avec le Source Reader, puis les transmettez à un sink avec le Sink Writer
Le second est plus facile à aborder lorsque vous souhaitez traiter vous-même les trames ou les échantillons. À l’inverse, si vous voulez confier la lecture et la synchronisation à la plateforme, le premier est la voie naturelle.
Ce qu’il faut retenir, c’est que Media Foundation est, au fond, une plateforme de traitement multimédia - ce qui diffère légèrement de la sensation de manipuler directement un ensemble d’objets COM.
Cependant, dès que l’on commence à observer les frontières entre ces composants, le visage COM s’intensifie soudainement. Le chapitre suivant passe ces points en revue un par un.
4. Les points où Media Foundation prend un visage COM
4.1. CoInitializeEx et MFStartup côte à côte à l’initialisation
C’est le premier endroit où beaucoup de gens ressentent une étrangeté. Avant même de parler d’ouvrir un fichier ou de capturer depuis une caméra, CoInitializeEx et MFStartup apparaissent.
CoInitializeExinitialise la bibliothèque COMMFStartupinitialise la plateforme Media Foundation
Autrement dit, l’initialisation COM seule ne suffit pas - l’initialisation côté Media Foundation est également nécessaire. C’est là qu’on comprend : « ce n’est pas juste une API vidéo, il y a en dessous un contrat basé sur COM assez substantiel ».
En pratique, décider des points suivants à ce stade facilite grandement la suite.
- Quel thread utilise Media Foundation ?
- Ce thread doit-il être en STA ou en MTA ?
- Qui a la responsabilité de
MFStartup/MFShutdownainsi que deCoInitializeEx/CoUninitialize?
Si l’on avance en laissant cette conception dans le flou, cela devient source de confusion plus tard, au niveau des callbacks et de l’intégration avec l’interface utilisateur.
4.2. Les échanges d’objets sont centrés sur les interfaces
En parcourant les API de Media Foundation, on constate que la plupart des valeurs de retour et des paramètres de sortie sont des interfaces COM.
IMFSourceReaderIMFMediaTypeIMFTransformIMFActivateIMFSampleIMFMediaBuffer
Ce qui est caractéristique, c’est que non seulement les données elles-mêmes, mais aussi les informations de type et les objets de configuration sont exprimés via des interfaces.
Par exemple :
IMFTransformest l’interface représentant un MFTIMFAttributesest un magasin clé/valeurIMFMediaTypehérite d’IMFAttributeset constitue une « description du format multimédia »
Même quelque chose d’aussi proche d’une donnée de configuration qu’un media type est ainsi porté par une interface COM. C’est ici que le contexte d’IUnknown, QueryInterface, AddRef / Release et HRESULT s’introduit naturellement.
flowchart TD
IUnknown["IUnknown"]
IUnknown --> IMFAttributes["IMFAttributes"]
IMFAttributes --> IMFMediaType["IMFMediaType"]
IMFAttributes --> IMFActivate["IMFActivate"]
IUnknown --> IMFSourceReader["IMFSourceReader"]
IUnknown --> IMFTransform["IMFTransform"]
Arrivé ici, on commence à percevoir : « Media Foundation est une API multimédia, mais la façon dont elle exprime ses frontières est résolument COM ».
4.3. L’apparition des Activation Objects
C’est dans les activation objects que le caractère COM de Media Foundation se manifeste le plus fortement.
IMFActivate est un objet auxiliaire permettant de créer l’objet réel ultérieurement. Intuitivement, il est plus simple de le voir comme quelque chose de proche d’une class factory COM.
Dans les situations où il apparaît, la valeur retournée par une API d’énumération n’est pas « l’objet réel directement utilisable », mais, dans un premier temps, un tableau d’IMFActivate*.
On instancie ensuite uniquement ce dont on a besoin avec ActivateObject.
sequenceDiagram
participant App as Application
participant Enum as API d'énumération
participant Act as IMFActivate
participant Obj as IMFTransform / sink, etc.
App->>Enum: Appelle l'énumération
Enum-->>App: Tableau d'IMFActivate*
App->>Act: Consulte les attributs
App->>Act: ActivateObject(...)
Act-->>App: L'objet COM réel
Cette structure s’accorde bien avec le fait que Media Foundation est conçu pour découvrir a posteriori des composants interchangeables et les assembler.
De plus, comme l’activation object lui-même peut porter des attributes, le déroulement tend naturellement à suivre l’ordre suivant : « examiner d’abord les attributs des candidats », « les configurer si nécessaire », « les instancier plus tard ». C’est là encore très COM.
4.4. Les paramètres et les informations de type centrés sur IMFAttributes et les GUID
En manipulant Media Foundation, on arrive à un point où les paramètres semblent soudain n’être qu’un amas de GUID. Au centre de cela se trouve IMFAttributes, un magasin clé/valeur indexé par des GUID. Il est utilisé extrêmement fréquemment dans l’ensemble de Media Foundation.
IMFMediaType est particulièrement important : il hérite d’IMFAttributes et porte les informations de format multimédia sous forme d’attributs.
Il s’agit par exemple des informations suivantes.
- Le major type (audio ou vidéo)
- Le subtype (H.264, AAC, RGB32, PCM, etc.)
- La taille des trames
- La fréquence d’images
- La fréquence d’échantillonnage
- Le nombre de canaux
flowchart LR
MediaType["IMFMediaType"] --> Major["MF_MT_MAJOR_TYPE"]
MediaType --> Subtype["MF_MT_SUBTYPE"]
MediaType --> Detail["Taille / FPS / fréquence d'échantillonnage, etc."]
On a facilement l’impression d’une « forêt de GUID » à ce stade, mais ce qui se passe réellement est assez direct.
- Les paramètres sont portés par un magasin d’attributs
- Le media type est lui aussi exprimé comme un magasin d’attributs
- Le format est négocié entre source, transform et sink en consultant ces attributs
Il s’agit simplement du fait que des interfaces de type COM et des GUID sont utilisés pour exprimer les paramètres et les informations de type.
4.5. L’asynchrone, les callbacks et les threads gérés à la manière COM
Ce qui est facile à négliger dans la pratique de Media Foundation, c’est le traitement asynchrone et le modèle de threads.
Par exemple, le Source Reader est par défaut en mode synchrone. En mode synchrone, ReadSample bloque.
Selon l’état du fichier, du réseau ou du périphérique, cette attente peut devenir sensiblement perceptible.
Pour passer en mode asynchrone, vous transmettez un callback lors de la création du Source Reader.
Le déroulement consiste à préparer un objet implémentant IMFSourceReaderCallback, à le définir dans l’attribut MF_SOURCE_READER_ASYNC_CALLBACK, puis à créer le reader.
Un point encore un peu plus important est l’apartment. Le traitement asynchrone de Media Foundation utilise une work queue, et le thread de la work queue est en MTA. Par conséquent, l’implémentation devient plus simple si l’application est également traitée en MTA.
sequenceDiagram
participant App as Thread applicatif
participant Reader as Source Reader
participant Queue as MF work queue (MTA)
participant Cb as IMFSourceReaderCallback
App->>Reader: ReadSample(...)
Reader-->>App: Retourne immédiatement
Reader->>Queue: Traite en interne
Queue->>Cb: OnReadSample(...)
Voici les points à surveiller autour des callbacks.
- Ne pas toucher directement, depuis le callback, aux objets STA du thread d’interface utilisateur
- Rendre l’implémentation du callback thread-safe
- Si une mise à jour de l’interface est nécessaire, ne renvoyer que le résultat vers le thread d’interface utilisateur
- Fixer d’emblée dans son esprit la question : « de quel thread proviennent les callbacks de Media Foundation ? »
Media Foundation n’absorbe pas automatiquement les contraintes des objets STA à votre place. Il est donc plus simple de s’organiser en orientant le worker qui utilise Media Foundation vers le MTA, et en construisant un pont explicite vers l’interface utilisateur.
4.6. Mais Media Foundation ≠ COM
Après avoir lu jusqu’ici, on est tenté de penser que « Media Foundation n’est finalement rien d’autre que du COM ». Mais ce n’est pas tout à fait exact.
Media Foundation possède des concepts propres à la plateforme qui ne se réduisent pas aux généralités de COM.
MFStartup/MFShutdown- Media Session
- Topology
- Le topology loader
- La presentation clock
- Source Reader / Sink Writer
Ce sont là les propres attributions de Media Foundation : comment faire circuler le pipeline multimédia.
Par exemple, dans la Media Session, lorsque l’application transmet une partial topology, le topology loader complète les transforms nécessaires pour la résoudre en une full topology. Il ne s’agit pas là d’une généralité COM, mais d’une fonctionnalité que Media Foundation possède en tant que plateforme de traitement multimédia.
flowchart LR
Partial["Partial Topology<br/>Source -> Output"] --> Loader["Topology Loader"]
Loader --> Full["Full Topology<br/>Source -> Decoder MFT -> Output"]
Media Foundation utilise COM pour exprimer les contrats entre ses composants, tout en fonctionnant, par-dessus, comme une plateforme de traitement multimédia. Garder cette vision à deux niveaux évite de s’y perdre.
5. Guide rapide pour choisir
Pour décider du premier point d’entrée, le schéma suivant suffit souvent.
flowchart TD
Start["Ce que vous voulez faire"] --> Q1{"De quoi avez-vous besoin en premier ?"}
Q1 -- "Lire des trames / échantillons" --> A1["Source Reader"]
Q1 -- "Écrire dans un fichier" --> A2["Sink Writer"]
Q1 -- "Besoin de contrôle de lecture ou de sync A/V" --> A3["Media Session"]
Q1 -- "Insérer un convertisseur personnalisé" --> A4["MFT"]
5.1. Commencer par le Source Reader
Le Source Reader est un point d’entrée très accessible lorsqu’on veut extraire des données de fichiers ou de périphériques.
Il convient par exemple aux cas suivants.
- Récupérer des trames depuis un fichier vidéo
- Décoder un fichier audio pour en extraire des échantillons
- Récupérer des trames depuis une caméra
- Connecter une source Media Foundation à votre propre pipeline de traitement
Le Source Reader charge un decoder si nécessaire et transmet les données à l’application. En revanche, il ne prend pas en charge la gestion de la presentation clock, la synchronisation A/V, ni le rendu à l’écran lui-même.
Il est plus simple de le voir comme un point d’entrée pour « obtenir des données », et non pour « effectuer une lecture ».
5.2. Écrire dans un fichier avec le Sink Writer
Le Sink Writer est le point d’entrée lorsqu’on veut écrire de l’audio ou de la vidéo dans un fichier.
Voici des usages typiques.
- Enregistrer des trames générées dans un fichier vidéo
- Encoder et écrire des échantillons audio
- Convertir des données lues vers un autre format avant de les enregistrer
Le Sink Writer trouve et charge un encoder si nécessaire, et gère le flux de données vers le media sink. Il est souvent combiné avec le Source Reader, mais les deux sont des composants indépendants ; il n’est pas obligatoire de les utiliser ensemble.
5.3. Gérer la lecture et la synchronisation avec la Media Session
Si l’objectif n’est pas « extraire des données d’un fichier » mais assurer une véritable lecture, il est plus naturel de raisonner autour de la Media Session.
La Media Session entre en jeu lorsque vous avez des besoins comme ceux-ci.
- Gérer la lecture / l’arrêt / le seek
- Confier la synchronisation audio-vidéo à la plateforme
- Gérer le pipeline en incluant le contrôle de qualité et les changements de format
- Composer le flux source / transform / sink à l’aide d’une topology
En entrant dans cette couche, on se rapproche du « cœur de Media Foundation » davantage qu’avec le Source Reader / Sink Writer. Les concepts propres à Media Foundation - topology, session event, etc. - se multiplient en conséquence.
5.4. Insérer des composants personnalisés avec un MFT
Le MFT est le modèle commun de Media Foundation pour les transforms.
On y entre dans des situations comme celles-ci.
- Créer son propre décodeur ou encodeur
- Insérer des composants de traitement vidéo ou audio dans le pipeline
- Énumérer les codecs et convertisseurs pour les choisir soi-même
- Exercer un contrôle plus poussé que la résolution automatique par défaut
Dans le monde du MFT, les contrats de type COM occupent une place très importante : IMFTransform, IMFActivate, la media type negotiation, la gestion des samples / buffers.
C’est pourquoi plutôt que d’entrer directement par le MFT comme premier point d’entrée, il est plus clair de d’abord déterminer lequel du Source Reader, du Sink Writer ou de la Media Session est réellement nécessaire.
6. Liste de vérification pour la pratique
Pour finir, voici en un seul tableau les points à vérifier en premier dans la pratique.
| Élément | Ce qu’il faut vérifier | Ce qui risque de se produire en cas d’oubli |
|---|---|---|
| Responsabilité d’initialisation | Décider où appeler CoInitializeEx et MFStartup, et qui gère la finalisation |
Initialisation manquée, confusion dans l’ordre de finalisation |
| Apartment | Décider à l’avance si le thread qui touche MF sera en STA ou en MTA | Confusion autour des callbacks, conflits avec l’interface utilisateur |
| Mode du Source Reader | Décider synchrone ou asynchrone au moment de la création | ReadSample bloque de façon inattendue ; impossible de changer par la suite |
| Media type negotiation | Énumérer les formats de sortie et indiquer explicitement celui réellement utilisé | MF_E_INVALIDMEDIATYPE, réception d’un format différent de celui attendu |
| Durée de vie des objets | Clarifier les responsabilités de Release, Unlock, ShutdownObject |
Fuites mémoire, buffers retenus, incohérences à la fermeture |
| Activation object | Distinguer si le résultat de l’énumération est l’objet réel ou un IMFActivate |
Échec en supposant à tort qu’un QueryInterface est possible |
| Topology | Savoir si l’on manipule une partial topology ou une full topology | Se retrouver bloqué en supposant que « ça devrait se connecter automatiquement » |
| Vérification des erreurs | Vérifier systématiquement HRESULT, les stream flags et les events |
Passer à côté d’un échec partiel |
| Intégration UI | Ne jamais toucher l’interface directement depuis un callback ; ne renvoyer que le résultat vers le thread d’interface utilisateur | Blocages, conditions de concurrence, bogues difficiles à diagnostiquer |
Les trois points suivants sont particulièrement prioritaires.
- Ne pas se tromper sur l’API d’entrée initiale
- Déterminer d’abord lequel du Source Reader, du Sink Writer ou de la Media Session est réellement nécessaire
- Décider l’apartment en premier
- Si l’UI en STA et la work queue de Media Foundation doivent cohabiter, décider d’abord comment construire le pont entre elles
- Ne pas négliger la media type negotiation
- Avancer sur la base d’un « c’est probablement ce format-là » devient très confus par la suite
7. Extraits de code
On ne présente pas ici des exemples complets, mais seulement des extraits suffisants pour repérer où apparaît le visage COM.
7.1. Initialisation
template <class T>
void SafeRelease(T** pp)
{
if (pp != nullptr && *pp != nullptr)
{
(*pp)->Release();
*pp = nullptr;
}
}
HRESULT InitializeMediaFoundationForCurrentThread()
{
HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (FAILED(hr))
{
return hr;
}
hr = MFStartup(MF_VERSION);
if (FAILED(hr))
{
CoUninitialize();
return hr;
}
return S_OK;
}
void UninitializeMediaFoundationForCurrentThread()
{
MFShutdown();
CoUninitialize();
}
Ici, CoInitializeEx et MFStartup sont placés côte à côte.
C’est le tout premier endroit où l’atmosphère COM s’épaissit soudainement lorsqu’on travaille avec Media Foundation.
Dans certaines implémentations, une autre couche peut déjà être responsable de l’initialisation COM. Même dans ce cas, il est plus sûr de fixer à l’avance qui porte cette responsabilité.
7.2. Créer un Source Reader en mode synchrone
HRESULT ReadOneVideoSample(PCWSTR path)
{
IMFSourceReader* pReader = nullptr;
IMFMediaType* pType = nullptr;
IMFSample* pSample = nullptr;
HRESULT hr = MFCreateSourceReaderFromURL(path, nullptr, &pReader);
if (FAILED(hr)) goto done;
hr = MFCreateMediaType(&pType);
if (FAILED(hr)) goto done;
hr = pType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
if (FAILED(hr)) goto done;
hr = pType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32);
if (FAILED(hr)) goto done;
hr = pReader->SetCurrentMediaType(
MF_SOURCE_READER_FIRST_VIDEO_STREAM,
nullptr,
pType);
if (FAILED(hr)) goto done;
DWORD streamFlags = 0;
LONGLONG timestamp = 0;
hr = pReader->ReadSample(
MF_SOURCE_READER_FIRST_VIDEO_STREAM,
0,
nullptr,
&streamFlags,
×tamp,
&pSample);
if (FAILED(hr)) goto done;
// Extraire l'IMFMediaBuffer de pSample et le traiter
done:
SafeRelease(&pSample);
SafeRelease(&pType);
SafeRelease(&pReader);
return hr;
}
Voici ce qui devient visible ici.
- Le reader comme le media type sont des interfaces COM
- Les paramètres sont basés sur des GUID
- Les valeurs de retour sont des
HRESULT - En mode synchrone,
ReadSamplebloque
Même un simple « je veux juste lire une trame » prend, à la frontière de Media Foundation, un visage résolument COM.
7.3. Créer un Source Reader en mode asynchrone
HRESULT CreateSourceReaderAsync(
PCWSTR path,
IMFSourceReaderCallback* pCallback,
IMFSourceReader** ppReader)
{
IMFAttributes* pAttributes = nullptr;
HRESULT hr = MFCreateAttributes(&pAttributes, 1);
if (FAILED(hr))
{
return hr;
}
hr = pAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, pCallback);
if (SUCCEEDED(hr))
{
hr = MFCreateSourceReaderFromURL(path, pAttributes, ppReader);
}
SafeRelease(&pAttributes);
return hr;
}
Ici, pour activer le mode asynchrone, le callback est placé dans les attributs avant que le reader ne soit créé.
Autrement dit :
- Le callback lui-même est une interface COM
- La configuration asynchrone passe par
IMFAttributes - Le mode est fixé au moment de la création
voilà la forme que cela prend.
En pratique, il est important de rendre l’implémentation d’IMFSourceReaderCallback thread-safe et de ne pas y introduire directement d’objets d’interface utilisateur.
7.4. Énumérer et instancier des MFT avec MFTEnumEx
HRESULT FindH264Decoder(IMFTransform** ppTransform)
{
*ppTransform = nullptr;
IMFActivate** ppActivate = nullptr;
UINT32 count = 0;
MFT_REGISTER_TYPE_INFO inputType = {};
inputType.guidMajorType = MFMediaType_Video;
inputType.guidSubtype = MFVideoFormat_H264;
HRESULT hr = MFTEnumEx(
MFT_CATEGORY_VIDEO_DECODER,
MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_LOCALMFT,
&inputType,
nullptr,
&ppActivate,
&count);
if (FAILED(hr))
{
return hr;
}
if (count == 0)
{
CoTaskMemFree(ppActivate);
return MF_E_TOPO_CODEC_NOT_FOUND;
}
hr = ppActivate[0]->ActivateObject(
__uuidof(IMFTransform),
reinterpret_cast<void**>(ppTransform));
for (UINT32 i = 0; i < count; ++i)
{
ppActivate[i]->Release();
}
CoTaskMemFree(ppActivate);
return hr;
}
Ici, le résultat de l’énumération n’est pas renvoyé d’emblée sous forme d’IMFTransform*, mais sous forme d’IMFActivate**.
Ce n’est qu’en appelant ActivateObject que l’on obtient enfin l’IMFTransform réel.
Ce déroulement illustre remarquablement bien cette sensation propre à Media Foundation de « prendre soudain un visage COM ».
8. Conclusion
Ce n’est pas un hasard si les sujets liés à COM se multiplient soudainement lorsqu’on travaille avec Media Foundation.
- Media Foundation est une plateforme de traitement multimédia
- Ses frontières - source, transform, sink, activation, callback, etc. - sont exprimées via des interfaces COM
- C’est pourquoi les sujets
IUnknown,HRESULT, GUID, apartment et callback apparaissent naturellement - Cependant, le cœur de Media Foundation est un pipeline multimédia doté d’une Media Session et de topologies - ce n’est pas une simple reformulation de COM
En pratique, réfléchir dans l’ordre suivant permet de bien s’organiser.
- Déterminer avant tout lequel du Source Reader, du Sink Writer, de la Media Session ou du MFT est nécessaire
- Décider en amont la politique concernant l’apartment et les callbacks
- Traiter avec soin la media type negotiation et la durée de vie des objets
Il n’est pas nécessaire de tout comprendre dès le départ. En gardant d’abord à l’esprit que « Media Foundation est une plateforme de traitement multimédia, avec COM profondément intégré à ses frontières », la documentation comme le code deviennent beaucoup plus faciles à suivre.
9. Références
- Media Foundation and COM - Microsoft Learn
- Overview of the Media Foundation Architecture - Microsoft Learn
- Initializing Media Foundation - Microsoft Learn
- Source Reader - Microsoft Learn
- Using the Source Reader to Process Media Data - Microsoft Learn
- Using the Source Reader in Asynchronous Mode - Microsoft Learn
- Sink Writer - Microsoft Learn
- Activation Objects - Microsoft Learn
- About Topologies - Microsoft Learn
- IMFAttributes interface - Microsoft Learn
- IMFMediaType interface - Microsoft Learn
- IMFTransform interface - Microsoft Learn
- MFTEnumEx function - Microsoft Learn
-
[Notions de base sur STA/MTA en COM pour éviter les blocages KomuraSoft Blog](https://comcomponent.com/fr/blog/2026/01/31/000-sta-mta-com-relationship/) -
[Pourquoi créer un wrapper C++/CLI pour utiliser une DLL native C++ depuis C# KomuraSoft Blog](https://comcomponent.com/fr/blog/2026/03/07/000-cpp-cli-wrapper-for-native-dlls/)
Articles associés
Articles récents partageant les mêmes étiquettes, pour approfondir des sujets proches.
Comment incruster une image et du texte dans les images d'une vidéo MP4 avec Media Foundation
Comment incruster une image et du texte dans chaque image d'une vidéo MP4 avec Media Foundation pour produire un nouveau MP4, en structur...
Comment convertir du YUV en RGB avec Media Foundation
Comment convertir des trames YUV en RGB avec Media Foundation : la conversion automatique du Source Reader vers RGB32, ou la conversion m...
Extraire une image fixe d'un MP4 à un instant précis avec Media Foundation
Comment récupérer, avec le Source Reader, la frame la plus proche d'un instant donné dans un MP4, corriger le stride et l'octet alpha du ...
Compatibilité descendante des interfaces DLL et COM — Tableau de décision : quels changements cassent les appelants
Quels changements apportés à une DLL ou à un composant COM cassent réellement leurs appelants ? Nous détaillons les trois niveaux de comp...
Les applications métier fonctionnent-elles sous Windows on Arm ? — La réalité de l'émulation x64 (Prism) et des DLL/COM natifs
Une réponse, destinée aux développeurs et aux services informatiques, à la question « notre application métier fonctionnera-t-elle sous W...
Sujets associés
Ces pages replacent le sujet dans un contexte plus large de services et de décisions.
Thèmes techniques Windows
Portail des sujets sur le développement Windows, l'analyse des incidents et la valorisation des actifs existants.
Migration ActiveX
Choisir de conserver, encapsuler ou remplacer des composants COM / ActiveX / OCX.
Services liés à ce sujet
Cet article est directement lié aux services suivants.
Développement d'applications Windows
Le traitement multimédia Windows impliquant Media Foundation, COM et HRESULT est proche des thématiques d'implémentation que nous traitons dans le cadre du développement d'applications Windows.
Conseil technique et revue de conception
Si vous souhaitez d'abord clarifier les frontières de type COM et l'ordre d'initialisation, nous pouvons intervenir côté conception via une consultation technique et une revue de conception.
Questions fréquentes
Questions souvent posées lors d’une consultation sur le sujet de cet article.
- Qu'est-ce que Media Foundation ? Est-ce différent de COM ?
- Media Foundation est une plateforme de traitement multimédia de Windows pour gérer la vidéo et l'audio ; l'API dans son ensemble n'est pas purement du COM en tant que tel. Cependant, les frontières entre les composants tels que source, transform, sink, activation, attributes et callback sont exprimées via des interfaces COM, si bien que les notions d'IUnknown, HRESULT, GUID et apartment apparaissent naturellement lorsqu'on l'utilise. Il est plus exact de la considérer comme « une plateforme de traitement multimédia dont les frontières sont profondément imprégnées de COM ».
- Pourquoi faut-il à la fois MFStartup et CoInitializeEx ?
- Parce que leurs rôles sont différents. CoInitializeEx initialise la bibliothèque COM, tandis que MFStartup initialise la plateforme Media Foundation. L'initialisation COM seule ne suffit pas ; l'initialisation côté Media Foundation est également nécessaire. En pratique, décider à l'avance quel thread utilise Media Foundation, s'il doit être en STA ou en MTA, et qui a la responsabilité de MFStartup / MFShutdown ainsi que de CoInitializeEx / CoUninitialize facilite grandement la gestion ultérieure des callbacks et de l'intégration avec l'interface utilisateur.
- Comment choisir entre Source Reader, Sink Writer, Media Session et MFT ?
- Si vous voulez extraire des trames ou des échantillons d'un fichier ou d'une caméra, le Source Reader est le point d'entrée. Si vous voulez écrire de l'audio ou de la vidéo générés dans un fichier, c'est le Sink Writer. Si vous voulez confier à la plateforme la lecture, l'arrêt, le déplacement (seek), la synchronisation audio/vidéo et le contrôle de qualité, il vaut mieux raisonner autour de la Media Session. Pour insérer vos propres décodeurs ou convertisseurs dans le pipeline, vous passez au MFT, mais comme les contrats de type COM y sont très présents, il est recommandé de d'abord vérifier lequel des trois premiers est réellement nécessaire.
- À quoi faut-il faire attention avec les callbacks asynchrones de Media Foundation ?
- Le traitement asynchrone de Media Foundation utilise une work queue dont le thread est en MTA ; l'implémentation devient donc plus simple si le côté application se rapproche également du MTA. Il est important de rendre l'implémentation d'IMFSourceReaderCallback thread-safe et de ne jamais toucher directement, depuis le callback, aux objets STA du thread d'interface utilisateur. Si une mise à jour de l'interface est nécessaire, ne renvoyez que le résultat vers le thread d'interface utilisateur. Il faut également noter que le mode synchrone ou asynchrone du Source Reader est fixé à la création et ne peut plus être modifié par la suite.
Profil de l’auteur
Page de présentation de l’auteur de l’article.
Go Komura
Représentant de KomuraSoft LLC
Spécialisé dans le développement de logiciels Windows, le conseil technique et l’analyse de pannes, notamment pour les systèmes existants et les incidents difficiles à reproduire.
Liens publics