共用方式為


如何建立播放清單

本主題描述如何使用時序來源播放一連串的檔案。

概述

若要依序播放媒體檔案,應用程式必須在序列中新增拓撲,以建立播放清單,並將這些拓撲排入媒體會話以播放。

在媒體會話開始播放目前拓撲之前,排序器來源會先初始化並載入下一個拓撲,以確保順暢播放。 這可讓應用程式在需要時快速啟動下一個拓撲。

媒體會話負責將資料傳送到接收端,並按順序在來源中播放拓撲結構。 此外,媒體會話會管理區段的呈現時間。

如需排序器來源如何管理拓撲的詳細資訊,請參閱 關於 Sequencer 來源

此逐步解說包含下列步驟:

  1. 必要條件
  2. 初始化媒體基礎
  3. 建立媒體基礎物件
  4. 建立媒體來源
  5. 建立部分拓撲
  6. 將拓撲新增至序列器來源
  7. 在媒體會話上設定第一個拓撲
  8. 佇列媒體會話上的下一個拓撲
  9. 釋出序列器來源

本主題所顯示的程式碼範例是來自主題 的摘錄—Sequencer 原始程式碼範例,其中包含完整的範例程式碼。

先決條件

開始進行此逐步解說之前,請先熟悉下列媒體基礎概念:

另請參閱 如何使用 Media Foundation 播放媒體檔案,因為此處的範例程式代碼 shwon 會展開該主題中的程式代碼。

初始化媒體基礎

在您可以使用任何媒體基礎介面或方法之前,請先呼叫 MFStartup 函式來初始化 Media Foundation。 如需詳細資訊,請參閱 初始化媒體基礎

    hr = MFStartup(MF_VERSION);

建立媒體基礎架構物件

接下來,建立下列 Media Foundation 物件:

  • 媒體會話。 此物件會公開 IMFMediaSession 介面,其提供播放、暫停和停止目前拓撲的方法。
  • 序列器來源。 這個物件會公開 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_TOPOLOGY_SOURCESTREAM_NODE 拓撲節點上設定 MF_TOPONODE_MEDIASTART 屬性和 MF_TOPONODE_MEDIASTOP 屬性。 指定媒體開始時間和結束時間(相對於原始來源的開始時間),作為 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 ,在媒體會話上設定第一個拓撲。

    呼叫 setTopology ,並將 dwSetTopologyFlags 參數設定為 NULL。 當目前的拓撲完成時,此指令會通知媒體會話啟動指定的拓撲。 因為在這種情況下,指定的拓撲結構是首個拓撲,並且目前沒有正在播放的內容,媒體會話會立即開始新的播放。

    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 來源事件

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

釋出序列器源代碼

最後,關閉排序器來源。 若要這樣做,請在排序器來源上呼叫 IMFMediaSource::Shutdown 方法。 此呼叫會關閉排序器來源中的所有基礎原生媒體來源。

發佈排序器來源之後,應用程式應該依序呼叫 IMFMediaSession::Close 以及 IMFMediaSession::Shutdown來關閉媒體會話。

為了避免記憶體洩漏,應用程式在不再需要 Media Foundation 介面時必須釋放指標。

後續步驟

本逐步解說說明如何使用排序器來源建立基本播放清單。 建立播放清單之後,您可能會想要新增進階功能,例如區段略過、變更播放狀態,以及在區段內搜尋。 下列清單提供相關主題的連結:

序列器來源