你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS_直播類app_HTTP Live Streaming

iOS_直播類app_HTTP Live Streaming

編輯:IOS開發綜合
https://developer.apple.com/streaming/   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 的實時流媒體協議

這二種基本是完全不同的東西,目前比較方便又好用的我建議使用 HTTP 漸進下載的方法。

 

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

 

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


要詳細了解原理,我們先看看這個所需要的步驟。

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

 

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

然後給這些封裝成成為符合MPEG-2(MPEG 2 TS、MPEG2 PS之所以使用這個,主要是因為聲音和視頻會交織在一起,也會有關鍵幀來讓視頻可以直接播放).

 

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

 

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

 

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

 

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

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

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 的後綴支持

.m3u8 application/x-mpegURL
.ts video/MP2T

 

最後就是客戶端,如果是 HTML 直接在 HTML5 中直接支持這種視頻可以使用如下標簽




 

如果是應用客戶端(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字符編碼。

      #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、MP3、或者 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 TechnologiesVedio Technologies
[重點]在編碼中圖,不要修改視頻編碼器的設置,比如視頻大小或者編碼解碼器類型。如果避免不了,那修改動作必須發生在一個片段邊界。並且需要早之後相連的片段上用EXT-X-DISCONTINUITY 進行標記。

流切片器

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

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

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

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

媒體片段文件

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

索引文件(PlayLists)

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

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

#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

為了更精確,你可以在 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)

#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

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

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

#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

同理,繼續向下抓:(拼接地址: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
抓取結果:

#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

相比於第二次又獲取了一個片段的索引,而且只要是第二次之後,資源地址都會包含 .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配置原理:

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

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

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

3、添加頭文件

YCHLS-Demo.h

4、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直播具體的實現流程。

部分源碼貼出

開啟本地服務器:

- (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);
    }

視頻下載:

- (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];
    }
}

播放本地視頻:

- (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];
    }
}

播放在線視頻

- (IBAction)playLiveStreaming {

    NSURL *url = [[NSURL alloc] initWithString:TEST_HLS_URL];
    MPMoviePlayerViewController *player = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
    [self presentMoviePlayerViewControllerAnimated:player];
}

 

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 plaincopy
  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. }
  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved