android NV21转I420
作者:admin 日期:2015-10-13
最近做一个视频流我app,要用android的摄像头采集数据发到远程保存。我之前对视频和流媒体这块没什么研究,找了找资料发现可以这么干:
Camera->MediaCodec->MediaMuxer
摄像头采集这块资料上一般是用YV12,再通信几次copy就转成I420格式了,再把I420的数据喂到MediaCodec。而我的安卓机的摄像头只支持NV21格式的预览编码,找了很久没有找到可用的资料,最后才大概知道了这两者的关系。
YUV相关的我就不说了,与RGB类似的另一种颜色的表示方式,Y表示亮度, UV表示色度。而根据一些人类视觉的特点发现人类对亮度比较敏感对色度比较不敏感。所以提出对每个像素的Y分量进行采样,而对4个像素只进行一组UV分量的采样。就是对4个像素来说,有4个Y、1个U、1个V。这就是yuv420。
光这个yuv420也有很多和排列方式,NV21和I420就是其中的两种方式。
假定有一张图片的大小为width*height, YUV420图片数据的大小就是width*height*3/2
NV21
前面width*height个字节存的是每个像素的Y分量,后面的width*height/2字节是VUVUVUVU...这样存的。
I420
前面的width*height个字节还是每个像素的Y分量,接下来的width*height/4字节是U分量,最后的width*height/4字节是V分量。
了解了上面的东西之后,NV21转I420也就比较简单了,下面是JAVA代码。
public byte[] nv21ToI420(byte[] data, int width, int height) { byte[] ret = globalBuffer; int total = width * height; ByteBuffer bufferY = ByteBuffer.wrap(ret, 0, total); ByteBuffer bufferU = ByteBuffer.wrap(ret, total, total / 4); ByteBuffer bufferV = ByteBuffer.wrap(ret, total + total / 4, total / 4); bufferY.put(data, 0, total); for (int i=total; i<data.length; i+=2) { bufferV.put(data[i]); bufferU.put(data[i+1]); } return ret; }
globalBuffer是我分配的一个缓冲区,这样就不需要每次分配缓冲区了。