视频一些基础知识整理

最近接收一个项目,用到视频的内容,简单点说,就将一端的视频采集下来,然后通过网络传输到另外一端并显示出来

采集设备不是IP摄像头,是USB摄像头,因此要涉及采集原始数据的知识

由于网络传输效率问题,因此必须采用一种合理的压缩方式,最容易想到是H264,实际上传MJPG也是可以的(效率低一些)

H264那么意味着要涉及编码、解码的问题

另外显示也是个问题,还好linux有framebuffer技术

 

以上思路,是可行的。

事实上,对于没有接触过视频方面知识的人而言,是提不出以下这些问题的:

  1. 那么USB摄像头采集下来的图像是什么格式的?
  2. 怎么设置USB采集的格式?
  3. 转换H264?
  4. H264怎么传输给对方?
  5. H264要转换成什么数据?怎么转换?

对于这些问题解决,如果都能够解决,我觉得对视频相关处理知识也就差不多了。

Q1:USB摄像头采集下来的图像是什么格式的?

  可以看下USB摄像头使用说明书,一般常见如MJPG、YUV

       MJPG是单帧压缩,可以理解压缩成一张张JPG的图片,我们知道JPG的图片要比无压缩bmp图片小很多,大概可以做到原先10分之一的大小。

       但对于视频而言,每秒25帧的图片,就算jpg也是很大的,传输通道会压力很大,因此USB采集用MJPG格式的,往往是用于本机显示,或不具备H264压缩条件地方。

       YUV是另外一种颜色表示,相对于前面MJPG(传统意义上RGB),这个是亮度与颜色,YUV的原理是把亮度与色度分离,研究证明,人眼对亮度的敏感超过色度。利用这个原理,可以把色度信息减少一点,人眼也无法查觉这一点。YUV三个字母中,其中”Y”表示明亮度(Lumina nce或Luma),也就是灰阶值;而”U”和”V”表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。

        YUV的出现本质上还是为了节省带宽,减少冗余信息的输出。同样也存在多种定义:YUV422 YUV444 YUV420 YUV411,数字越小说明带宽越小,目前主流的是422 以及 420 ,当然相互之间是可以转换的。大致可以看下图:

  

 

 图中也明显发现,444的效率最低的,当然效果是最好的。一般采用比较多的是420 422

 

 Q2:Linux下如何采集USB摄像头数据?

      当前Linux版本,基本上都是支持的。那就是V4L2,这个应该纳入到Linux内核当中,只要未裁剪掉,应该都支持

V4L2 是专门为 linux 设备设计的一套视频框架,其主体框架在 linux 内核,可以理解为是整个 linux 系统上面的视频源捕获驱动框架。

  这个库,怎么使用?网上资料很多,也不复杂,这里不啰嗦

  大致流程:初始化结构体,申请空间   -> 绑定到USB设备(ioctl)  -> 获取数据USB数据  然后该干嘛的干嘛

//设置分辨率与帧数
ret = v4l_capture_setup(enc, enc->src_picwidth, enc->src_picheight, enc->cmdl->fps); //开始取流 ret = v4l_start_capturing(); if (ret < 0) { return -1; } //获取摄像头数据 ret = v4l_get_capture_data(&v4l2_buf); if (ret < 0) { goto err2; } //获取V4L2摄像头数据 memcpy(inbuf,cap_buffers[v4l2_buf.index].start,cap_buffers[v4l2_buf.index].length); /////// if (src_scheme == PATH_V4L2) { v4l_put_capture_data(&v4l2_buf); }

  

 

为了后续H264压缩方便,往往USB采集的格式要使用YUV格式

对了,初始化的时候,还有告诉USB摄像头多少分辨率/帧数

 

带宽预算:(以800*600来考虑)

每张完整图片字节:x*y*3   =800*600*3 B = 1440000字节

每秒数据量:如果24帧,那么要*24 。24*1440000=34560000字节 ~= 32.9M

通过YUV422优化:可以节省1/3,最终大概=21.9M,是USB2.0上限了

 

如果USB摄像头是2.0的话,也就最多800*600*24 效果了。

否则:要么降帧数,要么降分辨率

这个也很重要,有时候硬件限制也是个麻烦事情。

 

另外,需要注意点:

由于USB2.0已经接近极限,因此对设备本身要求很高,

包括容易忽视连接线(延长线),这个如果不加屏蔽,不是双绞线的话,也会有问题的

 

Q3:采集数据需要H264压缩?

一般来说,需要GPU压缩或APU压缩,当然厉害一点设备,也可以采用FFmpeg来压缩(实践证明,这个在x86架构下还行,ARM不行)

是不是,我们经常用到的 “硬解码” “软解码”的概念 差不多

 

说下H264

  据说我们人眼是每秒24帧,如果超过这个数,不会觉得“卡顿”,实际上如果超过12帧,也差不多很流畅了。基于这个理解,那么视频就好比每秒播放多少张图片,张数越高,效果越好,但也带来问题:数据量非常大。

  但是,往往视频每帧之间(特别是连续的)变动就很少,比如我们的背景,往往几乎不变。这样如果有一种算法,可以算出哪些是变化,哪些是不变的,传输的时候就传变化的,那就可以大大节省带宽,效果也能达到原先效果

  基于这个思路,H264就是干这个的,当然H264是一个标准。目前市场上主流还是H264,当然也有H265,本质上还是相差不大

       为了更好理解H264,所以也定义一些知识:

 

H264压缩技术主要采用

了以下几种方法对视频数据进行压缩。包括:

(1) 帧内预测压缩:解决的是空域数据冗余问题。(就是独立帧,可以理解为单独一张图片,比如JPEG图片)
(2) 帧间预测压缩:(运动估计与补偿),解决的是时域数据冗余问题。(实际上就是增量压缩)
(3) 整数离散余弦变换(DCT):将空间上的相关性变为频域上无关的数据,然后进行量化。
(4) CABAC压缩。

 

经过压缩后的帧分为:I帧,P帧和B帧:

I帧:关键帧,采用帧内压缩技术。(数据量也是最大的)
P帧:向前参考帧,在压缩时,只参考前面已经处理的帧。采用帧间压缩技术。
B帧:双向参考帧,在压缩时,它即参考前面的帧,又参考它后面的帧。采用帧间压缩技术。

 

由此可以理解:I帧是关键的,也是独立的,可以变成一个完整画面,但数据量也是最大的

B帧 P帧,都是基于I帧,单独B帧 P帧是不可能显示一个完整画面的,但一帧的数据量少,也是H264的精髓所在

 

那么如何安排I B P呢?

1. 感觉还是跟场景结合起来,H264运用最广的就是视频监控,视频监控有以下一些特点:

  不变的数据大,变化数据少

       一般需要网络传输,带宽越小越好

       分辨率要求比较高

这样,我们I帧不用考虑太频繁,例如每隔50帧安排一个I帧(2s一帧),往往也足够了,也比较合理,再小下去提升也有限

BP可以多一点,其他24帧都是BP帧

 

2. 如果是行车记录仪或摄像机?

  此时特点,变成动态比较多,带宽要求比较低。

       此时可能也不需要H264了,直接MPEG压缩不香吗?

       如果非得要H264,那么I帧考虑频繁点

 

另外,还有GOP概念,最终来说还是一组数据,这一组数据就是GOP

两个I帧之间是一个图像序列;一个图像序列中只有一个I帧。

 

 

 

 

这里也插入下一些实践知识:

如果I帧没有?会什么效果

  绿屏

 

如果I帧长时间不更新?(前面收到过I帧,但过程中有段时间没有收到)

      看图像实际变化,如果变化不大的,可能是局部花屏

       如果变化比较大,花屏

     如果变化很大,可能是绿屏

 

如果偶尔丢失B P帧?

      分辨率足够的话,偶尔丢一下,感觉不出来的

 

如果长期丢失B P帧?

      图像会跳帧(“卡”),I帧在,图像本身没有问题,但看起来很不连续。

 

 

虽然理解上算法不复杂,但是要CPU计算,也是很费资源的,

因此,H264也是考量压缩端计算能力,也考量解压端计算能力,好在目前主流CPU都是集成GPU,这部分工作可以交给GPU来完成

也就是说,如果方案采用的CPU本身就很弱,那就很麻烦,H264虽然你知道,但肯定不好实现

 

posted @ 2020-04-24 16:37  小刚学长  阅读(718)  评论(0编辑  收藏  举报