- 采集视频和音频数据
得到CMSampleBufferRef类型的数据,代表视频的CMSampleBufferRef中保存的数据是yuv420格式的视频帧,代表音频的CMSampleBufferRef中保存的数据是PCM格式的音频帧。 - 前处理
美颜算法,视频的模糊效果,水印等都是在这个环节做。一般现在都使用GPUImage。 - 编码
对视频进行硬编码得到h264数据,对音频进行硬编码得到AAC数据。重难点在于要在分辨率,帧率,码率等参数设计上找到最佳平衡点。iOS8之后可以使用VideoToolbox.frarmework进行硬编码。 - 对编码后的音视频数据进行FLV封包
- 建立RTMP连接并上推到服务器
- 服务端处理:需要在服务器做一些流处理工作,让推送上来的流适配各个平台多种不同的协议,例如RTMP, HLS。
- 拉流(看播)端解码和渲染,也就是音视频的播放。解码也必须要硬解码,这个很早就支持。这块儿的难点在于音画同步。
RTMP:
Real Time Messaging Protocol是Macromedia开发的一套视频直播协议,现在属于Adobe公司。实时性好,一般使用这种协议来上传视频流,也就是视频流推送到服务器。延迟在1-3秒。
相对其它协议而言,RTMP协议初次建立连接的时候握手过程过于复杂,视不同的网络状况会给首开带来100ms以上的延迟。
HTTP-FLV:
即使用HTTP协议流式的传输媒体内容。相对于RTMP,HTTP更简单和广为人知,而且不担心被Adobe的专利绑架。内容延迟同样可以做到1~3秒,打开速度更快,因为HTTP本身没有复杂的状态交互。所以从延迟角度来看,HTTP-FLV要优于RTMP。
HLS:
即Http Live Streaming, 是由苹果提出的,基于HTTP的流媒体传输协议。它有一个非常大的优点:HTML5可以直接打开播放。这就意味着可以把一个直播链接通过微信等转发分享,不需要安装任何独立的APP,有浏览器即可,所以流行度很高。
其实是一个“文本协议”,并不是一个“流媒体协议”。直播客户端获取到的,并不是一个完整的数据流。HLS协议在服务器端将直播数据流存储为连续的,很短时长的媒体文件(MPEG-TS格式),而客户端则不断的下载并播放这些小文件,因为服务器端总是会将最新的直播数据生成新的小文件,这样客户端只要不停的按顺序播放从服务器获取到的文件,就实现了直播。
由此可见,基本上可以认为,HLS是以点播的技术方式来实现直播。由于数据通过HTTP协议传输,所以不用考虑防火墙或者代理的问题,而且分段文件的时长很短,客户端可以很快的选择和切换码率,以适应不同带宽条件下的播放。不过HLS的这种技术特点决定了延迟一般总是会高于普通的流媒体直播协议。
每一个.m3u8 文件,分别对应若干个 ts 文件,这些 ts 文件才是真正存放视频的数据,m3u8 文件只是存放了一些 ts 文件的配置信息和相关路径,当视频播放时,.m3u8 是动态改变的,video 标签会解析这个文件,并找到对应的 ts 文件来播放,所以一般为了加快速度,.m3u8 放在 Web 服务器上,ts 文件放在 CDN 上。
支持的视频流编码为H.264,音频流编码为AAC。
RTP:
Real-time Transport Protocol,用于Internet上针对多媒体数据流的一种传输层协议。 和前面的协议的一个重要的区别就是默认是使用UDP协议来传输数据。
观看直播视频有以下方式:HLS, RTMP, HTTP-FLV,RTP。
好看的指标参数:
码率:每秒传送的比特数,单位为bps。码率越高,视频越清晰。
帧率:即fps,每秒钟多少帧。
分辨率:影响图像大小,与图像大小成正比。
YUV是一种图片储存格式,跟RGB格式类似。YUV中,y表示亮度,单独只有Y就可以形成一张图片,只不过这张图片是灰色的。u和v表示色差(u和v也被称为Cb-蓝色差,Cr-红色差)。
一张yuv格式的图像,占用字节数为 width * height * 3 / 2,而一张RGB格式的图像,占用字节数为width * height * 3,相比较RGB,YUV只是一半的占用字节数。
PCM格式,就是录制声音时,保存的最原始的声音数据格式。
h264,一种压缩格式,将视频帧分为关键帧和非关键帧。关键帧的数据是完整的。包含了所有的颜色数据。这样的视频帧称为I帧。
非关键帧数据不完整,但是它能够根据前面或者后面的帧数据,甚至自己的部分帧数据,将自身数据补充完整。这种视频帧被称为 B/P 帧。
总体来说,h264跟yuv相比,最大的不同就是它是压缩的(通常此过程称为编码,不只是简单的压缩)
aac: 性质同h264一样,是PCM的压缩格式。
flv: 是音频和视频的封包格式,RTMP传输的时候要求是flv格式。
为了便于视频内容的存储和传输,通常需要减少视频内容的体积,也就是需要将原始的内容元素(图像和音频)经过压缩,压缩算法也简称编码格式。例如视频里边的原始图像数据会采用 H.264 编码格式进行压缩,音频采样数据会采用 AAC 编码格式进行压缩。
视频内容经过编码压缩后,确实有利于存储和传输; 不过当要观看播放时,相应地也需要解码过程。因此编码和解码之间,显然需要约定一种编码器和解码器都可以理解的约定。就视频图像编码和解码而言,这种约定很简单:
编码器将多张图像进行编码后生产成一段一段的 GOP ( Group of Pictures ) , 解码器在播放时则是读取一段一段的GOP 进行解码后读取画面再渲染显示。
GOP ( Group of Pictures ) 是一组连续的画面,由一张 I 帧和数张 B / P 帧组成,是视频图像编码器和解码器存取的基本单位,它的排列顺序将会一直重复到影像结束。
sps&pps是h264中的概念,它包含了一些编码信息,如profile,图像尺寸等信息。硬编码以后,sps&pps数据能够通过关键帧获取。
AudioSpecificConfig是aac中的概念,它包含了音频信息,如采样率,声道数等信息。
RTMP连接成功后,一定要先发送sps&pps,AudioSpecificConfig这两个数据对应的tag,否则视频是播放不出来的。
H264里有两种时间戳:DTS(Decoding Time Stamp)和PTS(Presentation Time Stamp)。其实际意义是,PTS是真正录制和播放的时间戳,而DTS是解码的时间戳。
对于普通的无B帧视频,PTS/DTS应该是相等的,因为解码的时候不需要先解出后面的帧。
对于有B帧的视频,I帧的PTS依然等于DTS,P帧的PTS > DTS,B帧的PTS < DTS。
也可以换个方式来理解:
若视频没有B帧,则I和P都是解码后即刻显示。
若视频含有B帧,则I是解码后即刻显示,P是先解码后显示,B是后解码先显示。
- 改写播放器逻辑让播放器拿到第一个关键帧后就给予显示。
- 在APP业务逻辑层面方面优化,比如提前做好DNS解析(省几十毫秒),和提前做好测速选线(择取最优线路)
- 除了移动端可以做体验优化之外,直播流媒体服务端架构也可以降低延迟。例如收流服务器主动推送GOP至边缘节点,边缘节点缓存GOP,播放端则可以快速加载,减少回源延迟。
- 在切换直播间的场景下,可以做预加载操作。
这个现象的原因是CPU在处理视频帧的时候处理得太慢,默认的音视频同步方案是视频同步到音频,导致了音频播放过快,视频跟不上。
可以通过修改framedrop的数值来解决不同步的问题,framedrop是在视频帧处理不过来的时候丢弃一些帧达到同步的效果。
代码如下:
IJKFFOptions *options = [IJKFFOptions optionsByDefault];
[options setPlayerOptionIntValue: 5 forKey:@"framedrop"];