Camera2 预览旋转方向、拍照、录像成像旋转


前言

自己在开发MTK相机、RK 相机 Camera2 预览旋转方向、拍照、录像成像旋转问题,简单整理总结,后续相关开发可直接参考

一、思考问题

自己在开发公司MTK平台上Camera2相机过程中,遇到一些问题,对于开发过相机的朋友应该也会遇到各种各种问题,特别是Android系统定制,各种情况很复杂;涉及到不同的平台,核心思想一样,但是实际应用架构,业务就完全不一样了。 下面先抛出几个问题:

  • 相机开发中遇到预览、成像[拍照照片、录像视频] 方向不对、拉伸压缩 怎么办
  • 相机分为几个层 驱动、系统、应用层,相机的流程成像原理怎样的
  • 从常识上看,我们的手机相机拍照、录像都是横竖屏的,人永远是正的,为什么呢?
  • 上面用到了Gsensor 来判断方向,虽然有了Gsonsor 方向+屏幕物理方向,但是系统用到了强制横竖屏,屏幕物理方向是错乱的
  • 屏幕方向问题[存在横屏+竖屏各两个方向],不清楚客户实际机器是横屏、竖屏、横竖屏;
  • 装配方向,实际的装配方向不确定,摄像头本身是有一个方向的,如果摄像头方向不是按照正常装配的,那么肯定预览和成像方向不对
  • 每个平台相机源码不一致,在更改系统源码的过程中,源码不一致,那么相机Camera2 开发流程、预览、成像原理、人脸检测、特效、架构
    又是怎样的? 方便修改问题

二、基础补充、资源参考

相机整个模块确实太专业、复杂了。 无论从硬件外设、驱动【USBCamera免驱】、相机 都比较专业、覆盖面及广,针对思考中的问题 给出自己认为比较好相关博客,方便了解,助于梳理流程、提升认知。

对于上层应用或者Framework 系统应用开发者,只需要了解基本的架构、API、使用方法,当然这些也不简单的
下面提供部分资源,方便快速了解,充电:

架构图了解

MTKCamera2相机架构
Camera2架构
Android Camera架构简析

Camera相关专栏

Camera Framework 专栏
小驰私房菜系列
小驰私房菜MTK系列
小驰Camera 开发系列
Camera 相机开发
展讯平台 Camera
官方文档:谷歌官方 API 描述

零散知识了解

MTK 相机UI介绍
Camera2 相机认知
Camera2学习笔记
camera2关于拍照预览方向旋转90度和拍照图片镜像功能实现
Camera2 预览集成、简单拍照:熟悉预览步骤流程比较有用
Camera镜像上下左右颠倒问题的解决办法
MTK相机成像质量差
Camera应用分析

部分相机源码参考,学习API使用,梳理流程,偏应用层

极客相机 Camera2 API
Camera2 API详解
极客相机源码
Camera2 相机Demo
Camera2 专业相机Demo
拍照、预览、录像Demo
使用Camera2 拍照

Camera2 系统相关

Camera2 Service 启动

如上资源可能不能解决项目中的实际问题,每个ODM厂家平台的源码不一样,修改问题地方不一样,包名、类 都不一样,但思路、思想一样。当然具体问题具体分析,针对性充电对自己解决问题还是有很大帮助的。

三、核心问题:预览方向不对【图片、视频】、成像存储不对、拉伸问题

当前只给出MTK平台相关解决思路,和代码片段

预览

根据gsensor 方向,适配需要旋转的方向,来解决视频、图片预览方向问题
vendor\mediatek\proprietary\packages\apps\Camera2\host\src\com\mediatek\camera\ui\preview\TextureViewController.java
updatePreviewSize 方法中 最终通过gsenmsor 方向来

    考虑旋转方向: 
     Log.d(MYTAG,"6666666666  setAspectRatio  mPreviewAspectRatio :"+mPreviewAspectRatio +"    mTextureView:"+mTextureView);
	    int  gSensorOrientation= mApp.getGSensorOrientation();
      int rotationNum= 360-gSensorOrientation;
			mTextureView.setRotation(rotationNum);
			Log.d(MYTAG,"6666666666 genju  sensor fangxiang  xuanzhuan   gSensorOrientation:"+gSensorOrientation+"  rotate dushu:"+rotationNum);
	    Log.d(MYTAG,"6666666666   rotation 90");
      mTextureView.setAspectRatio(mPreviewAspectRatio);   

视频保存

遇到视频保存,方向不对问题
视频保存倒置问题,竖屏录像保存的视频会倒置180度。 修改文件:vendor/mediatek/proprietary/packages/apps/Camera2/common/src/com/mediatek/camera/common/mode/video/VideoHelper.java

configRecorderSpec 方法中,recorderSpec.orientationHint 值 根据gsensor 方向,动态适配两种不同的竖屏方向的视频保存方向

