HLS流媒体
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等。
總結
- 上一篇: HEVC-CABAC
- 下一篇: 计算机的发展