Camera2 Image转NV21

项目需要对Android相机预览帧进行图像处理。而Camera2从ImageReader(设置通用的ImageFormat.YUV_420_888格式)中获取的是YUV格式数据。其中YUV本身只存储颜色信息,不包含图像宽高信息,回调后的YUV数据分别存储在Image Planes的3个数组中。

设置相机预览大小1920 * 1440后打印3个planes数组信息如下:

         int width = image.getWidth();int height = image.getHeight();ByteBuffer buffer = planes[i].getBuffer();int rowStride = planes[i].getRowStride();int pixelStride = planes[i].getPixelStride();Log.v(TAG, "pixelStride " + pixelStride);Log.v(TAG, "rowStride " + rowStride);Log.v(TAG, "width " + width);Log.v(TAG, "height " + height);Log.v(TAG, "buffer size " + buffer.remaining());


从上至下依次对应Y、U、V三个分量的buffer数据。可见Y的buffer大小就是width * height。U和V的buffer大小是width * height的1/2。

  • 为什么是NV21格式?

NV21格式每四个Y分量共用一组U分量和V分量,Y连续排序,U与V交叉排序。即如下排列:

Y Y   Y Y   Y Y   Y Y
Y Y   Y Y   Y Y   Y Y
Y Y   Y Y   Y Y   Y Y
Y Y   Y Y   Y Y   Y Y
V U   V U   V U   V U
V U   V U   V U   V U

对于一组NV21数据,Y的size为width * height,U和V的size都是width * height * 1 / 4,总size为width * height * 3 / 2

根据第3个通道planes[2].getPixelStride() = 2可知V分量每两个连续的V之间隔了一个像素值,实际隔出的那个值就是一个U值。而plane[0]就是所有的Y值。

仔细观察U和V的buffer size发现比Y的buffer size的一半少了一个像素值。举例来说,planes[1] 代表的是U分量,PixelStride为2,取U分量索引为0, 2, 4, 6 … 1382398,省略了最后一个V值,size就是1382399。

  • 如何转化成NV21?

综上,NV21数据可先由planes[0]+planes[2]组合而成,最后再从planes[1]中取出最后的值追加到末尾。
Java代码如下:

    private static byte[] convertPlanes2NV21(int width, int height, ByteBuffer yPlane, ByteBuffer uPlane, ByteBuffer vPlane) {int totalSize = width * height * 3 / 2;byte[] nv21Buffer = new byte[totalSize];int len = yPlane.capacity();yPlane.get(nv21Buffer, 0, len);vPlane.get(nv21Buffer, len, vPlane.capacity());byte lastValue = uPlane.get(uPlane.capacity() - 1);nv21Buffer[totalSize - 1] = lastValue;return nv21Buffer;}
  • 优化速度

项目需要对Camera2每一帧图像数据的处理速度进行优化,故相机Image转NV21的操作放到JNI层去处理,同时省略了追加最后一值的操作(不影响结果)。
JNI代码如下:

Java_com_libyuv_util_YuvUtils_convertPlanes2NV21(JNIEnv *env, jclass type,jint width, jint height,jobject yPlane, jobject vPlane,jbyteArray bufferArray) {jbyte *y_buffer = (jbyte *) env->GetDirectBufferAddress(yPlane);jbyte *v_buffer = (jbyte *) env->GetDirectBufferAddress(vPlane);jbyte *Dst_data = env->GetByteArrayElements(bufferArray, NULL);int len = width * height;memcpy(Dst_data, y_buffer, static_cast<size_t>(len));jlong vBufferCapacity = env->GetDirectBufferCapacity(vPlane);memcpy(Dst_data + len, v_buffer, static_cast<size_t>(vBufferCapacity));env->ReleaseByteArrayElements(bufferArray, Dst_data, 0);
}

