Camera2 实现重力感应四个方向调试相机预览

Camera2API 实现重力感应四个方向调试相机预览


需求

Camera2 相机预览实现四个重力感应方向预览方向正常

场景

  • 实际有个客户需求,用到了四个方向的重力感应,但是之前的工程代码只有两个方向,导致屏幕无法四个方向正常显示
  • 相机预览两个重力感应方向已经满足了需求,但是客户重力感应模块、板卡 实际物理装配时候不可能按照要求装配的,不同厂家的磨具不一样导致板卡方向装配不一样。基于这样的实际情况,软件就需要适配四个方向,两个重力感应预览方向就无法满足实际要求了。
  • 实际产品案例:监控、HDMIN、车载Camera…

需求实现

setAspectRatio 设置显示长宽

设置显示组件长宽
textureView.setAspectRatio(width, height)


 private void setupCamera(int width, int height) {
   
   
        CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
        try {
   
   
            for (String cameraId : manager.getCameraIdList()) {
   
   
              ...............
                int orientation = getResources().getConfiguration().orientation;
                if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
   
   
                    Log.d(TAG, "setupCamera: ORIENTATION_LANDSCAPE  " + mPreviewSize.getWidth() + " x " + mPreviewSize.getHeight());
                    textureView.setAspectRatio(1920, 1080);
                } else {
   
   
                    textureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
                    Log.d(TAG, "setupCamera:  ORIENTATION_PORT  " + mPreviewSize.getWidth() + " x " + mPreviewSize.getHeight());
                }

                break;
            }
        } catch (CameraAccessException e) {
   
   
            e.printStackTrace();
        }
    }

使用位置:在View 组件流传递过来时候, onSurfaceTextureAvailable 方法中,去设置 setupCamera

 TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
   
   
        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
   
   
            setupCamera(width, height);
            configureTransform(width, height);
            openCamera();
        }


        @Override
        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
   
   
            configureTransform(width, height);
        }

        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
   
   
            return false;
        }

        @Override
        public void onSurfaceTextureUpdated(SurfaceTexture surface) {
   
   

        }
    };
				

postScale postRotate 设置缩放和旋转

比如长宽肯定是1920*1080,根据实际产品长宽进行设置,但是如果是竖屏状态下,还是需要这个图像输出流的比例数出来,那么就必须进行缩放,才能完全显示出来的。

补充下基本知识点:
Matrix的操作,总共分为translate(平移),rotate(旋转),scale(缩放)和skew(倾斜)四种,每一种变换在Android的API里都提供了set, post和pre三种操作方式,除了translate,其他三种操作都可以指定中心点。

set是直接设置Matrix的值,每次set一次,整个Matrix的数组都会变掉,这也就意味着你对同一个矩阵先调用setScale,再调用setTranslate,那么矩阵只会执行Translate的操作,前面的scale操作是无效的。

post是后乘,当前的矩阵乘以参数给出的矩阵。可以连续多次使用post,来完成所需的整个变换。例如,要将一个图片先缩放,再平移则可以通过:

同样的道理,如上面设置显示长宽的后面就需要又缩放和旋转逻辑了, 输出流的地方是不会变的,那么接收的地方就需要根据实际情况如重力感应和物理场景【竖屏-横屏】进行流显示的变化了->缩放、旋转操作


onSurfaceTextureAvailable ->  configureTransform(width, height) -> Configuration config =  getResources().getConfiguration()【根据重力感应方向,计算缩放比例和旋转角度及选择方向了】

