Bien démarrer avec MFPlay

[MFPLAY peut être utilisé dans les systèmes d’exploitation spécifiés dans la section Configuration requise. Il est possible qu’il soit modifié ou indisponible dans les versions ultérieures. ]

MFPlay est une API permettant de créer des applications de lecture multimédia en C++.

Cette rubrique contient les sections suivantes :

Configuration requise

MFPlay nécessite Windows 7.

À propos de MFPlay

MFPlay dispose d’un modèle de programmation simple, tout en présentant les principales fonctionnalités dont la plupart des applications de lecture ont besoin. Une application crée un objet lecteur qui contrôle la lecture. Pour lire un fichier multimédia, l’objet lecteur crée un élément multimédia, qui peut être utilisé pour obtenir des informations sur le contenu du fichier multimédia. L’application contrôle la lecture via des méthodes sur l’interface IMFPMediaPlayer de l’objet lecteur. Si vous le souhaitez, l’application peut recevoir des notifications d’événements via une interface de rappel. Le diagramme suivant illustre ce processus.

conceptual diagram: application and player point to each other, both point to media item, which points to media file

Lecture d’un fichier multimédia

Pour lire un fichier multimédia, appelez la fonction MFPCreateMediaPlayer.

// Global variables
IMFPMediaPlayer *g_pPlayer = NULL;

const WCHAR *sURL = L"C:\\Users\\Public\\Videos\\example.wmv";

HRESULT PlayVideo(HWND hwnd, const WCHAR* sURL)
{
    // Create the player object and play a video file.

    return MFPCreateMediaPlayer(
        sURL,
        TRUE,   // Start playback automatically?
        0,      // Flags.
        NULL,   // Callback pointer.
        hwnd,
        &g_pPlayer
        );
}

La fonction MFPCreateMediaPlayer crée une nouvelle instance de l’objet lecteur MFPlay. La fonction prend les paramètres suivants :

  • Le premier paramètre est l’URL du fichier à ouvrir. Il peut s’agir d’un fichier local ou d’un fichier sur un serveur multimédia.
  • Le deuxième paramètre spécifie si la lecture démarre automatiquement. En définissant ce paramètre sur TRUE, le fichier est lu dès que MFPlay le charge.
  • Le troisième paramètre définit différentes options. Pour les options par défaut, passez zéro (0).
  • Le quatrième paramètre est un pointeur vers une interface de rappel facultative. Ce paramètre peut être NULL, comme illustré. Le rappel est décrit dans la section Réception d’événements du lecteur.
  • Le cinquième paramètre est un handle de la fenêtre d’application. Si le fichier multimédia contient un flux vidéo, la vidéo s’affiche dans la zone cliente de cette fenêtre. Pour la lecture audio uniquement, ce paramètre peut être NULL.

Le dernier paramètre reçoit un pointeur vers l’interface IMFPMediaPlayer de l’objet lecteur.

Avant l’arrêt de l’application, veillez à libérer le pointeur IMFPMediaPlayer. Vous pouvez le faire dans votre gestionnaire de messages WM_CLOSE.

void OnClose(HWND /*hwnd*/)
{
    SafeRelease(&g_pPlayer);
    SafeRelease(&g_pPlayerCB);
    PostQuitMessage(0);
}

Remarque

Cet exemple utilise la fonction SafeRelease pour libérer les pointeurs d’interface.

 

Pour une lecture vidéo simple, c’est tout le code dont vous avez besoin. Le reste de ce tutoriel montre comment ajouter d’autres fonctionnalités, en commençant par la façon de contrôler la lecture.

Contrôle de la lecture

Le code affiché dans la section précédente lit le fichier multimédia jusqu’à la fin. Vous pouvez arrêter et démarrer la lecture en appelant les méthodes suivantes dans l’interface IMFPMediaPlayer :

  • IMFPMediaPlayer::Pause met la lecture en pause. Pendant que la lecture est en pause, la trame vidéo la plus récente reste affichée et aucun son n’est émis.
  • IMFPMediaPlayer::Stop arrête la lecture. Aucune vidéo n’est affichée et la position de lecture revient au début du fichier.
  • IMFPMediaPlayer::Play reprend la lecture après un arrêt ou une pause.

Le code suivant met en pause ou reprend la lecture lorsque vous appuyez sur ESPACE.

//-------------------------------------------------------------------
// OnKeyDown
//
// Handles the WM_KEYDOWN message.
//-------------------------------------------------------------------

void OnKeyDown(HWND hwnd, UINT vk, BOOL fDown, int cRepeat, UINT flags)
{
    HRESULT hr = S_OK;

    switch (vk)
    {
    case VK_SPACE:

        // Toggle between playback and paused/stopped.
        if (g_pPlayer)
        {
            MFP_MEDIAPLAYER_STATE state = MFP_MEDIAPLAYER_STATE_EMPTY;
            
            g_pPlayer->GetState(&state);

            if (state == MFP_MEDIAPLAYER_STATE_PAUSED ||  
                state == MFP_MEDIAPLAYER_STATE_STOPPED)
            {
                g_pPlayer->Play();
            }
            else if (state == MFP_MEDIAPLAYER_STATE_PLAYING)
            {
                g_pPlayer->Pause();
            }
        }
        break;
    }
}

