iOS_直播類app_HTTP Live Streaming

http://www.2cto.com/kf/201606/513980.html
css

 

 
https://developer.apple.com/library/ios/technotes/tn2224/_index.html
 
 
這個是 Apple 爲了提升流播效率開發的技術,特色是將流媒體切分爲若干 TS 片斷(好比每10秒一段),而後經過一個 擴展的 m3u 列表文件將這些 TS 片斷集中起來供客戶端播放器接收。

這樣作相比使用 RTSP 協議的好處在於,一旦切分完成,以後的分發過程徹底不須要額外使用任何專門軟件,普通的網絡服務器便可,大大下降了 CDN 邊緣服務器的配置要求,可使用任何現成的 CDN。
 
分發使用的協議是最多見 HTTP,代理服務器對這個協議的緩存優化至關成熟,而不多有代理服務器對 RTSP 的進行緩存優化。這對播放(軟)實時視頻有至關大的優點,由於這樣分發後,對源服務器的負載壓力小得多。

對於非實時視頻,一樣的好處也是存在的:若是你要在一段長達一小時的視頻中跳轉,若是使用單個 MP4 格式的視頻文件,而且也是用 HTTP 協議,那麼須要代理服務器支持 HTTP range request 以獲取大文件中的一部分。不是全部的代理服務器都對此有良好的支持。
 
而 HTTP Live Streaming 則只須要根據 列表文件中的時間軸找出對應的 TS 片斷下載便可,不須要 range request,對代理服務器的要求小不少。全部代理服務器都支持小文件的高效緩存。

此外,HTTP Live Streaming 還有一個巨大優點:自適應碼率流播(adaptive streaming)。效果就是客戶端會根據網絡情況自動選擇不一樣碼率的視頻流,條件容許的狀況下使用高碼率,網絡繁忙的時候使用低碼率,而且自動在兩者間隨意切換。
 
這對移動設備網絡情況不穩定的狀況下保障流暢播放很是有幫助。
實現方法是 服務器端提供多碼率視頻流,而且在列表文件中註明,播放器根據播放進度和下載速度自動調整。

至於爲何要用 TS 而不是 MP4,這是由於 兩個 TS 片斷能夠無縫拼接,播放器能連續播放,而 MP4 文件因爲編碼方式的緣由,兩段 MP4 不能無縫拼接,播放器連續播放兩個 MP4 文件會出現破音和畫面間斷,影響用戶體驗。

前兩年我嘗試過一個基於 HTML5 < audio > 標籤 + CBR MP3 格式 + Icecast 流媒體服務器的網絡廣播臺的網頁應用(預想是給  http://apple4.us 作 Livecast 的,就是聽衆只須要訪問一個網頁就可以幾乎實時聽到訪談節目),採用的正是 HTTP Live Streaming 的思路。經過對 MP3 音頻流進行幀切分,基本能作到連續播放。惟一問題是瀏覽器不支持 TS 格式, < audio > 標籤在兩段 MP3 以前切換時會破音。這樣只能對談話類內容適用,若是播放連續的音樂有時候會聽出破綻。

iOS 設備上啓用 HTTP Live Streaming 很是簡單,也是蘋果官方推薦的方式。
 
Adobe 的 Flash 流媒體服務器的新版本也要支持這個技術的 。這樣普及開來是好事,用戶體驗更好、網絡壓力更低。
 
 

經常使用的流媒體協議主要有 HTTP 漸進下載和基於RTSP/RTP 的實時流媒體協議html

這二種基本是徹底不一樣的東西,目前比較方便又好用的我建議使用 HTTP 漸進下載的方法。html5

 

在這個中 apple 公司的 HTTP Live Streaming 是這個方面的表明。它最初是蘋果公司針對iPhone、iPod、iTouch和iPad等移動設備而開發的流.如今見到在桌面也有不少應用了, HTML5 是直接支持這個。java

 

咱們能夠看看 HTTP Live Streaming 是怎麼樣工做的。平時的直播技術中,播放模式中必須等待整個文件下載完才行,在 HLS 技術中 Web 服務器向客戶端提供接近實時的音視頻流。但在使用的過程當中是使用的標準的 HTTP 協議,因此這時,只要使用 HLS 的技術,就能在普通的 HTTP 的應用上直接提供點播和直播。ios


要詳細瞭解原理,咱們先看看這個所須要的步驟。git

?
1
視頻採集 ->編碼器 -> 流分割 -> 普通 web 服務(索引文件和視頻文件) -> 客戶端

 

內容準備的過程大約二種,一是視頻採集,編碼器首先將攝像機實時採集的音視頻數據壓縮編碼爲符合特定標準的音視頻基本流,也能夠拿編碼完了的文件,有一點必須保證,就是必定要使用H.264視頻和AAC音頻,由於發明這個的是蘋果公司,只支持這個。github

而後給這些封裝成成爲符合MPEG-2(MPEG 2 TS、MPEG2 PS之因此使用這個,主要是由於聲音和視頻會交織在一塊兒,也會有關鍵幀來讓視頻能夠直接播放).web

 

流分割部分在這個中,比起 RTSP 之類和普通點播的最大不一樣,就是他會給 MPEG-2 分割成不少個 ts 的文件。分割過程大可能是按時間來切,根據國外的資料,建議切 10s 一個的文件,若是碼流高能夠 5 秒一次。sql

 

在分割還有一點不一樣,就是這時流分割器會生成一個含有指向這些小TS文件指針的索引文件,因此這個文件也必須在 web 服務器上,不能少。每多 10s 時,就會多一個 ts 文件,因此索引也會根着修改爲最新的幾段視頻。數組

 

最後,這些切分了的小的一系列的 ts 文件,放到普通的 web 服務器中就好了。這時在 CDN 中也是同樣,由於請求這些文件會使用標準的 HTTP 協議。

 

索引文件後綴是.m3u8 ,索引文件採用擴展的M3U播放列表格式,其實就一文本。

內部的視頻的地址會是以下

?
1
2
3
http: //media.example.com/s_96ksegment1.ts
http: //media.example.com/s_96ksegment2.ts
http: //media.example.com/s_96ksegment3.ts

 

因此這時能夠直接作 Cache 和直接放到 Web 服務器中,簡單方便。
若是 MIME 的信息輸出不對的話,記的要修改這加入 ts 和 m3u8 的後綴支持

?
1
2
.m3u8 application/x-mpegURL
.ts video/MP2T

 

最後就是客戶端,若是是 HTML 直接在 Html5 中直接支持這種視頻可使用以下標籤

?
1
 

 

若是是應用客戶端(Safari QuickTime之類),就得裝軟件來支持,客戶端會根據選擇的流的索引來下載文件,當下載了最少二段後開始播放。直接 m3u8 的索引結束。

 

另外,HTTP能夠設計成的自適應比特率流,在不一樣網絡環境,選擇下載不一樣碼流的視頻。

因此整個 HTTP Live Streaming 不管是直播仍是點播,都能作到近似實時的方式來進行流播放。理論的最小時延是每一個切片的長.

 
 
 

HTTP Live Streaming直播(iOS直播)技術分析與實現

  

  HTTP Live StreamingHLS)技術,並實現了一個HLS編碼器HLSLiveEncoder,C++寫的。

其功能是採集攝像頭與麥克風,實時進行H.264視頻編碼和AAC音頻編碼,並按照HLS的協議規範,生成分段的標準TS文件以及m3u8索引文件

 

經過HLSLiveEncoder和第三方Http服務器(例如:Nginx),成功實現了HTTP Live Streaming直播,並在iphone上測試經過。

HLS技術要點分析

  HTTP Live StreamingHLS)是蘋果公司(Apple Inc.)實現的基於HTTP的流媒體傳輸協議,可實現流媒體的直播和點播,主要應用在iOS系統,爲iOS設備(如iPhone、iPad)提供音視頻直播和點播方案。

HLS點播,基本上就是常見的分段HTTP點播,不一樣在於,它的分段很是小。要實現HLS點播,重點在於對媒體文件分段,目前有很多開源工具可使用,只談HLS直播技術。

 

  相對於常見的流媒體直播協議,例如RTMP協議、RTSP協議、MMS協議等,HLS直播最大的不一樣在於,直播客戶端獲取到的,並非一個完整的數據流。

HLS協議在服務器端將直播數據流存儲爲連續的、很短時長的媒體文件(MPEG-TS格式),而客戶端則不斷的下載並播放這些小文件,由於服務器端老是會將最新的直播數據生成新的小文件,這樣客戶端只要不停的按順序播放從服務器獲取到的文件,就實現了直播。

 

因而可知,基本上能夠認爲,HLS是以點播的技術方式來實現直播。因爲數據經過HTTP協議傳輸,因此徹底不用考慮防火牆或者代理的問題,並且分段文件的時長很短,客戶端能夠很快的選擇和切換碼率,以適應不一樣帶寬條件下的播放。

不過HLS的這種技術特色,決定了它的延遲通常老是會高於普通的流媒體直播協議。

  根據以上的瞭解要實現HTTP Live Streaming直播,須要研究並實現如下技術關鍵點

  1. 採集視頻源和音頻源的數據
  2. 對原始數據進行H264編碼和AAC編碼
  3. 視頻和音頻數據封裝爲MPEG-TS包
  4. HLS分段生成策略及m3u8索引文件
  5. HTTP傳輸協議

      其中第1點和第2點,我以前的文章中已經提到過了,而最後一點,咱們能夠藉助現有的HTTP服務器,因此,實現第3點和第4點是關鍵所在。

    原文:http://www.cnblogs.com/haibindev/archive/2013/01/30/2880764.html

    程序框架與實現

      經過以上分析,實現HLS LiveEncoder直播編碼器,其邏輯和流程基本上很清楚了:分別開啓音頻與視頻編碼線程,經過DirectShow(或其餘)技術來實現音視頻採集,隨後分別調用libx264和libfaac進行視頻和音頻編碼。兩個編碼線程實時編碼音視頻數據後,根據自定義的分片策略,存儲在某個MPEG-TS格式分段文件中,當完成一個分段文件的存儲後,更新m3u8索引文件。以下圖所示:

    \

      上圖中HLSLiveEncoder當收到視頻和音頻數據後,須要首先判斷,當前分片是否應該結束,並建立新分片,以延續TS分片的不斷生成。

    須要注意的是,新的分片,應當從關鍵幀開始,防止播放器解碼失敗。核心代碼以下所示:

    \

      TsMuxer的接口也是比較簡單的。

    \

    HLS分段生成策略和m3u8

    1. 分段策略

    • HLS的分段策略,基本上推薦是10秒一個分片,固然,具體時間還要根據分好後的分片的實際時長作標註
    • 一般來講,爲了緩存等方面的緣由,在索引文件中會保留最新的三個分片地址,以相似「滑動窗口」的形式,進行更新。

      2. m3u8文件簡介

        m3u8,是HTTP Live Streaming直播的索引文件。

      m3u8基本上能夠認爲就是.m3u格式文件,

      區別在於,m3u8文件使用UTF-8字符編碼。

      ?
      1
      2
      3
      4
      5
      6
      #EXTM3U                     m3u文件頭,必須放在第一行
      #EXT-X-MEDIA-SEQUENCE       第一個TS分片的序列號
      #EXT-X-TARGETDURATION       每一個分片TS的最大的時長
      #EXT-X-ALLOW-CACHE          是否容許cache
      #EXT-X-ENDLIST              m3u8文件結束符
      #EXTINF                     extra info,分片TS的信息,如時長,帶寬等

  一個簡單的m3u8索引文件

