Écriture d’une source multimédia personnalisée

Cette rubrique explique comment implémenter une source multimédia personnalisée dans Microsoft Media Foundation. Il contient les sections suivantes :

Création du descripteur de présentation

La méthode IMFMediaSource::CreatePresentationDescriptor retourne une copie du descripteur de présentation de la source. Pour créer le descripteur de présentation, vous devez connaître le nombre de flux dans le contenu source et les formats possibles de chaque flux. Pour chaque flux, créez un descripteur de flux comme suit :

  1. Créez un tableau de types de médias. Chaque type de média dans le tableau représente un format possible pour le flux. Pour plus d’informations sur la création de types de médias, consultez Types de médias.
  2. Appelez MFCreateStreamDescriptor pour créer le descripteur de flux. Transmettez le tableau des types de média. La fonction retourne un pointeur IMFStreamDescriptor .
  3. Appelez IMFStreamDescriptor::GetMediaTypeHandler pour obtenir le gestionnaire de type de média du descripteur de flux.
  4. Appelez IMFMediaTypeHandler::SetCurrentMediaType pour définir le format de flux par défaut. Utilisez l’un des types de supports que vous avez créés à l’étape 1. En règle générale, vous devez utiliser le format avec la qualité la plus élevée.
  5. Si vous le souhaitez, définissez des attributs sur le descripteur de flux. Pour obtenir la liste des attributs qui s’appliquent aux descripteurs de flux, consultez Attributs de descripteur de flux.

Créez maintenant le descripteur de présentation :

  1. Appelez MFCreatePresentationDescriptor et transmettez le tableau des descripteurs de flux. La fonction retourne un pointeur IMFPresentationDescriptor .
  2. Choisissez la sélection de flux par défaut en appelant IMFPresentationDescriptor::SelectStream pour sélectionner un ou plusieurs flux. Au moins un flux doit être sélectionné dans la configuration par défaut.
  3. Si vous le souhaitez, définissez des attributs sur le descripteur de présentation. Pour obtenir la liste des attributs qui s’appliquent aux descripteurs de flux, consultez Attributs du descripteur de présentation.

Vous devez créer le descripteur de présentation une seule fois, soit au démarrage, soit après que la source a analysé suffisamment de données sources pour déterminer le contenu. La méthode CreatePresentationDescriptor doit retourner une copie du descripteur de présentation. Pour créer la copie, appelez IMFPresentationDescriptor::Clone. Le renvoi d’une copie empêche le client de modifier l’état du descripteur de présentation d’origine, tel que les attributs ou la sélection du flux. Toutefois, n’oubliez pas que Clone crée une copie superficielle, de sorte que le client peut potentiellement modifier les descripteurs de flux sous-jacents.

Démarrage de la source du média

La méthode IMFMediaSource::Start démarre la source du média ou recherche une nouvelle position. Un appel à Démarrer provoque une recherche lorsque l’état précédent a été suspendu ou en cours d’exécution, et qu’une nouvelle heure de début est spécifiée. Sinon, la méthode Start provoque un démarrage. Une fois l’opération De démarrage terminée, envoyez les événements suivants.

  1. Envoyez un événement MENewStream pour chaque nouveau flux, c’est-à-dire chaque flux qui a été précédemment désélectionné et qui est maintenant sélectionné. Les données d’événement sont un pointeur vers le flux.
  2. Envoyez un événement MEUpdatedStream pour chaque flux qui a été sélectionné précédemment et qui est toujours sélectionné. Les données d’événement sont un pointeur vers le flux. (N’envoyez pas d’événement pour les flux désélectionnés.)
  3. Si la source recherche, envoyez un événement MESourceSeeked . Sinon, envoyez un événement MESourceStarted . Les données d’événement sont l’heure de début spécifiée dans la méthode Start . Pour l’événement MESourceStarted, si l’heure de début est VT_EMPTY, définissez l’attribut MF_EVENT_SOURCE_ACTUAL_START sur l’événement. La valeur de l’attribut est l’heure de début réelle.
  4. Pour chaque flux, si la source recherche, envoyez un événement MEStreamSeeked . Sinon, envoyez un événement MEStreamStarted . Les données d’événement sont l’heure de début. (La source multimédia peut mettre en file d’attente un événement sur le flux en appelant la méthode IMFMediaEventGenerator::QueueEvent du flux.)

Lorsqu’un flux est désélectionné, arrêtez le flux. Le flux ne doit plus mettre en file d’attente d’événements à ce stade.

Le format d’heure de la méthode Start est indiqué dans le paramètre pguidTimeFormat . Le format d’heure standard, indiqué par GUID_NULL, est d’unités de 100 nanosecondes. Une source multimédia doit prendre en charge ce format d’heure.

Recherche

Lors de la recherche, la position de début demandée peut ne pas se trouver sur une limite d’échantillon exacte. En outre, pour le contenu compressé, la position de début peut se trouver entre les images clés. Un flux doit remettre des échantillons à partir du point le plus tôt nécessaire pour produire un échantillon non compressé à la position de départ demandée. Pour la vidéo, cela signifie commencer à partir de l’image clé précédente. Le pipeline est chargé de supprimer les trames supplémentaires du décodeur, de sorte que la lecture démarre à l’heure demandée.

L’heure de début indiquée dans les événements sources (MESourceStarted, MESourceSeeked, MEStreamStarted et MEStreamSeeked) est l’heure de début demandée (valeur indiquée dans la méthode Start ), quelle que soit la position de début réelle.

Par exemple, supposons que les premières images d’un flux vidéo présentent les caractéristiques suivantes :

Exemple 1 2 3 4
Temps 33 msec 66 msec 100 msec 133 msec
Image clé ? Oui Non Non Oui

 

Si la méthode Start est appelée avec une valeur de 100 millisecondes, la source doit générer la vidéo à partir de l’image 1, la première image clé antérieure à cette heure. L’événement start indique toujours 100 millisecondes dans les données de l’événement.

Suspension de la source multimédia

La méthode IMFMediaSource::P ause interrompt la source du média.

Pendant que la source est suspendue, un flux peut créer de nouveaux exemples et les stocker dans une file d’attente, mais le flux ne les remet pas. Voici quelques exceptions à cette règle :

  • Les sources dynamiques doivent supprimer les données en pause.
  • Si la source obtient des données d’un réseau, elle peut suspendre le serveur.

Si le client appelle IMFMediaStream::RequestSample pendant que la source est suspendue, la requête est également mise en file d’attente jusqu’à ce que la source soit redémarré. Les demandes ne doivent pas être supprimées.

La suspension est autorisée uniquement à partir de l’état démarré. Sinon, Pause doit retourner MF_E_INVALID_STATE_TRANSITION.

Génération de données sources

Media Foundation utilise un modèle d’extraction, ce qui signifie que les flux génèrent et fournissent des exemples en réponse aux demandes du pipeline. Un flux peut fournir des exemples lorsque la source multimédia est en cours d’exécution et que le flux est sélectionné. Un flux fournit des données uniquement lorsque le client demande un nouvel exemple.

Exemple de demande

Le client demande un nouvel exemple en appelant IMFMediaStream::RequestSample. Voici la séquence d’opérations :

  1. Le client appelle IMFMediaStream::RequestSample. L’argument est un pointeur vers un objet de jeton facultatif que le client utilise pour suivre la demande. Le client implémente le jeton. Les jetons doivent exposer l’interface IUnknown . Le client peut également passer un pointeur NULL au lieu d’un jeton.

  2. Si le client a fourni un jeton, le flux multimédia appelle AddRef sur le jeton et place le jeton dans une file d’attente premier entrant, premier sorti. La méthode retourne et les étapes restantes se produisent de manière asynchrone.

  3. Lorsque davantage de données sont disponibles, le flux multimédia crée un exemple. (Cette étape est décrite plus en détail dans la section suivante.)

  4. Le flux multimédia extrait le premier jeton de la file d’attente.

  5. Si le jeton n’est pas NULL, le flux multimédia définit l’attribut MFSampleExtension_Token sur l’exemple de média. La valeur de l’attribut est un pointeur vers le jeton.

  6. Le flux multimédia envoie un événement MEMediaSample . Les données d’événement sont un pointeur vers l’interface IMFSample de l’exemple.

  7. Si le client a fourni un jeton, le flux multimédia appelle Release sur l’objet jeton.

Si le flux multimédia ne peut pas répondre à la demande RequestSample du client, il extrait le jeton de la file d’attente et appelle Release sur le jeton, mais n’envoie pas d’événement MEMediaSample .

Le client peut utiliser le jeton pour suivre la status de la demande. Lorsque le client reçoit l’événement MEMediaSample , il peut obtenir le jeton à partir de l’exemple et le mettre en correspondance avec la requête d’origine. Le client peut également utiliser le jeton pour détecter si la source du média a supprimé la demande. Si le nombre de références du jeton tombe à zéro et que le flux multimédia n’envoie pas d’événement MEMediaSample, cela signifie que la demande a été supprimée.

Les étapes répertoriées ici supposent que la méthode RequestSample est implémentée en tant qu’opération asynchrone. Si la méthode est synchrone, vous n’avez pas besoin de placer le jeton de demande dans une file d’attente. Toutefois, si la génération de données prend beaucoup de temps, une approche asynchrone est recommandée, par exemple si la source lit des données à partir d’un flux d’octets.

