Erste Schritte mit MFPlay

[MFPlay ist für die Verwendung in den Betriebssystemen verfügbar, die im Abschnitt „Anforderungen“ angegeben sind. In nachfolgenden Versionen wird sie möglicherweise geändert oder entfernt. ]

MFPlay ist eine API zum Erstellen von Medienwiedergabeanwendungen in C++.

Dieses Thema enthält folgende Abschnitte:

Anforderungen

MFPlay erfordert Windows 7.

Informationen zu MFPlay

MFPlay verfügt über ein einfaches Programmiermodell und stellt gleichzeitig die wichtigsten Features bereit, die die meisten Wiedergabeanwendungen benötigen. Eine Anwendung erstellt ein Playerobjekt, das die Wiedergabe steuert. Zum Wiedergeben einer Mediendatei erstellt das Playerobjekt ein Medienelement, mit dem Informationen zum Inhalt der Mediendatei abgerufen werden können. Die Anwendung steuert die Wiedergabe über Methoden auf der IMFPMediaPlayer-Schnittstelle des Playerobjekts. Optional kann die Anwendung Ereignisbenachrichtigungen über eine Rückrufschnittstelle abrufen. Das folgende Diagramm veranschaulicht diesen Prozess:

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

Wiedergeben einer Mediendatei

Rufen Sie zum Wiedergeben einer Mediendatei die Funktion MFPCreateMediaPlayer auf.

// 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
        );
}

Die Funktion MFPCreateMediaPlayer erstellt eine neue Instanz des MFPlay-Playerobjekts. Die Funktion verwendet die folgenden Parameter:

  • Der erste Parameter ist die URL der zu öffnenden Datei. Dies kann eine lokale Datei oder eine Datei auf einem Medienserver sein.
  • Der zweite Parameter gibt an, ob die Wiedergabe automatisch gestartet wird. Wenn Sie diesen Parameter auf TRUE festlegen, wird die Datei wiedergegeben, sobald MFPlay sie lädt.
  • Der dritte Parameter legt verschiedene Optionen fest. Übergeben Sie für die Standardoptionen Null (0).
  • Der vierte Parameter ist ein Zeiger auf eine optionale Rückrufschnittstelle. Dieser Parameter kann wie gezeigt NULL sein. Der Rückruf wird im Abschnitt Empfangen von Ereignissen vom Player beschrieben.
  • Der fünfte Parameter ist ein Handle für das Anwendungsfenster. Wenn die Mediendatei einen Videostream enthält, wird das Video im Clientbereich dieses Fensters angezeigt. Bei der reinen Audiowiedergabe kann dieser Parameter NULL sein.

Der letzte Parameter empfängt einen Zeiger auf die IMFPMediaPlayer-Schnittstelle des Playerobjekts.

Bevor die Anwendung heruntergefahren wird, müssen Sie den IMFPMediaPlayer-Zeiger freigeben. Sie können dies im Nachrichtenhandler WM_CLOSE tun.

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

Hinweis

In diesem Beispiel wird die Funktion SafeRelease zum Freigeben von Schnittstellenzeigern verwendet.

 

Für die einfache Videowiedergabe ist das alles, was Sie benötigen. Im restlichen Tutorial wird gezeigt, wie Sie weitere Features hinzufügen, angefangen mit der Steuerung der Wiedergabe.

Steuern der Wiedergabe

Der im vorherigen Abschnitt gezeigte Code gibt die Mediendatei wieder, bis das Ende der Datei erreicht ist. Sie können die Wiedergabe beenden und starten, indem Sie die folgenden Methoden auf der IMFPMediaPlayer-Schnittstelle aufrufen:

  • IMFPMediaPlayer::Pause hält die Wiedergabe an. Während die Wiedergabe angehalten ist, wird der letzte Videoframe angezeigt, und Audio ist stumm.
  • IMFPMediaPlayer::Stop beendet die Wiedergabe. Es wird kein Video angezeigt, und die Wiedergabeposition wird auf den Anfang der Datei zurückgesetzt.
  • IMFPMediaPlayer::Play setzt die Wiedergabe nach dem Beenden oder Anhalten fort.

Mit dem folgenden Code wird die Wiedergabe angehalten oder fortgesetzt, wenn Sie die LEERTASTE drücken.

//-------------------------------------------------------------------
// 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;
    }
}

In diesem Beispiel wird die Methode IMFPMediaPlayer::GetState aufgerufen, um den aktuellen Wiedergabestatus abzurufen („Angehalten“, „Beendet“ oder „Wiedergabe“), und die Wiedergabe entsprechend angehalten oder fortgesetzt.

Empfangen von Ereignissen vom Player

MFPlay verwendet eine Rückrufschnittstelle, um Ereignisse an Ihre Anwendung zu senden. Es gibt zwei Gründe für diesen Rückruf:

  • Die Wiedergabe erfolgt in einem separaten Thread. Während der Wiedergabe können bestimmte Ereignisse auftreten, wie z. B. das Erreichen des Dateiendes. MFPlay verwendet den Rückruf, um Ihre Anwendung über das Ereignis zu informieren.
  • Viele der IMFPMediaPlayer-Methoden sind asynchron. Das bedeutet, dass sie vor Abschluss des Vorgangs wieder verfügbar sind. Mit asynchronen Methoden können Sie über den UI-Thread einen Vorgang starten, dessen Ausführung möglicherweise lange dauert, ohne dass die Benutzeroberfläche blockiert wird. Nach Abschluss des Vorgangs signalisiert MFPlay den Rückruf.

Um Rückrufbenachrichtigungen zu empfangen, implementieren Sie die IMFPMediaPlayerCallback-Schnittstelle. Diese Schnittstelle erbt IUnknown und definiert eine einzelne Methode: OnMediaPlayerEvent. Übergeben Sie zum Einrichten des Rückrufs einen Zeiger an die IMFPMediaPlayerCallback-Implementierung im pCallback-Parameter der MFPCreateMediaPlayer-Funktion.

Hier sehen Sie das erste Beispiel aus diesem Tutorial, das geändert wurde, um den Rückruf einzuschließen.

// 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
        );
}

Die OnMediaPlayerEvent-Methode enthält einen einzelnen Parameter, bei dem es sich um einen Zeiger auf die MFP_EVENT_HEADER-Struktur handelt. Das eEventType-Element dieser Struktur teilt Ihnen mit, welches Ereignis aufgetreten ist. Wenn beispielsweise die Wiedergabe gestartet wird, sendet MFPlay das Ereignis MFP_EVENT_TYPE_PLAY.

Jeder Ereignistyp verfügt über eine entsprechende Datenstruktur, die Informationen für dieses Ereignis enthält. Jede dieser Strukturen beginnt mit einer MFP_EVENT_HEADER-Struktur. Wandeln Sie in Ihrem Rückruf den MFP_EVENT_HEADER-Zeiger in die ereignisspezifische Datenstruktur um. Wenn der Ereignistyp beispielsweise MFP_PLAY_EVENT ist, ist die Datenstruktur MFP_PLAY_EVENT. Im folgenden Code wird die Behandlung dieses Ereignisses im Rückruf veranschaulicht.

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.
    }  
}

In diesem Beispiel wird das MFP_GET_PLAY_EVENT-Ereignis verwendet, um den pEventHeader-Zeiger in eine MFP_PLAY_EVENT-Struktur umzuwandeln. HRESULT aus dem Vorgang, der das Ereignis ausgelöst hat, wird im Feld hrEvent der Struktur gespeichert.

Eine Liste aller Ereignistypen und der entsprechenden Datenstrukturen finden Sie unter MFP_EVENT_TYPE.

Hinweis zu Threading: MFPlay ruft standardmäßig den Rückruf aus demselben Thread auf, der MFPCreateMediaPlayer aufgerufen hat. Dieser Thread muss über eine Nachrichtenschleife verfügen. Alternativ können Sie das MFP_OPTION_FREE_THREADED_CALLBACK-Flag im creationOptions-Parameter von MFPCreateMediaPlayer übergeben. Dieses Flag bewirkt, dass MFPlay Rückrufe aus einem separaten Thread aufruft. Beide Optionen haben Auswirkungen auf Ihre Anwendung. Bei Verwendung der Standardoption kann Ihr Rückruf keine Aktion ausführen, die auf Ihre Nachrichtenschleife wartet (also beispielsweise auf eine Benutzeroberflächenaktion warten), da dadurch Ihr Fenstervorgang blockiert wird. Die Option für freie Threads bedeutet, dass Sie kritische Bereiche verwenden müssen, um alle Daten zu schützen, auf die Sie in Ihrem Rückruf zugreifen. In den meisten Fällen ist die Standardoption am einfachsten.

Abrufen von Informationen zu einer Mediendatei

