使用顺序器源

本主题介绍如何使用顺序器源。 它包含下列部分:

有关顺序器源的一般概述,请参阅关于顺序器源

概述

顺序器源公开以下接口。

接口 说明
IMFMediaSource 公开通用媒体源功能。
IMFSequencerSource 可让应用程序添加或删除拓扑。
IMFMediaSourceTopologyProvider 检索在媒体会话上排队的下一个拓扑。
IMFMediaSourcePresentationProvider 媒体会话用于结束段。 应用程序不使用此接口。
IMFGetService 查询 服务接口的顺序器源。

 

若要播放媒体源序列,请执行以下步骤:

  1. 若要创建顺序器源,请调用 MFCreateSequencerSource 函数。
  2. 对于每个段,请创建一个播放拓扑,如创建播放拓扑中所述。 若要将拓扑添加到演示文稿,请调用 IMFSequencerSource::AppendTopology
  3. 在开始播放之前,请在顺序器源上调用 IMFMediaSource::CreatePresentationDescriptor。 此方法返回指向第一段的演示文稿描述符的指针。 若要获取与此段关联的拓扑,请在 IMFMediaSourceTopologyProvider 接口的顺序器源上调用 QueryInterface。 将演示文稿描述符传递给 IMFMediaSourceTopologyProvider::GetMediaSourceTopology 方法。 此方法返回指向拓扑的指针。
  4. 通过调用媒体会话的 IMFMediaSession::SetTopology 方法,将第一段的拓扑传递给媒体会话。
  5. 调用 IMFMediaSession::Start 以开始播放。
  6. 当顺序器源准备好预注册下一段时,它会发送其事件数据为 IMFPresentationDescriptor 接口指针的 MENewPresentation 事件。 同样,通过在顺序器源上调用 GetMediaSourceTopology,并通过调用 SetTopology 在媒体会话上设置拓扑,以获取段的拓扑。 不需要重新启动媒体源;它将自动播放到下一段。
  7. 在应用程序退出之前,通过调用 IMFMediaSource::Shutdown 关闭顺序器源。

以下代码演示如何获取拓扑并在媒体会话上设置它:

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

有关完整的代码示例,请参阅顺序器源示例代码

添加拓扑

顺序器源维护两个拓扑列表:输入列表预注册列表

输入列表是对应于播放列表段的拓扑集合,按照应用程序通过调用 IMFSequencerSource::AppendTopology 添加拓扑的顺序。 此方法为每个拓扑分配类型 MFSequencerElementId唯一段标识符。 段标识符设置为所有源拓扑节点的属性。 应用程序可以使用 MF_TOPONODE_SEQUENCE_ELEMENTID 属性从源节点获取段标识符。 如果应用程序多次在同一拓扑上调用 AppendTopology,则输入列表可以具有重复的拓扑;但是,它们通过唯一的段标识符进行标识。

预注册列表是已初始化的输入列表拓扑的集合,用于准备播放。 这可让媒体会话在活动拓扑结束时无缝地过渡到下一个拓扑。 应用程序无法直接从预注册列表中添加或删除拓扑;从输入列表中选择用于播放的拓扑时,顺序器源会生成它。 这会导致顺序器源将输入列表中的下一个拓扑添加到预注册列表。 执行此操作后,顺序器源会异步引发 MENewPresentation 事件,并将预注册拓扑的表示描述符作为事件数据传递。 应用程序必须使用媒体会话的 IMFMediaEventGenerator 接口侦听此事件,并通过调用 IMFMediaSession::SetTopology 将预注册拓扑排入媒体会话队列。 必须在媒体会话完成活动拓扑的播放之前完成此操作。 SetTopology 向媒体会话告知必须在播放活动拓扑结束后播放的下一个拓扑。 为确保无缝转换,应用程序必须在媒体会话完成播放以前的拓扑之前调用 SetTopology。 否则,段之间会有间隙。

只要活动的拓扑后面有拓扑,就会引发 MENewPresentation 事件。 因此,如果输入列表仅包含一个拓扑,或者活动拓扑是输入列表中的最后一个拓扑,则不会引发此事件。

预注册列表与输入列表同步,每次在输入列表中添加或删除拓扑时刷新。

删除拓扑

若要从顺序器源中删除拓扑,应用程序必须调用 IMFSequencerSource::DeleteTopology 方法并指定段标识符。

在调用 DeleteTopology 之前,应用程序必须确保媒体会话不使用应用程序要删除的拓扑。 为此,在应用程序调用 DeleteTopology 之前,必须执行以下两项操作:

  • 为拓扑接收具有 MF_TOPOSTATUS_ENDED 的 MESessionTopologyStatus 事件,以确保媒体会话已完成播放。

  • 为下一个拓扑接收明有 MF_TOPOSTATUS_STARTED_SOURCE 的 MESessionTopologyStatus,以确保媒体会话已开始播放下一个拓扑,并接收 MESessionEnded 事件,以确保媒体会话使用顺序源中的最后一个拓扑完成。

如果删除的段是活动的拓扑,则停止播放,顺序器源将引发 MEEndOfPresentationSegment 事件。 如果活动的拓扑也是最后一个拓扑,则会引发 MEEndOfPresentation 事件。

跳到段

应用程序可以通过启动具有段偏移量的媒体会话,跳到序列中的特定段,如下所示:

  1. 调用 MFCreateSequencerSegmentOffset 函数以创建段偏移量。 在 dwId 参数中指定段的标识符。 (首次将拓扑添加到顺序器源时,IMFSequencerSource::AppendTopology 方法返回了标识符。)hnsOffset 参数指定相对于段开始的时间偏移量。 此时将开始播放。 对于 pvarSegmentOffset 参数,传入空 PROPVARIANT 的地址。 函数返回时,此 PROPVARIANT 包含段偏移量。

  2. 在媒体会话上调用 IMFMediaSession::Start 方法。 对于 pguidTimeFormat 参数,请使用 GUID 值MF_TIME_FORMAT_SEGMENT_OFFSET。 此值表示按段偏移量查找。 对于 pvarStartPosition 参数,传递上一步创建的 PROPVARIANT 的地址。

下面的代码示例演示如何跳到序列中指定段的开头。

// Skips to the specified segment in the sequencer source

HRESULT CPlaylist::SkipTo(DWORD index)
{
    if (index >= m_count)
    {
        return E_INVALIDARG;
    }

    MFSequencerElementId ID = m_segments[index].SegmentID;

    PROPVARIANT var;

    HRESULT hr = MFCreateSequencerSegmentOffset(ID, NULL, &var);
    
    if (SUCCEEDED(hr))
    {
        hr = m_pSession->Start(&MF_TIME_FORMAT_SEGMENT_OFFSET, &var);
        PropVariantClear(&var);
    }
    return hr;
}

当应用程序跨段查找时,应用程序会收到多个事件,因为顺序器源结束当前段并准备播放新段。 由于这些事件是异步接收的,因此很难预测事件的确切顺序。 这些事件如下所示:

有关顺序器源发送的事件的更多详细信息,请参阅顺序器源事件主题。

如何创建播放列表

顺序器源