Introducción a MFPlay

[MFPlay está disponible para su uso en los sistemas operativos especificados en la sección Requisitos. Puede modificarse o no estar disponible en versiones posteriores. ]

MFPlay es una API para crear aplicaciones de reproducción multimedia en C++.

Este tema contiene las siguientes secciones:

Requisitos

MFPlay requiere Windows 7.

Acerca de MFPlay

MFPlay tiene un modelo de programación simple, al tiempo que proporciona el conjunto básico de características que la mayoría de las aplicaciones de reproducción necesitan. Una aplicación crea un objeto de reproductor que controla la reproducción. Para reproducir un archivo multimedia, el objeto del reproductor crea un elemento multimedia, que se puede usar para obtener información sobre el contenido del archivo multimedia. La aplicación controla la reproducción mediante métodos de la interfaz IMFPMediaPlayer del objeto reproductor. Opcionalmente, la aplicación puede obtener notificaciones de eventos a través de una interfaz de devolución de llamada. El siguiente diagrama ilustra este proceso.

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

Reproducción de un archivo multimedia

Para reproducir un archivo multimedia, llame a la función 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 función MFPCreateMediaPlayer crea una nueva instancia del objeto del reproductor MFPlay. La función toma los siguientes parámetros:

  • El primer parámetro es la dirección URL del archivo que se va a abrir. Puede ser un archivo local o un archivo en un servidor multimedia.
  • El segundo parámetro especifica si la reproducción se inicia automáticamente. Al establecer este parámetro en TRUE, el archivo se reproducirá tan pronto como MFPlay lo cargue.
  • El tercer parámetro establece varias opciones. Para las opciones predeterminadas, pase cero (0).
  • El cuarto parámetro es un puntero a una interfaz de devolución de llamada opcional. Este parámetro puede ser NULL, como se muestra. La devolución de llamada se describe en la sección Recepción de eventos del reproductor.
  • El quinto parámetro es un identificador de la ventana de la aplicación. Si el archivo multimedia contiene una secuencia de vídeo, el vídeo aparecerá dentro del área cliente de esta ventana. Para la reproducción de solo audio, este parámetro puede ser NULL.

El último parámetro recibe un puntero a la interfaz IMFPMediaPlayer del objeto reproductor.

Antes de que se cierre la aplicación, asegúrese de liberar el puntero IMFPMediaPlayer. Puede hacerlo en el controlador de mensajes de WM_CLOSE.

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

Nota:

En este ejemplo se usa la función SafeRelease para liberar punteros de interfaz.

 

Para una reproducción de vídeo simple, es todo el código que necesita. El resto de este tutorial mostrará cómo agregar más características, empezando por cómo controlar la reproducción.

Controlar la reproducción

El código que se muestra en la sección anterior reproducirá el archivo multimedia hasta que llegue al final del archivo. Puede detener e iniciar la reproducción llamando a los siguientes métodos de la interfaz IMFPMediaPlayer:

  • IMFPMediaPlayer::Pause pausa la reproducción. Mientras la reproducción está en pausa, se muestra el fotograma de vídeo más reciente y el audio es silencioso.
  • IMFPMediaPlayer::Stop detiene la reproducción. No se muestra ningún vídeo y la posición de reproducción se restablece al inicio del archivo.
  • IMFPMediaPlayer::Play reanuda la reproducción después de detener o pausar.

El código siguiente pausa o reanuda la reproducción al presionar la barra espaciadora.

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

En este ejemplo se llama al método IMFPMediaPlayer::GetState para obtener el estado de reproducción actual (pausado, detenido o reproducido) y se pausa o reanuda según corresponda.

Recepción de eventos del reproductor

MFPlay usa una interfaz de devolución de llamada para enviar eventos a la aplicación. Hay dos motivos para esta devolución de llamada:

  • La reproducción se produce en un subproceso independiente. Durante la reproducción, es posible que se produzcan determinados eventos, como llegar al final del archivo. MFPlay usa la devolución de llamada para notificar a la aplicación del evento.
  • Muchos de los métodos IMFPMediaPlayer son asincrónicos, lo que significa que vuelven antes de que se complete la operación. Los métodos asíncronos permiten iniciar una operación desde el subproceso de interfaz de usuario que puede tardar mucho tiempo en completarse, sin que la interfaz de usuario se bloquee. Una vez completada la operación, MFPlay señala la devolución de llamada.

Para recibir notificaciones de devolución de llamada, implemente la interfaz IMFPMediaPlayerCallback. Esta interfaz hereda IUnknown y define un único método, OnMediaPlayerEvent. Para configurar la devolución de llamada, pase un puntero a su implementación de IMFPMediaPlayerCallback en el parámetro pCallback de la función MFPCreateMediaPlayer.

Este es el primer ejemplo de este tutorial, modificado para incluir la devolución de llamada.

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

El método OnMediaPlayerEvent tiene un único parámetro, que es un puntero a la estructura MFP_EVENT_HEADER. El miembro eEventType de esta estructura indica qué evento se produjo. Por ejemplo, cuando se inicia la reproducción, MFPlay envía el evento MFP_EVENT_TYPE_PLAY.

