MFPlay

MFPlayは非推奨であり、Media Sessionを使用することとされています。

IMFPMediaPlayer* gPlayer = NULL; // MFPlay playerオブジェクト

void OnFileOpen(HWND hWnd)
{
    WCHAR pwszURL[] = L"C:\\sample.wmv";

    BOOL fStartPlayback = TRUE;
    MFP_CREATION_OPTIONS creationOptions = 0;

    HRESULT hr = MFPCreateMediaPlayer(pwszURL, fStartPlayback, creationOptions, NULL, hWnd, &gPlayer);
}

void OnClose(HWND /*hWnd*/)
{
    if (gPlayer)
    {
        gPlayer->Shutdown();
        gPlayer->Release();
        gPlayer = NULL;
    }
}
Windows-classic-samples/winmain.cpp at master · Microsoft/Windows-classic-samples · GitHub

Media Player (IMFPMediaPlayer)

MFPlayプレーヤーオブジェクトを表します。

MFPCreateMediaPlayer()

MFPlayプレーヤーを作成できます。

HRESULT MFPCreateMediaPlayer(
  LPCWSTR                 pwszURL,         // Media FileのURLを含む文字列。後で指定するならばNULLでも良い
  BOOL                    fStartPlayback,  // 自動再生させるならばTRUE
  MFP_CREATION_OPTIONS    creationOptions, // オプション
  IMFPMediaPlayerCallback *pCallback,      // MFPlayのイベント通知を受け取るためのコールバック。イベントを受け取らないならばNULLでも良い
  HWND                    hWnd,            // 映像を描画するためのウィンドウ。音声だけならばNULLでも良い
  IMFPMediaPlayer         **ppMediaPlayer  // 作成されたMFPlayを受け取るためのポインタ
);
MFPCreateMediaPlayer function | Microsoft Learn

pwszURLをNULLとしたときは、fStartPlaybackをFALSEとしなければなりません。

LPCWSTR pwszURL = L"C:\\sample.wmv";
IMFPMediaPlayer* ppMediaPlayer = NULL;

// 指定ファイルを読み込み再生する
HRESULT hr = MFPCreateMediaPlayer(pwszURL, TRUE, 0, NULL, hWnd, &ppMediaPlayer);
Playing a Media File - Getting Started with MFPlay - Win32 apps | Microsoft Learn

CreateMediaItemFromURL()

URLからMedia Itemを作成できます。

HRESULT CreateMediaItemFromURL(
  LPCWSTR       pwszURL,      // Media FileのURLを含む文字列
  BOOL          fSync,        // 完了までブロックさせ同期して実行させるならばTRUE
  DWORD_PTR     dwUserData,   // Media Itemに保管する任意のデータ
  IMFPMediaItem **ppMediaItem // fSyncがTRUEのときに、Media Itemを受け取るポインタ
);
IMFPMediaPlayer::CreateMediaItemFromURL | Microsoft Learn

MFPCreateMediaPlayer()の引数のpCallbackをNULLとしてコールバックを受け取らないときは、fSyncをTRUEとしてppMediaItemに有効なポインタを与えます。

この関数はその結果に応じて、下表のような値を返します。

  Return code Description
0x0 S_OK The method succeeded.
0x80004003 E_POINTER Invalid pointer.

fSyncをTRUEとしているのに、ppMediaItemに有効なポインタを指定していない

0x80070057 E_INVALIDARG Invalid argument.
0xC00D36B2 MF_E_INVALIDREQUEST Invalid request.

このエラーはfSyncをFALSEとしているのに、MFPCreateMediaPlayer()でコールバックを提供しないときに発生する。

0xC00D3E85 MF_E_SHUTDOWN The object's Shutdown method was called.

このエラーは、MFStartup()を呼び出していないときにも発生する。

0xC00D36C3 MF_E_UNSUPPORTED_SCHEME Unsupported protocol.

SetPosition()

再生位置を指定できます。

HRESULT SetPosition(
  REFGUID           guidPositionType, // 時間の単位。有効な値はMFP_POSITIONTYPE_100NS
  const PROPVARIANT *pvPositionValue
);
IMFPMediaPlayer::SetPosition | Microsoft Learn
PROPVARIANT vPositionValue;
PropVariantInit(&vPositionValue);

vPositionValue.vt = VT_I8;
vPositionValue.hVal.QuadPart = 10000000; // 1秒 (10000000[100nsec]) の位置から再生する;

HRESULT hr = gPlayer->SetPosition(
    MFP_POSITIONTYPE_100NS,
    &vPositionValue
    );

PropVariantClear(&vPositionValue);

Media Item (IMFPMediaItem)

Media Itemを表します。

GetMetadata()