Cet exemple appelle la méthode IMFPMediaPlayer::GetState pour obtenir l’état actuel de la lecture (en pause, arrêté ou en cours) et met en pause ou reprend selon.

Réception d’événements du lecteur

MFPlay utilise une interface de rappel pour envoyer des événements à votre application. Deux raisons justifient ce rappel :

  • La lecture a lieu sur un thread distinct. Pendant la lecture, certains événements peuvent se produire, comme atteindre la fin du fichier. MFPlay utilise le rappel pour notifier votre application de l’événement.
  • De nombreuses méthodes IMFPMediaPlayer sont asynchrones, ce qui signifie qu’elles sont retournées avant la fin de l’opération. Les méthodes asynchrones vous permettent de démarrer une opération à partir de votre thread d’interface utilisateur, qui risque de prendre beaucoup de temps sans pour autant entraîner le blocage de votre interface utilisateur. Une fois l’opération terminée, MFPlay signale le rappel.

Pour recevoir des notifications de rappel, implémentez l’interface IMFPMediaPlayerCallback. Cette interface hérite d’IUnknown et définit une seule méthode, OnMediaPlayerEvent. Pour configurer le rappel, passez un pointeur vers votre implémentation IMFPMediaPlayerCallback dans le paramètre pCallback de la fonction MFPCreateMediaPlayer.

Voici le premier exemple de ce tutoriel, modifié pour inclure le rappel.

// Global variables.
IMFPMediaPlayer *g_pPlayer = NULL;
IMFPMediaPlayerCallback *g_pCallback = NULL;

// Call an application-defined function to create the callback object.
hr = CreateMyCallback(&g_pCallback);

// Create the player object and play a video file.

const WCHAR *sURL = L"C:\\Users\\Public\\Videos\\example.wmv";

if (SUCCEEDED(hr))
{
    hr = MFPCreateMediaPlayer(
        sURL,
        TRUE,        // Start playback automatically?
        0,           // Flags.
        g_pCallback, // Callback pointer.
        hwnd,
        &g_pPlayer
        );
}

La méthode OnMediaPlayerEvent a un seul paramètre, qui est un pointeur vers la structure MFP_EVENT_HEADER. Le membre eEventType de cette structure vous indique quel événement s’est produit. Par exemple, lorsque la lecture démarre, MFPlay envoie l’événement MFP_EVENT_TYPE_PLAY.

Chaque type d’événement a une structure de données correspondante qui contient des informations pour cet événement. Chacune de ces structures commence par une structure MFP_EVENT_HEADER. Dans votre rappel, castez le pointeur MFP_EVENT_HEADER en structure de données spécifique à l’événement. Par exemple, si le type d’événement est MFP_PLAY_EVENT, la structure de données est MFP_PLAY_EVENT. Le code suivant montre comment gérer cet événement dans le rappel.

void STDMETHODCALLTYPE MediaPlayerCallback::OnMediaPlayerEvent(
    MFP_EVENT_HEADER *pEventHeader
    )
{
    switch (pEventHeader->eEventType)
    {
    case MFP_EVENT_TYPE_PLAY:
        OnPlay(MFP_GET_PLAY_EVENT(pEventHeader));
        break;

    // Other event types (not shown).

    }
}

// Function to handle the event.
void OnPlay(MFP_PLAY_EVENT *pEvent)
{
    if (FAILED(pEvent->header.hrEvent))
    {  
        // Error occurred during playback.
    }  
}

Cet exemple utilise l’événement MFP_GET_PLAY_EVENT pour caster le pointeur pEventHeader en structure MFP_PLAY_EVENT. Le HRESULT de l’opération qui a déclenché l’événement est stocké dans le champ hrEvent de la structure.

Pour obtenir la liste de tous les types d’événements et des structures de données correspondantes, consultez MFP_EVENT_TYPE.

Remarque sur le threading : Par défaut, MFPlay appelle le rappel à partir du même thread qui a appelé MFPCreateMediaPlayer. Ce thread doit avoir une boucle de message. Vous pouvez également passer l’indicateur MFP_OPTION_FREE_THREADED_CALLBACK dans le paramètre creationOptions de MFPCreateMediaPlayer. Cet indicateur indique que MFPlay appelle les rappels à partir d’un thread distinct. Les deux options ont des implications pour votre application. L’option par défaut signifie que votre rappel ne peut rien faire de ce qui attend sur votre boucle de message, par exemple attendre une action d’interface utilisateur, car cela bloque votre procédure de fenêtre. L’option « free-threaded » signifie que vous devez utiliser des sections critiques pour protéger les données auxquelles vous accédez dans votre rappel. Dans la plupart des cas, l’option par défaut est la plus simple.

