【腾讯优测干货分享】Android 相机预览方向及其适配探索
本文来自于腾讯bugly开发者社区,未经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/583ba1df25d735cd2797004d
由于Android系统的开放策略,Android手机呈现碎片化的趋势,兼容性问题一直是Android App 开发者头疼的难题。本文以Android相机预览方向为例,探索在Android机型适配上的一些思路。
1. android相机简介
由于Android系统的开放策略,Android手机呈现碎片化的趋势,兼容性问题一直是Android App 开发者头疼的难题。本文以Android相机预览方向为例,探索在Android机型适配上的一些思路。
1.1 相机架构
先了解下Camera的框架,它是分层的结构。由上向下分别是
1)应用层
2)Camera系统的Java类
3)Camera的JNI代码
4)Camera的本地框架
5)Camera服务部分
6)Camera HAL(Hardware Abstraction Layer)硬件抽象层
图一Camera architecture
其中Camera HAL主要的接口文件为CameraHardwareInterface.h ,需要各个系统根据自己的情况实现。由于设备底层硬件的千变万化,android框架不可能提供统一的硬件驱动以及接口实现,只能提供标准的接口,因此硬件提供商需要自己开发设备驱动,并去实现android框架提供的接口。
而实际上,由于机器的硬件配置不同,厂商的底层实现不同,Andriod版本的不同,在一部手机上调试正常的程序,不一定能在其他机型上正常运行。其中与摄像头相关的适配问题包括摄像头个数、preview size大小、预览方向、闪光灯、对焦方式、帧率等等。
本文以相机预览方向为例,探讨这个问题产生的原因,以及一些可行的解决方法。
2. 相机预览方向适配问题的产生
2.1相机的安装方向
相机图像数据都是来自于相机硬件的图像传感器(Image Sensor),这个Sensor被固定到手机之后是有一个默认的取景方向,且不会改变。比如MI3手机的屏幕“自然”方向和后置相机的图像传感器方向是如图二所示的。
图二MI3手机的屏幕“自然”方向和后置相机的图像传感器方向
在MI3手机上,对于一个横屏应用来说,屏幕“自然”方向和后置相机的图像传感器方向一致,因此看到的图像是正的,如图三所示。而对于一个竖屏应用来说,屏幕“自然”方向和后置相机的图像传感器方向是不一致,从图像传感器的角度看,它看到的图像是侧过来的,如图四所示,需要将相机预览图像顺时针旋转90度,才和屏幕“自然”方向一致。在Android系统中,提供camera.setDisplayOrientation(angle)方法,用来设置相机预览图像顺时针旋转的角度。
图三MI3手机横屏的相机应用
图四MI3手机竖屏的相机应用
2.2相机的安装方向如何获取?
Android官方提供orientation这个属性来读取,官方定义如图五所示:orientation表示相机图像的方向。它的值是相机图像顺时针旋转到设备自然方向一致时的角度。例如假设设备是竖屏的。后置相机传感器是横屏安装的。当你面向屏幕时,如果后置相机传感器顶边的和设备自然方向的右边是平行的,则后置相机的orientation是90。如果前置相机传感器顶边和设备自然方向的右边是平行的,则前置相机的orientation是270。
int android.hardware.Camera.CameraInfo.orientation
public int orientation
Added in API level 9 The orientation of the camera image. The value is the angle that the camera image needs to be rotated clockwise so it shows correctly on the display in its natural orientation. It should be 0, 90, 180, or 270. For example, suppose a device has a naturally tall screen. The back-facing camera sensor is mounted in landscape. You are looking at the screen. If the top side of the camera sensor is aligned with the right edge of the screen in natural orientation, the value should be 90. If the top side of a front-facing camera sensor is aligned with the right of the screen, the value should be 270.
图五camerainfo.orientation定义
以MI3为例,通过程序调用取到的后置相机的orientation是90,前置相机的orientation是270。我理解的orientation是相机采集的图像顺时针旋转到屏幕自然方向的角度。图六所示是MI3手机的后置相机和前置相机对准同一个小人,后置前置相机采集到的图像及前置相机预览的图像。需要特别说明的是,对于前置相机来说,相机预览的图像是相机采集到的图像的镜像, 关注图六中小人头发在前置采集到的图像和预览的图像中头发的不同。因此在MI3手机上做竖屏应用时,对于后置相机的预览方向,只需要旋转后置相机的orientation,即90度即可和屏幕方向保持一致;对于前置相机的预览方向,由于系统对前置相机采集到的图像做了镜像,因此需要旋转270-180,也是90度即可和屏幕方向保持一致。
图六MI3手机上orientation的例子。
2.3官方推荐的相机预览方向适配做法
通过orientation属性的含义可以知道,我们可以用它和应用的方向来做相机预览方向的适配,图七是官方网站推荐的代码。但并不是所有手机的orientation值都靠谱,比如VIVO V1手机第一次获取后置相机的CameraInfo的orientation值是90,而当执行了mCamera = Camera.open();之后再获取CameraInfo的orientation值就是0,而且以后获取的都是 0 ,除非重启手机。无论是这款手机上的哪个应用,只要执行了一次Camera.open()之后,其他所有程序中获取CameraInfo的orientation都是是0。因此按照此方法做适配不能解决所有手机上的问题。
图七 Android官方推荐的相机预览方向的适配做法
3. 相机预览方向适配
3.1方案一:App端添加兼容性代码
思路是在App端对特殊的手机添加兼容性代码,如下所示。这样可以解决部分问题,但当版本发出后,又发现问题只能等版本升级修复;同时由于手机型号,系统版本的很多组合,而且客户端要维护一套很长的代码。很自然的想到把相机预览方向的角度做成后台配置,就有了方案二。
if (is VIVO V1 mobile) {
camera.setDisplayOrientation(90);
} else if (is MotoXPro mobile) {
camera.setDisplayOrientation(270);
} else {
Android官方推荐的相机预览方向适配做法
}
3.2方案二:Server端动态配置
为了解决方案一的弊端,可以将相机预览方向顺时针旋转的角度抽取出来,作为一个变量从server端下发。这样可以做到机型无关,版本发布后,出现问题可以通过Server端上线新的配置来解决。但新机型上问题的发现,确认,解决,上线均需要一定的人力耗费,而且有滞后性。还有没有更好的解决方案呢?
if (get angle from server) {
camera.setDisplayOrientation(angle);
} else {
Android官方推荐的相机预览方向适配做法
}
3.3方案三:Server端动态配置与用户自助引导相结合
公司一直提倡开发人员有产品思维。从产品的角度说,用户在使用相机应用时,他是知道相机预览方向是正确的还是错误的,我们可以给用户一个旋转相机预览方向的按钮,当用户发现方向不对时,通过自助点击按钮解决问题。如下图所示
图八 发生问题时,引导用户自助旋转相机预览方向
这样即具有方案二的优点,同时又可以实时解决用户的问题,不需要用户等待我们后台下发正确的配置。进一步的,如果发现用户点击了旋转按钮,同时正确使用了相机功能,可以将本机型对应的angle上报给Server端。Server端可以自动或辅助人工以更新配置。对于QQ安全中心APP来说,在人脸验证过程需要打开前置相机,如果用户本次人脸验证点击了旋转预览方向按钮,同时又通过了人脸验证,我们可以认为用户正确使用了相机功能,Server端可以自动更新用户上报的angle,使和该用户同机型的其他用户都受益。
if (get angle from server) {
camera.setDisplayOrientation(angle);
} else {
Android官方推荐的相机预览方向适配做法
}
...
if (user click rotate icon) {
angle = angle + 90;
camera.setDisplayOrientation(angle);
}
...
report(angle);
4 结语
在做相机相关的App时,需要考虑的适配问题还有很多,远不止相机预览方向这一种。总的思路就是能实时解决的就不滞后,能动态配置的就不要写死在App端,有时可以换个角度,考虑技术和产品相结合的方案。
更多精彩内容欢迎关注腾讯优测的微信公众账号:
腾讯优测是专业的移动云测试平台,为应用、游戏、H5混合应用的研发团队提供产品质量检测与问题解决服务。不仅在线上平台提供app自动化测试、云真机远程操控与调试、私有自动化测试工具XTest等多种质量检测工具,更为VIP客户配备了专家团队提供定制化综合测试解决方案。
【腾讯优测干货分享】Android 相机预览方向及其适配探索的更多相关文章
- 腾讯优测干货精选|Android双卡双待适配——隐藏在数据库中的那些秘密
腾讯优测是专业的app自动化测试平台,除了提供兼容性测试,远程真机租用等多维度的测试服务,还有优分享-腾讯内部的移动研发测试干货精选~ 许多APP都希望获取用户通讯录联系人,利用通讯录关系链信息来丰富 ...
- 【腾讯优测干货分享】微信小程序之自动化亲密接触
本文来自于腾讯优测公众号(wxutest),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/HcPakz5CV1SHnu-U8n85pw 导语 山雨欲来风满楼,最 ...
- 【腾讯优测干货分享】安卓专项测试之GPU测试探索
本文来自于Dev Club 开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57c7ffdc0569a1191bce8a63 作者:章未哲——腾讯SNG质 ...
- 【腾讯优测干货分享】如何降低App的待机内存(四)——进阶:内存原理
本文来自于腾讯优测公众号(wxutest),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/3FTPFvZRqyAQnU047kmWJQ 1.4进阶:内存原理 在 ...
- 【腾讯优测干货分享】如何降低App的待机内存(三)——探索内存增长的原因
本文来自于腾讯优测公众号(wxutest),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/8BiKIt3frq9Yv9KV5FXlGw 1.3新问题的进一步挖 ...
- 【腾讯优测干货分享】如何降低App的待机内存(二)——规范测试流程及常见问题
本文来自于腾讯优测公众号(wxutest),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/806TiugiSJvFI7fH6eVA5w 作者:腾讯TMQ专项测 ...
- 【腾讯优测干货分享】越用越卡为哪般——如何降低App的待机内存(一)
本文来自于腾讯优测公众号(wxutest),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/1_FKMbi1enpcKMqto-o_FQ 作者:腾讯TMQ专项测试 ...
- 【腾讯优测干货分享】如何降低App的待机内存(五)——优化dex相关内存及本章总结
本文来自于腾讯优测公众号(wxutest),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/01Abwe0p1h3WLh28Tzg_Dw 1.5案例:优化dex相 ...
- 【腾讯优测干货分享】Android内存泄漏的简单检查与分析方法
本文来自于Dev Club 开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57d14047603a5bf1242ad01b 导语 内存泄漏问题大约是An ...
随机推荐
- BitHacks
备份文件时看到的.我以前居然下过这东西. 2016-12-4 12:05:52更新 纯文本格式真棒.假如使用word写的我能拷过来格式还不乱?? Markdown真好. Bit Hacks By Se ...
- 「理解HTTP」之常见的状态码segmentfault
状态码的职责是当客户端向服务器端发送请求时,描述返回请求结果.借助状态码,用户可以知道服务器端是正常处理了请求,还是出现了什么错误. RFC2616定义的状态码,由3位数字和原因短信组成.数字中的第一 ...
- 好用的绿色工具(mss2sql,jd-gui)
1.sql server导入mysql 神器(速度不是一般的快) mss2sql.exe 2.java 反序列化工具 jd-gui.exe
- DelphiXE10.1项目中增加预编译的方法
操作: 菜单选择Proceject->Options->Delphi Compilerz在Conditional Defines(第一行)中添加预编译标识.例:VCL代码:uses{$IF ...
- System.getProperty()方法大全
System.out.println("当前程序所在目录:" + System.getProperty("user.dir")); // 当前程序所在目录 Sy ...
- java-并发-高级并发对象1
以往说到的线程对象都是java平台中非常初级的API,用于处理一些基本的任务,对于一些复杂高级的工作,就需要一些高级的并发对象,尤其是针对于当今的应用程序,要充分利用现在的多核多处理器系统的性能. 以 ...
- svn的牛逼操作反向merge
反向merge,轻松回滚.
- c# http get请求与post请求实例
//http请求工具类 using System;using System.Collections.Generic;using System.IO;using System.Linq;using Sy ...
- 【转】通过Hibernate将数据 存入oracle数据库例子
一. Hibernate介绍 Hibernate是基于对象/关系映射(ORM,Object/Relational Mapping)的一个解决方案.ORM方案的思想是将对象模型表示的对象映射到关系型数据 ...
- (转)Eclipse和MyEclipse安装和使用git(egit)图解笔记
Eclipse.MyEclipse使用git插件(egit)图解 (转)原文来自:http://www.xuebuyuan.com/446322.html 在开发Java.JavaEE等相关程序时,我 ...