Metadataを含むProperty storeを取得できます。

HRESULT GetMetadata(
  IPropertyStore **ppMetadataStore
);
IMFPMediaItem::GetMetadata (mfplay.h) | Microsoft Learn

Callback (IMFPMediaPlayerCallback)

IMFPMediaPlayerCallbackインターフェイスは、IMFPMediaPlayerで発生するイベントを受け取るためのコールバックの定義に用います。

IMFPMediaPlayer* gPlayer = NULL; // MFPlay playerオブジェクト
BOOL gHasVideo = FALSE;          // 映像を含むならばTRUE

class MediaPlayerCallback;
MediaPlayerCallback* gPlayerCB = NULL; // コールバック オブジェクト


class MediaPlayerCallback : public IMFPMediaPlayerCallback
{
    long mRef; // 参照カウント

public:
    MediaPlayerCallback() : mRef(1)
    {
    }

    STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
    {
        static const QITAB qit[] =
        {
            QITABENT(MediaPlayerCallback, IMFPMediaPlayerCallback),
            { 0 },
        };
        return QISearch(this, qit, riid, ppv);
    }

    STDMETHODIMP_(ULONG) AddRef()
    {
        return InterlockedIncrement(&mRef);
    }

    STDMETHODIMP_(ULONG) Release()
    {
        ULONG count = InterlockedDecrement(&mRef);
        if (count == 0)
        {
            delete this;
            return 0;
        }
        return count;
    }

    void STDMETHODCALLTYPE OnMediaPlayerEvent(MFP_EVENT_HEADER* pEventHeader);
};


HRESULT OnMediaItemCreated(MFP_MEDIAITEM_CREATED_EVENT* pEvent)
{
    HRESULT hr = S_OK;
    if (gPlayer)
    {
        BOOL bHasVideo = FALSE;
        BOOL bIsSelected = FALSE;

        // Media Itemが映像を含むか確認する
        hr = pEvent->pMediaItem->HasVideo(&bHasVideo, &bIsSelected);

        if (SUCCEEDED(hr))
        {
            gHasVideo = bHasVideo && bIsSelected;

            // プレイヤーにMedia Itemを設定する
            hr = gPlayer->SetMediaItem(pEvent->pMediaItem);
        }
    }
    return hr;
}

HRESULT OnMediaItemSet(MFP_MEDIAITEM_SET_EVENT* /*pEvent*/)
{
    return gPlayer->Play();
}

void MediaPlayerCallback::OnMediaPlayerEvent(MFP_EVENT_HEADER* pEventHeader)
{
    if (FAILED(pEventHeader->hrEvent))
    {
        // Playback error
    }
    else
    {
        HRESULT hr = S_OK;
        switch (pEventHeader->eEventType) // MFP_EVENT_TYPE
        {
        case MFP_EVENT_TYPE_MEDIAITEM_CREATED: // 新しいMedia Itemが作成された
            hr = OnMediaItemCreated(MFP_GET_MEDIAITEM_CREATED_EVENT(pEventHeader));
            if (FAILED(hr)) // Error playing this file
            break;

        case MFP_EVENT_TYPE_MEDIAITEM_SET: // Media Itemの再生の用意ができた
            hr = OnMediaItemSet(MFP_GET_MEDIAITEM_SET_EVENT(pEventHeader));
            if (FAILED(hr)) // Play failed
            break;
        }
    }
}

これを利用するには、次のようにMFPCreateMediaPlayer()の引数で渡します。

void OnFileOpen(HWND hWnd)
{
    WCHAR pwszURL[] = L"C:\\sample.wmv";

    BOOL fStartPlayback = FALSE;
    MFP_CREATION_OPTIONS creationOptions = 0;

    gPlayerCB = new (std::nothrow) MediaPlayerCallback();

    // MFP_EVENT_TYPE_MEDIAITEM_CREATED イベントを受け取るため、MFPlayオブジェクト作成時にファイルを指定しない
    HRESULT hr = MFPCreateMediaPlayer(NULL, fStartPlayback, creationOptions, gPlayerCB, hWnd, &gPlayer);

    hr = gPlayer->CreateMediaItemFromURL(pwszURL, FALSE, 0, NULL);
}

void OnPaint(HWND hWnd)
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps);

    if (gPlayer && gHasVideo)
    {
        // 映像を含むため、背景を描画しない
        gPlayer->UpdateVideo();
    }
    else
    {
        // 映像を含まないため、クライアント領域を塗りつぶす
        FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
    }

    EndPaint(hWnd, &ps);
}
Windows-classic-samples/winmain.cpp at master · Microsoft/Windows-classic-samples · GitHub
Microsoft Learnから検索