Android Camera 预览角度和拍照保存图片角度相关

--基于Android R(11)

关于Camera

Camera Framework 的架构

Android Camera Framework 是一个分层架构,由以下组件组成:

  • HAL(硬件抽象层): HAL 抽象底层相机硬件,提供与不同设备相机进行交互的标准接口.
  • CameraService : CameraService 是框架的核心,管理相机设备并为应用程序提供访问 HAL 的接口.
  • Camera 应用程序 : Camera 应用程序是面向用户的界面,允许用户控制相机设置、预览取景器并拍摄照片或视频.

以 Android 原生 Camera2 应用程序为例,PhotoModule 和 VideoModule 展示了如何使用 Camera Framework 构建高级相机应用程序.

PhotoModule 负责管理照片拍摄.

VideoModule 负责管理视频录制.

Android 最新Camera框架
Camera 架构
AndroidO Camera(API 2)openCamera 流程

关于Camera预览

Camera的图像数据来源于摄像头硬件的图像传感器,图像传感器被固定到手机上后会有一个默认的方向.

如果默认的图像传感器为横向,而所用设备拍照是竖向的,比如手机,但得到的图片数据依然会是横向的,因为这个数据取决于图像传感器的方向.

由于Camera默认是横向的,竖向拍照时得到的照片和预览的照片会有所不同.

Camera1 API 上可以利用setDisplayOrientation(int rotateDegree)设置预览角度调节预览图片.

setDisplayOrientation只是改变了预览的角度,而拍摄生成图片的角度还是和默认图片传感器方向一致.

Camera2 API --通过TextureView.setTransform(matrix) 接口来调整textureView的显示来达到目的,设置预览方向.

./packages/apps/Camera2/src/com/android/camera/one/v2/OneCameraImpl.java:400:                builder.set(CaptureRequest.JPEG_ORIENTATION,
./packages/apps/Camera2/src/com/android/camera/one/v2/SimpleOneCameraFactory.java:199:                rootBuilder.setParam(CaptureRequest.JPEG_ORIENTATION,
./packages/apps/Camera2/src/com/android/camera/one/v2/OneCameraZslImpl.java:824:                builder.set(CaptureRequest.JPEG_ORIENTATION,

public void openCamera(){
      CameraManager manager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
        try {
           ......
    //调整预览画面显示方向
        configureTextureViewTransform(mTextureView.getWidth(),mTextureView.getHeight());
            manager.openCamera(cameraId, mStateCallback, null);
           ......
        }
}

private void configureTextureViewTransform(int viewWidth, int viewHeight) {
        if (null == mTextureView) {
            return;
        }
        int rotation = 0 ;/*activity.getWindowManager().getDefaultDisplay().getRotation();*/
        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 || 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(90 * (rotation - 2), centerX, centerY);
        }else if (Surface.ROTATION_180 == rotation) {
            matrix.postRotate(180, centerX, centerY);
        }
        mTextureView.setTransform(matrix);
    }
关于Camera拍照生成图片角度处理

利用Camera拍照时,读取图片数据存储为图片,取到的数据直接来源于图像传感器采集到的图像数据.

所以拍摄生成图片的角度还是和默认图片传感器方向一致.

可以利用代码修改---拍摄生成图片的角度.

Camera2 API -- 通过CaptureRequest.JPEG_ORIENTATION来设置拍照的图像方向

修改生成图片镜像
Android 7.1 RK3288 A40i Camera2 拍照镜像分析

./packages/apps/Camera2/src/com/android/camera/PhotoModule.java

    void saveFinalPhoto(final byte[] jpegData, final ExifInterface exif, CameraProxy camera) {
            if (mNamedImages == null)
                mNamedImages = new NamedImages();
            if (mNamedImages.mQueue.size() == 0)
                mNamedImages.nameNewImage(System.currentTimeMillis());

            int orientation = Exif.getOrientation(exif);

            float zoomValue = 1.0f;
            if (mCameraCapabilities.supports(CameraCapabilities.Feature.ZOOM)) {
                zoomValue = mCameraSettings.getCurrentZoomRatio();
            }
            
            ...
            
                exif.setTag(directionRefTag);
                exif.setTag(directionTag);
            }
            
+           //add text
+           Bitmap bitmap = CameraUtil.makeBitmap(jpegData, exifWidth * exifHeight);//jpeg byte 数组转换为bitmap
+           Matrix matrix = new Matrix();
+           matrix.postScale(-1, 1);//利用matrix 对矩阵进行转换 x轴镜像
+           bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
+           ByteArrayOutputStream baos = new ByteArrayOutputStream();
+           bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);//重新转换为 .jpeg 数据
+           byte [] tm_jpegData = baos.toByteArray();
+           //add text
+
            onMediaSavedListenerAfterBurstCapture mediaSavedListener = new onMediaSavedListenerAfterBurstCapture(
                    (mBurstPictureLength - mIndex));
            getServices().getMediaSaver().addImage(
-                            jpegData, title, date, mLocation, width, height,
+                            tm_jpegData, title, date, mLocation, width, height,
                             orientation, exif, mediaSavedListener);
                }
            // Animate capture with real jpeg data instead of a preview

Android9.0 Camera2 横屏问题修改记录
Android Camera预览角度和拍照保存图片角度学习

修改摄像头旋转方向

可以驱动层,hal层,framework层,app层修改.

--- a/frameworks/base/core/java/android/hardware/Camera.java
+++ b/frameworks/base/core/java/android/hardware/Camera.java
@@ -399,7 +399,7 @@ public class Camera {
      * @see android.app.admin.DevicePolicyManager#getCameraDisabled(android.content.ComponentName)
      */
     public static Camera open(int cameraId) {
-        return new Camera(cameraId);
+        return rotateCamera(i);
     }

     /**
    public static Camera open() {
        int numberOfCameras = getNumberOfCameras();
        CameraInfo cameraInfo = new CameraInfo();   
         for (int i = 0; i < numberOfCameras; i++) {
             getCameraInfo(i, cameraInfo);
             if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
-                return new Camera(i);
+                return rotateCamera(i);
             }
         }
         return null;
     }

+    //add text
+    private static Camera rotateCamera(int cameraId) {
+        Camera camera = new Camera(cameraId);
+        Parameters parameters = camera.getParameters();
+        CameraInfo cameraInfo = new CameraInfo();
+        getCameraInfo(cameraId, cameraInfo);
+        if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {//0 后置
+            camera.setDisplayOrientation(270);
+            parameters.setRotation(270);
+        } else if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {// 1 前置
+            camera.setDisplayOrientation(90);
+            parameters.setRotation(90);
+        }
+        camera.setParameters(parameters);
+        return camera;
+    }
+    //add text
+

修改某个apk应用拿到的SENSOR_ORIENTATION方向,影响Camera拍照生成图片角度.

frameworks/base/core/java/android/hardware/camera2/CameraCharacteristics.java

    @PublicKey
    @NonNull
    public static final Key<Integer> SENSOR_ORIENTATION =
            new Key<Integer>("android.sensor.orientation", int.class);

    @Nullable
    public <T> T get(Key<T> key) {
        //add text  
        Log.d("tag",  "Activity name: " + ActivityThread.currentActivityThread().currentActivityName() + " ,key = " + key);
            if(key != null && SENSOR_ORIENTATION.equals(key)){
                if(ActivityThread.currentOpPackageName().contains("com.xxx")){
                    //String cameraId = CameraManager.getCameraId();
                    if(cameraId != null){
                        T value = (T)(Object)90;
                        Log.d("tag",  "value = " + value + " ,ori = " + mProperties.get(key));
                        return value;
                }
            }
        //add text    
        return mProperties.get(key);
    }   

三方Camera App Framework方向控制(API2)

改变摄像头成像方向

camera3_profiles_rk356x.xml,这个配置说明了这个板子所有支持的摄像头配置.

RK 硬件的camera配置文件中找到ov8858摄像头设备,并修改其sensor.orientation value 的值.

hardware/rockchip/camera/etc/camera/camera3_profiles_rk356x.xml
<Profiles cameraId="0" name="ov8858" moduleId="m00">
        <Supported_hardware>
            <hwType value="SUPPORTED_HW_RKISP1"/>
        </Supported_hardware>
        ...
    <!-- Sensor -->
    <sensor.orientation value="270"/><!-- Sensor -->

rk356x OpenCamera流程浅析

相关推荐
lw向北.4 分钟前
Qt For Android之环境搭建(Qt 5.12.11 Qt下载SDK的处理方案)
android·开发语言·qt
不爱学习的啊Biao12 分钟前
【13】MySQL如何选择合适的索引?
android·数据库·mysql
Clockwiseee40 分钟前
PHP伪协议总结
android·开发语言·php
mmsx7 小时前
android sqlite 数据库简单封装示例(java)
android·java·数据库
众拾达人10 小时前
Android自动化测试实战 Java篇 主流工具 框架 脚本
android·java·开发语言
吃着火锅x唱着歌11 小时前
PHP7内核剖析 学习笔记 第四章 内存管理(1)
android·笔记·学习
_Shirley12 小时前
鸿蒙设置app更新跳转华为市场
android·华为·kotlin·harmonyos·鸿蒙
hedalei14 小时前
RK3576 Android14编译OTA包提示java.lang.UnsupportedClassVersionError问题
android·android14·rk3576
锋风Fengfeng14 小时前
安卓多渠道apk配置不同签名
android
枫_feng15 小时前
AOSP开发环境配置
android·安卓