Le flux est chargé de mettre en mémoire tampon toutes les données qui s’accumulent entre les appels à RequestSample.

Lorsque le flux multimédia atteint la fin du flux, il envoie un événement MEEndOfStream après le dernier exemple. Une fois chaque flux terminé, la source multimédia envoie un événement MEEndOfPresentation . Une fois qu’un flux multimédia a envoyé l’événement MEEndOfStream, la méthode RequestSample retourne MF_E_END_OF_STREAM jusqu’à ce que la source soit redémarrée.

Allocation d’exemples

Lorsque le flux est prêt à remplir une demande d’exemple en attente, il crée un exemple et ajoute une ou plusieurs mémoires tampons multimédias à l’exemple. Pour plus d’informations sur la création de mémoires tampons multimédias, consultez Mémoires tampons multimédias.

Le flux doit définir l’horodatage et la durée, s’ils sont connus. L’horodatage est relatif à la source. Dans la plupart des cas, le début du contenu correspond à un horodatage de zéro. Par exemple, si la source lit à partir d’un fichier multimédia, le début du fichier a un horodatage de zéro.

L’horodatage de l’exemple n’est pas nécessairement égal à l’heure de présentation. La session multimédia se traduit de l’heure source à l’heure de présentation. Pour les données compressées, le flux doit générer des données à partir de l’image clé la plus proche avant l’heure de début. Cela permet au décodeur de remettre l’image qui apparaît à l’heure de début demandée. (Sinon, le décodeur doit attendre la trame clé suivante.)

Si la vitesse de lecture est plus rapide ou plus lente que 1,0, le pipeline ajuste la fréquence de l’horloge de présentation. La source n’ajuste pas les horodatages sur les échantillons.

La source peut définir des informations supplémentaires sur l’exemple en définissant des attributs. Pour obtenir la liste des exemples d’attributs, consultez Exemples d’attributs.

Lacunes dans le flux

Si un flux contient un écart de longueur significative, il est recommandé d’envoyer un événement MEStreamTick . Cet événement avertit le client qu’un exemple est manquant. Les données d’événement sont l’horodatage de l’échantillon manquant, en unités de 100 nanosecondes (VT_I8). Cet événement peut empêcher les composants en aval d’attendre des exemples qui n’arriveront pas. Le flux peut envoyer autant d’événements MEStreamTick que nécessaire pour couvrir l’écart dans le flux.

Arrêt de la source multimédia

Lorsque le client a terminé d’utiliser la source multimédia, il appelle IMFMediaSource::Shutdown. À l’intérieur de cette méthode, la source du média doit rompre les nombres de références circulaires. En règle générale, il y a des références circulaires entre la source multimédia et les flux multimédias.

Si vous utilisez la file d’attente d’événements pour implémenter IMFMediaEventGenerator, appelez IMFMediaEventQueue::Shutdown dans la file d’attente d’événements. Cette méthode arrête la file d’attente d’événements et signale tout appelant en attente d’un événement.

Après l’arrêt, toutes les méthodes sur la source retournent MF_E_SHUTDOWN, à l’exception des méthodes IUnknown .

Sources dynamiques

À compter de Windows 7, Media Foundation prend automatiquement en charge les appareils de capture audio et vidéo. Pour la vidéo, l’appareil doit fournir un minidriver de diffusion en continu du noyau (KS) dans la catégorie de capture vidéo. Media Foundation utilise le chemin PnP pour énumérer l’appareil. Pour l’audio, Media Foundation utilise l’API d’appareil multimédia Windows (MMDevice) pour énumérer les appareils de point de terminaison audio. Si l’appareil répond à ces critères, il n’est pas nécessaire d’implémenter une source multimédia personnalisée.

Toutefois, vous souhaiterez peut-être implémenter une source multimédia personnalisée pour un autre type d’appareil ou une autre source de données dynamique. Il n’y a que quelques différences entre une source en direct et d’autres sources multimédias :

  • Dans la méthode IMFMediaSource::GetCharacteristics , retournez l’indicateur MFMEDIASOURCE_IS_LIVE .
  • Le premier échantillon doit avoir un horodatage de zéro.
  • Les événements et les états de diffusion en continu sont gérés de la même façon que les sources multimédias, à l’exception de l’état suspendu.
  • En pause, ne mettez pas en file d’attente les exemples. Supprimez toutes les données générées pendant la pause.
  • Les sources actives ne prennent généralement pas en charge la recherche, la lecture inversée ou le contrôle de débit.

Sources multimédias

Tutoriel : Écriture d’une source multimédia personnalisée