如何建立播放清單
本主題描述如何使用時序來源來播放一連串的檔案。
概觀
若要在序列中播放媒體檔案,應用程式必須在序列中新增拓撲,以建立播放清單,並將這些拓撲排入媒體會話以播放。
排序器來源可確保在媒體會話開始播放目前拓撲之前,初始化和載入下一個拓撲,以確保順暢播放。 這可讓應用程式在需要時快速啟動下一個拓撲。
媒體會話負責將資料摘要至接收,並在序列來源中播放拓撲。 此外,媒體會話會管理區段的簡報時間。
如需排序器來源如何管理拓撲的詳細資訊,請參閱 關於 Sequencer 來源。
此逐步解說包含下列步驟:
本主題所示的程式碼範例是 Sequencer 來源範例程式碼主題的摘錄,其中包含完整的範例程式碼。
必要條件
開始進行此逐步解說之前,請先熟悉下列媒體基礎概念:
另請參閱 如何使用 Media Foundation 播放媒體檔案,因為此處的範例程式碼 shwon 會展開該主題中的程式碼。
初始化媒體基礎
在您可以使用任何 Media Foundation 介面或方法之前,請先呼叫 MFStartup 函式來初始化 Media Foundation。 如需詳細資訊,請參閱 初始化媒體基礎。
hr = MFStartup(MF_VERSION);
建立媒體基礎物件
接下來,建立下列 Media Foundation 物件:
- 媒體會話。 此物件會公開 IMFMediaSession 介面,其提供播放、暫停和停止目前拓撲的方法。
- Sequencer 來源。 這個物件會公開 IMFSequencerSource 介面,這個介面提供在序列中新增、更新和刪除拓撲的方法。
- 呼叫 MFCreateMediaSession 函式 以建立媒體會話。
- 呼叫 IMFMediaEventQueue::BeginGetEvent 以向媒體會話要求第一個事件。
- 呼叫 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 來源。
將所有拓撲新增至排序器來源之後,應用程式必須標幟序列中的最後一個區段,才能結束管線中的播放。 如果沒有此旗標,排序器來源預期會新增更多拓撲。
呼叫 IMFSequencerSource::AppendTopology 方法,將特定拓撲新增至排序器來源。
hr = m_pSequencerSource->AppendTopology( pTopology, SequencerTopologyFlags_Last, &SegmentId );
AppendTopology 會將指定的拓撲新增至序列。 這個方法會傳回 pdwId 參數中的區段識別碼。
如果拓撲是排序器來源的最後一個拓撲,請在 dwFlags 參數中傳遞SequencerTopologyFlags_Last。 此值定義于 MFSequencerTopologyFlags 列舉中。
呼叫 IMFSequencerSource::UpdateTopologyFlags 來更新與輸入清單中區段識別碼相關聯的拓撲旗標。 在此情況下,呼叫會指出指定的區段是排序器中的最後一個區段。 (如果 AppendTopology call.) 中指定最後一個拓撲,則此呼叫是選擇性的。
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 方法。 這個方法會傳回媒體會話所解析的部分拓撲。
如需部分拓撲的相關資訊,請參閱 關於拓撲。
擷取序列來源第一個拓撲的原生媒體來源。
呼叫 IMFMediaSource::CreatePresentationDescriptor 方法,為媒體來源建立簡報描述元。
呼叫 IMFMediaSourceTopologyProvider::GetMediaSourceTopology 方法來擷取簡報的相關拓撲。
呼叫 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 來源。
如需取得排序器來源通知的詳細資訊,請參閱 Sequencer 來源事件。
在 MENewPresentation 事件處理常式中,從事件資料擷取下一個區段的簡報描述元。
呼叫 IMFMediaSourceTopologyProvider::GetMediaSourceTopology 方法,以取得簡報的相關拓撲。
藉由呼叫 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來關閉和關閉媒體會話。
若要避免記憶體流失,應用程式必須在不再需要時釋出媒體基礎介面的指標。
後續步驟
本逐步解說說明如何使用排序器來源建立基本播放清單。 建立播放清單之後,您可能會想要新增進階功能,例如區段略過、變更播放狀態,以及在區段內搜尋。 下列清單提供相關主題的連結:
相關主題