非同期メソッドの呼び出し

Media Foundation では、多くの操作が非同期的に実行されます。 非同期操作は、呼び出し元のスレッドをブロックしないため、パフォーマンスを向上させることができます。 Media Foundation の非同期操作は、名前付け規則 Begin.End. を持つメソッドのペアによって定義されます。 これら 2 つのメソッドを組み合わせて、ストリームに対する非同期読み取り操作を定義します。

非同期操作を開始するには、 Begin メソッドを呼び出します。 Begin メソッドには、常に少なくとも 2 つのパラメーターが含まれます。

  • IMFAsyncCallback インターフェイスへのポインター。 アプリケーションでは、このインターフェイスを実装する必要があります。
  • オプションの状態オブジェクトへのポインター。

IMFAsyncCallback インターフェイスは、操作の完了時にアプリケーションに通知します。 このインターフェイスを実装する方法の例については、「 非同期コールバックの実装」を参照してください。 state オブジェクトは省略可能です。 指定した場合は、 IUnknown インターフェイスを実装する必要があります。 状態オブジェクトを使用して、コールバックで必要な状態情報を格納できます。 状態情報が不要な場合は、このパラメーターを NULL に設定できます。 Begin メソッドには、そのメソッドに固有の追加のパラメーターが含まれている場合があります。

Begin メソッドがエラー コードを返す場合は、操作がすぐに失敗し、コールバックが呼び出されないことを意味します。 Begin メソッドが成功した場合は、操作が保留中であることを意味し、操作の完了時にコールバックが呼び出されます。

たとえば、 IMFByteStream::BeginRead メソッドはバイト ストリームで非同期読み取り操作を開始します。

    BYTE data[DATA_SIZE];
    ULONG cbRead = 0;

    CMyCallback *pCB = new (std::nothrow) CMyCallback(pStream, &hr);

    if (pCB == NULL)
    {
        hr = E_OUTOFMEMORY;
    }

    // Start an asynchronous request to read data.
    if (SUCCEEDED(hr))
    {
        hr = pStream->BeginRead(data, DATA_SIZE, pCB, NULL);
    }

コールバック メソッドは IMFAsyncCallback::Invoke です。 これには、 IMFAsyncResult インターフェイスへのポインターである pAsyncResult という 1 つのパラメーターがあります。 非同期操作を完了するには、非同期 Begin メソッドと一致する End メソッドを呼び出します。 End メソッドは常に IMFAsyncResult ポインターを受け取ります。 Invoke メソッドで受け取ったのと同じポインターを常に渡します。 End メソッドを呼び出すまでは、非同期操作は完了しません。 Invoke メソッド内から End メソッドを呼び出すか、別のスレッドから呼び出すことができます。

たとえば、バイト ストリームで IMFByteStream::BeginRead を完了するには、 IMFByteStream::EndRead を呼び出します。

    STDMETHODIMP Invoke(IMFAsyncResult* pResult)
    {
        m_hrStatus = m_pStream->EndRead(pResult, &m_cbRead);

        SetEvent(m_hEvent);

        return S_OK;
    }

End メソッドの戻り値は、非同期操作の状態を示します。 ほとんどの場合、非同期操作が正常に完了したかどうかに関係なく、アプリケーションは非同期操作の完了後に何らかの作業を実行します。 いくつかのオプションがあります。

  • Invoke メソッド内で作業を行います。 この方法は、アプリケーションが呼び出し元のスレッドをブロックしたり 、Invoke メソッド内で何かを待機したりしない限り、許容されます。 呼び出し元のスレッドをブロックすると、ストリーミング パイプラインがブロックされる可能性があります。 たとえば、一部の状態変数を更新しても、同期読み取り操作を実行したり、ミューテックス オブジェクトで待機したりしない場合があります。
  • Invoke メソッドで、イベントを設定し、すぐにを返します。 アプリケーションの呼び出し元スレッドはイベントを待機し、イベントが通知されたときに処理を行います。
  • Invoke メソッドで、プライベート ウィンドウ メッセージをアプリケーション ウィンドウに投稿し、すぐに返します。 アプリケーションは、そのメッセージ ループで作業を行います。 (SendMessage はコールバック スレッドをブロックできるため、SendMessage ではなく PostMessage を呼び出してメッセージを投稿してください)。

Invoke は別のスレッドから呼び されることを覚えておく必要があります。 アプリケーションは、 Invoke 内で実行されるすべての作業がスレッド セーフであることを確認する責任があります。

既定では、 Invoke を呼び出すスレッドでは、コールバック オブジェクトの動作に関する想定は行われません。 必要に応じて、 IMFAsyncCallback::GetParameters メソッドを実装して、コールバック実装に関する情報を返すことができます。 それ以外の場合、このメソッドは E_NOTIMPLを返すことができます。

    STDMETHODIMP GetParameters(DWORD* pdwFlags, DWORD* pdwQueue)
    {
        // Implementation of this method is optional.
        return E_NOTIMPL;
    }

Begin メソッドで状態オブジェクトを指定した場合は、IMFAsyncResult::GetState を呼び出すことで、コールバック メソッド内から取得できます。

非同期コールバック メソッド