Share via


プレイリストを作成する方法

このトピックでは、シーケンス ソースを使用して一連のファイルを再生する方法について説明します。

概要

一連のメディア ファイルを再生するには、アプリケーションで順番にトポロジを追加してプレイリストを作成し、再生のためにメディア セッションでこれらのトポロジをキューに入れなければなりません。

シーケンサー ソースは、メディア セッションが現在のトポロジの再生を開始する前に、次のトポロジを初期化して読み込むことで、シームレスな再生を保証します。 これにより、アプリケーションは必要なときにいつでも次のトポロジをすばやく開始できます。

メディア セッションは、シンクにデータを供給し、シーケンス ソース内のトポロジを再生する役割を担います。 さらに、メディア セッションでは、セグメントのプレゼンテーション時間を管理します。

シーケンサー ソースがトポロジを管理する方法の詳細については、「 Sequencer ソースについて」を参照してください。

このチュートリアルには、次の手順が含まれています。

  1. 前提条件
  2. Media Foundation の初期化
  3. Media Foundation オブジェクトの作成
  4. メディア ソースの作成
  5. 部分トポロジの作成
  6. Sequencer ソースへのトポロジの追加
  7. メディア セッションでの最初のトポロジの設定
  8. メディア セッションでの次のトポロジのキュー
  9. Sequencer ソースの解放

このトピックに示すコード例は、完全なサンプル コードを含む Sequencer ソース サンプル コードに関するトピックからの抜粋です。

前提条件

このチュートリアルを開始する前に、次の Media Foundation の概念を理解しておいてください。

また、「 Media Foundation を使用してメディア ファイルを再生する方法」も参照してください。この例のコード shwon は、そのトピックのコードを展開しているためです。

Media Foundation の初期化

Media Foundation のインターフェイスまたはメソッドを使用する前に、 MFStartup 関数を呼び出して Media Foundation を初期化します。 詳細については、「 Media Foundation の初期化」を参照してください。

    hr = MFStartup(MF_VERSION);

Media Foundation オブジェクトの作成

次に、次の Media Foundation オブジェクトを作成します。

  • メディア セッション。 このオブジェクトは、現在のトポロジを再生、一時停止、停止するメソッドを提供する IMFMediaSession インターフェイスを公開します。
  • Sequencer ソース。 このオブジェクトは IMFSequencerSource インターフェイスを公開します。これにより、トポロジをシーケンスで追加、更新、および削除するメソッドが提供されます。
  1. MFCreateMediaSession 関数を呼び出して、メディア セッションを作成します。
  2. IMFMediaEventQueue::BeginGetEvent を呼び出して、メディア セッションから最初のイベントを要求します。
  3. MFCreateSequencerSource 関数を呼び出して、シーケンサー ソースを作成します。

次のコードは、メディア セッションを作成し、最初のイベントを要求します。

//  Create a new instance of the media session.
HRESULT CPlayer::CreateSession()
{
    // Close the old session, if any.
    HRESULT hr = CloseSession();
    if (FAILED(hr))
    {
        goto done;
    }

    assert(m_state == Closed);

    // Create the media session.
    hr = MFCreateMediaSession(NULL, &m_pSession);
    if (FAILED(hr))
    {
        goto done;
    }

    // Start pulling events from the media session
    hr = m_pSession->BeginGetEvent((IMFAsyncCallback*)this, NULL);
    if (FAILED(hr))
    {
        goto done;
    }

    m_state = Ready;

done:
    return hr;
}

メディア ソースの作成

次に、最初のプレイリストセグメントのメディアソースを作成します。 ソース リゾルバーを使用して、URL からメディア ソースを作成します。 これを行うには、 MFCreateSourceResolver 関数を呼び出してソース リゾルバーを作成し、 IMFSourceResolver::CreateObjectFromURL メソッドを呼び出してメディア ソースを作成します。

メディア ソースの詳細については、「 メディア ソース」を参照してください。

部分トポロジの作成

シーケンサー ソース内の各セグメントには、独自の部分トポロジがあります。 次に、メディア ソースの部分トポロジを作成します。 部分トポロジの場合、トポロジ ソース ノードは、中間変換を指定せずに出力ノードに直接接続されます。 メディア セッションでは、トポロジ ローダー オブジェクトを使用してトポロジを解決します。 トポロジが解決されると、必要なデコーダーとその他の変換ノードが追加されます。 シーケンサー ソースには、完全なトポロジを含めることもできます。

