Camera 方向 与 LCD 方向匹配 及 YUV sensor AF / snapshot 流程
完整的链接:http://www.cnblogs.com/Pitter99/articles/5554299.html
一、关于Camera 方向 跟 LCD 方向的配置问题:
物理硬件上:
因为 sensor 是矩形(长方形),分长和宽,长宽比通常是 4:3,且 sensor 扫描方向都是按长边扫描,以2M芯片为例,芯片从 (1,1) 像素点开始曝光,依次到终点(1200,1600).
而 LCD 有两种扫描方式: 沿短边扫描(物理竖屏) 和 沿长边扫描(物理横屏)。
沿短边: (1,1) -> (800,600)
沿长边: (1,1) -> (600,800)
比如手机及平板,硬件上安装应该是保证物理上sensor的长宽方向和平板的长宽方向是一致的,比如手机是 600*800 分辨率, 平板是 800*600 分辨率,长宽方向不同,因此在手机设计时需要做旋转,使sensor长宽方向跟 LCD 一致。
(1) LCD沿长边扫描(物理横屏)时 LCD (从左到右)与camera 扫描方向一致 (左到右)。
(2) LCD沿着短边扫描(物理竖屏)时,LCD 与camera 扫描方向垂直,camera 从上到下,LCD 从左到右。LCD预览图像需要将图像旋转 90°。如果安装错误,将camera扫描方向跟 LCD扫描方向一致,就会导致 LCD 预览图像被拉伸。
软件上:
手机后置摄像头一般加 90 度的旋转,前置一般加 270 °的旋转,framework 会从 HAL 层(HAL层从dtsi 返回)读取这个数值,然后在 surfaceflinger 处理
而对于平板,则不需要加旋转,我们在配置平板的前后摄像头 mount_angle 时直接设置为 0 即可
在手机竖屏时,sensor是竖直放置,即按长边扫描的方向在竖直方向上,如果闪光灯曝光不足,就会使得右半部分没法曝光,因此在LCD 上显示的时候,因此左半部分是正常,右半部分是曝光不足的
http://wenku.baidu.com/link?url=7VSHC5qF-1peOGWQOFMEVceDJkSvgHaCZBcSwCo715BNPP6Lhwd-gdEZdaed4PnuF9J294QV7VhVl-C2SjexqaniPqZLM7wQFFpD3Am_a1y
如果后置不加90°旋转,则预览是正常的,但拍出来的照片向左旋转90°,放在电脑上显示也是向左旋转90°
如果前置不加90°旋转,则预览是正常的,但拍出来的照片向右旋转90°,放在电脑上显示也是向右旋转90°----估计都是因为电脑是横屏的
Android 2.2是第一个包含了YUV格式解码器(YuvImage)的版本;在以前的版本中,必须手动完成解码。
Framework/base/core/java/android/hardware/camera.java
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.
竖屏拍照的照片,直接使用的话,会旋转90度,参考系统图库的代码,需要先查询mediascanner的orientation字段,然后应用再把角度旋转过来,这样显示就ok了
强制横屏 就可以了 android:screenOrientation="landscape"
--------------------------------------------------------------下面这个解释应该是正确的----------------------------------------------------------
不过根据游标查询媒体库的角度是不全面的,不能解决个别问题,比如调用系统相机通过媒体库uri生成大图,用这种方法每次都会返回0,但是实际是反转90 度。根据我的调查,
原因是媒体库的uri(格式“content:....”)并不是图片的物理路径,它是图片在媒体数据库中的查询地址,所以如果用媒体库生成大图的时候如果没有对转角值进行初始化设置
(我猜的 因为我生成大图就没有插入任何其他的元数据),默认就是0,而实际默认转角是根据硬件设置的, 平板电脑大多感觉都是横屏(反转90 为了默认适配横屏)。
解决方法就是根绝媒体库的uri(如“content:..../47.”)获取图片的物理地址(如 “/xx/xx/xx1545515.jpg”), 再根据物理地址通过EXIFInterface来获取图片的实际转角,
再根据获取的角度来使用Maxtri来转正。(如果你用媒体库 uri.getpath()获取转角 返回的就是0)
-------------------------------------------------------------------------------------------------------------------------------------------------
takePicture方法的最简单形式是将所有的参数都设置为null。尽管能够捕获照片,但是不能获得它的引用。因此,至少应该实现一种回调方 法。一种最安全的回调方法是Camera.PictureCallback.onPictureTaken。它确保会被调用,并且在压缩图像时被调用。为 了利用该方法,我们将在活动中实现Camera.PictureCallback,并添加一个onPictureTaken方法。
public class SnapShot extends Activity implements SurfaceHolder.Callback, Camera.PictureCallback { public void onPictureTaken(byte[] data, Camera camera) { }
该onPictureTaken方法有两个参数:第一个是实际的JPEG图像数据的字节数组,第二个是捕获该图像的Camera对象的引用。由于给定了实际的JPEG数据,因此为了保存它,
只需要将其写入磁盘的某个位置。正如我们已经知道的那样,可以利用MediaStore指定它的位置和元数据。
当执行onPictureTaken方法时,可以调用Camera对象上的startPreview。当调用takePicture方法时预览已经自动暂停,并且这个方法会告诉我们,现在可以安全地重新启动它。
public void onPictureTaken(byte[] data, Camera camera) { Uri imageFileUri = getContentResolver().insert(Media.EXTERNAL_ CONTENT_URI, new ContentValues()); try { OutputStream imageFileOS = getContentResolver(). openOutputStream(imageFileUri); imageFileOS.write(data); imageFileOS.flush(); imageFileOS.close(); }catch (FileNotFoundException e) { } catch (IOException e) { } camera.startPreview(); }
上述的代码片段向MediaStore中插入了一条新记录,并返回一个URI。然后,利用这个URI可以获得一个OutputStream,用于写入JPEG数据。这将在MediaStore指定的位置中创建一个文件,并将它链接到新的记录。如果后面想要更新存储在MediaStore记录中的元数据,可以利用一个新的ContentValues对象对记录进行更新。
ContentValues contentValues = new ContentValues(3); contentValues.put(Media.DISPLAY_NAME, "This is a test title");
EXIF(Exchangeable Image File)是“可交换图像文件”的缩写,当中包含了专门为数码相机的照片而定制的元数据,可以记录数码照片的拍摄参数、缩略图及其他属性信息。
元数据是对数据资源的描述,英文名称是“Metadata”, 通常被解释为data about data,即关于数据的数据。 元数据是信息共享和交换的基础和前提,用于描述数据集的内容、 质量、表示方式、空间参考、管理方式以及数据集的其他特征。
Android Camera API2中采用CameraMetadata用于从APP到HAL的参数交互 : http://www.2cto.com/kf/201510/448174.html
Android camera HAL四个callback : http://blog.youkuaiyun.com/kickxxx/article/details/19111005
Android Camera HAL V3 Vendor Tag及V1,V3参数转换 : http://blog.youkuaiyun.com/dfysy/article/details/42805929
二、YUV sensor AF 流程 :
首先看看YUV 怎么调用到对应的驱动:
06-03 19:13:37.869 314 4564 E mm-camera-sensor: csiphy_open:89 csiphy subdev name = /dev/v4l-subdev1 --- 前置 csiphy
06-03 19:13:37.879 314 4564 E mm-camera-sensor: sensor_init:474 subdev name v4l-subdev13
06-03 19:13:43.529 314 4742 E mm-camera-sensor: csiphy_open:89 csiphy subdev name = /dev/v4l-subdev0 --- 后置 csiphy
06-03 19:13:43.539 314 4742 E mm-camera-sensor: sensor_init:474 subdev name v4l-subdev13 --- 为什么都是13,代码逻辑有问题,字符数组没有分先后
将 slave->subdev_name 保存在 g_subdev_name 字符数组,因此只能保存到最后一次调用的,就是前置---但不影响正常使用,因为不会改变 slave->subdev_name
HAL -> initDefaultParameters ->
后置5M YUV : 从 FOCUS_MODES_MAP_YUV[AUTO,MARCO,FIXED,INFINITY] 解析,并取第一个数组元素(AUTO) 作为默认的 AF 模式,并调用 setFocusMode()设置
前置2M YUV : FOCUS_MODES_MAP_FRONT[FIXED,INFINITY] 解析,并取第一个数组元素(FIXED) 作为默认的 AF 模式
以上2个camera 如果都没有获取到 focusMode ,则都设置 FOCUSE_MODE_FIXED 为默认 AF 模式
在setFocusMode 函数中 , 如果 m_pCapability->cam.sensor_format == CAM_FORMAT_YCBCR -> 调用 EXT_CAM_FOCUS ,嵌入下面指令
(1)CAM_INTF_NATIVE_CMD_FOCUS --- YUV
(2)CAM_INTF_PARM_FOCUS_MODE --- Bayer