Media foundation——Media source:Writing a Custom Media Source

来源:互联网 发布:学arm用先学单片机吗 编辑:程序博客网 时间:2024/06/05 00:52

编写自定义的媒体源(Writing a Custom Media Source)


本主题描述如何在微软MF基础上实现自定义媒体源。它包含以下部分:

  • 创建表示描述符
  • 开始媒体源
    • 索引
  • 暂停媒体源
  • 产生源数据
    • 样本请求
    • 分配采样样本
    • 流中的间隙
  • 关闭媒体源
  • Live源


创建表示描述符

IMFMediaSource::CreatePresentationDescriptor方法,返回一个来自源表示描述符的拷贝。要创建演示文稿描述符,您必须知道源内容中流的数目和每一个流的可能格式。对于每一个流,创建一个流描述符(stream descriptor)如下:

1.创建一个媒体类型(media type)的数组。在数组中的每一个媒体类型表示一个流可能的格式。更多的关于创建媒体类型,参考: Media Types。

2.调用MFCreateStreamDescriptor 来创建流的描述符。通过媒体类型数组。函数返回IMFStreamDescriptor指针。

3.调用 IMFStreamDescriptor::GetMediaTypeHandler来获得流描述符的媒体类型处理程序。

4.使用一个在step 1 中创建好的媒体类型。调用 IMFMediaTypeHandler::SetCurrentMediaType来设置默认的流格式。一般来说,你应该使用最优质的格式。

5.可选,在流描述符上设置属性。参见 Stream Descriptor Attributes,可以获取适用于流描述符的属性列表。


现在创建表示描述符:

1.调用 MFCreatePresentationDescriptor 传入流描述符的数组,函数返回IMFPresentationDescriptor指针。

2.调用  IMFPresentationDescriptor::SelectStream来选择一条或多条默认的流。在默认的配置中至少有一个流必须被选中。

3.可选的,在演示文稿描述符上设置属性。查看Presentation Descriptor Attributes.来获取适用于流描述符的属性列表。

你应该创建一次演示文稿描述符来确定内容,无论是在启动之前或源程序的源程序解析足够的源数据之后。 CreatePresentationDescriptor 方法应该返回一个演示文稿描述符的副本。调用 IMFPresentationDescriptor::Clone来创建副本。返回一个副本可以防止客户端修改原始的演示文稿描述符的状态,例如属性或流选择。然而,要知道,克隆创建一个浅的副本,所以客户端可以修改底层的流描述符。


开始媒体源(Starting the Media Source)

IMFMediaSource::Start 方法 开始媒体源或者索引到一个新的位置。无论之前的状态是暂停或者播放,一个Start调用会引起seek操作,并指定一个新的开始时间。否则,Start方法将导致开始。当Start操作完成时,产生如下的事件。

1.发送一个 MENewStream 事件给每一个新的流——以前没有被选中的流现在会被选中。事件的数据是向流的指针。

2.发送 MEUpdatedStream  事件给每个以前被选定,现在也是被选定的流。事件的数据是向流的指针。(不要向没有选中的流发送事件)。

3.如果源正在被索引,发送 MESourceSeeked 事件。否则发送MESourceStarted  事件。事件的数据是在Start 方法中设定好的开始时间。对于MESourceStarted  事件,如果开始事件是VT_EMPTY, 那么给事件设置 MF_EVENT_SOURCE_ACTUAL_START属性。属性值是实际开始时间。

4.对于每条流,如果正在被索引,那么发送  MEStreamSeeked事件。否则发送MESourceStarted  事件。事件的数据就是开始时间。(媒体源通过调用 IMFMediaEventGenerator::QueueEvent 方法,能够在流上排队事件)。


当一条流没有被选中,关闭这条流。这条流就不能够再排队任何事件了。

 Start 方法的时间格式在pguidTimeFormat parameter 被给出。标准时间格式,通过GUID_NULL,100纳秒为单位。一个媒体源必须支持这种事件格式。

索引(seeking)

当索引的时候,请求的起始位置可能不会落在一个精确的样本边界上。此外,对于压缩的内容,开始位置可能介于关键帧之间。流应将采样从最早的点需要要求在起始位置产生一个压缩的样品。对于视频来讲,这意味着从前一个关键帧开始。该管道负责从解码器中删除多余的帧,以便在被请求的时间开始播放。

在源事件 (MESourceStartedMESourceSeekedMEStreamStarted, and MEStreamSeeked中的起始时间是请求的起始时间(时间值在 Start 方法中定义),而不考虑实际起始位置。

例如,假设一个视频流的前几帧有以下特点:

Sample1234Time33 msec66 msec100 msec133 msecKey frame?YesNoNoYes如果 Start  方法在100millisec的时候被调用,源需要从帧1输出视频,因为它是在此之前的第一个关键帧。事件数据中的启动事件还是会显示100毫秒。


暂停媒体源(Pausing the Media Source)

 IMFMediaSource::Pause 方法用于暂停媒体源。

当源被暂停时,一个流可以创建新的样本,并将它们存储在队列中,但流不发送样本。下面是这个规则的一些例外情况:

  • 实时的源应该在暂停时删除数据。
  • 如果源从网络获取数据,它可能会暂停服务器。

如果源被暂停的时候,客户端调用 IMFMediaStream::RequestSample 方法,请求也会在队列中,直到源程序再次启动。请求不能够被丢弃。

暂停只能在开始状态是才会被允许,否则 Pause 应该会返回MF_E_INVALID_STATE_TRANSITION


产生源数据(Generating Source Data)


MF使用了pull module, 意味着流通过响应管道的请求来产生和传递样本。当媒体源正在运行并且流被选中的时候,流就能够传递样本。只有当客户端请求一个新的样本时,数据流才提供数据。


样本请求(Sample Request)

客户端通过 IMFMediaStream::RequestSample方法来请求信的样本。这里是操作的顺序:

1.客户端调用IMFMediaStream::RequestSample。参数是一个指向一个可选的令牌对象,这样客户端用于跟踪该请求。客户端实现这个令牌。令牌必须暴露IUnknown接口。客户端可以通过一个空指针来代替一个令牌。

2.如果客户端提供了令牌,媒体流调用AddRef的令牌,令牌放在FIFO队列。方法的返回以及其余的步奏都是异步发生。

3.当更多的数据可用时,媒体流就产生了新的样本。

4.媒体流从队列中拉出第一个令牌。

5.如果令牌不为空的话,流媒体设置 MFSampleExtension_Token 属性的媒体样本。属性的值是一个令牌指针。

6.媒体流发送 MEMediaSample 事件。事件数据是一个指向 IMFSample 接口的样本。

7.如果客户端提供了一个令牌,媒体流在令牌对象上调用Release。

如果媒体不能满足客户的 RequestSample 请求,它从队列中把令牌取出并调用释放令牌命令,但不发送MEMediaSample事件。


0 0
原创粉丝点击