-----------------------------------------
FFmpeg431的官方地址已经无法打开,
我将ffmepg4.3.1的开发包和源码上传到了百度云:
链接:https://pan.baidu.com/s/1-3xSO6ytyQLlSId0Xiak4w
提取码:fyxy
------------------------------------------
音视频是一门很复杂的技术,涉及的概念、原理、理论非常多,很多初学者不学 基础理论,而是直接做项目,往往会看到c/c++的代码时一头雾水,不知道代码到底是什么意思,这是为什么呢?
因为没有学习音视频的基础理论,就比如学习英语,不学习基本单词,而是天天听英语新闻,总也听不懂。
所以呢,一定要认真学习基础理论,然后再学习播放器、转码器、非编、流媒体直播、视频监控、等等。
切片命令行:
ffmpeg -i ande_302.mp4 -fflags flush_packets -max_delay 2 -flags -global_header -hls_time 5
-hls_list_size 0 -vcodec libx264 -acodec aac -r 30 -g 60 -y index.m3u8
HTTP Live Streaming(缩写是HLS)是一个由苹果公司提出的基于HTTP的流媒体网络传输协议。
是苹果公司QuickTime X和iPhone软件系统的一部分。
它的工作原理是把整个流分成一个个小的基于HTTP的文件来下载,每次只下载一些。当媒体流正在播放时,客户端可以选择从许多不同的备用源中以不同的速率下载同样的资源,允许流媒体会话适应不同的数据速率。
在开始一个流媒体会话时,客户端会下载一个包含元数据的extended M3U (m3u8)playlist文件,用于寻找可用的媒体流。HLS只请求基本的HTTP报文,与实时传输协议(RTP)不同,HLS可以穿过任何允许HTTP数据通过的防火墙或者代理服务器。它也很容易使用内容分发网络来传输媒体流。
在服务器端,流媒体文件被切割成一个一个的小分片,这些小分片有着相同的时长(常用10s),每一个小分片是一个ts文件。同时 产生一个索引文件(m3u8),索引文件里存放了ts文件的URL。
客户端请求方式分两种,一种是点播(vod),一种是直播(live)
Video on demand:视频点播,有求才播放
vod:客户端一次获取整个m3u8文件,按照里面的URL获取ts文件,采用HTTP协议。
live:由于M3u8文件时实时更新的,所以客户端每隔一段时间获取m3u8文件,再根据里面的URL获取ts文件,采用HTTP协议。
RTMP指Adobe的RTMP(Realtime Message Protocol),广泛应用于低延时直播,也是编码器和服务器对接的实际标准协议,在PC(Flash)上有最佳观看体验和最佳稳定性。
HLS指Apple的HLS(Http Live Streaming),本身就是Live(直播)的,不过Vod(点播)也能支持。
HLS是Apple平台的标准流媒体协议,和RTMP在PC上一样支持得天衣无缝。
HLS全称为HTTP Live Streaming,是苹果公司提出的基于HTTP的流媒体网络传输协议。它的工作原理是把整个媒体流分成一个个小的基于HTTP的媒体分片来下载,每次只下载一些分片。在开始一个流媒体会话时,客户端会下载一个包含媒体分片的索引文件,即extended M3U playlist文件(m3u8),用于寻找可用的媒体分片。
HLS中,索引文件可以嵌套,一般只有一级索引和二级索引;媒体流封分片装格式只支持MPEG-2传输流(ts)、WebVTT [WebVTT]文件或Packed Audio文件。
下图为索引文件(m3u8)和媒体分片(ts)之间的关系图:一级m3u8嵌套二级m3u8,二级m3u8描述ts分片。
1、 服务器将媒体文件转换为m3u8及ts分片;对于直播源,服务器需要实时动态更新。
2、 客户端请求m3u8文件,根据索引获取ts分片;点播与直播服务器不同的地方是, 直播的 m3u8 文件会不断更新,而点播的 m3u8 文件是不会变的,只需要客户端在开始时请求一次即可。
客户端与服务器通过HTTP协议进行交互,以两级m3u8嵌套为例,客户端先GET请求到一级m3u8,一级m3u8里面包含了服务器端可以用于传播的一个或多个不同带宽的URL,这URL可以获取到二级m3u8;二级m3u8包含了多个ts分片的duration及其URL,最后带过这个URL下载ts分片。
交互方式如下:
优势:
客户端支持简单,只需要支持 HTTP 请求即可,HTTP 协议无状态,只需要按顺序下载媒体片段即可。
使用 HTTP 协议网络兼容性好,HTTP 数据包也可以方便地通过防火墙或者代理服务器。
当媒体流正在播放时,客户端可以选择从许多不同的备用源中以不同的速率下载同样的资源(多码流自适应),允许流媒体会话适应不同的数据速率。
劣势:
因其自身的实现方式,HLS存在延迟(最少有一个分片),对于直播等实时敏感的场景,体验不好。
跨平台:PC主要的直播方案是RTMP,也有一些库能播放HLS,譬如jwplayer,基于osmf的hls插件也一大堆。所以实际上如果选一种协议能跨 PC/Android/IOS,那就是HLS。
IOS上苛刻的稳定性要求:IOS上最稳定的当然是HLS,稳定性不差于RTMP在PC-flash上的表现。
友好的CDN分发方式:目前CDN对于RTMP也是基本协议,但是HLS分发的基础是HTTP,所以CDN的接入和分发会比RTMP更加完善。能在各种CDN之间切换,RTMP也能,只是可能需要对接测试。
简单:HLS作为流媒体协议非常简单,apple支持得也很完善。Android对HLS的支持也会越来越完善。至于DASH/HDS,好像没有什么特别的理由,就像linux已经大行其道而且开放,其他的系统很难再广泛应用。
总之,SRS支持HLS主要是作为输出的分发协议,直播以RTMP+HLS分发,满总各种应用场景。点播以HLS为主。
HLS协议很大一部分内容即是对M3U8文本协议的描述。
M3U8即播放索引文件,也称为Playlist,是由多个独立行组成的文本文件,必须通过 URI(.m3u8 或 .m3u) 或者 HTTP Content-Type 来识别(application/vnd.apple.mpegurl 或 audio/mpegurl)。
每行由用 \n 或者 \r\n来标识换行。每一行可以是一个URI、空白行或是一个 以# 号开头的字符串。
以 # 开头的是 tag 或者注释,以 #EXT 开头的是 tag, 其余的为注释, 在解析时应该忽略。URI 表示一个ts分片地址或是Playlist地址。URI 可以用绝对地址或者相对地址,如果使用相对地址,那么是相对于当前Playlist的地址。
有些tag带有属性值,多个属性用逗号分隔。
常见的m3u8文件如下所示:
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=700,000
http://xxx.itv.cmvideo.cn/low.m3u8?channel-id=bstvod&Contentid=4007432528
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1300,000
http://xxx.itv.cmvideo.cn/mid.m3u8?channel-id=bstvod&Contentid=4007432527
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2300,000
http://xxx.itv.cmvideo.cn/high.m3u8?channel-id=bstvod&Contentid=4007432526
#EXTM3U
#EXT-X-VERSION:1
#EXT-X-TARGETDURATION:11
#EXT-X-MEDIA-SEQUENCE:19674922
#EXT-X-PROGRAM-DATE-TIME:2019-03-28T04:33:40Z
#EXTINF:10,
19674922.ts?
#EXT-X-PROGRAM-DATE-TIME:2019-03-28T04:33:50Z
#EXTINF:10,
19674923.ts?
#EXT-X-PROGRAM-DATE-TIME:2019-03-28T04:34:00Z
#EXTINF:10,
19674924.ts?
名词说明:
1、 Media Playlist:二级m3u8,携带ts分片url的m3u8;
2、 Master Playlist:一级m3u8;
3、 Media Segment:ts分片
4、 Attribute Lists:属性列表
Attribute Lists :
• 有的 tags 的值带有 Attribute Lists。
• 一个 Attribute List是一个用逗号分隔的 attribute/value 对列表。
• 格式为: AttributeName=AttributeValue。
tag以#EXT开头,主要分为以下几类:
1) Basic Tags
Basic Tags 可以用在 Media Playlist 和 Master Playlist 里面。
• EXTM3U: 必须在文件的第一行, 标识是一个 Extended M3U Playlist 文件。
• EXT-X-VERSION: 表示 Playlist 兼容的版本。
2) Media Segment Tags
每一个 Media Segment 通过一系列的 Media Segment tags 跟一个 URI 来指定。有的 Media Segment tags 只应用于下一个 segment, 有的则是应用所有下面的 segments。
一个 Media Segment tag 只能出现在 Media Playlist 里面。
• EXTINF: 用于指定 Media Segment 的 duration。
• EXT-X-BYTERANGE: 用于指定 URI 的 sub-range。
• EXT-X-DISCONTINUITY: 表示后续分片属性发生变化,如文件格式/编码/序号。
• EXT-X-KEY: 表示Media Segment 已加密,该值用于解密。
• EXT-X-MAP: 表示Media Segment的头部信息,比如PAT/PMT 或者WebVTT头。
• EXT-X-PROGRAM-DATE-TIME: 和 Media Segment 的第一个sample一起来确定时间戳。
3)Media Playlist Tags
Media Playlist tags 描述 Media Playlist 的全局参数。 同样地, Media Playlist tags 只能出现在 Media Playlist 里面。
• EXT-X-TARGETDURATION: 用于指定最大的 Media Segment duration。
• EXT-X-MEDIA-SEQUENCE: 用于指定第一个 Media Segment 的序号。
• EXT-X-DISCONTINUITY-SEQUENCE: 用于不同 Variant Stream 之间同步。
• EXT-X-ENDLIST: 表示Media Playlist结束。
• EXT-X-PLAYLIST-TYPE: 可选, 指定整个 Playlist 的类型。
• EXT-X-I-FRAMES-ONLY: 表示每个 Media Segment 均为I-frame。
4)Master Playlist Tags
Master Playlist tags 定义 Variant Streams, Renditions 和其他显示的全局参数。 Master Playlist tags 只能出现在 Master Playlist 中。
• EXT-X-MEDIA: 用于关联同一个内容的多个 Media Playlist 的多种翻译。
• EXT-X-STREAM-INF:用于指定下级Media Playlist相关属性。
• EXT-X-I-FRAME-STREAM-INF:与EXT-X-STREAM-INF类似,但指向的下级Media Playlist包含Media Segment均为I-frame。
• EXT-X-SESSION-DATA: 可以随意存放一些 session 数据。
5) Media or Master Playlist Tags
这里的 tags 可以出现在 Media Playlist 或者 Master Playlist 中。 但是如果同时出现在同一个 Master Playlist 和 Media Playlist 中时, 必须为相同值。
• EXT-X-INDEPENDENT-SEGMENTS: 表示每个 Media Segment 可以独立解码。
• EXT-X-START: 标识一个优选的点来播放这个 Playlist。
HLS是提供一个m3u8地址:
Apple的Safari浏览器直接就能打开m3u8地址,譬如:
http://demo.srs.com/live/livestream.m3u8
Android不能直接打开,需要使用html5的video标签,然后在浏览器中打开这个页面即可,譬如:
PC:video.js
HLS协议规定
视频的封装格式是TS。
视频的编码格式为H264,音频编码格式为MP3、AAC或者AC-3。
除了TS视频文件本身,还定义了用来控制播放的m3u8文件(文本文件)。
HLS的m3u8,是一个ts的列表,也就是告诉客户端或浏览器可以播放这些ts文件,譬如:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:13
#EXT-X-MEDIA-SEQUENCE:430
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:11.800
news-430.ts
#EXTINF:10.120
news-431.ts
#EXT-X-DISCONTINUITY
#EXTINF:11.952
news-430.ts
#EXTINF:12.640
news-431.ts
#EXTINF:11.160
news-432.ts
#EXT-X-DISCONTINUITY
#EXTINF:11.751
news-430.ts
#EXTINF:2.040
news-431.ts
#EXT-X-ENDLIST
EXTM3U
每个M3U文件第一行必须是这个tag,提供标示作用
EXT-X-VERSION
用以标示协议版本。这里是3, 那么这里用的就是HLS协议第三个版本,此标签只能有0或1个,不写代表使用版本1
EXT-X-TARGETDURATION
所有切片的最大时长,有些Apple设备这个参数不正确会无法播放。
EXT-X-MEDIA-SEQUENCE
切片的开始序号。每一个切片都有唯一的序号,相邻之间序号+1。这个编号会继续增长,保证流的连续性。
EXTINF
ts 切片的实际时长。duration : 媒体持续时间
#EXTINF
EXT-X-PLAYLIST-TYPE
类型,vod 表示点播 ,live:直播。
EXT-X-ENDLIST
文件结束符号。表示不再向播放列表文件添加媒体文件。
bandwidth指定视频流的比特率,PROGRAM-ID无用无需关注,每一个#EXT-X-STREAM-INF的下一行是二级index文件的路径,可以用相对路径也可以用绝对路径。
例子中用的是相对路径。这个文件中记录了不同比特率视频流的二级index文件路径,客户端可以自己判断自己的现行网络带宽,来决定播放哪一个视频流。
也可以在网络带宽变化的时候平滑切换到和带宽匹配的视频流。
二级文件实际负责给出ts文件的下载地址,这里同样使用了相对路径。#EXTINF表示每个ts切片视频文件的时长。#EXT-X-TARGETDURATION指定当前视频流中的切片文件的最大时长,也就是说这些ts切片的时长不能大于#EXT-X-TARGETDURATION的值。
#EXT-X-PLAYLIST-TYPE:VOD的意思是当前的视频流并不是一个直播流,而是点播流,换句话说就是该视频的全部的ts文件已经被生成好了,#EXT-X-ENDLIST这个表示视频结束,有这个标志同时也说明当前的流是一个非直播流。
点播VOD的特点就是当前时间点可以获取到所有index文件和ts文件,二级index文件中记录了所有ts文件的地址。这种模式允许客户端访问全部内容。上面的例子中就是一个点播模式下的m3u8的结构。
Live 模式就是实时生成M3u8和ts文件。它的索引文件一直处于动态变化的,播放的时候需要不断下载二级index文件,以获得最新生成的ts文件播放视频。如果一个二级index文件的末尾没有#EXT-X-ENDLIST标志,说明它是一个Live视频流。
客户端在播放VOD模式的视频时其实只需要下载一次一级index文件和二级index文件就可以得到所有ts文件的下载地址,除非客户端进行比特率切换,否则无需再下载任何index文件,只需顺序下载ts文件并播放就可以了。
但是Live模式下略有不同,因为播放的同时,新ts文件也在被生成中,所以客户端实际上是下载一次二级index文件,然后下载ts文件,再下载二级index文件(这个时候这个二级index文件已经被重写,记录了新生成的ts文件的下载地址),再下载新ts文件,如此反复进行播放。
ts文件为传输流文件(MPEG2 - tranport stream),
视频编码主要格式h264/mpeg4,音频为acc/MP3。
ts文件分为三层:
ts层Transport Stream、pes层 Packet Elemental Stream、es层 Elementary Stream.
es层就是音视频压缩数据,pes层是在音视频数据es上加了时间戳(pts,dts)等对数据帧的说明信息,ts层就是在pes层加入数据流的识别和传输必须的信息
Rtp:real time protocol, rtcp
ts层
ts包大小固定为188字节,ts层分为三个部分:ts header、adaptation field、payload。ts header固定4个字节;adaptation field可能存在也可能不存在,主要作用是给不足188字节的数据做填充;payload是pes数据。
pes层
pes层是在每一个视频/音频帧上加入了时间戳等信息,pes包内容很多,我们只留下最常用的。
es层
es层指的就是音视频数据,我们只介绍h.264视频。
h.264视频:
打包h.264数据我们必须给视频数据加上一个nalu(Network Abstraction Layer unit),
nalu包括nalu header和nalu type,
nalu header固定为0x00000001(帧开始)或0x000001(帧中)。
h.264的数据是由slice组成的,slice的内容包括:视频、sps、pps等。
nalu type决定了后面的h.264数据内容。