Camera2 预览旋转方向、拍照、录像成像旋转
文章目录
- 前言
- 一、思考问题
- 二、基础补充、资源参考
- 架构图了解
- Camera相关专栏
- 零散知识了解
- 部分相机源码参考,学习API使用,梳理流程,偏应用层
- 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)预览、拉伸、成像异常在对应的文件中修改
部分源码参考片段