Introdução à MFPlay
[A MFPlay está disponível para uso nos sistemas operacionais especificados na seção Requisitos. Ela pode estar indisponível ou ter sido alterada em versões subsequentes. ]
A MFPlay é uma API para criar aplicativos de reprodução de mídia em C++.
Este tópico contém as seguintes seções:
- Requisitos
- Sobre a MFPlay
- Reproduzir um arquivo de mídia
- Controlar a reprodução
- Receber eventos do player
- Obter informações sobre um arquivo de mídia
- Gerenciar a reprodução de vídeo
- Limitações da MFPlay
- Tópicos relacionados
Requisitos
A MFPlay requer o Windows 7.
Sobre a MFPlay
A MFPlay tem um modelo de programação simples, ao mesmo tempo em que fornece o conjunto principal de recursos que a maioria dos aplicativos de reprodução precisa. Um aplicativo cria um objeto do player que controla a reprodução. Para reproduzir um arquivo de mídia, o objeto do player cria um item de mídia, que pode ser usado para obter informações sobre o conteúdo do arquivo de mídia. O aplicativo controla a reprodução por meio de métodos na interface IMFPMediaPlayer do objeto do player. Opcionalmente, o aplicativo pode obter notificações de eventos por meio de uma interface de retorno de chamada. O diagrama a seguir ilustra esse processo.
Reproduzir um arquivo de mídia
Para reproduzir um arquivo de mídia, chame a função 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
);
}
A função MFPCreateMediaPlayer cria uma nova instância do objeto do player MFPlay. A função usa os seguintes parâmetros:
- O primeiro parâmetro é o URL do arquivo a ser aberto. Isso pode ser um arquivo local ou um arquivo em um servidor de mídia.
- O segundo parâmetro especifica se a reprodução é iniciada automaticamente. Ao definir esse parâmetro como TRUE, o arquivo será reproduzido assim que a MFPlay carregá-lo.
- O terceiro parâmetro define várias opções. Para as opções padrão, passe zero (0).
- O quarto parâmetro é um ponteiro para uma interface de retorno de chamada opcional. Este parâmetro pode ser NULL, como mostrado. O retorno de chamada é descrito na seção Receber eventos do player.
- O quinto parâmetro é um identificador para a janela do aplicativo. Se o arquivo de mídia contiver um fluxo de vídeo, o vídeo aparecerá dentro da área do cliente desta janela. Para reprodução somente áudio, esse parâmetro pode ser NULL.
O último parâmetro recebe um ponteiro para a interface IMFPMediaPlayer do objeto do player.
Antes que o aplicativo seja desligado, certifique-se de liberar o ponteiro IMFPMediaPlayer. Você pode fazer isso no manipulador de mensagens WM_CLOSE.
void OnClose(HWND /*hwnd*/)
{
SafeRelease(&g_pPlayer);
SafeRelease(&g_pPlayerCB);
PostQuitMessage(0);
}
Observação
Este exemplo usa a função SafeRelease para liberar ponteiros de interface.
Para uma reprodução de vídeo simples, esse é todo o código que você precisa. O restante deste tutorial mostrará como adicionar mais recursos, começando com como controlar a reprodução.
Controlar a reprodução
O código mostrado na seção anterior reproduzirá o arquivo de mídia até que ele atinja o final do arquivo. Você pode parar e iniciar a reprodução chamando os seguintes métodos na interface IMFPMediaPlayer:
- IMFPMediaPlayer::Pause pausa a reprodução. Enquanto a reprodução é pausada, o quadro de vídeo mais recente é exibido e o áudio é silenciado.
- IMFPMediaPlayer::Stop interrompe a reprodução. Nenhum vídeo é exibido e a posição da reprodução é redefinida para o início do arquivo.
- IMFPMediaPlayer::Play retoma a reprodução após parar ou pausar.
O código a seguir pausa ou retoma a reprodução quando você pressiona ESPAÇO.
//-------------------------------------------------------------------
// 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;
}
}
Este exemplo chama o método IMFPMediaPlayer::GetState para obter o estado de reprodução atual (pausado, parado ou em reprodução) e pausa ou retoma de acordo.
Receber eventos do player
A MFPlay usa uma interface de retorno de chamada para enviar eventos para seu aplicativo. Há dois motivos para esse retorno de chamada:
- A reprodução ocorre em um thread separado. Durante a reprodução, determinados eventos podem ocorrer, como chegar ao final do arquivo. A MFPlay usa o retorno de chamada para notificar seu aplicativo sobre o evento.
- Muitos dos métodos IMFPMediaPlayer são assíncronos, o que significa que retornam antes que a operação seja concluída. Os métodos assíncronos permitem iniciar uma operação a partir do thread da interface do usuário que pode levar muito tempo para ser concluída, sem que isso cause o bloqueio da interface do usuário. Após a conclusão da operação, a MFPlay sinaliza o retorno de chamada.
Para receber notificações de retorno de chamada, implemente a interface IMFPMediaPlayerCallback. Essa interface herda IUnknown e define um único método, OnMediaPlayerEvent. Para configurar o retorno de chamada, passe um ponteiro para sua implementação IMFPMediaPlayerCallback no parâmetro pCallback da função MFPCreateMediaPlayer.
Aqui está o primeiro exemplo deste tutorial, modificado para incluir o retorno de chamada.
// 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
);
}
O método OnMediaPlayerEvent tem um único parâmetro, que é um ponteiro para a estrutura MFP_EVENT_HEADER. O membro eEventType dessa estrutura informa qual evento ocorreu. Por exemplo, quando a reprodução é iniciada, a MFPlay envia o evento MFP_EVENT_TYPE_PLAY.
Cada tipo de evento tem uma estrutura de dados correspondente que contém informações para esse evento. Cada uma dessas estruturas começa com uma estrutura MFP_EVENT_HEADER. No retorno de chamada, converta o ponteiro MFP_EVENT_HEADER para a estrutura de dados específica do evento. Por exemplo, se o tipo de evento for MFP_PLAY_EVENT, a estrutura de dados será MFP_PLAY_EVENT. O código a seguir mostra como manipular esse evento no retorno de chamada.
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.
}
}
Este exemplo usa o eventoMFP_GET_PLAY_EVENT para converter o ponteiro pEventHeader em uma estrutura MFP_PLAY_EVENT. O HRESULT da operação que disparou o evento é armazenado no campo hrEvent da estrutura.
Para obter uma lista de todos os tipos de eventos e as estruturas de dados correspondentes, consulte MFP_EVENT_TYPE.
Uma observação sobre threading: por padrão, a MFPlay invoca o retorno de chamada do mesmo thread que chamou MFPCreateMediaPlayer. Esse thread deve ter um loop de mensagem. Como alternativa, você pode passar o sinalizador MFP_OPTION_FREE_THREADED_CALLBACK no parâmetro creationOptions de MFPCreateMediaPlayer. Esse sinalizador faz com que a MFPlay invoque retornos de chamada de um thread separado. Qualquer uma das opções tem implicações para o seu aplicativo. A opção padrão significa que o retorno de chamada não pode fazer nada que aguarde no loop da mensagem, como aguardar uma ação da interface do usuário, porque isso bloqueará o procedimento de janela. A opção de thread livre significa que você precisa usar seções críticas para proteger todos os dados que você acessa em seu retorno de chamada. Na maioria dos casos, a opção padrão é a mais simples.
Obter informações sobre um arquivo de mídia
Quando você abre um arquivo de mídia na MFPlay, o player cria um objeto chamado item de mídia que representa o arquivo de mídia. Esse objeto expõe a interface IMFPMediaItem, que você pode usar para obter informações sobre o arquivo de mídia. Muitas das estruturas de eventos da MFPlay contêm um ponteiro para o item de mídia atual. Você também pode obter o item de mídia atual chamando IMFPMediaPlayer::GetMediaItem no player.
Dois métodos particularmente úteis são IMFPMediaItem::HasVideo e IMFPMediaItem::HasAudio. Esses métodos consultam se a fonte de mídia contém vídeo ou áudio.
Por exemplo, o código a seguir testa se o arquivo de mídia atual contém um fluxo 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();
}
Se o arquivo de origem contiver um fluxo de vídeo selecionado para reprodução, bHasVideo e bIsSelected são definidos como TRUE.
Gerenciar a reprodução de vídeo
Quando a MFPlay reproduz um arquivo de vídeo, ela desenha o vídeo na janela que você especificou na função MFPCreateMediaPlayer. Isso ocorre em um thread separado de propriedade do pipeline de reprodução do Microsoft Media Foundation. Na maioria das vezes, seu aplicativo não precisa gerenciar esse processo. No entanto, há duas situações em que o aplicativo deve notificar a MFPlay para atualizar o vídeo.
- Se a reprodução for pausada ou parada, a MFPlay deverá ser notificada sempre que a janela de vídeo do aplicativo receber uma mensagem WM_PAINT. Isso permite que a MFPlay pinte novamente a janela.
- Se a janela for redimensionada, a MFPlay deverá ser notificada para que possa dimensionar o vídeo para corresponder ao novo tamanho da janela.
O método IMFPMediaPlayer::UpdateVideo lida com ambos os casos. Chame esse método dentro dos manipuladores de mensagens WM_PAINT e WM_SIZE para a janela de vídeo.
Importante
Chame a função GDI BeginPaint antes de chamar 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 você especifique o contrário, a MFPlay mostra o vídeo na taxa de proporção correta, usando letterbox, se necessário. Se você não quiser preservar a taxa de proporção, chame IMFPMediaPlayer::SetAspectRatioMode com o sinalizador MFVideoARMode_None. Isso fará com que a MFPlay estique o vídeo para preencher todo o retângulo, sem usar letterbox. Normalmente, você deve usar a configuração padrão e deixar a MFPlay fazer letterbox no vídeo. A cor padrão do letterbox é preta, mas você pode alterar isso chamando IMFPMediaPlayer::SetBorderColor.
Limitações da MFPlay
A versão atual da MFPlay tem as seguintes limitações:
- A MFPlay não oferece suporte a conteúdo protegido por DRM.
- Por padrão, a MFPlay não oferece suporte a protocolos de streaming de rede. Para obter mais informações, consulte IMFPMediaPlayer::CreateMediaItemFromURL.
- A MFPlay não oferece suporte a SSPLs (listas de reprodução do lado do servidor) ou outros tipos de fonte que reproduzem mais de um segmento. Em termos técnicos, a MFPlay interrompe a reprodução após a primeira apresentação e ignora quaisquer eventos MENewPresentation da fonte de mídia.
- A MFPlay não oferece suporte a transições ininterruptas entre fontes de mídia.
- A MFPlay não suporta a mistura de vários fluxos de vídeo.
- Somente os formatos de mídia suportados nativamente no Media Foundation são suportados pela MFPlay. (Isso inclui componentes do Media Foundation de terceiros que podem ser instalados no sistema.)
Tópicos relacionados