核心代码如下:
private void configureTransform(int viewWidth, int viewHeight) {
   
   
        if (null == textureView || null == mPreviewSize) {
   
   
            return;
        }
        int rotation = getWindowManager().getDefaultDisplay().getRotation();
        Configuration config =  getResources().getConfiguration();
        if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
   
   
            Log.d(TAG, "configureTransform: ORIENTATION_PORTRAIT");
            if(Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation){
   
   
              isRotation = true;
            }
        } else if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
   
   
            Log.d(TAG, "configureTransform: ORIENTATION_LANDSCAPE");
            if(Surface.ROTATION_0 == rotation || Surface.ROTATION_180 == rotation){
   
   
              isRotation = true;
            }
        }
        Log.d(TAG, "configureTransform: isRotation = "+isRotation);
        if(isRotation){
   
   
            rotation = rotation + 1;
            if(rotation > 3){
   
   
               rotation = rotation - 3;
            }
        }
        Log.d(TAG," aaaaaaaaaaaa rotation:"+rotation);
        Matrix matrix = new Matrix();
        RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
        RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
        float centerX = viewRect.centerX();
        float centerY = viewRect.centerY();
        if (Surface.ROTATION_90 == rotation) {
   
   
            bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
            matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
            float scale = Math.max(
                    (float) viewHeight / mPreviewSize.getHeight(),
                    (float) viewWidth / mPreviewSize.getWidth());
            matrix.postScale(scale, scale, centerX, centerY);
            matrix.postRotate(90 * (rotation - 2), centerX, centerY);
            Log.d(TAG," 00000000000000  ");
        }else  if ( Surface.ROTATION_270 == rotation) {
   
   
            bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
            matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
            float scale = Math.max(
                    (float) viewHeight / mPreviewSize.getHeight(),
                    (float) viewWidth / mPreviewSize.getWidth());
            matrix.postScale(scale, scale, centerX, centerY);
            matrix.postRotate(270, centerX, centerY);
            Log.d(TAG," bbbbbbbbbbbbbbbb  ");
        }  else if (Surface.ROTATION_180 == rotation) {
   
   
            float scale = (float)1080/ 1920;
            Log.d(TAG, "configureTransform: rizhi xianshi port state  scale:"+scale+"    centerX:"+centerX+"   centerY:"+centerY);
            matrix.postScale(scale, scale, centerX, centerY);
            textureView.setRotation(270f);
            Log.d(TAG, "configureTransform:   "+"    centerX:"+centerX+"   centerY:"+centerY);
            Log.d(TAG," 111111111111111  ");
        }else if(Surface.ROTATION_0 == rotation){
   
   
            float scale = (float)1080/ 1920;

            Log.d(TAG, "configureTransform: rizhi xianshi port state  scale:"+scale+"    centerX:"+centerX+"   centerY:"+centerY);
            matrix.postScale(scale, scale, centerX, centerY);
            textureView.setRotation(270f);
            Log.d(TAG," 222222222222222222  ");

        }
        textureView.setTransform(matrix);
    }

manager.openCamera 打开相机

打开相机就是一个比较常规操作了,如上显示组件 已经准备好,进行了算转和缩放操作,就是显示组件已经设置好了参数,接下来就打开相机,让流数据进来。
打开相机基本代码如下:


 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
   
   
            setupCamera(width
Android Camera开发入门:目录 第一篇: 前景  一、Android Camera开发前景;      1)camera相关应用的领域      2)相关岗位介绍;      3)市场招聘介绍;      4)发展前景介绍;  二、学习这门课的重要性;      1)适合的人群;      2)熟悉和了解Android Camera 应用开发流程的重要性 第二篇: 开发环境安装  一、jdk、sdk的配置;  二、android studio的安装介绍;  三、adb命令的使用; 第三篇: Camera 常用api和最新框架介绍  一、android camera api介绍      1)camera1、camera2 区别;      2camera 1、camera2 常用api介绍;      3)android camerax;  二、android camera最新框架介绍 第四篇:Camera api1实现预览、拍照、录像功能  一、预览  二、拍照  三、录像  四、获取实时预览流 第五篇: Camera2相机 打开功能实现第六篇: Camera2相机 预览功能实现  1)surfaceview、textureview 第七篇: Camera2相机 拍照功能实现 1)单拍; 第八篇:Camera2相机 录像功能实现1)正常录像 第九篇:Camera2预览方向、拍照方向设置     1) 预览变形问题如何处理? 第十篇:YUV流处理  1)如何获取实时预览流?  2)  思考:双码流方案如何实现?一边本地录像,一边后台推流 第十一篇:dumpsys media.camera 第十二篇:Camera2 Zoom变焦第十三篇:人脸识别(android 原生 & 三方人脸识别算法)第十四篇:Uvc UsbCamera第十五篇:Android Camera2拍摄RAW图第十六篇: Android Camera2同时打开前后摄 并 录像第十七篇: Android Camera2 视频慢动作  附:1)提供android开发相关资源      软件工具、Android相关学习书籍、学习相关网站博客等链接2)提供课程讲解中设计到的App 源码    * Camera API1使用源码    * Camera API2使用源码    * 调用三方算法人脸识别源码    *  录像慢动作源码    * Uvc UsbCamera相关源码3)课件
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

野火少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值