Cada tipo de evento tiene una estructura de datos correspondiente que contiene información para ese evento. Cada una de estas estructuras comienza con una estructura MFP_EVENT_HEADER. En la devolución de llamada, convierta el puntero MFP_EVENT_HEADER a la estructura de datos específica del evento. Por ejemplo, si el tipo de evento es MFP_PLAY_EVENT, la estructura de datos es MFP_PLAY_EVENT. En el siguiente código se muestra cómo controlar este evento en la devolución de llamada.

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

En este ejemplo se usa el evento MFP_GET_PLAY_EVENT para convertir el puntero pEventHeader a una estructura MFP_PLAY_EVENT. HRESULT de la operación que desencadenó el evento se almacena en el campo hrEvent de la estructura.

Para obtener una lista de todos los tipos de eventos y las estructuras de datos correspondientes, consulte MFP_EVENT_TYPE.

Nota sobre el subproceso: de forma predeterminada, MFPlay invoca la devolución de llamada desde el mismo subproceso que llamó a MFPCreateMediaPlayer. Este subproceso debe tener un bucle de mensajes. Como alternativa, puedes pasar la marca MFP_OPTION_FREE_THREADED_CALLBACK en el parámetro creationOptions de MFPCreateMediaPlayer. Esta marca hace que MFPlay invoque devoluciones de llamada desde un subproceso independiente. Cualquiera de las opciones tiene implicaciones para la aplicación. La opción de forma predeterminada significa que su devolución de llamada no puede hacer nada que espere en su bucle de mensajes, como esperar una acción de UI, porque eso bloquearía su procedimiento de ventana. La opción free-threaded significa que debe usar secciones críticas para proteger los datos a los que accede en la devolución de llamada. En la mayoría de los casos, la opción predeterminada es más sencilla.

Obtener información sobre un archivo multimedia

Al abrir un archivo multimedia en MFPlay, el reproductor crea un objeto denominado elemento multimedia que representa el archivo multimedia. Este objeto expone la interfaz IMFPMediaItem, que puede usar para obtener información sobre el archivo multimedia. Muchas de las estructuras de eventos MFPlay contienen un puntero al elemento multimedia actual. También puedes obtener el elemento multimedia actual llamando a IMFPMediaPlayer::GetMediaItem en el reproductor.

Dos métodos especialmente útiles son IMFPMediaItem::HasVideo y IMFPMediaItem::HasAudio. Estos métodos consultan si el origen multimedia contiene vídeo o audio.

Por ejemplo, el siguiente código comprueba si el archivo multimedia actual contiene una secuencia de vídeo.

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 el archivo de origen contiene una secuencia de vídeo seleccionada para la reproducción, bHasVideo y bIsSelected se establecen en TRUE.

Administrar la reproducción de vídeo

Cuando MFPlay reproduce un archivo de vídeo, dibuja el vídeo en la ventana que especificó en la función MFPCreateMediaPlayer. Esto ocurre en un subproceso independiente propiedad de la canalización de reproducción de Microsoft Media Foundation. En la mayoría de los casos, su aplicación no necesita administrar este proceso. Sin embargo, hay dos situaciones en las que la aplicación debe notificar a MFPlay que actualice el vídeo.

  • Si la reproducción está en pausa o detenida, MFPlay debe recibir una notificación cada vez que la ventana de vídeo de la aplicación recibe un mensaje de WM_PAINT. Esto permite a MFPlay volver a dibujar la ventana.
  • Si se cambia el tamaño de la ventana, se debe notificar a MFPlay para que pueda escalar el vídeo para que coincida con el nuevo tamaño de la ventana.

El método IMFPMediaPlayer::UpdateVideo controla ambos casos. Llame a este método dentro de los controladores de mensajes WM_PAINT y WM_SIZE para la ventana de vídeo.

Importante

Llame a la función BeginPaint de GDI antes de llamar a 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);
}

A menos que especifique lo contrario, MFPlay muestra el vídeo en la relación de aspecto correcta, utilizando la bandeja de letras si es necesario. Si no quiere conservar la relación de aspecto, llame a IMFPMediaPlayer::SetAspectRatioMode con la marcar MFVideoARMode_None. Esto hará que MFPlay expanda el vídeo para rellenar todo el rectángulo, sin pantalla ancha. Lo normal es utilizar la configuración predeterminada y dejar que MFPlay haga una pantalla ancha del vídeo. El color predeterminado de la pantalla ancha es negro, pero puede cambiarlo llamando a IMFPMediaPlayer::SetBorderColor.

Limitaciones de MFPlay

La versión actual de MFPlay tiene las siguientes limitaciones:

  • MFPlay no admite contenido protegido con DRM.
  • De forma predeterminada, MFPlay no admite protocolos de streaming de red. Para obtener más información, consulte IMFPMediaPlayer::CreateMediaItemFromURL.
  • MFPlay no admite listas de reproducción del lado servidor (SSPLs) ni otros tipos de origen que reproducen más de un segmento. En términos técnicos, MFPlay detiene la reproducción después de la primera presentación y omite los eventos MENewPresentation del origen multimedia.
  • MFPlay no admite transiciones sin problemas entre orígenes multimedia.
  • MFPlay no admite la mezcla de varias secuencias de vídeo.
  • MFPlay solo admite formatos multimedia compatibles de forma nativa en Media Foundation. (Esto incluye componentes de Media Foundation de terceros que se pueden instalar en el sistema).

Uso de MFPlay para reproducción de audio y vídeo