注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好。

原文链接:http://developer.android.com/training/camera/cameradirect.html


在这节课中,我们讨论如何直接通过框架内的API来控制相机硬件。

直接控制一个相机硬件需要的代码,比通过已存在的相机应用拍摄照片和视频所需要的代码要多。然而,如果你希望构建一个特制的相机应用,或者需要将一些东西整合入你的应用界面,那么这节课将会教授你如何去做。


一). 打开一个相机对象

要直接控制相机,首先应当获得一个相机(Camera)对象的实例。就像Android自己的相机应用所做的,推荐的访问相机的方法是在onCreate()方法中,通过一个独立的线程来启动。这个方法的优点在于访问相机需要一定的时间,这就导致如果在UI线程例访问相机,可能会造成UI停滞。在一个更加基本的实现中,打开一个相机可以推迟到onResume()方法中,使得代码重用更加方便,同时还能让控制流更加简洁。

调用Camera.open()后,如果相机已经再被另一个应用使用,那么会抛出一个异常,我们可以在try块中捕获它。

private boolean safeCameraOpen(int id) {
boolean qOpened = false; try {
releaseCameraAndPreview();
mCamera = Camera.open(id);
qOpened = (mCamera != null);
} catch (Exception e) {
Log.e(getString(R.string.app_name), "failed to open Camera");
e.printStackTrace();
} return qOpened;
} private void releaseCameraAndPreview() {
mPreview.setCamera(null);
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}

从API Level 9之后,相机框架能够支持多个相机。如果你使用过去的API,并且调用了无传递参数的open()方法,你会得到第一个后置摄像头。


二). 创建相机预览

拍摄照片通常需要让你的用户可以在按下快门键之前看见一个实时预览界面。要这样做,一可以使用SurfaceView来绘制相机预览,显示传感器元件捕捉到的实时画面。

Preview类

要开始显示一个相机预览,你需要Preview类。它需要实现“android.view.SurfaceHolder.Callback”接口,用来将图像数据从相机硬件传递给应用。

class Preview extends ViewGroup implements SurfaceHolder.Callback {

    SurfaceView mSurfaceView;
SurfaceHolder mHolder; Preview(Context context) {
super(context); mSurfaceView = new SurfaceView(context);
addView(mSurfaceView); // Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
...
}

Preview类必须在激活的相机预览启动之前传递给Camera对象,这方面知识将在下一节展开。

设置并启动预览

一个相机实例和与它相关联的相机预览必须以一个特定的顺序创建,相机对象在先。在下面的代码片段中,初始化相机的操作已经封装好了,所以我们可以看到Camera.startPreview()setCamera()方法中被调用,不管何时用户做了什么事情来改变当前激活的摄像头。预览界面必须在preview类中的surfaceChanged()回调函数中重新启动。

public void setCamera(Camera camera) {
if (mCamera == camera) { return; } stopPreviewAndFreeCamera(); mCamera = camera; if (mCamera != null) {
List<Size> localSizes = mCamera.getParameters().getSupportedPreviewSizes();
mSupportedPreviewSizes = localSizes;
requestLayout(); try {
mCamera.setPreviewDisplay(mHolder);
} catch (IOException e) {
e.printStackTrace();
} // Important: Call startPreview() to start updating the preview
// surface. Preview must be started before you can take a picture.
mCamera.startPreview();
}
}

三). 修改相机设置

相机设置改变相机拍摄照片的方式,相机设置从变焦到曝光补偿等等。下面的例子值修改了预览的尺寸,可以通过阅读相机源码来学习更多其他的设置。

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// Now that the size is known, set up the camera parameters and begin
// the preview.
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters); // Important: Call startPreview() to start updating the preview surface.
// Preview must be started before you can take a picture.
mCamera.startPreview();
}

四). 设置预览方向

大多数相机应用会将显示锁定在横屏模式,因为那是摄像头的自然方向。但这不会令你无法拍摄竖屏模式的照片,因为设备的方向会被记录在EXIF头中。setCameraDisplayOrientation()方法可以让你再不影响照片是如何拍摄的情况下改变预览的方向。然而,在Android API Level 14之前,你必须在改变方向之前停止你的相机预览,然后重新启动它。


五). 拍摄照片

一旦相机预览启动了,就可以通过Camera.takePicture()方法来拍摄照片。你可以创建Camera.PictureCallbackCamera.ShutterCallback对象,并将它们传递给Camera.takePicture()

如果你希望连续抓拍图像,你可以创建一个实现了onPreviewFrame()Camera.PreviewCallback。在这两件事情之间,你可以值捕获选中的预览框,或者设置一个调用takePicture()的延迟。


六). 重启相机预览

当一个照片拍好后,你必须在用户拍摄另一张照片之前重启相机预览。在下面的例子中,通过重载快门按钮,实现了重启的操作:

@Override
public void onClick(View v) {
switch(mPreviewState) {
case K_STATE_FROZEN:
mCamera.startPreview();
mPreviewState = K_STATE_PREVIEW;
break; default:
mCamera.takePicture( null, rawCallback, null);
mPreviewState = K_STATE_BUSY;
} // switch
shutterBtnConfig();
}

七). 停止相机预览并且释放相机

一旦你的应用完成了相机的拍摄,那么久到了释放资源的时间了。尤其要注意的是你要释放相机对象,不然的话你可能会导致其它应用的崩溃,这也包括你自己的应用。

那么什么时候应该停止预览并释放相机呢?当你的预览Surface被销毁时,那么这是一个信号,你需要停止预览并释放相机,见下面的例子,这些方法都来自Preview类:

public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null) {
// Call stopPreview() to stop updating the preview surface.
mCamera.stopPreview();
}
} /**
* When this function returns, mCamera will be null.
*/
private void stopPreviewAndFreeCamera() { if (mCamera != null) {
// Call stopPreview() to stop updating the preview surface.
mCamera.stopPreview(); // Important: Call release() to release the camera for use by other
// applications. Applications should release the camera immediately
// during onPause() and re-open() it during onResume()).
mCamera.release(); mCamera = null;
}
}

中这堂课的前半部分,上述步骤也是“setCamera()”方法的一部分,所以初始化一个相机一般都始于停止相机预览。

【Android Developers Training】 50. 控制相机的更多相关文章

  1. 【Android Developers Training】 65. 应用投影和相机视图

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  2. 【Android Developers Training】 44. 控制你应用的音量和播放

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  3. 【Android Developers Training】 45. 控制音频焦点

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  4. 【Android Developers Training】 47. 序言:拍摄照片

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  5. 【Android Developers Training】 83. 实现高效网络访问来优化下载

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  6. 【Android Developers Training】 64. 绘制形状

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  7. 【Android Developers Training】 61. 序言:使用OpenGL ES显示图像

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  8. 【Android Developers Training】 25. 保存文件

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  9. 【Android Developers Training】 108. 使用模拟定位进行测试

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

随机推荐

  1. vue1.0和vue2.0的区别(一)

    今天我们来说一说vue1.0和vue2.0的主要变化有哪些 一.在每个组件模板,不在支持片段代码 VUE1.0是: <template> <h3>我是组件</h3> ...

  2. gitlab 取消注册功能

    gitlab 默认安装完成以后是允许用户注册,公司内部使用所以准备禁用了注册功能,只允许管理员从后台开通权限: 1.进入"Admin Area" 2.在左边菜单栏最低下点击&quo ...

  3. Python爬虫02——贴吧图片爬虫V2.0

    Python小爬虫——贴吧图片爬虫V2.0 贴吧图片爬虫进阶:在上次的第一个小爬虫过后,用了几次发现每爬一个帖子,都要自己手动输入帖子链接,WTF这程序简直反人类!不行了不行了得改进改进. 思路: 贴 ...

  4. ES6核心内容精讲--快速实践ES6(二)

    Iterator和for...of 是什么: Iterator(遍历器)是专门用来控制如何遍历的对象,具有特殊的接口. 怎么用: Iterator(遍历器)对象带有next方法,每一次调用next方法 ...

  5. File 常用方法

    1.判断当前文件是否封装的文件夹目录 //返回true--是,false--不是 File file =new File("C:\\Users\\mac\\Desktop\\复习.txt&q ...

  6. LINQ基础(三)

    一.并行LINQ System.Linq名称空间中包含的类ParallelEnumerable可以分解查询的工作,使其分布在多个线程上. 尽管Enumerable类给IEnumerable<T& ...

  7. 谷歌安装器扫描时提示“需要root权限”,不用root也可以的!

    能FQ的用户会用谷歌服务,一般的新手机没有安装谷歌框架,但是在用谷歌安装器安装谷歌市场时会提示"需要root权限",我用的是360手机,按照下面的教程搞好了: 安装完GSM包就可以 ...

  8. Javascript编码规范,好的代码从书写规范开始,增强代码的可读性,可维护性,这是相当重要的!

    1. 前言 JavaScript在百度一直有着广泛的应用,特别是在浏览器端的行为管理.本文档的目标是使JavaScript代码风格保持一致,容易被理解和被维护. 虽然本文档是针对JavaScript设 ...

  9. ubuntu16.04 英文环境安装google chrome

    1.下载google wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb 2.安装缺少的依赖 ...

  10. 《物联网框架ServerSuperIO教程》-20.网络通讯控制器分组,提高交互的负载平衡能力。v3.6.6 版本发布

    20.1     概述 ServerSuperIO原来在网络通讯模式下,只有一个网络控制器,在自控模式.并发模式和单例模式下时都是异步处理返回的数据,并不会出现性能问题.但是在轮询模式下,一个网络控制 ...