yuv420数据快速裁剪
最近碰到一个项目需求,这个项目是两年多年已经量产的项目,这是一个车载后视镜项目,当时配置的后视摄像头是确定的,也就是说这个后视摄像头是厂家定制出去的,当时研发在做倒车显示的时候,显示的画面是完整的裸数据,没有裁剪过,也就是后视摄像头出来的CVBS数据是N制式的时候就是720X480的原始数据来显示的。
但是最近又接到一个需求,就是这个项目的机器可能会作为周转机器装到适合别的项目产品的车上,也就是配置的后视摄像头是不一样的,因此就会出现一些差异,在测试中发现最左边有一条白线,这是这种后视摄像头的原始数据出了问题,因此需要在现实的时候把数据给裁剪掉。
首先我们这种CVBS数据通过主控芯片上来后都是一种8位的YUV420数据,也就是Y数据存放在一起是连续的,UV数据放在一起也是连续的,按照这种格式也就是说每个像素点Y值是一个字节,对于UV数据是每两个像素点存储一个字节的数据,也就是说对应Y数据是减半的。其实裁剪也很简单,本来是可以利用CPU之外的另外加速器来处理的,因为是一个早期项目,早点完工解决问题就可以了,因此在CPU运算量富足的情况下采用了用CPU来裁剪,裁剪方法如下:
+
+ {
+ int heightcunt = 0;
+ int heightUVcunt = 0;
+ int newWidth =0 ;
+ int cropStartX;
+ int srcWidth;
+ int srcHeight;
+ int cropHeight;
+
+ cropStartX = 16;//裁剪左边多少个像素
+ if (mSystemType == 0) {//NTSC制式
+ srcWidth = 720;//裁剪前的原始宽度
+ cropHeight = 480;//裁剪后的高度
+ srcHeight = 480; //裁剪前的原始高度
+ } else {//PAL制式
+ srcWidth = 720;
+ cropHeight = 576;
+ srcHeight = 576;
+ }
+ newWidth = srcWidth - cropStartX;
+
+ for( heightcunt = 0; heightcunt < cropHeight; heightcunt++){
+ memcpy((void *)(v4l2_buf.addrVirY + newWidth*heightcunt),
+ (const void*)(v4l2_buf.addrVirY + cropStartX + srcWidth*heightcunt), newWidth);
+ }//addrVirY 存放Y数据的内存地址
+
+ for( heightUVcunt = 0; heightUVcunt < cropHeight; heightUVcunt++){
+ memcpy((void *)(v4l2_buf.addrVirY + newWidth*cropHeight + newWidth*heightUVcunt/2),
+ (const void*)(v4l2_buf.addrVirY + srcWidth*srcHeight+cropStartX/2 + srcWidth*heightUVcunt/2), newWidth/2);//Y数据之后就是UV的数据,他们是连续的,因此可以这样UV接着Y的数据顺序存放。
+ }
+ }
通过以上一个简单的运输把原始数据做了重新的排布组合,完成了项目需求。对于这种老项目的需求开发,有时是难免的,因此在考虑软件功能设计的时候尽量考虑扩展性。市场需求变化,公司管理市场的能力也各有不同,往往技术成为解决市场奇葩需求的最终方法,有时候你的老板同事觉得可能这样的改变很容易,实际上做这种事真的是人在江湖、身不由己,这种事做多了好累。程序员说设计的时候你考虑好兼容性、扩展性啊,实际上在很多项目上不是不考虑,而是当时的项目需求非常明确,给你的时间精力也是有限的,因此在满足了项目需求的情况下,多数时候都会够用就好。这种建议教训告诉我们,在精力许可的情况下尽可能多考虑一下这种多变性。