项目需求:把摄像头出来的NV21的YUV数据,转换为JPEG传导电脑端显示。NV21数据比较大,直接用于传输会比较耗费网络资源,所以需要压缩为jpg图片数据传输。之前考虑编码为H264传输,到电脑端在解码显示。经过测试,效果也不是很理想。由于应用场景只是在内网,传输效率还是比较高的。
1.安卓有现成的YUVimage可以压缩为
YuvImage yuvImage = new YuvImage(yuv, ImageFormat.NV21,w,h,null); ByteArrayOutputStream jpeg = new ByteArrayOutputStream(); yuvImage.compressToJpeg(new Rect(0,0,w,h),100,jpeg);
这个方法底层是使用jpeg库进行压缩的,有内存泄露(之前做项目的时候,压力测试扛不住半天就莫名崩溃,当时找这个BUG找了大概一周的时间,几乎每个可能出现内存泄露的地方都一一做了排查,根本想不到是系统底层的问题。后来无意间在论坛上发现了YUVimage压缩jpeg数据有内存泄露的BUG才去查了一下底层实现,果然如此。),经过多次调用后,会出现内存溢出,程序崩溃。居然系统自带的方法不能游泳,无奈,只能去寻找其他的解决方法。找了JPEG压缩算法,另外发现的turbojpeg加速压缩算法。
2.另外由于NV21不能直接作为JPEG压缩算法的输入,需要转换为I420。刚开始直接使用java转换NV21为I420,发现效率较低。固使用libyuv神库解决这样的转换问题。
3.经过整理:完善了相关的转换。目前实现了NV21到argb,jpeg等的相关转换
(1)nv21转换为JPEG
-
public static native int yuv2jpeg(byte[] nv21,int w,int h,int subsample,byte[] jpeg ,int quality,int flags); (2)yuv裁剪,然后压缩为jpeg public static native int yuvCrop2jpeg(byte[] nv21,int w,int h,int subsample,int x,int y,int cropW,int cropH,byte[] jpeg ,int quality,int flags); (3)获取jpeg图片的相关消息 public static native int getjpegInfo(byte[] jpeg,int size,int[] info); (4)jpeg转换为NV21 public static native int jpeg2yuv(byte[] jpeg,int size,byte[] yuv,int w,int h); (5)jpeg图片转换为argb8888 public static native int jpeg2argb(byte[] jpeg,int size,byte[] argb,int w,int h); (6)yuv数据转换为argb8888 public static native int yuv2argb(byte[] yuv,int size,int[] argb,int w,int h); (7)NV21转换为rgb565 public static native int yuv2rgb565(byte[] yuv,int size,byte[] rgb565,int w,int h);
代码实现和相关Demo见github:
https://github.com/liushiyun8/YuvJpegDemo