\

運行效果

  在Nginx工做目錄下啓動HLSLiveEncoder,並用VLC播放器鏈接播放

\

  經過iPhone播放的效果

\

 

 

 

蘋果官方對於視頻直播服務提出了 HLS (HTTP Live Streaming) 解決方案,該方案主要適用範圍在於:

使用 iPhone 、iPod touch、 iPad 以及 Apple TV 進行流媒體直播功能。(MAC 也能用)不使用特殊的服務軟件進行流媒體直播。須要經過加密和鑑定(authentication)的視頻點播服務。

首先,須要你們先對 HLS 的概念進行預覽。

HLS 的目的在於,讓用戶能夠在蘋果設備(包括MAC OS X)上經過普通的網絡服務完成流媒體的播放。 HLS 同時支持流媒體的實時廣播點播服務。同時也支持不一樣 bit 速率的多個備用流(平時根據當前網速去自適應視頻的清晰度),這樣客戶端也好根據當前網絡的帶寬去只能調整當前使用的視頻流。安全方面,HLS 提供了經過 HTTPS 加密對媒體文件進行加密並 對用戶進行驗證,容許視頻發佈者去保護本身的網絡。

 

HLS 是蘋果公司QuickTime X和iPhone軟件系統的一部分。它的工做原理是把整個流分紅一個個小的基於HTTP的文件來下載,每次只下載一些。當媒體流正在播放時,客戶端能夠選擇從許多不一樣的備用源中以不一樣的速率下載一樣的資源,容許流媒體會話適應不一樣的數據速率。

在開始一個流媒體會話時,客戶端會下載一個包含元數據的extended M3U (m3u8) playlist文件,用於尋找可用的媒體流。

 

HLS只請求基本的HTTP報文,與實時傳輸協議(RTP)不一樣,HLS能夠穿過任何容許HTTP數據經過的防火牆或者代理服務器。它也很容易使用內容分發網絡來傳輸媒體流。

蘋果對於自家的 HLS 推廣也是採起了強硬措施,當你的直播內容持續十分鐘
或者每五分鐘內超過 5 MB 大小時,你的 APP 直播服務必須採用 HLS 架構,不然不容許上架。(詳情

相關服務支持環境 (重要組成)

  • Adobe Flash Media Server:從4.5開始支持HLS、Protected HLS(PHLS)。5.0更名爲Adobe Media Server
  •  
  • Flussonic Media Server:2009年1月21日,版本3.0開始支持VOD、HLS、時移等。

  • RealNetworks的Helix Universal Server :2010年4月,版本15.0開始支持iPhone, iPad和iPod的HTTP直播、點播H.264/AAC內容,最新更新在2012年11月。
  •  
  • 微軟的IIS Media Services:從4.0開始支持HLS。
  •  
  • Nginx RTMP Module:支持直播模式的HLS。
  •  
  • Nimber Streamer
  •  
  • Unified Streaming Platform

  • VLC Media Player:從2.0開始支持直播和點播HLS。
  •  
  • Wowza Media Server:2009年12月9日發佈2.0,開始全面支持HLS。
  •  
  • VODOBOX Live Server:始支持HLS。
  •  
  • Gstreamill是一個支持hls輸出的,基於gstreamer的實時編碼器。

相關客戶端支持環境

iOS從3.0開始成爲標準功能。
Adobe Flash Player從11.0開始支持HLS。
Google的Android自Honeycomb(3.0)開始支持HLS。
VODOBOX HLS Player (Android,iOS, Adobe Flash Player)
JW Player (Adobe Flash player)
Windows 10 的 EDGE 瀏覽器開始支持HLS。
\
HLS架構

其中輸入視頻源是由攝像機預先錄製好的。

以後這些源會被編碼 MPEG-4(H.264 video 和 AAC audio)格式而後用硬件打包到MPEG-2的傳輸流中。

MPEG-2 傳輸流會被分散爲小片斷而後保存爲一個或多個系列的 .ts 格式的媒體文件。

這個過程須要藉助編碼工具來完成,好比 Apple stream segmenter

 

純音頻會被編碼爲一些音頻小片斷,一般爲包含 ADTS頭的AAC、MP三、或者 AC-3格式。

 

ADTS全稱是(Audio Data Transport Stream),是AAC的一種十分常見的傳輸格式。

通常的AAC解碼器都須要把AAC的ES流打包成ADTS的格式,通常是在AAC ES流前添加7個字節的ADTS header


 

ES流- Elementary Streams (原始流):對視頻、音頻信號及其餘數據進行編碼壓縮後 的數據流稱爲原始流。原始流包括訪問單元,好比視頻原始流的訪問單元就是一副圖像的編碼數據。

 

 

同時上面提到的那個切片器(segmenter)也會建立一個索引文件,一般會包含這些媒體文件的一個列表,也能包含元數據。他通常都是一個.M38U 個hi的列表。列表元素會關聯一個 URL 用於客戶端訪問。而後按序去請求這些 URL。

服務器端

服務端能夠採用硬件編碼和軟件編碼兩種形式,其功能都是按照上文描述的規則對現有的媒體文件進行切片並使用索引文件進行管理。而軟件切片一般會使用 Apple 公司提供的工具或者第三方的集成工具。

媒體編碼

媒體編碼器獲取到音視頻設備的實時信號,將其編碼後壓縮用於傳輸。而編碼格式必須配置爲客戶端所支持的格式,好比 H.264 視頻和HE-AAC 音頻。當前,支持 用於視頻的 MPEG-2 傳輸流和 純音頻 MPEG 基本流。編碼器經過本地網絡將 MPEG-2 傳輸流分發出去,送到流切片器那裏。標準傳輸流和壓縮傳輸流沒法混合使用。傳輸流能夠被打包成不少種不一樣的壓縮格式,這裏有兩個表詳細列舉了支持的壓縮格式類型。

Audio Technologies Vedio Technologies
[重點]在編碼中圖,不要修改視頻編碼器的設置,好比視頻大小或者編碼解碼器類型。若是避免不了,那修改動做必須發生在一個片斷邊界。而且須要早以後相連的片斷上用EXT-X-DISCONTINUITY 進行標記。

流切片器

流切片器(一般是一個軟件)會經過本地網絡從上面的媒體編碼器中讀取數據,而後將着這些數據一組相等時間間隔的  媒體文件。雖然沒一個片斷都是一個單獨的文件,可是他們的來源是一個連續的流,切完照樣能夠無縫重構回去。

切片器在切片同時會建立一個索引文件,索引文件會包含這些切片文件的引用。每當一個切片文件生成後,索引文件都會進行更新。索引用於追蹤切片文件的有效性和定位切片文件的位置。切片器同時也能夠對你的媒體片斷進行加密而且建立一個密鑰文件做爲整個過程的一部分。

文件切片器(相對於上面的流切片器)

若是已近有編碼後的文件(而不是編碼流),你可使用文件切片器,經過它對編碼後的媒體文件進行 MPEG-2 流的封裝而且將它們分割爲等長度的小片斷。切片器容許你使用已經存在的音視頻庫用於 HLS 服務。它和流切片器的功能類似,可是處理的源從流替換流爲了文件。

媒體片斷文件

媒體片斷是由切片器生成的,基於編碼後的媒體源,而且是由一系列的 .ts 格式的文件組成,其中包含了你想經過 MPEG-2 傳送流攜帶的 H.264 視頻 和 AAC
/MP3/AC-3 音頻。對於純音頻的廣播,切片器能夠生產 MPEG 基礎音頻流,其中包含了 ADTS頭的AAC、MP三、或者AC3等音頻。

索引文件(PlayLists)

一般由切片器附帶生成,保存爲 .M3U8 格式,.m3u 通常用於 MP3 音頻的索引文件。
Note若是你的擴展名是.m3u,而且系統支持.mp3文件,那客戶的軟件可能要與典型的 MP3 playList 保持一致來完成 流網絡音頻的播放。

下面是一個 .M3U8 的 playlist 文件樣例,其中包含了三個沒有加密的十秒鐘的媒體文件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<code class = "cpp" >#EXT-X-VERSION: 3
#EXTM3U
#EXT-X-TARGETDURATION: 10
#EXT-X-MEDIA-SEQUENCE: 1
 
# Old-style integer duration; avoid for newer clients.
#EXTINF: 10 ,
http: //media.example.com/segment0.ts
 
# New-style floating-point duration; use for modern clients.
#EXTINF: 10.0 ,
http: //media.example.com/segment1.ts
#EXTINF: 9.5 ,
http: //media.example.com/segment2.ts
#EXT-X-ENDLIST</code>

爲了更精確,你能夠在 version 3 或者以後的協議版本中使用 float 數來標記媒體片斷的時長,而且要明確寫明版本號,若是沒有版本號,則必須與 version 1 協議保持一致。你可使用官方提供的切片器去生產各類各樣的 playlist 索引文件,詳見媒體文件切片器

分佈式部分

分佈式系統是一個網絡服務或者一個網絡緩存系統,用於經過 HTTP 向客戶端發送媒體文件和索引文件。不用自定義模塊發送內容。一般僅僅須要很簡單的網絡配置便可使用。並且這種配置通常就是限制指定 .M38U 文件和 .ts 文件的 MIME 類型。詳見部署 HTTP Live Streaming

客戶端部分

客戶端開始時回去抓取 索引文件(.m3u8/.m3u),其中用URL來標記不一樣的流。索引文件能夠指定可用媒體文件的位置,解密的密鑰,以及任何能夠切換的流。對於選中的流,客戶端會有序的下載每個可得到的文件。每個文件都包含流中的連環碎片。一旦下載到足夠量的數據,客戶端會開始向用戶展現從新裝配好的媒體資源。

客戶端負責抓取任何解密密鑰,認證或者展現一個用於認證的界面,以後再解密須要的文件。

這個過程會一直持續知道出現 結束標記 #EXT-X-ENDLIST。若是結束標記不出現,該索引就是用於持續廣播的。客戶端會按期的加載一些新的索引文件。客戶端會重新更新的索引文件中去查找加密密鑰而且將關聯的URL加入到請求隊列中去。

HLS 的使用

使用 HLS 須要使用一些工具,固然大部分工具都是服務器端使用的,這裏簡單瞭解一下就行,包括 media stream segmenter, a media file segmenter, a stream validator, an id3 tag generator, a variant playlist generator.這些工具用英文註明是爲了當你在蘋果開發中心中尋找時方便一些。

會話模式

一般包含 Live 和 VOD (點播)兩種

點播VOD的特色就是能夠獲取到一個靜態的索引文件,其中那個包含一套完整的資源文件地址。這種模式容許客戶端訪問所有節目。VOD點播擁有先進的下載技術,包括加密認證技術和動態切換文件傳輸速率的功能(一般用於不一樣分辨率視頻之間的切換)。

Live 會話就是實時事件的錄製展現。它的索引文件一直處於動態變化的,你須要不斷的更新索引文件 playlist 而後移除舊的索引文件。這種類型經過向索引文件添加媒體地址能夠很容易的轉化爲VOD類型。在轉化時不要移除原來舊的源,而是經過添加一個#ET-X-ENDLIST 標記來終止實時事件。轉化時若是你的索引文件中包含 EXT-X-PLAYLIST-TYPE 標籤,你須要將值從EVENT 改成 VOD

ps:本身抓了一個直播的源,從索引中看到的結果是第一次回抓到表明不一樣帶寬的playList(抓取地址:http://dlhls.cdn.zhanqi.tv/zqlive/34338_PVMT5.m3u8)

?
1
2
3
4
5
6
7
8
<code class = "cpp" >#EXTM3U
#EXT-X-VERSION: 3
#EXT-X-STREAM-INF:PROGRAM-ID= 1 ,PUBLISHEDTIME= 1453914627 ,CURRENTTIME= 1454056509 ,BANDWIDTH= 700000 ,RESOLUTION=1280x720
34338_PVMT5_700/index.m3u8?Dnion_vsnae=34338_PVMT5
#EXT-X-STREAM-INF:PROGRAM-ID= 1 ,PUBLISHEDTIME= 1453914627 ,CURRENTTIME= 1454056535 ,BANDWIDTH= 400000
34338_PVMT5_400/index.m3u8?Dnion_vsnae=34338_PVMT5
#EXT-X-STREAM-INF:PROGRAM-ID= 1 ,PUBLISHEDTIME= 1453914627 ,CURRENTTIME= 1454056535 ,BANDWIDTH= 1024000
34338_PVMT5_1024/index.m3u8?Dnion_vsnae=34338_PVMT5</code>

這裏面的連接不是視頻源URL,而是一個用於流切換的主索(下面會有介紹)引我猜測是須要對上一次的抓包地址作一個拼接

組合的結果就是:http://dlhls.cdn.zhanqi.tv/zqlive/34338_PVMT5_1024/index.m3u8?Dnion_vsnae=34338_PVMT5(純屬小學智力題。。。)將它做爲抓取地址再一次的結果

?
1
2
3
4
5
6
7
8
9
10
<code class = "cpp" >#EXTM3U
#EXT-X-VERSION: 3
#EXT-X-MEDIA-SEQUENCE: 134611
#EXT-X-TARGETDURATION: 10
#EXTINF: 9.960 ,
35 /1454056634183_128883.ts?Dnion_vsnae=34338_PVMT5
#EXTINF: 9.960 ,
35 /1454056644149_128892.ts?Dnion_vsnae=34338_PVMT5
#EXTINF: 9.960 ,
35 /1454056654075_128901.ts?Dnion_vsnae=34338_PVMT5</code>

同理,繼續向下抓:(拼接地址:http://dlhls.cdn.zhanqi.tv/zqlive/34338_PVMT5_1024/index.m3u8?Dnion_vsnae=34338_PVMT5/35/1454056634183_128883.ts?Dnion_vsnae=34338_PVMT5/36/1454059958599_131904.ts?Dnion_vsnae=34338_PVMT5
抓取結果:

?
1
2
3
4
5
6
7
8
9
10
<code class = "cpp" >#EXTM3U
#EXT-X-VERSION: 3
#EXT-X-MEDIA-SEQUENCE: 134984
#EXT-X-TARGETDURATION: 10
#EXTINF: 9.280 ,
36 /1454059988579_131931.ts?Dnion_vsnae=34338_PVMT5
#EXTINF: 9.960 ,
36 /1454059998012_131940.ts?Dnion_vsnae=34338_PVMT5
#EXTINF: 9.960 ,
36 /1454060007871_131949.ts?Dnion_vsnae=34338_PVMT5</code>

相比於第二次又獲取了一個片斷的索引,並且只要是第二次以後,資源地址都會包含 .ts,說明裏面是有視頻資源URL的,不過具體的截取方法仍是須要查看前面提到的IETF的那套標準的HLS的協議,利用裏面的協議應該就能拼接出完整的資源路徑進行下載。反正我用蘋果自帶的MPMoviePlayerController直接播放是沒有問題的,的確是直播資源。與以前說過的蘋果自帶的QuickTime相似,都遵循了HLS協議用於流媒體播放。而每次經過拼接獲取下一次的索引,符合協議裏提到的不斷的更替索引的動做。

內容加密

若是內容須要加密,你能夠在索引文件中找到密鑰的相關信息。若是索引文件中包含了一個密鑰文件的信息,那接下來的媒體文件就必須使用密鑰解密後才能解密打開了。當前的 HLS 支持使用16-octet 類型密鑰的 AES-128 加密。這個密鑰格式是一個由着在二進制格式中的16個八進制組的數組打包而成的。

加密的配置模式一般包含三種:

模式一:容許你在磁盤上制定一個密鑰文件路徑,切片器會在索引文件中插入存在的密鑰文件的 URL。全部的媒體文件都使用該密鑰進行加密。模式二:切片器會生成一個隨機密鑰文件,將它保存在指定的路徑,並在索引文件中引用它。全部的媒體文件都會使用這個隨機密鑰進行加密。模式三:每 n 個片斷生成一個隨機密鑰文件,並保存到指定的位置,在索引中引用它。這個模式的密鑰處於輪流加密狀態。每一組 n 個片斷文件會使用不一樣的密鑰加密。

理論上,不按期的碎片個數生成密鑰會更安全,可是按期的生成密鑰不會對系統的性能產生太大的影響。

你能夠經過 HTTP 或者 HTTPS 提供密鑰。也能夠選擇使用你本身的基於會話的認證安排去保護髮送的key。更多詳情能夠參考經過 HTTPS 安全的提供預定

密鑰文件須要一個 initialization vector (IV) 去解碼加密的媒體文件。IV 能夠隨着密鑰按期的改變。

緩存和發送協議

HTTPS一般用於發送密鑰,同時,他也能夠用於平時的媒體片斷和索引文件的傳輸。可是當擴展性更重要時,這樣作是不推薦的。HTTPS 請求一般都是繞開 web 服務緩存,致使全部內容請求都是經過你的服務進行轉發,這有悖於分佈式網絡鏈接系統的目的。

處於這個緣由,確保你發送的網絡內容都明白很是重要。當處於實況廣播模式時索引文件不會像分片媒體文件同樣長時間的被緩存,他會動態不停地變化。

流切換

若是你的視頻具有流切換功能,這對於用戶來講是一個很是棒的體驗,處於不一樣的帶寬、不一樣的網速播放不一樣清晰度的視頻流,這樣只能的流切換能夠保證用戶感受到很是流暢的觀影體驗,同時不一樣的設備也能夠做爲選擇的條件,好比視網膜屏能夠再網速良好的狀況下播放清晰度更高的視頻流。

這種功能的實如今於,索引文件的特殊結構

\
流切換索引文件結構

有別於普通的索引,具有流熱切換的索引一般由主索引和連接不一樣帶寬速率的資源的子索引,由子索引再連接對引得.ts視頻切片文件。其中主索引只下載一次,而子索引則會不停按期的下載,一般會先使用主索引中列出的第一個子索引,以後纔會根據當時的網絡狀況去動態切換合適的流。客戶端會在任什麼時候間去切換不一樣的流。好比連入或者退出一個 wifi 熱點。全部的切換都會使用相同的音頻文件(換音頻沒多大意思相對於視頻)在不一樣的流之間平滑的進行切換。
這一套不一樣速率的視頻都是有工具生成的,使用variantplaylistcreator 工具而且爲mediafilesegmenter 或者mediastreamsegmenter 指定 -generate-variant-playlist 選項,詳情參考下載工具

概念先寫到這吧,前面的知識夠對HSL的總體結構作一個初步的瞭解。

 

 

 

Demo配置原理:

一、 須要導入第三方庫:ASIHttpRequest,CocoaHTTPServer,m3u8(其中ASI用於網絡請求,CocoaHTTPServer用於在ios端搭建服務器使用,m3u8是用來對返回的索引文件進行解析的)

\
ASI配置注意事項  \
MRC報錯處理

二、導入系統庫:libsqlite3.dylib、libz.dylib、libxml2.dylib、CoreTelephony.framework、SystemConfiguration.framework、MobileCoreServices.framework、Security.framework、CFNetwork.framework、MediaPlayer.framework

三、添加頭文件

?
1
<code class = "css" >YCHLS-Demo.h</code>

四、demo介紹

\
demo樣式  播放:直接播放在線的直播連接,是由系統的MPMoviePlayer完成的,它自帶解析HLS直播鏈的功能。 下載:遵循HLS的協議,經過索引文件的資源路徑下載相關的視頻切片並保存到手機本地。 播放本地視頻:使用下載好的視頻文件片斷進行連續播放。 清除緩存:刪除下載好的視頻片斷

原理:

經過ASI請求連接,經過m3u8庫解析返回的m3u8索引文件。再經過ASI下載解析出的視頻資源地址,仿照HLS中文件存儲路徑存儲。利用CocoaHTTPServer在iOS端搭建本地服務器,並開啓服務,端口號爲:12345(高位端口便可)。配置服務器路徑與步驟二存儲路徑一致。設置播放器直播連接爲本地服務器地址,直接播放,因爲播放器遵照HLS協議,因此可以解析咱們以前使用HLS協議搭建的本地服務器地址。點擊在線播放,校驗是否與本地播放效果一致。  \
HLS協議文件存儲結構

上面是HLS中服務器存儲視頻文件切片和索引文件的結構圖
整個流程就是:

先點擊下載,經過解析m3u8的第三方庫解析資源。(m3u8的那個庫只能解析一種特定格式的m3u8文件,代碼裏會有標註)點擊播放本地視頻播放下載好的資源。點擊播放是用來預覽直播的效果,與整個流程無關。其中進度條用來顯示下載進度。

總結:
整個Demo並不僅是讓咱們搭建一個Hls服務器或者一個支持Hls的播放器。目的在於瞭解Hls協議的具體實現,以及服務器端的一些物理架構。經過Demo的學習,能夠詳細的瞭解Hls直播具體的實現流程。

部分源碼貼出

開啓本地服務器:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<code class = "objectivec" >- ( void )openHttpServer
{
     self.httpServer = [[HTTPServer alloc] init];
     [self.httpServer setType:@ "_http._tcp." ];  // 設置服務類型
     [self.httpServer setPort: 12345 ]; // 設置服務器端口
 
     // 獲取本地Library/Cache路徑下downloads路徑
     NSString *webPath = [kLibraryCache stringByAppendingPathComponent:kPathDownload];
     NSLog(@ "-------------\\nSetting document root: %@\\n" , webPath);
     // 設置服務器路徑
     [self.httpServer setDocumentRoot:webPath];
     NSError *error;
     if (![self.httpServer start:&error])
     {
         NSLog(@ "-------------\\nError starting HTTP Server: %@\\n" , error);
     }</code>

視頻下載:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<code class = "objectivec" >- (IBAction)downloadStreamingMedia:(id)sender {
 
     UIButton *downloadButton = sender;
     // 獲取本地Library/Cache路徑
     NSString *localDownloadsPath = [kLibraryCache stringByAppendingPathComponent:kPathDownload];
 
     // 獲取視頻本地路徑
     NSString *filePath = [localDownloadsPath stringByAppendingPathComponent:@ "XNjUxMTE4NDAw/movie.m3u8" ];
     NSFileManager *fileManager = [NSFileManager defaultManager];
     // 判斷視頻是否緩存完成,若是完成則播放本地緩存
     if ([fileManager fileExistsAtPath:filePath]) {
         [downloadButton setTitle:@ "已完成" forState:UIControlStateNormal];
         downloadButton.enabled = NO;
     } else {
         M3U8Handler *handler = [[M3U8Handler alloc] init];
         handler.delegate = self;
         // 解析m3u8視頻地址
         [handler praseUrl:TEST_HLS_URL];
         // 開啓網絡指示器
         [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
     }
}</code>

播放本地視頻:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<code class = "objectivec" >- (IBAction)playVideoFromLocal:(id)sender {
 
     NSString * playurl = [NSString stringWithFormat:@ "http://127.0.0.1:12345/XNjUxMTE4NDAw/movie.m3u8" ];
     NSLog(@ "本地視頻地址-----%@" , playurl);
 
     // 獲取本地Library/Cache路徑
     NSString *localDownloadsPath = [kLibraryCache stringByAppendingPathComponent:kPathDownload];
     // 獲取視頻本地路徑
     NSString *filePath = [localDownloadsPath stringByAppendingPathComponent:@ "XNjUxMTE4NDAw/movie.m3u8" ];
     NSFileManager *fileManager = [NSFileManager defaultManager];
 
     // 判斷視頻是否緩存完成,若是完成則播放本地緩存
     if ([fileManager fileExistsAtPath:filePath]) {
         MPMoviePlayerViewController *playerViewController =[[MPMoviePlayerViewController alloc]initWithContentURL:[NSURL URLWithString: playurl]];
         [self presentMoviePlayerViewControllerAnimated:playerViewController];
     }
     else {
         UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@ "Sorry" message:@ "當前視頻未緩存" delegate:self cancelButtonTitle:@ "肯定" otherButtonTitles:nil, nil];
         [alertView show];
     }
}</code>

播放在線視頻

?
1
2
3
4
5
6
<code class = "objectivec" >- (IBAction)playLiveStreaming {
 
     NSURL *url = [[NSURL alloc] initWithString:TEST_HLS_URL];
     MPMoviePlayerViewController *player = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
     [self presentMoviePlayerViewControllerAnimated:player];
}</code>

 

ADTS是個啥

ADTS全稱是(Audio Data Transport Stream),是AAC的一種十分常見的傳輸格式。

通常的AAC解碼器都須要把AAC的ES流打包成ADTS的格式,通常是在AAC ES流前添加7個字節的ADTS header

也就是說你能夠吧ADTS這個頭看做是AAC的frameheader。

 

ADTS AAC
ADTS_header AAC ES ADTS_header AAC ES
...
ADTS_header AAC ES

2.ADTS內容及結構

ADTS 頭中相對有用的信息採樣率、聲道數、幀長度

想一想也是,我要是解碼器的話,你給我一堆得AAC音頻 ES流我也解不出來。

每個帶ADTS頭信息的AAC流會清晰的告送解碼器他須要的這些信息。

通常狀況下ADTS的頭信息都是7個字節,7*8 = 56 個bit,分爲2部分:

固定頭 adts_fixed_header(); 28bit

可變頭 adts_variable_header(); 28bit

\

其中:

syncword:同步頭 老是0xFFF,12 bit, all bits must be 1,表明着一個ADTS幀的開始

ID:MPEG Version: 0 for MPEG-4, 1 for MPEG-2

Layer:always: '00'

profile:表示使用哪一個級別的AAC,有些芯片只支持AAC LC 。

在MPEG-2 AAC中定義了3種:

\

sampling_frequency_index:

表示使用的採樣率下標,經過這個下標在Sampling Frequencies[ ]數組中查找得知採樣率的值。

There are 13 supported frequencies:

  • 0: 96000 Hz
  • 1: 88200 Hz
  • 2: 64000 Hz
  • 3: 48000 Hz
  • 4: 44100 Hz
  • 5: 32000 Hz
  • 6: 24000 Hz
  • 7: 22050 Hz
  • 8: 16000 Hz
  • 9: 12000 Hz
  • 10: 11025 Hz
  • 11: 8000 Hz
  • 12: 7350 Hz
  • 13: Reserved
  • 14: Reserved
  • 15: frequency is written explictly channel_configuration:表示聲道數
    • 0: Defined in AOT Specifc Config
    • 1: 1 channel: front-center
    • 2: 2 channels: front-left, front-right
    • 3: 3 channels: front-center, front-left, front-right
    • 4: 4 channels: front-center, front-left, front-right, back-center
    • 5: 5 channels: front-center, front-left, front-right, back-left, back-right
    • 6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel
    • 7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel
    • 8-15: Reserved
         可變頭 28bit
\
 

frame_length:

一個ADTS幀的長度包括ADTS頭和AAC原始流.

 

adts_buffer_fullness:0x7FF 說明是碼率可變的碼流

 

3.將AAC打包成ADTS格式

若是是經過嵌入式高清解碼芯片作產品的話,通常狀況的解碼工做都是由硬件來完成的。因此大部分的工做是把AAC原始流打包成ADTS的格式,而後丟給硬件就好了。

經過對ADTS格式的瞭解,很容易就能把AAC打包成ADTS。咱們只需獲得封裝格式裏面關於音頻採樣率、聲道數、元數據長度、aac格式類型等信息。而後在每一個AAC原始流前面加上個ADTS頭就OK了。

貼上ffmpeg中添加ADTS頭的代碼,就能夠很清晰的瞭解ADTS頭的結構:

[html] view plain copy
  1. intff_adts_write_frame_header(ADTSContext*ctx,
  2. uint8_t*buf,intsize,intpce_size)
  3. {
  4. PutBitContextpb;
  5.  
  6. init_put_bits(&pb,buf,ADTS_HEADER_SIZE);
  7.  
  8. /*adts_fixed_header*/
  9. put_bits(&pb,12,0xfff);/*syncword固定的 */
  10. put_bits(&pb,1,0);/*ID*/
  11. put_bits(&pb,2,0);/*layer*/
  12. put_bits(&pb,1,1);/*protection_absent*/
  13. put_bits(&pb,2,ctx->objecttype);/*profile_objecttype*/
  14. put_bits(&pb,4,ctx->sample_rate_index);
  15. put_bits(&pb,1,0);/*private_bit*/
  16. put_bits(&pb,3,ctx->channel_conf);/*channel_configuration*/
  17. put_bits(&pb,1,0);/*original_copy*/
  18. put_bits(&pb,1,0);/*home*/
  19.  
  20. /*adts_variable_header*/
  21. put_bits(&pb,1,0);/*copyright_identification_bit*/
  22. put_bits(&pb,1,0);/*copyright_identification_start*/
  23. put_bits(&pb,13,ADTS_HEADER_SIZE+size+pce_size);/*aac_frame_length*/
  24. put_bits(&pb,11,0x7ff);/*adts_buffer_fullness*/
  25. put_bits(&pb,2,0);/*number_of_raw_data_blocks_in_frame*/
  26.  
  27. flush_put_bits(&pb);
  28.  
  29. return0;
  30. }
相關文章
相關標籤/搜索