Obtention d’informations sur un fichier multimédia

Lorsque vous ouvrez un fichier multimédia dans MFPlay, le lecteur crée un objet appelé élément multimédia qui représente le fichier multimédia. Cet objet expose l’interface IMFPMediaItem, que vous pouvez utiliser pour obtenir des informations sur le fichier multimédia. La plupart des structures d’événements MFPlay contiennent un pointeur vers l’élément multimédia actuel. Vous pouvez également obtenir l’élément multimédia actuel en appelant IMFPMediaPlayer::GetMediaItem sur le lecteur.

Deux méthodes particulièrement utiles sont IMFPMediaItem::HasVideo et IMFPMediaItem::HasAudio. Ces méthodes cherchent à savoir si la source multimédia contient de la vidéo ou de l’audio.

Par exemple, le code suivant teste si le fichier multimédia actuel contient un flux vidéo.

IMFPMediaItem *pItem;
BOOL bHasVideo = FALSE;
BOOL bIsSelected = FALSE;

hr = g_pPlayer->GetMediaItem(TRUE, &pItem);
if (SUCCEEDED(hr))
{
    hr = pItem->HasVideo(&bHasVideo, &bIsSelected);
    pItem->Release();
}

Si le fichier source contient un flux vidéo sélectionné pour la lecture, bHasVideo et bIsSelected sont tous deux définis sur TRUE.

Gestion de la lecture vidéo

Lorsque MFPlay lit un fichier vidéo, il dessine la vidéo dans la fenêtre que vous avez spécifiée dans la fonction MFPCreateMediaPlayer. Cela se produit sur un thread distinct appartenant au pipeline de lecture Microsoft Media Foundation. Dans la plupart des cas, votre application n’a pas besoin de gérer ce processus. Toutefois, il existe deux situations où l’application doit notifier MFPlay pour mettre à jour la vidéo.

  • Si la lecture est en pause ou arrêtée, MFPlay doit être averti chaque fois que la fenêtre de vidéo de l’application reçoit un message WM_PAINT. Cela permet à MFPlay de repeindre la fenêtre.
  • Si la fenêtre est redimensionnée, MFPlay doit en être averti pour qu’il puisse adapter la vidéo à la nouvelle taille de fenêtre.

La méthode IMFPMediaPlayer::UpdateVideo gère les deux cas. Appelez cette méthode dans les gestionnaires de messages WM_PAINT et WM_SIZE pour la fenêtre de vidéo.

Important

Appelez la fonction BeginPaint GDI avant d’appeler UpdateVideo.

 

IMFPMediaPlayer *g_pPlayer;   // MFPlay player object

void OnSize(HWND hwnd, UINT state, int cx, int cy)
{
    HDC hdc;
    PAINTSTRUCT ps;

    if (g_pPlayer && (state == SIZE_RESTORED))
    {
        hdc = BeginPaint(hwnd, &ps);
        g_pPlayer->UpdateVideo();
         EndPaint(hwnd, &ps);
    }
}

void OnPaint(HWND hwnd)
{
    HDC hdc;
    PAINTSTRUCT ps;

    hdc = BeginPaint(hwnd, &ps);
    if (g_pPlayer)
    {
        g_pPlayer->UpdateVideo();
    }
      EndPaint(hwnd, &ps);
}

Sauf indication contraire de votre part, MFPlay affiche la vidéo avec les bonnes proportions en ajoutant des bandes noires (letterboxing), si nécessaire. Si vous ne souhaitez pas conserver les proportions, appelez IMFPMediaPlayer::SetAspectRatioMode avec l’indicateur MFVideoARMode_None. Cela permet à MFPlay d’étirer la vidéo pour remplir l’intégralité du rectangle sans ajouter de bandes noires. Généralement, vous utilisez le paramètre par défaut et laissez MFPlay ajouter des bandes noires à la vidéo. La couleur des bandes est par défaut noire, mais vous pouvez la changer en appelant IMFPMediaPlayer::SetBorderColor.

Limitations de MFPlay

La version actuelle de MFPlay présente les limitations suivantes :

  • MFPlay ne prend pas en charge le contenu protégé par DRM.
  • Par défaut, MFPlay ne prend pas en charge les protocoles de streaming réseau. Pour plus d’informations, consultez IMFPMediaPlayer::CreateMediaItemFromURL.
  • MFPlay ne prend pas en charge les playlists côté serveur (SSPL) ou autres types de sources qui lisent plusieurs segments. En termes techniques, MFPlay arrête la lecture après la première présentation et ignore les événements MENewPresentation de la source multimédia.
  • MFPlay ne prend pas en charge les transitions transparentes entre les sources multimédias.
  • MFPlay ne prend pas en charge le mélange de plusieurs flux vidéo.
  • Seuls les formats multimédias pris en charge en mode natif dans Media Foundation sont pris en charge par MFPlay. (Cela inclut les composants Media Foundation tiers susceptibles d’être installés sur le système.)

Utilisation de MFPlay pour la lecture audio/vidéo