Wenn Sie eine Mediendatei in MFPlay öffnen, erstellt der Player ein Objekt, das als Medienelement bezeichnet wird und die Mediendatei darstellt. Dieses Objekt macht die IMFPMediaItem-Schnittstelle verfügbar, mit der Sie Informationen zur Mediendatei abrufen können. Viele der MFPlay-Ereignisstrukturen enthalten einen Zeiger auf das aktuelle Medienelement. Sie können auch das aktuelle Medienelement abrufen, indem Sie IMFPMediaPlayer::GetMediaItem für den Player aufrufen.

Zwei besonders nützliche Methoden sind IMFPMediaItem::HasVideo und IMFPMediaItem::HasAudio. Diese Methoden fragen ab, ob die Medienquelle Video oder Audio enthält.

Der folgende Code testet beispielsweise, ob die aktuelle Mediendatei einen Videostream enthält:

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

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

Wenn die Quelldatei einen Videostream enthält, der für die Wiedergabe ausgewählt ist, werden bHasVideo und bIsSelected auf TRUE festgelegt.

Verwalten der Videowiedergabe

Wenn MFPlay eine Videodatei wiedergibt, wird das Video in das Fenster gezogen, das Sie in der MFPCreateMediaPlayer-Funktion angegeben haben. Dies geschieht in einem separaten Thread im Besitz der Microsoft Media Foundation-Wiedergabepipeline. In den meisten Fällen muss Ihre Anwendung diesen Prozess nicht verwalten. Es gibt jedoch zwei Situationen, in denen die Anwendung MFPlay zum Aktualisieren des Videos benachrichtigen muss.

  • Wenn die Wiedergabe angehalten oder beendet wird, muss MFPlay benachrichtigt werden, sobald das Videofenster der Anwendung eine WM_PAINT Nachricht empfängt. Dadurch kann MFPlay das Fenster aktualisieren.
  • Wenn die Größe des Fensters geändert wird, muss MFPlay benachrichtigt werden, damit das Video so skaliert werden kann, dass es mit der neuen Fenstergröße übereinstimmt.

Die IMFPMediaPlayer::UpdateVideo-Methode behandelt beide Fälle. Rufen Sie diese Methode sowohl im WM_PAINT- als auch im WM_SIZE-Nachrichtenhandler für das Videofenster auf.

Wichtig

Rufen Sie die GDI-Funktion BeginPaint auf, bevor Sie UpdateVideo aufrufen.

 

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);
}

Sofern Sie nichts anderes angeben, zeigt MFPlay das Video im richtigen Seitenverhältnis an. Bei Bedarf wird dafür Letterboxing verwendet. Wenn Sie das Seitenverhältnis nicht beibehalten möchten, rufen Sie IMFPMediaPlayer::SetAspectRatioMode mit dem Flag MFVideoARMode_None auf. Dies führt dazu, dass MFPlay das Video so skaliert, dass es das gesamte Rechteck ausfüllt, und zwar ohne Letterboxing. In der Regel sollten Sie die Standardeinstellung verwenden und zulassen, dass MFPlay Letterboxing für das Video nutzt. Die Letterbox-Standardfarbe ist schwarz. Sie können diese jedoch ändern, indem Sie IMFPMediaPlayer::SetBorderColor aufrufen.

Einschränkungen von MFPlay

Für die aktuelle Version von MFPlay gelten die folgenden Einschränkungen:

  • MFPlay unterstützt keine DRM-geschützten Inhalte.
  • MFPlay unterstützt standardmäßig keine Netzwerkstreamingprotokolle. Weitere Informationen finden Sie unter IMFPMediaPlayer::CreateMediaItemFromURL.
  • MFPlay unterstützt keine serverseitigen Wiedergabelisten (Server-Side Playlists, SSPLs) oder andere Quelltypen, die mehr als ein Segment wiedergeben. Technisch gesehen beendet MFPlay die Wiedergabe nach der ersten Anzeige und ignoriert alle MENewPresentation-Ereignisse von der Medienquelle.
  • MFPlay unterstützt keine nahtlosen Übergänge zwischen Medienquellen.
  • MFPlay unterstützt das Mischen mehrerer Videostreams nicht.
  • Nur Medienformate, die nativ in Media Foundation unterstützt werden, werden von MFPlay unterstützt. (Dazu gehören Media Foundation-Komponenten von Drittanbietern, die möglicherweise auf dem System installiert werden.)

Verwenden von MFPlay für die Audio-/Videowiedergabe