为什么巨大的原始视频可以编码成很小的视频呢?这其中的技术是什么呢?核心思想就是去除冗余信息:
1)空间冗余:图像相邻像素之间有较强的相关性
2)时间冗余:视频序列的相邻图像之间内容相似
3)编码冗余:不同像素值出现的概率不同
4)视觉冗余:人的视觉系统对某些细节不敏感
5)知识冗余:规律性的结构可由先验知识和背景知识得到
DNS 解析慢
为了有效降低 DNS 解析对首开的影响,我们可以提前完成播放域名->IP 地址的解析,
并缓存起来,播放的时候,直接传入带 IP 地址的播放地址,从而省去了 DNS 解析的耗时。
如果要支持用 IP 地址播放,是需要修改底层 ffmpeg 源码的。
播放策略
很多侧重点播的播放器,为了减少卡顿,会有一些缓冲策略,当缓冲足够多的数据之后 ,再送入解码播放。
而为了加快首开效果,需要对播放的缓冲策略做一些调整,如果第一帧还没有渲染出来的情况下,
不要做任何缓冲,直接送入解码器解码播放,这样就可以保证没有任何因为「主动」缓冲带来的首开延时。
播放参数设置
所有基于 ffmpeg 的播放器,都会遇到avformat_find_stream_info
这个函数耗时比较久,
从而增大了首开时间,该函数主要作用是通过读取一定字节的码流数据,
来分析码流的基本信息,如编码信息、时长、码率、帧率等等,它由两个参数来控制其读取的数据量大小和时长,
一个是 probesize,一个是 analyzeduration。
减少 probesize 和 analyzeduration 可以有效地减少avformat_find_stream_info
的函数耗时,
从而加快首开,但是需要注意的是,设置地太小可能会导致读取的数据量不足,从而无法解析出码流信息,导致播放失败,
或者出现只有音频没有视频,只有视频没有音频的问题。
服务端优化
服务器关键帧缓冲
CDN最近策略
首先如何判断是弱网
不一定要进行网络检测,可以检测两次发包的时间间隔,通过发包的状态与时间的长度判断网络状态。
根据上行带宽的状况来动态调整码率、FPS、分辨率
一般情况下视频轨码率默认设置为600Kbps,音频轨码率默认设置为64Kbps。
编码优化
对于视频编码器确定编码器开启了最低延迟,对于x264尤其明显。
尽量使用 ACC-LC Codec 来编码音频,HE-ACC 或者 HE-ACC 2 虽然编码效率高,但是编码所需时间更长,而产生更大体积的音频,造成包可能过大。
不要使用视频 MJPEG 的视频压缩格式,至少使用不带 B 帧的 MPEG4 视频压缩格式(Simple profile),甚至最好使用 H.264 baseline profile(X264 还有一个「-tune zerolatency」的优化开关)。
这样一个简单的优化可以降低延迟,因为它能够以更低的码率编码全帧率视频。
固定码率编码 CBR 可以一定程度上消除网络抖动影响,如果能够使用可变码率编码 VBR 可以节省一些不必要的网络带宽,降低一定的延迟。因此建议尽量使用 VBR 进行编码。
传输协议优化
在服务端节点和节点之间尽量使用 RTMP 而非基于 HTTP 的 HLS 协议进行传输,这样可以降低整体的传输延迟。
这个主要针对终端用户使用 HLS 进行播放的情况。
如果终端用户使用 RTMP 来播放,尽量在靠近推流端的收流节点进行转码,这样传输的视频流比原始视频流更小。
如果有必要,可以使用定制的 UDP 协议来替换 TCP 协议,省去弱网环节下的丢包重传可以降低延迟。
它的主要缺点在于,基于 UDP 协议进行定制的协议的视频流的传输和分发不够通用,CDN 厂商支持的是标准的传输协议。
另一个缺点在于可能出现丢包导致的花屏或者模糊(缺少关键帧的解码参考),这就要求协议定制方在 UDP 基础之上做好丢包控制。
4、丢帧处理
弱网环境下的丢帧策略。一般情况我们会有两种队列,分别是编码之前的原始数据队列和编码之后的编码队列。
弱网丢帧策略常见的实现有两种:一种是丢弃原始数据队列中未编码的数据帧,另外一种是丢弃编码队列中的数据帧。
这两种实现各有优缺点,无论采用哪种实现方式都以“不影响音视频的对齐”为第一准则。
丢掉了一定时间的视频帧同时也需要丢掉同等时间的音频帧。
播放优化
动态码率播放策略。除了动态调整 buffer 大小的策略之外,也可以利用实时监测的网络信息来动态调整播放过程中的码率,
在网络带宽不足的情况下降低码率进行播放,减少延迟。
解封装、解码、决定分辨率大小、编码、时间处理、封装。
首先需要明白为什么需要将NV21转换成I420,这是因为x264只支持编码I420的数据。
实际上就是YUV420p与YUV420sp之间的转换。
YUV420p与YUV420sp的相关知识请参考:《音视频基础知识-YUV图像》
具体转换参考:https://blog.csdn.net/yuanjinsong123/article/details/83895464
https://github.com/interviewandroid/AndroidInterView/blob/master/android/mediacodec.md
参考:https://blog.csdn.net/liuchen1206/article/details/79351137
PTS就是Presentation Time Stamp也就说这个帧什么时候会放在显示器上;
DTS就是Decode Time Stamp,就是说这个帧什么时候被放在编码器去解。
在没有B帧的情况下,DTS和PTS的输出顺序是一样的。
比特率表示经过编码(压缩)后的音、视频数据每秒钟需要用多少个比特来表示。比特率也叫做码率
也就是指每秒传送的比特(bit)数。
比如音频的比特率:比特率 =采样率 x 采用位数 x声道数。
帧率
码率
分辨率
量化参数(压缩比)
码率
帧率
GOP ( Group of Pictures ) 是一组连续的画面,由一张 I 帧和数张 B / P 帧组成,是视频图像编码器和解码器存取的基本单位。
也就是说GOP组是指一个关键帧I帧所在的组的长度,每个 GOP 组只有 1 个 I 帧。
GOP 组的长度格式也决定了码流的大小。
GOP越大,中间的P帧和B帧的数量就越多,所以解码出来的视频质量就越高,但是会影响编码效率。
文件大小 = (音频码率 + 视频码率)/ 8 * 影片时长(单位为秒s)
SPS又称作序列参数集。SPS中保存了一组编码视频序列的全局参数。包含了profile、level、宽高和颜色空间等信息。
所谓的编码视频序列即原始视频的一帧一帧的像素数据经过编码之后的结构组成的序列。
PPS是图像参数集。每一帧的编码后数据所依赖的参数保存于图像参数集中。
SurfaceView是一个有自己Surface的View。界面渲染可以放在单独线程而不是主线程中。它更像是一个Window,自身不能做变形和动画。
TextureView同样也有自己的Surface。但是它只能在拥有硬件加速层层的Window中绘制,它更像是一个普通View,可以做变形和动画。
参考官方的CameraView:https://github.com/google/cameraview
native 环境中创建的线程,如果需要访问 JNI,必须要调用 AttachCurrentThread 关联,并使用 DetachCurrentThread 解除链接。
技术交流,欢迎加我微信:ezglumes ,拉你入技术交流群。
扫码关注公众号【音视频开发进阶】,一起学习多媒体音视频开发~~~
喜欢就点个「在看」吧 ▽