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

相关推荐
Android技术之家4 分钟前
Android Studio 专属AI智能体+Skills完整版提示词(可直接复制使用)
android·ide·人工智能·android studio
xiegwei16 分钟前
Android 原生项目添加 Flutter Activity 示例及常见报错解决方案
android·flutter
于慨24 分钟前
Flutter Android gradle 8.14 file lock, incompatibility issue
android·flutter·issue
千百元27 分钟前
HBuildX 打包成apk完整过程
android
流星白龙9 小时前
【MySQL】7.MySQL基本查询(2)
android·mysql·adb
mldlds10 小时前
MySQL加减间隔时间函数DATE_ADD和DATE_SUB的详解
android·数据库·mysql
智算菩萨12 小时前
MP3音频编码原理深度解析与Python全参数调优实战:从心理声学模型到LAME编码器精细控制
android·python·音视频
studyForMokey13 小时前
【Android面试】Activity生命周期专题
android·面试·职场和发展
chehaoman14 小时前
MySQL的索引
android·数据库·mysql
恋猫de小郭17 小时前
React Native 鸿蒙 2026 路线发布,为什么它的适配成本那么高?
android·前端·react native