背景
在APP开发中会有很多业务使用到Camera,对于一些基础的功能,调用系统的拍摄功能就可以满足要求。但是需要自定义UI界面时,例如将摄像头捕获的视图展示在页面上的时候就需要使用到Camera这个类了。
本篇会介绍哪些知识点:
- 什么是SurfaceView?有什么作用?何为双缓冲机制?
- 相机涉及到方向的概念,如何旋转到正确的方向?
- Camera常用的API及相关属性。
- Camera的调用流程。
- 如何设置参数,适配预览区域大小?
- 如何切换前后摄像头。
SurfaceView
1、为什么需要SurfaceView
Android系统默认设定的刷新频率是60FPS(每隔16.6ms底层会发出VSYNC信号重绘界面)。但是当页面绘制过于复杂,就没有办法保证60FPS,则会出现卡顿现象。其中View,ViewGroup,Animator刷新UI界面的动作都是在主线程中执行的。如果页面逻辑过于复杂时,可能出现页面卡顿,甚至可能出现ANR问题。为了解决这个问题,便引入了SurfaceView(主要用于游戏、视频等视觉效果复杂、刷新率较高的场景)。
SurfaceView的改进是引入了双缓冲机制和多线程绘制。
2、双缓冲机制
如果不用画布,直接在窗口上绘制就是无缓冲绘图。
使用一个画布,先将所有的内容绘制到画布上面,后一次性绘制到窗口上就是单缓冲绘图,其中画布是一个缓冲区。
使用两个画布,先在一个画布上面绘制所有的图像,待绘制完以后在将该画布上面所有的内容拷贝到正式绘制的画布上,这就是双缓冲绘图。
双缓冲绘图比单缓冲绘图的优势在于 拷贝比直接绘制的效率要高。
在SurfaceView中,一般会开启一个新的线程,然后在新线程中通过SurfaceHolder的lockCanvas方法获取得Canvas(缓冲画布)进行绘制,绘制完以后在通过SurfaceHolder的unlockCanvasAndPost方法释放canvas并提交修改,下次刷新显示新内容即可。
3、Surface、SurfaceView、SurfaceHolder三者的关系
它们三者是典型的MVC模型。
Surface:Model层,持有缓冲画布Canvas和绘图内容相关的各种信息。
SurfaceView:View层,与用户进行交互,将Surface的内容显示给用户。
SurfaceHolder:Controller层,通过SurfaceHolder控制Surface中的数据。
相机方向
1、自然方向
人自然站立的方向。
2、设备方向
设备方向是设备与自然方向的顺时针夹角,例如手机竖着拿正对屏幕的方向是手机的自然方向,即设备方向为0°,如果手机横着拿正对屏幕且顶部在右边,则设备方向为90°。以此类推。
获取方向可以通过
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
或者通过OrientationEventListener 监听旋转。
3、摄像头方向
手机Camera的图像数据都是来自于摄像头硬件的图像传感器(Image Sensor),摄像头的方向取决于图像传感器的安装方向。安装之后,有一个默认的取景方向,且不会被改变。但为什么手机旋转以后预览画面也会跟着旋转到自然方向呢?是因为Android系统底层根据当前手机屏幕的方向对图像Sensor采集到的数据进行了旋转处理,然后才送给显示系统。
手机后置摄像头一般都是横屏安装的。
CameraInfo.orientation 表示相机图像的方向。它的值是相机图像顺时针旋转到自然方向的角度。
4、预览方向
通过setDisplayOrientation设置预览方向,默认情况是0°,即预览方向与摄像头方向一致,对于横屏应用,不需要设置预览方向。而对于竖屏应用则设置预览方向旋转90,与手机屏幕方向保持一致,这样才能得到正确的预览方向。
5、拍摄方向
相机采集图像后需要进行顺时针旋转的角度,即相机属性的orientation的值。当点击拍照时,得到的照片方向不一定与预览方向一致,因为通过setDisplayOrientation仅仅修改了预览图像的方向,不会影响到实际拍摄图像的方向,需要修改拍摄图像方向可以通过camera.setRotation实现。
适配预览区域大小
一般手机会提供多个预览和拍照尺寸,通过接口getSupportedPreviewSizes和getSupportedPictureSizes可以获得这些尺寸列表。如果previewSize比例与预览(SurfaceView)比例不一致,则看到的预览图像会变形拉伸。如何适配不同预览区大小解决拉伸问题,一般有2种方案:
一是根据previewSize比例修改SurfaceView的比例,调整预览区比例(只调整宽或高)为预览尺寸比例,从而使图像不发生变形。
二是根据SurfaceView大小固定,然后根据其比例选择最佳的(比例最接近的)预览尺寸。
切换前后摄像头
通过camera.open(int cameraId)获取camera实例时便可以通过cameraId指定摄像头。
Camera.CameraInfo.CAMERA_FACING_FRONT = 1 前置摄像头
Camera.CameraInfo.CAMERA_FACING_BACK = 0 后者摄像头
注:切换摄像头便是重新获取新的camera实例,所以在切换时需要将前一个实例释放掉。
Camera常见的API及属性
camera是Android摄像头硬件的相机类,位于硬件包"android.hardware.Camera"下,它主要用于摄像头捕获照片、启动/停止预览图片、拍照、获取视频帧等。
camera常见的API
- static Camera open():打开camera,返回一个camera实例。
- static Camera open(int cameraId):根据cameraId打开camera,返回一个camera实例。
- final void release():释放掉camera的资源。
- static int getNumberOfCameras():获取当前设备支持camera硬件个数。
- Camera.Parameters getParameters():获取camera的各项参数设置类。
- void setParameters(Camera.Parameters params):通过param将camera的各项参数写入到camera中。
- final void setDisplayOrientation(int degrees):设置预览的旋转度。
- final void setPreviewDisplay(SurfaceHolder holder):设置camera预览的surfaceHolder。
- final void startPreview():开始camera的预览。
- final void stopPreview():结束camera的预览。
- final void autoFocus(Camera.AutoFocusCallback cb):自动对焦。
- final takePicture(Camera.ShutterCallback shutter,Camera.PictureCallback raw,Camera.PictureCallback jpeg):拍照。
- final void lock():锁定Camera硬件,使其他应用无法访问
- final void unlock():解锁Camera硬件,使其他应用可以访问。
评论记录:
回复评论: