SurfaceView

首先需要明白什么是surface,在Android中可以先粗略地把它理解为是一个用来画图的地方;而surfaceview就是用来显示surface内容的地方。

android 相机 SurfaceTexture 预览 帧数据处理 camera surfaceview_父窗口

为什么要使用surfaceview

一般的View控件例如imageview等,他将自己绘制在父窗口上,而父窗口会每间隔16ms刷新一次(现在高刷屏可能更短?),这意味着普通控件也是16ms刷新一次内容,如果在刷新期间能快速完成绘制工作,则没有问题;但是如果界面更新频繁,绘制复杂(例如相机预览时镜头画面一直在刷新),就容易造成界面卡顿,影响用户体验。而SurfaceView的UI是在一个独立的线程中绘制,不会占用主线程资源,就解决了这一问题。

SurfaceHolder

类似于surface与surfacview之间的连通器,提供访问与控制surfaceview对应的surface的方法,可以直接通过surfaceview的getholder方法,获得“对应的surface的对应的surfaceholder”;
获得surfaceholder后,需要重写其静态子接口Callback的三个回调方法,分别会在surface创建、结构性变化、销毁前调用。
因此我们可以在surface创建时把相机初始化,销毁前将相机资源释放;

开启相机

  1. new 一个相机对象;
    Camera.open方法会根据输入参数开启相机
  2. 设置画面方向;相机默认的图片输入方向是横向的,摄像头捕获的画面信息最终就会以 byte[] 的方式存储横向画面。而本案例使用竖向画面,就需要吧画面整体旋转90度,因此可调用方法camera.setDisplayOrientation(90);
  3. 设置预览拍照参数;要获取相机的各种设置参数方法,需要获取Camera.Parameters对象,第一步中获取了camere对象,此时只需调用camera.getParameters();就能获取“对应的camera对象的对应的parameters对象”用于设置参数了。
  4. 设置好camera后选择surface预览,camera.startPreview()开启预览;

拍下照片

其实并不理解为什么需要两个PictureCallback,根据源码可以看到,应该是哪一个callback不为空,就会调用什么进去,而且再细究会看到这里调用的方法声明了native关键字——使用native关键字说明这个方法是原生函数,也就是这个方法是用C/C++语言实现的,并且被编译成了DLL,由java去调用,因此暂不细究,如果单纯java开发是不需要native的,与C++协作时才需要开发者自己使用这个关键字。
这些函数的实现体在DLL中,JDK的源代码中并不包含,你应该是看不到的。对于不同的平台它们也是不同的。这也是java的底层机制,实际上java就是在不同的平台上调用不同的native方法实现对操作系统的访问的。;这里先粗略将raw设置为空不用管,选择对jpeg进行操作;
可以看到takePicture需要三个输入形参,这里直接使用两个匿名类填充,而在外new一个实例的PictureCallback,并在里面对相机获取图片进行详细操作

public final void takePicture(Camera.ShutterCallback shutter,
                              Camera.PictureCallback raw,
                              Camera.PictureCallback jpeg)

android 相机 SurfaceTexture 预览 帧数据处理 camera surfaceview_java_02


android 相机 SurfaceTexture 预览 帧数据处理 camera surfaceview_java_03