public IRecorder.RecorderSpec configRecorderSpec(CamcorderProfile profile, String cameraId,
                                                     CameraDeviceManagerFactory.CameraApi api, ISettingManager settingManager) {
        sProfile = profile;
        IRecorder.RecorderSpec recorderSpec = new IRecorder.RecorderSpec();
        recorderSpec.videoSource = MediaRecorder.VideoSource.SURFACE;
			int gSensorOrientation=mApp.getGSensorOrientation();
	    int testDirection =	getRecordingRotation(mApp.getGSensorOrientation(),
                getCameraCharacteristics(mApp.getActivity(), cameraId));
        recorderSpec.orientationHint = getRecordingRotation(mApp.getGSensorOrientation(),
                getCameraCharacteristics(mApp.getActivity(), cameraId));
		  switch (testDirection){
             case 0:    //dao li zhuang tai
                 Log.d(MYTAG,"port dao li zhuang tai");
                 recorderSpec.orientationHint=180;
                 break;
             case  270:
                 Log.d(MYTAG,"land zhuang tai");
                 break;
             case  180: //zheng li
                 recorderSpec.orientationHint=0;
                 Log.d(MYTAG,"port zhengli zhuang tai");
                 break;
             default:
                 break;
         }		
        recorderSpec.isHEVC = VIDEO_FORMAT_HEVC
                .equals(settingManager.getSettingController().queryValue("key_video_format"));
        LogHelper.d(TAG, "[configRecorderSpec] recorderSpec.isHEVC = " + recorderSpec.isHEVC);
        if (VALUE_ON.equals(settingManager.getSettingController().queryValue("key_microphone"))) {
            recorderSpec.isRecordAudio = true;
            recorderSpec.audioSource = MediaRecorder.AudioSource.CAMCORDER;
        } else {
            recorderSpec.isRecordAudio = false;
        }
        recorderSpec.profile = sProfile;
        recorderSpec.maxDurationMs = 0;
        recorderSpec.maxFileSizeBytes = getRecorderMaxSize();
        recorderSpec.location = mCameraContext.getLocation();
		Log.d(MYTAG,"configRecorderSpec  gSensorOrientation:"+gSensorOrientation+"   testDirection:"+testDirection);
        return recorderSpec;
    }

预览拉伸


PreviewManager,这个地方修改,强制写死横竖屏状态下预览分辨率,如果横屏状态下不写,调试发现自动设置情况下会导致预览变形

 import java.util.concurrent.CopyOnWriteArrayList;
+import android.util.Log;
+import android.content.res.Configuration;
+import android.view.WindowManager;
 
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import android.content.Context;
 /**
  * A manager for camera preview module, now it support surfaceview or textureview.
  */
@@ -222,8 +227,18 @@ public class PreviewManager {
                 @Override
                 public void run() {
                     notifyPreviewAreaChanged();
-                    mPreviewFrameLayout.setPreviewSize((int) mPreviewArea.width(),
-                            (int) mPreviewArea.height());
+            Configuration newConfig = mApp.getActivity().getResources().getConfiguration();
+                       if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
+                                mPreviewFrameLayout.setPreviewSize(1080,
+                            1920);
+                 WindowManager wm = (WindowManager) mApp.getActivity().getSystemService(Context.WINDOW_SERVICE);
+                 int width = wm.getDefaultDisplay().getWidth();
+                 int height = wm.getDefaultDisplay().getHeight();
+                 int gOrientation= mApp.getGSensorOrientation();
+             } else if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
+                       mPreviewFrameLayout.setPreviewSize(1920,
+                            1080);
+             }
                 }
             });
         }


PreviewTextureView,这个地方修改,横竖屏状态下Measure区分,且横屏状态下 width 和 height 相反,解决镜像变形问题

@@ -43,12 +43,15 @@ import android.util.AttributeSet;
 import android.view.Display;
 import android.view.TextureView;
 import android.view.WindowManager;
+import android.util.Log;
+import android.content.res.Configuration;
 
 /**
  * A {@link TextureView} that can be adjusted to a specified aspect ratio.
  */
 
 public class PreviewTextureView extends TextureView {
+    private static final String MYTAG = "PreviewTextureView";
 
     private static final double ASPECT_TOLERANCE = 0.03;
     private double mAspectRatio = 0.0;
@@ -131,7 +134,15 @@ public class PreviewTextureView extends TextureView {
             previewWidth = shortSide;
             previewHeight = longSide;
         }
+               Log.d(MYTAG," onMeasure previewWidth:"+previewWidth+"  previewHeight:"+previewHeight);
+             Configuration config =  getResources().getConfiguration();
+        if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
+                 Log.d(MYTAG," portscreen onMeasure previewWidth:"+previewWidth+"  previewHeight:"+previewHeight);
         setMeasuredDimension(previewWidth, previewHeight);
+        } else if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
+                 Log.d(MYTAG," landscreen onMeasure previewWidth:"+previewHeight+"  previewHeight:"+previewWidth);
+          setMeasuredDimension(previewHeight, previewWidth);
+        }
     }

其它

增强缩略图质量,部分客户反馈缩略图显示不清晰   BitmapCreator.java 
 

FaceViewCtrl.java  showView 方法, 屏蔽人脸检测框导致在强制横竖屏情况下 人脸检测方框显示异常。
     private void showView() {
         if (mFaceView != null && mFaceView.getVisibility() != View.VISIBLE) {
             LogHelper.d(TAG, "[showView]");
-            mFaceView.setVisibility(View.VISIBLE);
+           // mFaceView.setVisibility(View.VISIBLE);
         }
     }

总结

1)在布局、预览镜像和Activity及对应控制管理的方法中对布局和镜像旋转、设置预览分辨率等来解决
2)Manifest.xml 配置修改,规避窗体变化导致布局镜像异常
3)预览、拉伸、成像异常在对应的文件中修改

部分源码参考片段

  • 19
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值