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获得预览数据

相关推荐
潘潘潘31 分钟前
Android多线程机制简介
android
CYRUS_STUDIO2 小时前
利用 Linux 信号机制(SIGTRAP)实现 Android 下的反调试
android·安全·逆向
CYRUS_STUDIO3 小时前
Android 反调试攻防实战:多重检测手段解析与内核级绕过方案
android·操作系统·逆向
黄林晴6 小时前
如何判断手机是否是纯血鸿蒙系统
android
火柴就是我6 小时前
flutter 之真手势冲突处理
android·flutter
法的空间7 小时前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
循环不息优化不止7 小时前
深入解析安卓 Handle 机制
android
恋猫de小郭7 小时前
Android 将强制应用使用主题图标,你怎么看?
android·前端·flutter
jctech7 小时前
这才是2025年的插件化!ComboLite 2.0:为Compose开发者带来极致“爽”感
android·开源
用户2018792831677 小时前
为何Handler的postDelayed不适合精准定时任务?
android