HLS Spec
#EXTM3U
#EXT-X-TARGETDUATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10
fileSequence0.ts
Maseter Playlist:
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=20000000
gear1/prog_index.m3u8
Media Segments
由一个uri和一个可选的byte range来组成。有一个唯一的sequence number;必须是连续的不能被中断;包含足够的信息来初始化decoder,如H.264包含一个IDR帧。
支持的媒体格式
有MPEG2-ts, Fragmented MPEG-4
Playlists
如果一个playlist中所有的uri是一个playlist,那么就是一个master playlist。
PlayList Tags
ExTM3U | 扩展的M3U播放文件 |
EXT-X-VERSION | 兼容的版本 |
EXT-X-TARGETDURATION | 最大的Media Segment duration |
EXT-X-MEDIA-SEQUENCE | media的序列号 |
EXT-X-DISCONTINUITY-SEQUECE | 在不同的流的听众之间同步 |
EXT-X-I-FRAMES-ONLY | 所有的segment都描述了一个I-frame |
EXT-X-MEDIA | 被用来在PlayList中表示相同内容的不用语种/译文的版本,比如可以通过使用3个这种tag表示3中不用语音的音频,或者用2个这个tag表示不同角度的video在PlayLists中。这个标签是独立存在的,其格式如下: #EXT-X-MEDIA:<attribute-list>:该属性列表中包含:URI、TYPE、GROUP-ID、LANGUAGE、NAME、DEFAULT、AUTOSELECT。 (a) URI:如果没有,则表示这个tag描述的可选择版本在主PlayList的EXT-X-STREAM-INF中存在; (b) TYPE:AUDIO and VIDEO; (c) GROUP-ID:具有相同ID的MEDIA tag,组成一组样式; (d) LANGUAGE:确定使用的主要语言。 (e) NAME:人类可读的语言的翻译。 (f) DEFAULT: YES或是NO,默认是No,如果是YES,则客户端会以这种选项来播放,除非用户自己进行选择。 (g) AUTOSELECT:YES或是NO,默认是No,如果是YES,则客户端会根据当前播放环境来进行选择(用户没有根据自己偏好进行选择的前提下)。 |
EXT-X-STREAM-INF | 指定一个包含多媒体信息的 media URI 作为PlayList,一般做M3U8的嵌套使用,它只对紧跟后面的URI有效,格式如下: #EXT-X-STREAM-INF:<attribute-list> <URI> 有以下属性: (a) BANDWIDTH:带宽,必须有。 (b) PROGRAM-ID:该值是一个十进制整数,惟一地标识一个在PlayList文件范围内的特定的描述。一个PlayList 文件中可能包含多个有相同ID的此tag。(这个属性在后面的协议版本废除了) (c) CODECS:指定流的编码类型,不是必须的。 (d) RESOLUTION:分辨率。 (e) AUDIO:这个值必须和AUDIO类别的“EXT-X-MEDIA”标签中“GROUP-ID”属性值相匹配。 (f) VIDEO:这个值必须和VIDEO类别的“EXT-X-MEDIA”标签中“GROUP-ID”属性值相匹配。 示例: #EXT-X-STREAM-INF:PROGRAM-ID=1, BANDWIDTH=500000, RESOLUTION=720x480 mid_video_index.M3U8 |
HLS playback
Android HLS播放过程
HLS prepare的过程,取消带宽切换,记录以前的带宽index:morigBandwidthIndex,目前的带宽Index:mCurBandwidthIndex; streamMask:新的URI流,resumeMask:uri没有变得流。
在ChangeConfiguration中,停止和抛弃不在需要的fetcher,如果目前的uri和新的rui相同,使用原来的fetcher,否则disFetcher=ture;
在seek的过程中,触发kwhatChangeConfiguration2,否则发送kwhatconfiguration3
处理kwahtchangeconfiguration2时,seek time>0, 清理掉已经缓冲的mPacketSource中的buffer
处理KwhatConfiguration3时,如果uri有变换,设置switching为true,依据新的URI或新增的流创建PlaylistFetcher;
PlaylistFetch:监控缓冲队列,刷新播放列表,触发下载
HttpDownload:由于下载指定的ts
ATSParser:解析相应的playlist
AnotherPacketSource:保存相应的解析的数据
数据获取的流程
从Nuplayerdecoder的onRequesetInputBuffers->httpLivesource的dequeueAccessUnit->LiveSession的dequeueAccessunit-> AnotherPacketSource
然后queue到MediaCodec
Seek过程
根据seek的时间、firstSeqNumberInPlaylist、lastSeqNumberPlayList,获取seek的时间位于那个片段n+1内,然后startTimeUs=seektime-(0.......n)总时间为startimeUs,设置mStartTimeUsRelative=true;在seek的过程中,如果是H264,需要判断是否是IDR帧,如果是isStartTimeReached,开始保存数据。
Playlist的更新
如果每次检测playlist都没有变化,时间就会相应的增加:
INITIAL_MIINIMUM_RELOAD_DELAY | itemDuration-10s | |
FIRST_UNCHANGED_RELOAD_ATTEMPT | targetDuration/2-5s | |
SECOND_UNCHANGED_RELOAD_ATTEMPT | targetDuration*3/2 | |
THIRD_UNCHANGED_RELOAD_ATTEMPT | targetDuration*3 -30s |
在refreshPlaylist中:如果发现没有变化mRefreshState+1
HLS buffering
1.获取当前缓冲的buffer的时间,如果缓冲的时间小于30s,会立刻启动下载
2.如果大于30s,就会计算下一次监控buffer的delayUS
delay的时间取决于两个要素,第一个是多缓冲的时间,和刷新playlist的时间。
多缓冲的时间T1=buffer duration-minbuffer duration
刷新的时间:T2=mLastPlaylistFetchTime+minPlaylistAgeUs-Now
delay=min(T1,T2);
带宽切换
通过提供不同的带宽和下载速度下的资源,可以做到动态切换分辨率;主要依据两个变量,一个是实际带宽,另外一个是缓存的大小;
如果实际的带宽大于阈值,并且缓存大于阈值,就上升带宽;
如果实际带宽小于阈值,并且缓存小于阈值,就下降带宽。
带宽的计算:下载量/下载时间;
每一个ts被按照47K分片进行下载,然后记录每次下载的size,duration,和开始下载的时间。队列中的最后一项的开始时间减去第一项的就是有效期;
当队列中的数据满足条件后,会每1s检测一次带宽;计算好的bw仍然会被保存在长度为3的带宽队列里面;
短期带宽:去对应带宽队列中的带宽的,数据队列中的item,然后是size的总和/duration;
带宽稳定性的检测:
当max小于等于最小的133%时,短期带宽大于min的70%时,是稳定的;最大最小来自带宽队列。
Buffer检测:
往下切换,min(20,targetDuration*9/4);
往上切换,min(15, targetDuration*7/4);
如果所有的track都大于kupSwitchMarkUs就会往上切换;任何一个小于kDownSwthcMarkUs就往下切换。
启动时间计算
带宽上升时:
9const int64_t LiveSession::kUpSwitchMarginUs = 5000000ll;
下降:
带宽数据的合并:
如果带宽切换的过程中,如果下载的新数据的时间戳-旧数据时间戳大于限制,启动旧数据下载;
否则,结束旧数据下载,合并mPacketSource2和mPacketSource的数据。
ATS Parser:
TS流的包结构长度固定为188字节,而PS流的包长度可变。
节目关联表(Program Association Table,PAT)
标识 位数 说明
sync_byte 8 bits 固定是0x47
transport_error_indicator 1 bits 值为0,表示当前包没有发生传输错误。
payload_unit_start_indicator 1 bits 值为1,负载数据从包头数据1字节后开始
transport_priority 1 bits 值为0,表示当前包是低优先级。传输优先级标志(1:优先级高)
PID 13 bits PID=0x0000,说明是PAT表。
transport_scrambling_control 2 bits 值为0x00,表示节目没有加密。
adaptation_field_control 2 bits 值为0x01,改Packet区域含控制调整字段
continuity_counter 4 bits 值为0x00,表示当前传送的相同类型的包是第0个。
节目映射表(Program Map Table, PMT)
PMT表中包含的数据如下:
- 当前节目中所有Video ES流的PID
- 当前节目所有Audio ES流的PID
- 当前节目PCR的PID等。