Android Camera2 获取预览数据

一、Camera2简介

Camera2是Google在Android 5.0后推出的一个全新的相机API,Camera2和Camera没有继承关系,是完全重新设计的,且Camera2支持的功能也更加丰富,但是提供了更丰富的功能的同时也增加了使用的难度。Google的官方Demo:

https://github.com/googlesamples/android-Camera2Basic

二、Camera2预览流程

Camera2 API使用流程如下

三、使用Camera2获取预览数据

1.获取预览数据

一般情况下,大多设备其实只支持ImageFormat.YUV_420_888ImageFormat.JPEG格式的预览数据,而ImageFormat.JPEG是压缩格式,一般适用于拍照的场景,而不适合直接用于算法检测,因此我们一般取ImageFormat.YUV_420_888作为我们获取预览数据的格式,对于YUV不太了解的同学可以戳这里

mImageReader = ImageReader.newInstance(mPreviewSize.getWidth(), mPreviewSize.getHeight(),
                ImageFormat.YUV_420_888, 2);
mImageReader.setOnImageAvailableListener(
               new OnImageAvailableListenerImpl(), mBackgroundHandler);

其中OnImageAvailableListenerImpl的实现如下

private class OnImageAvailableListenerImpl implements ImageReader.OnImageAvailableListener {
        private byte[] y;
        private byte[] u;
        private byte[] v;
        private ReentrantLock lock = new ReentrantLock();

        @Override
        public void onImageAvailable(ImageReader reader) {
            runOnSubThread(new Runnable() {
                @Override
                public void run() {
                    Image image = reader.acquireNextImage();
                    // Y:U:V == 4:2:2
                    if (image.getFormat() == ImageFormat.YUV_420_888) {
                        Image.Plane[] planes = image.getPlanes();
                        // 加锁确保y、u、v来源于同一个Image
                        lock.lock();
                        // 重复使用同一批byte数组,减少gc频率
                        if (y == null) {
                            y = new byte[planes[0].getBuffer().limit() - planes[0].getBuffer().position()];
                            u = new byte[planes[1].getBuffer().limit() - planes[1].getBuffer().position()];
                            v = new byte[planes[2].getBuffer().limit() - planes[2].getBuffer().position()];
                        }
                        if (image.getPlanes()[0].getBuffer().remaining() == y.length) {
                            planes[0].getBuffer().get(y);
                            planes[1].getBuffer().get(u);
                            planes[2].getBuffer().get(v);
							//2.处理数据
                            byte[] nv21 = new byte[planes[0].getRowStride() * mPreviewSize.getHeight() * 3 / 2];
                            yuv422ToYuv420sp(y, u, v, nv21, planes[0].getRowStride(), mPreviewSize.getHeight());
                        }
                        lock.unlock();
                    }
                    image.close();
                }
            });
        }
    }
2.将YUV_420_888的数据转化成nv21
	/**
     * 将Y:U:V == 4:2:2的数据转换为nv21
     *
     * @param y      Y 数据
     * @param u      U 数据
     * @param v      V 数据
     * @param nv21   生成的nv21,需要预先分配内存
     * @param stride 步长
     * @param height 图像高度
     */
    public void yuv422ToYuv420sp(byte[] y, byte[] u, byte[] v, byte[] nv21, int stride, int height) {
        System.arraycopy(y, 0, nv21, 0, y.length);
        // 注意,若length值为 y.length * 3 / 2 会有数组越界的风险,需使用真实数据长度计算
        int length = y.length + u.length / 2 + v.length / 2;
        int uIndex = 0, vIndex = 0;
        for (int i = stride * height; i < length; i += 2) {
            nv21[i] = v[vIndex];
            nv21[i + 1] = u[uIndex];
            vIndex += 2;
            uIndex += 2;
        }
        List<FacePreviewInfo> facePreviewInfos = HrHelper.getInstance().onPreviewFrame(nv21, true);
        HrHelper.getInstance().clearLeftFace(facePreviewInfos);
    }

四、参考

进击的丸子

Android Camera2入门系列2 - ImageReader获得预览数据

相关推荐
长亭外的少年3 分钟前
如何查看 Android 项目的依赖结构树
android
深海呐2 小时前
Android 从本地选择视频,用APP播放或进行其他处理
android·音视频·从本地选择视频,用app播放·从本地选择视频,并拿到信息·跳转到本地视频列表
深海呐2 小时前
Android Google登录接入
android·google登录接入·android 谷歌登录接入·google登录·android google
daiyang123...2 小时前
MySQL【知识改变命运】11
android·数据库·mysql
8931519603 小时前
Android开发教程案例源码分享-匹配动画多个头像飘动效果
android·android开发·android教程·kotlin教程·android头像飘动动画·android匹配动画·android多个头像飘动动画
老码沉思录4 小时前
Android开发实战班 - 网络编程 - WebSocket 实时通信
android·网络·websocket
江上清风山间明月4 小时前
Android 14 screenrecord录制视频失败的原因分析
android·视频·大小·失败·录制·screenrecord·0kb
keeng20084 小时前
Compose学习记录(3): ViewModel数据驱动更新组件
android
唐诺5 小时前
android MQTT使用示例
android·mqtt
菠菠萝宝5 小时前
【YOLOv8】安卓端部署-1-项目介绍
android·java·c++·yolo·目标检测·目标跟踪·kotlin