冲顶大会有前端什么事吗?

时间:2021-1-8 作者:admin

Media Presentation Description from DASHI-IF live simulator

http://vm2.dashif.org/dash/vod/testpic_2s/

基本原理是,后台将一份完整的流文件切片,生成 Initial Segment 和 Media Segments,这些就是流的片段文件,比如 `.mp4`,`.ts`等。更详细的内容,下面会进行详述。

那该协议的延时性怎么样呢?

这个主要取决于你的协议,最极致的时延是比 HTTP-FLV 还要快,差不多 <= 2~3s。其中,最主要的是它定义的模板解析机制,直接根据时间戳来协定。

## MPD 基本简介

DASH 其实只是一系列概念,原意是 `Dynamic Adaptive Streaming over HTTP`。它主要是基于 mpd 文件来做的切片和文件的 download。整个模式有点类似于 HLS,但是其可以应用于所有的 视频格式,比如 mp4,webm。它将整个的视频文件,切片分为一个个具体的 HTTPFLV segments。不过,其更优于 HLS,这个已经在上面阐述清楚了。

MPD 的播放模式,其实就是根据 XML 的内容,协商出来播放的切片 URL 地址。一个简易的 MPD 文件为:

Media Presentation Description from DASHI-IF live simulator

https://vm2.dashif.org/livesim-dev/ato_10/testpic_2s/

XML 文件里面的每一个标签内容,都是遵循 MPEG-DASH LA 的标准。其内部包含 N+1 个 Periods Tag。每一个 Period 包含相关的 media stream,比如 video:不同的编码,视角,带宽等、 audio:不同语言,类型,带宽等。一些共同的参数,比如 codec,frame rate, audio-channel 在同一个 Period 是不能改变的。所以,尽可能在一个 Period 提供更丰富的描述信息来说是非常重要的。虽然,Period 里面的信息不能动态改变,但是,用户可以自己手动选择,自己想要的分辨率,带宽大小等等。

Period 可以包含多个流,所以,还可以提供插入广告,或者视角流的切分等功能。这个也是 MPEG-DASH 设计的初衷,通过一份文件协商出多个媒体流的内容。其基础架构内容为:

![此处输入图片的描述](https://example.com/905e5f13e46fab87a66cb5ca3950ff9c)

这里,我们先简单介绍一下,几个重点 TAG 具体的内容。

### MPD

该是 MPD 里面文件的最外层的 Tag,有相关的属性来对其进行描述。该标签里面的属性极为重要,它决定了该 MPD 描述的文件属性和 媒体流 的播放顺序和内容。

> 再说三遍: MPD 文件非常重要! MPD 文件非常重要! MPD 文件非常重要!

其基本属性为:

![image.png-127.6kB](https://example.com/4bf792ecc1b4860081ebb7115a61b373)

接下来,我们一个一个简单介绍一下:

*   id: 设置 MPD 的 identifier,一般不需要。
*   profiles: 设置 MPD 的基本标准,具体内容,参考下表 profles。

![此处输入图片的描述](https://example.com/3ff61367b70671e1b70fe02c2e236de0)

*   type: 用来设置 MPD 文件的基本属性。取值有两个

    *   static:segment 的时长需要在 @availabilityStartTime 和 @availabilityEndTime 之间。
    *   dynamic:主要根据 availabilityStartTime 时间决定。
*   availabilityStartTime: 设置所有 segment 的参考时间,如果 type 为 dynamic,则该属性是必须的。

*   availabilityEndTime: 对于 static 文件来说的静态文件范围。

*   pulishTime: 设置 MPD 文件生成的绝对时间(wall-clock)

*   mediaPresentationDuration: 设置当前 mediaSegments 的总时间长。例如 `PT20M`,表示时长为 20min。当 MPD.minimumUpdatePeriod 和 Period.duration 没有设置时,该属性可以作为替代。

*   minimumUpdatePeriod: 设置当前 MPD 文件的更新时间。当 type = static 时,该属性不应该出现。

*   minBufferTime:用来设置最小 segment 时长,例如:`PT2S`。该通常和 `Representation.bandwidth(bps)` 一起使用,来计算最小 segment 大小值。

*   timeShiftBufferDepth: 用来设置 MPD 中 segment 的有效区间。或者可以理解为 过期时间。这里,后面我们会详述一下。

*   maxSegmentDuration: 设置最大 segment 时长。

上面我们已经了解 MPD 标签里面的基本属性,这些属性在整个 MPEG-DASH 里面非常重要,后面,我们将简单讲解一下关于 MPD 更新和文件过期的点。

### MPD 文件更新机制

MPD 文件的更新主要取决于 @minimumUpdatePeriod 属性设置,例如:`minimumUpdatePeriod="PT10S"`。用来标识,MPD 文件从上一次 MPD 获取时间开始,10s 后检查一次更新。如果没有该属性,或者为 0,则代表该 MPD 文件不会过期。整个更新逻辑为:

![image.png-97.2kB](https://example.com/8b47d0cc2eecfebed2563860dba68ad5)

那当 MPD 文件发生更新时,有一些内容需要注意:

*   MPD.id 属性值必须和以前的 MPD 一致
*   Period.id 属性必须和以前的 Period 一致
*   MPD.publishTime 需要和更新时间一致

更详细的内容,可以参考 ISO/ITU 官方标准 `5.4 Media Presentation Description updates`。

### Segment 文件过期

特别针对于直播切片文件来说,由于服务器容量有限,所以,并不会一直被保存在服务器当中。最好的办法就是协定对应 Segment 的过期时间。那这个过期时间是怎么确定的呢?

主要根据以下公式:

[max(AST, now-timeShiftBufferDepth), now]

*   AST:是 MPD.availabilityStartTime 属性.
*   timeShiftBufferDepth: 是 MPD.timeShiftBufferDepth 属性,用来协定过期时间。

因为通常情况,`max(AST, now-timeShiftBufferDepth) = now-timeShiftBufferDepth`。所以,上面的范围可以精简为:

now-timeShiftBufferDepth <= time <= now

整个时长区间是由 `MPD.timeShiftBufferDepth` 属性值来控制的。例如,MPD 标签的设置值为:

timeShiftBufferDepth=”PT5M”

那么,文件有效期范围为,具体最新 MPD 文件 publishTime 前 5min 之内的链接是有效的。

### Period

Period 主要是用来包含具体 流媒体 的数据,其本身只是起到设置 `startTime` 和区分多个 `Period@id` 的作用。它的基本属性没有多少:

![image.png-43.6kB](https://example.com/6b41b100ecec3d9e739a0b2814e76ca6)

这里,我直接用文本的形式表达一下:

xs:sequence
<xs:element name=”BaseURL” type=”BaseURLType” minOccurs=”0″ maxOccurs=”unbounded”/>
<xs:element name=”SegmentBase” type=”SegmentBaseType” minOccurs=”0″/>

<xs:element name="SegmentList" type="SegmentListType" minOccurs="0"/> 
<xs:element name="SegmentTemplate" type="SegmentTemplateType" minOccurs="0"/> 
<xs:element name="AssetIdentifier" type="DescriptorType" minOccurs="0"/>

<xs:element name="EventStream" type="EventStreamType" minOccurs="0" maxOccurs="unbounded"/> 
<xs:element name="AdaptationSet" type="AdaptationSetType" minOccurs="0" maxOccurs="unbounded"/>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>

<xs:attribute ref=”xlink:href”/>
<xs:attribute ref=”xlink:actuate” default=”onRequest”/>
<xs:attribute name=”id” type=”xs:string” />
<xs:attribute name=”start” type=”xs:duration”/>
<xs:attribute name=”duration” type=”xs:duration”/>
<xs:attribute name=”bitstreamSwitching” type=”xs:boolean” default=”false”/>
<xs:anyAttribute namespace=”##other” processContents=”lax”/>

对于 Period 我们主要关注一下 attribute 属性内容。

*   id: 用来标识 Period 的唯一性。如果 MPD.type=`dynamic`,则该 id 不会在 MPD 更新时改变。

*   start: 用来设置 Period 下,Segment 参考的开始时间。不过,该 start 的确定并不是根据本身的 Period 来决定,还需要根据前一个 Period 来确定:

    *   如果当前的 Period 没有 start 属性,但是前一个 Period 是正常的,有 start 和 duration 属性。那么当前的 `Period.start = prevPeriod.start + prevPeriod.duration`
    *   如果当前的 Period 没有 start 属性,`MPD.type = static`,该 Period 是该 MPD 第一个出现的 Period 标签,那么 start 值默认会被设置为 0
*   duration: 用来决定当前 Period 的时长

*   bitstreamSwitching: 是否允许改变切流,默认为 false。

例如:

// …

### AdapationSet

AdaptionSet 主要是用来对当前包含的流进行基本信息的表述,相当于 MP4 中的 ftype+moof box 信息。

主要属性如下,

xs:sequence

<xs:element name="Accessibility" type="DescriptorType" minOccurs="0" maxOccurs="unbounded"/>

<xs:element name="Role" type="DescriptorType" minOccurs="0" maxOccurs="unbounded"/> 
<xs:element name="Rating" type="DescriptorType" minOccurs="0" maxOccurs="unbounded"/> 
<xs:element name="Viewpoint" type="DescriptorType" minOccurs="0" maxOccurs="unbounded"/> 
<xs:element name="ContentComponent" type="ContentComponentType" minOccurs="0" maxOccurs="unbounded"/>

<xs:element name="BaseURL" type="BaseURLType" minOccurs="0" maxOccurs="unbounded"/> 
<xs:element name="SegmentBase" type="SegmentBaseType" minOccurs="0"/>

<xs:element name="SegmentList" type="SegmentListType" minOccurs="0"/>

<xs:element name="SegmentTemplate" type="SegmentTemplateType" minOccurs="0"/> 
<xs:element name="Representation" type="RepresentationType" minOccurs="0" maxOccurs="unbounded"/>

<xs:attribute ref=”xlink:href”/>
<xs:attribute ref=”xlink:actuate” default=”onRequest”/> <xs:attribute name=”id” type=”xs:unsignedInt”/>
<xs:attribute name=”group” type=”xs:unsignedInt”/> <xs:attribute name=”lang” type=”xs:language”/>
<xs:attribute name=”contentType” type=”xs:string”/> <xs:attribute name=”par” type=”RatioType”/>
<xs:attribute name=”minBandwidth” type=”xs:unsignedInt”/> <xs:attribute name=”maxBandwidth” type=”xs:unsignedInt”/>
<xs:attribute name=”minWidth” type=”xs:unsignedInt”/> <xs:attribute name=”maxWidth” type=”xs:unsignedInt”/>
<xs:attribute name=”minHeight” type=”xs:unsignedInt”/> <xs:attribute name=”maxHeight” type=”xs:unsignedInt”/>
<xs:attribute name=”minFrameRate” type=”FrameRateType”/> <xs:attribute name=”maxFrameRate” type=”FrameRateType”/>
<xs:attribute name=”segmentAlignment” type=”ConditionalUintType” default=”false”/>
<xs:attribute name=”subsegmentAlignment” type=”ConditionalUintType” default=”false”/>
<xs:attribute name=”subsegmentStartsWithSAP” type=”SAPType” default=”0″/>
<xs:attribute name=”bitstreamSwitching” type=”xs:boolean”/>

看图会不会更清晰:

![image.png-295.5kB](https://example.com/ac7b54e34784259c798c7f804249eb60)

这些属性,我就不一一多说了,大家看一个 Demo 理解一下:
这里的描述信息,并不只局限于 AS(AdaptionSet) 一个属性,还可以用在 Representation 上。

### Representation

Representation 是嵌套在 AS 里面,它也是流的相关描述信息,其实也就相当于是一个 IS(Initial Segment)。

主要信息有:

![image.png-273.2kB](https://example.com/b9535b4a0a216d0dad19f73be195b657)

主要用法就是给当前的流提供基本描述信息:
指定 Rep(Representation)的生效范围是在当前的 Period 的范围之内,也就是从:`Period.start - Period.endTime`。Rep 的描述信息为了使用率最大,被 Rep 包含的 Stream 都可以用该内容作为描述信息。

另外,我们还可以结合 `dependencyId` 和 `id` 来重复利用 Rep 的内容。通过 `dependencyId` 指定模板 Rep@id,实现信息的直接复用。
## MPD 如何表达 Segments

在 MPD 中,描述 Segments 主要由 `SegmentBase, SegmentTemplate and SegmentList`。一个完整的 Rep 需要:

*   N+1 SegmentList 标签
*   1 SegmentTemplate
*   N+1 BaseURL 标签,[0,1] SegmentBase,没有 SegmentTemplate 和 SegmentList 标签。

这里,我们简单描述一下对应 Segment tag 的内容。

### SegmentBase

SegmentBase 只在 static MPD 文件中使用,其基本内容其实是几个 Segments tag 共享内容,基本属性为:

xs:sequence
<xs:element name=”Initialization” type=”URLType” minOccurs=”0″/>
<xs:element name=”RepresentationIndex” type=”URLType” minOccurs=”0″/>
<xs:any namespace=”##other” processContents=”lax” minOccurs=”0″ maxOccurs=”unbounded”/>

<xs:attribute name=”timescale” type=”xs:unsignedInt”/>
<xs:attribute name=”presentationTimeOffset” type=”xs:unsignedLong”/>
<xs:attribute name=”timeShiftBufferDepth” type=”xs:duration”/>
<xs:attribute name=”indexRange” type=”xs:string”/>
<xs:attribute name=”indexRangeExact” type=”xs:boolean” default=”false”/>
<xs:attribute name=”availabilityTimeOffset” type=”xs:double”/>
<xs:attribute name=”availabilityTimeComplete” type=”xs:boolean”/>

// extension prop
<xs:extension base=”SegmentBaseType”>
xs:sequence
<xs:element name=”SegmentTimeline” type=”SegmentTimelineType” minOccurs=”0″/>
<xs:element name=”BitstreamSwitching” type=”URLType” minOccurs=”0″/>

<xs:attribute name=”duration” type=”xs:unsignedInt”/>
<xs:attribute name=”startNumber” type=”xs:unsignedInt”/>

如果觉得不清楚,可以看这张图:

![image.png-194.7kB][108]

`Initialization` Tag 可以作为元素,也可以直接作为 Segments Tag 的属性,来设置 Initial Segment 的 URL 链接。基本设置为:

v-0144p-0100k-libx264.mp4

indexRange 设置 media Segment 的字节范围,range 则设置 Initial Segment 的字节范围。

另外,还有几个属性比较重要:

*   presentationTimeOffset:设置当前 Segment 相对于 Period 开始的偏移时间。
*   timeShiftBufferDepth:默认覆盖 MPD 的属性,并且该值不能比 MPD 的小。
*   availabilityTimeOffset:设置当前 Segment 可以获得的时间偏移量。

不过,在实际使用时,使用 SegmentBase 的情况很少,大家对其有印象即可。

### SegmentList

该标签是用来标识一整套 Segment 的 URL list 内容。具体内容信息可以参考:

<xs:element name=”SegmentURL” type=”SegmentURLType” minOccurs=”0″ maxOccurs=”unbounded”/>

<xs:attribute name=”media” type=”xs:anyURI”/>
<xs:attribute name=”mediaRange” type=”xs:string”/>
<xs:attribute name=”index” type=”xs:anyURI”/>
<xs:attribute name=”indexRange” type=”xs:string”/>

主要内容为:

![image.png-125.4kB](https://example.com/8216bc285a0cc9454d35f487a00c7a30)

该 Tag 常常用来包含一个完整的视频 List 内容。
### SegmentTemplate

SegmentTemplate 主要应用在文件切片数量过于庞大,如果使用 `SegmentList` 标签,则有点得不偿失。对于一些 live scenarios,比如直播,连麦等等。使用 `SegmentTemplate` 应该是非常有用的。它可以通过 startNumber,以及对应的 模板URL,来提供给客户端进行相关链接解析。例如:

具体属性内容为:

![image.png-35.5kB](https://example.com/31bdce6bdfa129e0b36d6ffe77b51633)

*   index: 对于 Template 字段,对 $Number$ 和 $Time$ 标识符进行替换。
*   initialization: 用来标识 Initialization Segment 的具体地址,在该属性里面只能使用标识符$RepresentationID$。

使用 template 的方式,能够很大的减小 MPD 文件大小,不过会额外增加以下客户端解析 MPD 的时间。除了上面使用 `$Number$` 形式进行解码外,还可以使用 `$RepresentationID$` 的标识符来进行字符替换:

那一共有哪些标识符可以使用呢?在哪些标签里面才能使用这些标识符呢?我们简单描述一下:

### Identifier 用途

Identifier 常常用在 SegmentTemplate 标签中,只有以下属性可以使用标识符:`media`, `index`, `initialization` 和 `bitstreamSwitching` 属性。

*   $RepresentationID$: 对应于 `Representation` 标签中的 id 属性,比如上面就是 `V300`。。。

完整标识符解释内容,可以关注微信公众号:前端小吉米,输入:MPD.identifier 获取。

SegmentTimeline 里面会通过多个 `S` 标签,来标识在同一个 `MPD duration` 内的 Segment 内容。也就是说,SegmentTimeline 只是提供了一个模板容器,具体的流的标识还是由 `S` 标签内容来决定。直接看一个最简单的 ST(SegmentTimeline):
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。