トポロジ オブジェクトを作成するには、 MFCreateTopology 関数を使用し、 IMFTopologyNode インターフェイスを使用してストリーム ノードを作成します。

これらのプログラミング要素を使用してトポロジを作成する手順の詳細については、「 再生トポロジの作成」を参照してください。

アプリケーションは、ソース ノードを構成することで、ネイティブ ソースの選択された部分を再生できます。 これを行うには、トポロジ ノードで MF_TOPONODE_MEDIASTART 属性と MF_TOPONODE_MEDIASTOP 属性 MF_TOPOLOGY_SOURCESTREAM_NODE 設定します。 UINT64 型として、ネイティブ ソースの開始に対するメディアの開始時刻とメディア停止時間を指定します。

Sequencer ソースへのトポロジの追加

次に、作成した部分トポロジをシーケンサー ソースに追加します。 セグメントと呼ばれる各シーケンス要素には、MFSequencerElementId 識別子が割り当てられます。 シーケンサー ソースがトポロジを管理する方法の詳細については、「 Sequencer ソースについて」を参照してください。

すべてのトポロジがシーケンサー ソースに追加された後、アプリケーションは、パイプラインでの再生を終了するために、シーケンス内の最後のセグメントにフラグを設定する必要があります。 このフラグがない場合、シーケンサー ソースでは、追加されるトポロジが増えると想定されます。

  1. 特定のトポロジをシー ケンサー ソースに追加するには、IMFSequencerSource::AppendTopology メソッドを呼び出します。

        hr = m_pSequencerSource->AppendTopology(
            pTopology, 
            SequencerTopologyFlags_Last, 
            &SegmentId
            );
    

    AppendTopology は、指定したトポロジをシーケンスに追加します。 このメソッドは 、pdwId パラメーターでセグメント識別子を返します。

    トポロジがシーケンサー ソースの最後のトポロジである場合は、 dwFlags パラメーターに SequencerTopologyFlags_Lastを渡します。 この値は、 MFSequencerTopologyFlags 列挙で定義されます。

  2. IMFSequencerSource::UpdateTopologyFlags を呼び出して、入力リストのセグメント識別子に関連付けられているトポロジのフラグを更新します。 この場合、呼び出しは、指定されたセグメントがシーケンサーの最後のセグメントであることを示します。 (この呼び出しは、 AppendTopology 呼び出しで最後のトポロジが指定されている場合は省略可能です)。

        BOOL bFirstSegment = (NumSegments() == 0);
    
        if (!bFirstSegment)
        {
            // Remove the "last segment" flag from the last segment.
            hr = m_pSequencerSource->UpdateTopologyFlags(LastSegment(), 0);
            if (FAILED(hr))
            {
                goto done;
            }
        }
    

アプリケーションは、 IMFSequencerSource::UpdateTopology を呼び出し、新しいトポロジを pTopology に渡すことで、セグメントのトポロジを別のトポロジに置き換えることができます。 新しいトポロジに新しいネイティブ ソースがある場合、ソースはソース キャッシュに追加されます。 プリロール リストも更新されます。

メディア セッションでの最初のトポロジの設定

次に、メディア セッションのシーケンス ソースの最初のトポロジをキューに入れます。 シーケンサー ソースから最初のトポロジを取得するには、アプリケーションで IMFMediaSourceTopologyProvider::GetMediaSourceTopology メソッドを呼び出す必要があります。 このメソッドは、メディア セッションによって解決される部分トポロジを返します。

部分トポロジの詳細については、「 トポロジについて」を参照してください。

  1. シーケンス ソースの最初のトポロジのネイティブ メディア ソースを取得します。

  2. IMFMediaSource::CreatePresentationDescriptor メソッドを呼び出して、メディア ソースのプレゼンテーション記述子を作成します。

  3. IMFMediaSourceTopologyProvider::GetMediaSourceTopology メソッドを呼び出して、プレゼンテーションに関連付けられているトポロジを取得します。

  4. IMFMediaSession::SetTopology を呼び出して、メディア セッションで最初のトポロジを設定します。

    dwSetTopologyFlags パラメーターを NULL に設定して SetTopology を呼び出します。 これにより、現在のトポロジが完了したときに、指定したトポロジを開始するようにメディア セッションに指示されます。 この場合、指定したトポロジが最初のトポロジであり、現在のプレゼンテーションがないため、メディア セッションは新しいプレゼンテーションをすぐに開始します。

    NULL 値は、トポロジ プロバイダーによって返されるトポロジは常に部分トポロジであるため、メディア セッションでトポロジを解決する必要があることを示します。