Camera2 YUV_420_888转NV21相关推荐

  1. android Camera2 API适配百度人脸识别SDK

    Camera2 API替换Camera API之后的问题 camera和camera2的最主要区别之一就是camera2不再支持nv21的输出,通常我们为了使视频预览更加的流畅,会采用YUV_420_ ...

  2. 【Android Camera2】玩转图像数据 -- NV21图像旋转,镜像,转rgba代码分析,性能优化

    [Android Camera2]玩转图像数据 业务场景介绍 NV21数据旋转 逐像素遍历法 NV21数据镜像 逐像素遍历法 中心翻转法 NV21转RGB/RGBA数据 逐像素遍历法 NV21组合操作 ...

  3. CameraX API 的 YUV_420_888 图像转换为NV21数据和Bitmap

    CameraX打开相机预览的功能这里不赘述,大家可以在Android官网找到 CameraX 概览  |  Android 开发者  |  Android Developershttps://deve ...

  4. argb888与rgb888转换程序_将Android camera2 api YUV_420_888转换为RGB

    在我的方法中,我使用OpenCV Mat和脚本 https://gist.github.com/camdenfullmer/dfd83dfb0973663a7974 首先,使用上面链接中的代码将YUV ...

  5. Android平台RTMP推送模块如何对接NV21、YV12、RGB、YUV等编码前数据

    前言 我们在对接Android平台摄像头或者屏幕采集.编码打包推送场景的时候,随着采集设备的不同,出来的数据也是多样化的,比如NV21.YV12.RGB.YUV等,更有图像数据甚至是翻转或者倒置的,如 ...

  6. android 颜色反转 api,来自Android camera2 API的图像数据在Galaxy S5上翻转和压缩

    我正在实现一个应用程序,它使用来自相机的实时图像进行实时图像处理.使用现已弃用的android.hardware.Camera,它有限制地工作;提高灵活性和性能我想使用新的android.hardwa ...

  7. 安卓camera2 API获取YUV420_888格式详解

    安卓音视频开发中的一个环节是摄像头采集数据,Android平台上摄像头采集的API有两套,camera1和camera2.本文主要讲的是camera2这套API采集数据,并指明YUV420_888格式 ...

  8. YUV_420_888数据裁剪

    YUV_420_888是YUV_420的一个大类,android camera2的ImageReader中设置了YUV_420_888后具体返回数据U和V是单独处于不同平面还是相同平面交叉排列要看具体 ...

  9. Camera2 YUV420_888

    Camera2 YUV420_888转RGB 官网文档介绍 Android PAI 对 YUV420_888的介绍 ,大致意思如下: 它是YCbCr的泛化格式,能够表示任何4:2:0的平面和半平面格式 ...

最新文章

  1. 大家买PDA干什么,来看SPB的调查
  2. JCIFS实现单点登录
  3. 字符串原样输出程序python_Python格式化字符串(格式化输出)
  4. 请MM吃饭之工厂模式实现
  5. C++中如何读取一个数的位数_C语言编写程序求水仙花数
  6. iscsi存储常见错误
  7. 常用cpu位数与变量长度表(不同编译器可能有差异)
  8. 爱奇艺《青春有你3》节目组决定终止节目录制
  9. Compiled from Servlet.java (version 1.7 : 51.0 查看Servlet源码
  10. Android的setVisibility的三个参数
  11. 6. jQuery 效果 - 淡入淡出
  12. sqlserver安装目录_SQL 2008R2安装教程
  13. 硬盘的老化测试软件,硬盘检测工具使用方法
  14. js replace 中文分号_关于js分号的问题?
  15. 移动硬盘文件或目录损坏且无法读取要怎么办啊
  16. 操作系统的几种基本类型
  17. lms全称是什么意思_LMS是什么意思
  18. Python 从入门到爬虫极简教程
  19. 给初学者:用VB写外挂 ———— 序言
  20. 基于聚类(Kmeans)算法实现客户价值分析系统(电信运营商)

热门文章

  1. 奇迹mu服务器架设全教程
  2. 【常识】气体单位%Vol、ppm、%LEL
  3. (转)通过修改键盘映射替代损坏按键
  4. directshow视频旋转90度
  5. 程序设计思维与实践 Week14 限时大模拟A - 猫睡觉问题
  6. linux crontab清理脚本,crontab定时清理日志
  7. 项目源代码迁移到另一个gitlab的方法(保留原来的提交记录)
  8. 服务器修复oxc0000098,Win10系统无法开机0xc0000098错误怎么办_win10无法开机提示0xc0000098错误代码如何修复...
  9. 三菱FX5U添加新模块
  10. 关于idea中提交svn时一直显示performing VCS refresh