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流程浅析

相关推荐
inmK12 小时前
蓝奏云官方版不好用?蓝云最后一版实测:轻量化 + 不限速(避更新坑) 蓝云、蓝奏云第三方安卓版、蓝云最后一版、蓝奏云无广告管理工具、安卓网盘轻量化 APP
android·工具·网盘工具
giaoho2 小时前
Android 热点开发的相关api总结
android
咖啡の猫3 小时前
Android开发-常用布局
android·gitee
程序员老刘4 小时前
Google突然“变脸“,2026年要给全球开发者上“紧箍咒“?
android·flutter·客户端
Tans54 小时前
Androidx Lifecycle 源码阅读笔记
android·android jetpack·源码阅读
雨白4 小时前
实现双向滑动的 ScalableImageView(下)
android
峥嵘life5 小时前
Android Studio新版本编译release版本apk实现
android·ide·android studio
studyForMokey7 小时前
【Android 消息机制】Handler
android
敲代码的鱼哇7 小时前
跳转原生系统设置插件 支持安卓/iOS/鸿蒙UTS组件
android·ios·harmonyos
翻滚丷大头鱼7 小时前
android View详解—动画
android