// Queues the next topology on the session.

HRESULT CPlaylist::QueueNextSegment(IMFPresentationDescriptor *pPD)
{
    IMFMediaSourceTopologyProvider *pTopoProvider = NULL;
    IMFTopology *pTopology = NULL;

    //Get the topology for the presentation descriptor
    HRESULT hr = m_pSequencerSource->QueryInterface(IID_PPV_ARGS(&pTopoProvider));
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pTopoProvider->GetMediaSourceTopology(pPD, &pTopology);
    if (FAILED(hr))
    {
        goto done;
    }

    //Set the topology on the media session
    m_pSession->SetTopology(NULL, pTopology);

done:
    SafeRelease(&pTopoProvider);
    SafeRelease(&pTopology);
    return hr;
}

メディア セッションでの次のトポロジのキュー

次に、アプリケーションで MENewPresentation イベントを処理する 必要があります。

Sequencer ソースは、メディア セッションがその後に別のセグメントを持つセグメントの再生を開始すると 、MENewPresentation を発生させます。 このイベントは、プリロール リストの次のセグメントのプレゼンテーション記述子を指定することで、シーケンス ソース内の次のトポロジについてアプリケーションに通知します。 アプリケーションは、トポロジ プロバイダーを使用して関連付けられているトポロジを取得し、メディア セッションでキューに登録する必要があります。 その後、シーケンサー ソースによってこのトポロジが事前登録され、プレゼンテーション間のシームレスな切り替えが保証されます。

アプリケーションが複数のセグメントをシークすると、アプリケーションは、シーケンサー ソースがプリロール リストを更新し、正しいトポロジを設定するときに、いくつかの MENewPresentation イベントを受け取ります。 アプリケーションでは、各イベントを処理し、イベント データで返されたトポロジをメディア セッションでキューに登録する必要があります。 セグメントのスキップの詳細については、「 Sequencer ソースの使用」を参照してください。

Sequencer ソース通知を取得する方法については、「 Sequencer ソース イベント」を参照してください。

  1. MENewPresentation イベント ハンドラーで、イベント データから次のセグメントのプレゼンテーション記述子を取得します。

  2. IMFMediaSourceTopologyProvider::GetMediaSourceTopology メソッドを呼び出して、プレゼンテーションに関連付けられたトポロジを取得します。

  3. IMFMediaSession::SetTopology メソッドを呼び出して、メディア セッションでトポロジを設定します。

    メディア セッションでは、現在のプレゼンテーションが完了すると、新しいプレゼンテーションが開始されます。

HRESULT CPlaylist::OnNewPresentation(IMFMediaEvent *pEvent)
{
    IMFPresentationDescriptor *pPD = NULL;

    HRESULT hr = GetEventObject(pEvent, &pPD);

    if (SUCCEEDED(hr))
    {
        // Queue the next segment on the media session
        hr = QueueNextSegment(pPD);
    }

    SafeRelease(&pPD);
    return hr;
}

Sequencer ソースの解放

最後に、シーケンサー ソースをシャットダウンします。 これを行うには、シーケンサー ソースで IMFMediaSource::Shutdown メソッドを呼び出します。 この呼び出しにより、シーケンサー ソース内の基になるネイティブ メディア ソースがすべてシャットダウンされます。

シーケンサー ソースを解放した後、アプリケーションは、その順序で IMFMediaSession::Close と IMFMediaSession:: Shutdown を呼び出して、メディア セッションを閉じて シャットダウンする必要があります。

メモリ リークを回避するには、不要になったら、アプリケーションで Media Foundation インターフェイスへのポインターを解放する必要があります。

次の手順

このチュートリアルでは、シーケンサー ソースを使用して基本的なプレイリストを作成する方法を示しました。 プレイリストを作成した後、セグメントのスキップ、再生状態の変更、セグメント内でのシークなどの高度な機能を追加できます。 次の一覧では、関連トピックへのリンクを示します。

Sequencer ソース