文章目录
流媒体技术背景
传统的视频监控行业技术栈多采用私有协议SDK、onvif/rtsp等协议栈。这些协议目前对浏览器而言都不友好,在以前IE浏览器还流行的时期,可以通过ocx插件的方式来对接这些协议,但是随着IE的没落以及目前流行的chrome、火狐浏览器对原生插件的愈加不友好,通过插件的方式来实现访问监控视频的方式将愈发困难。
如果要在chrome,火狐浏览器上访问监控视频,以下几种方案可性:
- rtmp - 目前最主流的直播方案,但需要加载Flash插件,且Flash已经停止更新。
-
http-flv - 支持h5无插件播放,但是不支持H265,且同域名下的直播窗口不能同时打开多个。
-
ws-flv - 原理和http-flv,只是传输协议不同,使用的是websocket,没有同域名下的直播窗口不能同时打开多个的限制。
-
webrtc - 主流浏览器都支持的标准,无插件,适用于低延迟交互式场景,但目前技术还不成熟。
-
hls - 兼容性最好,桌面浏览器,包括手机浏览器甚至是手机QQ、手机微信都支持,但延时很大。
直播行业相对视频监控行业来说,商业化程度更高,更面向于普通消费者,用户规模更大,产业链也更加成熟。但是由于利益格局的划分、巨头间标准制定的角力,目前直播的技术标准和用户体验是割裂的。
在桌面web端,之前直播技术由Adobe旗下的flash/rtmp技术主导,不过由于Adobe的不作为,以及谷歌苹果等公司的抵制,flash已经进入死亡倒计时。目前来看,http-flv已经接手rtmp的大旗,成为了新的事实上的桌面web端直播标准。但是http-flv由于其不支持H265的短板(Adobe官方可能永远也不会支持H265),其地位也并不稳固,现在也有公司正在尝试使用webrtc进行视频直播,但是由于该技术跨界太大,其技术栈又太庞杂,整个上下游产业链也并不完善,目前在直播界,还未看见大规模采用该直播技术的方案实施。
在手机APP端,由于播放技术自己可以主导,也由于历史沿革原因,目前一般沿用rtmp技术方案(需要指出的是微信小程序也支持rtmp播放器),用户体验比较好,延时一般3秒或以下。
在移动web端,可采用的直播方案更少,目前基本只能采用苹果公司主导的hls方案,但是由于hls的技术特性,延时非常大(一般5秒以上,最大可达10秒以上),其观看体验跟手机APP、桌面web端是严重割裂的。
通过我们上述的分析看出,目前直播技术方案,在每种端都不一样,用户体验也差距巨大,目前并没有一种多平台支持、令人满意的通用解决方案。目前要实现一个完善的直播产品,最少要采用包括rtmp/http-flv/hls这3种技术方案,而且这三种技术方案目前也并不能让人满意(rtmp/http-flv不支持H265,hls延时高)。
参考: https://github.com/xiongziliang/ZLMediaKit/wiki/%E6%B5%81%E5%AA%92%E4%BD%93%E7%9B%B8%E5%85%B3%E6%8A%80%E6%9C%AF%E4%BB%8B%E7%BB%8D
音视频编码与音视频数据
媒体文件
一个完整的媒体文件, 包括音频, 视频和基础元信息, 比如常见的文件有mp4(MPEG-4中的标准之一), mov, flv, avi, rmvb, 就是一种封装格式。
媒体文件包含了音频和视频两部分, 通过一些特定的编码算法, 进行编码压缩后的数据。
H265, H264, VP9, Xvid等就是视频编码格式。MP3,AAC就是音频编码格式。
例: 将一个Xvid视频编码文件和一个MP3音频编码文件按AVI封装标准封装以后,就得到一个AVI后缀的媒体文件。
注: 媒体文件 指的是 多媒体容器格式文件
音频编码格式
最常见音频编码格式:
- AAC(MPEG-4中的音频标准, 有损压缩格式)
- MP3PRO
- MP3
- AC-3
AC-3是杜比公司的技术。而AAC是MPEG-4中的音频标准, AAC是目前比较先进和具有优势的技术。
监控领域应用比较多的编码格式:
-
AAC
-
G711
-
G726
格式解析 G711:
G711的内容是将14bit(uLaw)或者13bit(aLaw)采样的PCM数据编码成8bit的数据流,播放的时候在将此8bit的数据还原成14bit或者13bit进行播放。参考: https://blog.csdn.net/q2519008/article/details/80900838
音频编解码介绍: https://zhuanlan.zhihu.com/p/337966591
视频编码格式
视频编码标准有两大系统: MPEG和ITU-T, 国际上制定视频编码技术的组织有两个,一个是"国际电联(ITU-T)",它制定的标准有H261, H263,H263+,H264等。另一个是"国际标准化组织(ISO)",它制定的标准有MPEG-1,MPEG-2,MPEG-4等。
常见编码格式:
- Xvid(MPEG-4)
- H.265(目前用的不够多)
- H264(目前最常用编码格式, 除了H265, 是目前压缩率最高的编码格式)
- H263
- MPEG1,MPEG2
H264的优势:
- 低码率:和MPEG2和MPEG4 ASP等压缩技术相比,在同等图像质量下,采用H.264技术压缩后的数据量只有MPEG2的1/8,MPEG4的1/3。
- 高质量的图象 :H.264能提供连续、流畅的高质量图象(DVD质量)。
- 容错能力强 :H.264提供了解决在不稳定网络环境下容易发生的丢包等错误的必要工具。
- 网络适应性强 :H.264提供了网络抽象层(Network Abstraction Layer),使得H.264的文件能容易地在不同网络上传输(例如互联网,CDMA,GPRS,WCDMA,CDMA2000等)。
注: 常见的视频编码格式实际上都属于有损压缩, 包括H264和H265, 也是有损编码, 有损编码才能在质量得以保证的前提下得到更高的压缩率和更小体积。
存储封装格式
常见的存储封装格式有如下:
- AVI (.avi)
- ASF(.asf)
- WMV (.wmv)
- QuickTime ( .mov)
- MPEG (.mpg / .mpeg)
- MP4 (.mp4)
- m2ts (.m2ts / .mts )
- Matroska (.mkv / .mks / .mka )
- RM ( .rm / .rmvb)
- TS/PS
视频码率, 帧率, 分辨率
码率
码率是指在单位时间内的数据量, 使用单位是kb/s 或者 Mb/s。一般来说同样分辨率下,如果视频文件的码率越大,压缩比就越小,画面质量就越高。
码率越大, 文件体积越大。
文件体积(kB/s 或者 MB/s) = 平均码率(b/s) * 文件时长(秒 s) / 8 。(平均码率指的是视频和音频总体的平均码率)
例: 一部90分钟1Mbps码率的720P RMVB文件, 其体积=5400 * 1Mbps / 8 = 675MB。
帧率
帧率也称为FPS(Frames Per Second) - 帧/秒, 指的是每秒刷新次数。
分辨率
视频分辨率是指视频成像产品所成图像的大小或尺寸。
长度 * 宽度 = 像素点个数。
例:
480P: 640 * 480 个像素点 = 307200个像素点
1080P: 1920 * 1080 个像素点 = 2073600个像素点
三者关系
- 码率和帧率没有任何关系, 不会相互影响。
- 码率影响着 占用带宽, 文件体积, 图像质量(相同分辨率情况下)。
- 帧率影响着 CPU消耗 和 画面流畅度。
- 分辨率影响着 图像尺寸 和 清晰度。
YUV
YUV与RGB
YUV格式,YUV是一种颜色编码方法,主要用于电视相同以及模拟视频领域,它将亮度信息(Y) 与 色彩信息(UV)分离,没有UV信息一样可以显示完整的图像。YUV不像RGB那样要求三个独立的视频信号同时传输,所以用YUV方式传送占用极少的带宽。
YUV分为三个分量,“Y”表示图像的明亮度,也就是灰度值。“UV”表示图像的色彩。
YUV利用亮度"Y",色彩“UV”代替RGB三原色来压缩图像。RGB三原色一个像素每种颜色各占1字节,所以一个像素需要占用3字节(24bits)。
YUV的采样方式
YUV的采样有许多种,常用的有YUV444,YUV422,YUV420,YUV411等。
YUV 4:4:4采样,每一个Y对应一组UV分量。
YUV 4:2:2采样,每两个Y共用一组UV分量。
YUV 4:2:0采样,每四个Y共用一组UV分量。
假设YUV的采样率是4:2:2 (YUV422),即每一个像素对于亮度Y的采样频率是1,对于色彩U和V,则是每相邻的每个像素格取一个U,V。对于单个像素来说,U和V的采样频率为亮度Y的一半。
例-YUV与RGB的大小对比:
对于三个像素点,如果使用RGB来表示,3 * 8 * 3 = 72bits。
如果使用YUV来表示,(Y)3 * 8 +(U)3* 8 * 0.5 +(Y)3* 8 * 0.5 = 24 + 12 + 12 = 48bits。
例-YUV与RGB互相转换的公式如下(RGB取值范围均为0-255):
cdns查阅到两组公式
公式一
//Y:0~255 U:-128~127 V:-128~127
Y = 0.299R + 0.587G + 0.114B
U = -0.147R - 0.289G + 0.436B
V = 0.615R - 0.515G - 0.100B
//RGB:0 ~ 255
R = Y + 1.14V
G = Y - 0.39U - 0.58V
B = Y + 2.03U
公式二
//YUV:0~255
Y = 0.298R + 0.612G + 0.117B;
U = -0.168R - 0.330G + 0.498B + 128;
V = 0.449R - 0.435G - 0.083B + 128;
//RGB:0~255
R = Y + 1.4075( V - 128);
G = Y - 0.3455( U - 128) - 0.7169( V - 128);
B = Y + 1.779( U - 128);
例 - YUV -> RGB 图片转换代码:
//YUV_NV12(YUV420) -> RGB
//NV12的UV分量是交叉排列的
/*
width:N Height:M
1: Y-1 ... ... Y-N
2: Y-1 ... ... Y-N
...
M: Y-1 ... ... Y-N
1: U-1V-1 ... ... U-N/2 V-N/2
...
M/2: .....
*/
int yuv2rgb_nv12(unsigned char* pYuvBuf, unsigned char* pRgbBuf, int height, int width)
{
if(width < 1 || height < 1 || pYuvBuf == NULL || pRgbBuf == NULL)
{
return 0;
}
const long len = height * width;
// Y与UV数据地址
unsigned char *yData = pYuvBuf;
unsigned char *uvData = yData + len;
// R、G、B数据地址
unsigned char *rData = pRgbBuf;
unsigned char *gData = rData + len;
unsigned char *bData = gData + len;
int R[4], G[4], B[4];
int Y[4], U, V;
int y0_Idx, y1_Idx, uIdx, vIdx;
for (int i = 0; i < height; i=i+2)
{
for (int j = 0; j < width; j=j+2)
{
y0_Idx = i * width + j;
y1_Idx = (i + 1) * width + j;
// Y[0]、Y[1]、Y[2]、Y[3]分别代表 Y00、Y01、Y10、Y11
Y[0] = yData[y0_Idx];
Y[1] = yData[y0_Idx + 1];
Y[2] = yData[y1_Idx];
Y[3] = yData[y1_Idx + 1];
uIdx = (i / 2) * width + j;
vIdx = uIdx + 1;
U = uvData[uIdx];
V = uvData[vIdx];
R[0] = Y[0] + 1.402 * (V - 128);
G[0] = Y[0] - 0.34414 * (U - 128) + 0.71414 * (V - 128);
B[0] = Y[0] + 1.772 * (U - 128);
R[1] = Y[1] + 1.402 * (V - 128);
G[1] = Y[1] - 0.34414 * (U - 128) + 0.71414 * (V - 128);
B[1] = Y[1] + 1.772 * (U - 128);
R[2] = Y[2] + 1.402 * (V - 128);
G[2] = Y[2] - 0.34414 * (U - 128) + 0.71414 * (V - 128);
B[2] = Y[2] + 1.772 * (U - 128);
R[3] = Y[3] + 1.402 * (V - 128);
G[3] = Y[3] - 0.34414 * (U - 128) + 0.71414 * (V - 128);
B[3] = Y[3] + 1.772 * (U - 128);
// 像素值限定在 0-255
for (int k = 0; k < 4; ++k)
{
if(R[k] >= 0 && R[k] <= 255)
{
R[k] = R[k];
}
else
{
R[k] = (R[K] < 0) ? 0 : 255;
}
if(G[k] >= 0 && G[k] <= 255)
{
G[k] = G[k];
}
else
{
G[k] = (G[K] < 0) ? 0 : 255;
}
if(B[k] >= 0 && B[k] <= 255)
{
B[k] = B[k];
}
else
{
B[k] = (B[K] < 0) ? 0 : 255;
}
}
*(rData + y0_Idx) = R[0];
*(gData + y0_Idx) = G[0];
*(bData + y0_Idx) = B[0];
*(rData + y0_Idx + 1) = R[1];
*(gData + y0_Idx + 1) = G[1];
*(bData + y0_Idx + 1) = B[1];
*(rData + y1_Idx) = R[2];
*(gData + y1_Idx) = G[2];
*(bData + y1_Idx) = B[2];
*(rData + y1_Idx + 1) = R[3];
*(gData + y1_Idx + 1) = G[3];
*(bData + y1_Idx + 1) = B[3];
}
}
return 1;
}
YUV的实战教程: https://blog.csdn.net/leixiaohua1020/article/details/50534150
YUV格式
YUV的查查格式有两大类:packed和planar,还有SemiPlanar。
packed的YUV格式: 每个像素点的Y,U,V是连续交错存储的。
常见存储方式:
- VYUY422:V1 Y1 U1 Y2 V2 Y3 U2 Y4 …
- YUYV422:Y1 U1 Y2 V1 Y3 U2 Y4 V2 …
- YVYU422:Y1 V1 Y2 U1 Y3 V2 Y4 U2 …
- UYVY422:U1 Y1 V1 Y2 U2 Y3 V2 Y4…
- YUV420 Packet: Y1 U1 Y2 Y3 U2 Y4 Y5 V1 Y6 Y7 V2 Y8
planar的YUV格式: 先连续存储所有像素点的Y,接着存储所有像素点的U,随后是所有像素点的V。
常见存储方式:
- YUV422P
- YUV420P
SemiPlanar的YUV格式: 先连续存储所有像素点的Y,再连续交错U和V。
常见存储方式:
- YUV422SP
- YUV420SP
注:
其中YUV420P和YUV420SP根据U,V的顺序,又可分出2种格式
YUV420P:U前V后即YUV420P,也叫I420,
V前U后,叫YV12(YV表示Y画面跟着V,12表示12bit)
YUV420SP:U前V后叫NV12
V前U后叫NV21。
数据排列如下:
I420:YYYYYYYY UU VV => YUV420P
YV12:YYYYYYYY VV UU => YUV420P
NV12:YYYYYYYY UVUV => YUV420SP
NV21:YYYYYYYY VUVU => YUV420SP
I帧(关键帧)、P帧(差别帧)、B帧(双向差别帧)、IDR帧
I帧是一个全帧压缩编码帧。它将全帧图像信息进行JPEG压缩编码及传输。
特点:
- I帧不需要参考P帧,B帧即可生成一个完整图像
- I帧是P帧和B帧的参考帧(其质量直接影响到同组中以后各帧的质量)
- I帧是帧组GOP的基础帧,在一组中只有I帧
- I帧所占数据的信息量比较大
注: IDR帧(即时解码刷新帧)。第一个I帧叫做IDR帧。
P帧:前向预测编码帧,以I帧为参考帧。采用运动补偿的方法传送它与前面的I帧/P帧的差值及运动矢量。解码时必须将I帧中的预测值与预测误差求和后才能重构完整的P帧图像。
特点:
-
P帧是I帧后面相隔1~2帧的编码帧
-
P帧属于前向预测的帧间编码。它只参考前面最靠近它的I帧或P帧
-
P帧可以是其后面P帧的参考帧,也可以是其前后的B帧的参考帧
-
由于P帧是参考帧,它可能造成解码错误的扩散
-
由于是差值传送,P帧的压缩比较高
B帧:双向预测内插编码帧,以前面的I/P帧和画面的P帧为参考帧。B帧传送的是它与前面的I/P帧,和画面的P帧之间的预测误差及运动矢量。
- B帧是双向预测编码帧
- B帧压缩比最高,因为它只反映丙参考帧间运动主体的变化情况,预测比较准确
- B帧不是参考帧,不会造成解码错误的扩散
音频参数
声道数: 可分为单声道和双声道,双声道又为立体声,在硬件中要占两条线路。
量化位数: 位宽,一般为8位/16位。
采样率: 也称为采样速度或者采样频率,定义了每秒从连续信号中提取并组成离散信号的采样个数,它用赫兹(Hz)来表示。每秒的采样个数。
比特率: 每秒传送的比特(bit)数。单位为 bps(Bit Per Second),比特率越高,传送的数据越大,音质越好。
音频比特率 = 采样率 * 量化位数 * 声道数
编解码
硬编解码
通过硬件实现编解码,减轻CPU计算的负担,如GPU等
软编解码
如H265,H264,MPEG-4等编解码的算法,更消耗CPU
补充
CDN
CDN的核心理念,就是将内容缓存再终端用户附近。
简单说,把靠近用户的地方,建一个缓存服务器,把远端的内容,复制一份,放在用户附近。
原理:
CDN,又称为内容分发网络。CDN就是采用更多的缓存服务器(CDN边缘节点),布放在用户访问相对集中的地区/网络中。当用户访问网络时,利用全局负载均衡技术,将用户的访问指向距离最近的缓存服务器上,由缓存服务器响应用户请求。
CDN并不是只能缓存视频内容,它还可以对网站的静态资源(例如各类图片,html,css,js等)进行分发,对移动应用APP的静态内容(apk文件、APP内的图片视频等)进行分发。
CDN的好处
-
采用CDN技术,最大的好处,就是加速了网站的访问——用户与内容之间的物理距离缩短,用户的等待时间也得以缩短。
- 分发至不同线路的缓存服务器,也让跨运营商之间的访问得以加速。
- 例如中国移动手机用户访问中国电信网络的内容源,可以通过在中国移动假设CDN服务器,进行加速。效果是非常明显的。
-
CDN还有安全方面的好处。内容进行分发后,源服务器的IP被隐藏,受到攻击的概率会大幅下降。而且,当某个服务器故障时,系统会调用临近的健康服务器,进行服务,避免对用户造成影响。
参考: https://blog.csdn.net/qq_38987057/article/details/85317970
弱网优化
- 播放器Buffer
- 丢帧策略 (优先丢P帧,其次I帧,最后音频)
- 自适应码率算法
- 双向链路优化