我们已经了解到 m3u8 其实是一个文件,是 HLS 协议实现点播 & 直播的,还有 TS 文件。这里还有一篇讲解 AVPlayer 的,等编辑完再更新地址。
理论
HTTP Live Streaming (HLS) sends audio and video over HTTP from an ordinary web server for playback on iOS-based devices—including iPhone, iPad, iPod touch, and Apple TV—and on desktop computers (macOS). Using the same protocol that powers the web, HLS deploys content using ordinary web servers and content delivery networks. HLS is designed for reliability and dynamically adapts to network conditions by optimizing playback for the available speed of wired and wireless connections.
HLS supports the following:
- Live broadcasts and prerecorded content (video on demand, or VOD)
- Multiple alternate streams at different bit rates
- Intelligent switching of streams in response to network bandwidth changes
- Media encryption and user authentication
HLS 的了解主要参考苹果文档,包括其协议、格式、部署等
制作
先了解下如何制作 m3u8,有以下几种常用的方式
ffmpeg
1 | # 1、先用 ffmpeg 把 abc.mp4 文件转换为 abc.ts 文件: |
1 | // 1 |
参考:
FFmpeg 切片
mediastreamsegmenter
1 | which mediastreamsegmenter |
通过如上校验是否安装 mediastreamsegmenter,如果没有输出 ‘/usr/local/bin/mediastreamsegmenter’,则可以通过 More Downloads for Apple Developers 搜索 & 下载 & 安装(这里本人安装时候要求系统为 10.13.4 以上)
然后使用 VLC media player + mediastreamsegmenter 进行切割,但是进行切割时候都出现 error,如下
1 | Sep 20 2018 11:47:37.447: audio pid set at c8 |
还需要后续测试,而参考文章里面有使用另一个工具 XAMPP 来推 HLS 流。
参考
mediafilesegmenter
同样来自工具 mediastreamsegmenter,下载参考上述 More Downloads for Apple Developers。
1 | mediafilesegmenter -B TEST -i test.m3u8 -t 10 -f ./video ~/Movies/test.mp4 |
1 | Sep 20 2018 11:59:30.144: Processing file /Users/chen/Desktop/mm/good.mp4 |
此命令还为新增与媒体文件同名的 plist & iframe_index.m3u8,plist。mediafilesegmenter 与 mediastreamsegmenter 区别主要是一个是针对文件,一个针对的是 UDP 的实时 HLS 流。
Media Stream Segmenter(mediastreamsegmenter)通过UDP网络连接或 stdin 接收 MPEG-2 传输流,并将其分成一系列持续时间相同的小媒体段。然后,它会创建一个索引文件,其中包含对各个媒体段的引用。
媒体文件分段器(mediafilesegmenter)将 MOV,MP4,M4V,M4A 或 MP3 文件分成媒体段并创建索引文件。可以使用几乎任何Web服务器基础结构部署索引文件和媒体段,以便流式传输到 iOS,macOS 和 tvOS。
参考:
GStreamer & Gstreamill
Gstreamill 是一个支持 hls 输出的,基于 gstreamer 的实时编码器。
播放测试
把切割成功的 m3u8 & ts 源文件放在 Mac 的 WebServer -> Documents 目录下,并开启 Apache 后,即可使用 Safari 或者 QuickTime(使用“文件”>“打开位置…”或“⌘L”打开URL)等播放器来测试播放。
解析
这里主要解析 m3u8 描述文件 & ts 媒体文件,mp4 暂忽略
源码 Demo QHFlvParserMan 是采用 Swift 实现的,内容可结合此工程进行了解。
M3U8 标签
这个在 AVPlayer 那里也有简单介绍过
1 | // ffmpeg 输出的 |
它们的共同字段是
而在使用
1 | http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8 |
它的 m3u8 文件如下
1 | #EXTM3U |
总结:
- EXTM3U:所有 HLS 播放列表必须以此标记开头
- EXT-X-ENDLIST:区分是点播还是直播
- 二级目录是 绝对路径还是相对路径
- 二级目录是 ts 文件 还是 m3u8
- 当二级目录是 m3u8 时,需要再次访问获取最终的 ts,而直播就是通过这种不断刷新 m3u8 来实现播放
参考:
TS
TS 文件的结构与 HLS 类似,一个个的分段结构。TS 是以 188字节 来分段。
每一段:TS层(Head + Pes层(Head + ES层)),TS层 的内容是通过 PID 值来标识的,主要内容包括:PAT表、PMT表、音频流、视频流。
因此 TS 文件大致结构图如下:
TSHead | PAT/PMT | Stuffing Bytes |
---|---|---|
TSHead | Adaptation Field | Pes1 |
TSHead | \ | Pes2 - Pes(N-1) |
TSHead | Adaptation Field | PesN |
如下参考里面有说明 TSHead、PAT、PMT、Adapt、PES、ES 等字段的内容。
此处写出本人解码时遇到的几个点
- TSHead 的 payload_unit_start_indicator 对应 PAT & PMT:在前4个字节后会有一个调整字节。所以实际数据应该为去除第一个字节后的数据。即上面数据中红色部分不属于有效数据包。而对于 Adapt & 其他:0x01表示含有PSI或者PES头。所以解析 PAT/PMT 时需要通过此字段来判断是否空一个字节。
- 顺序查找,先是 PID为0 的 PAT,通过其 Programs 里面的 PID 查找 PMT,再又 PMT 里面的 Streams 来查找音视频数据。这也就是 “解析 ts 流要先找到 PAT 表,只要找到 PAT 就可以找到 PMT,然后就可以找到 音视频流 了” 的意思
- 在 PAT/PMT 遇到 section_length 这种 length 的解析,它是指后面数据的长度,即从解析出 length 的字节之后开始计算,如果length 的 Index 是 3(index 是从 0 开始的,即 length 是第四个字节),那么整个类型的实际数据长度则为 3 + 1 + length = len。
- PMT 的 stream_type :流类型,标志是 Video 还是 Audio 还是其他数据,h.264编码 对应 0x1b,aac编码 对应 0x0f,mp3编码 对应 0x03
- adaption 包含 PCR:Program Clock Reference,节目时钟参考,用于恢复出与编码端一致的系统时序时钟 STC(System Time Clock)。
ES
(暂未解析)
参考: