注:本文翻译自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. 解决U盘容量变小问题

    今天又想重新给电脑刷刷kali linux新版本了貌似N久没更,直接重新刷系统吧...然后发现USB容量变小,这就尴尬了,接着总结了个小方法. 解决方法:1.先把u盘插好,运行cmd,2.输入disk ...

  2. 策略模式(stragegy)

    策略模式(stragegy) 定义了算法族,分别封装起来,让它们之间可以相互替换,此模式让算法独立于使用算法的客户(Head First 设计模式).    策略模式,针对接口编程,而不依赖于具体的实 ...

  3. 获取JUnit的执行结果

    junit执行之后会有一个结果展示,下面就来看一下怎么获取这些结果并将其存储为一个对象 junit代码如下: package test; import org.junit.After; import ...

  4. 使用Html5下WebSocket搭建简易聊天室

    一.Html5WebSocket介绍 WebSocket protocol 是HTML5一种新的协议(protocol).它是实现了浏览器与服务器全双工通信(full-duplex). 现在,很多网站 ...

  5. struts2.1.6教程八、验证机制

    注意:要想实现校验,action必须继承自ActionSupport类. 1.基于手工编码的校验 我们建立struts2validate项目 ,其中reg.jsp页面主要代码如下: <body& ...

  6. 开涛spring3(4.3) - 资源 之 4.3 访问Resource

    4.3.1  ResourceLoader接口 ResourceLoader接口用于返回Resource对象:其实现可以看作是一个生产Resource的工厂类. public interface Re ...

  7. SharePoint 无法删除搜索服务应用程序

    在SharePoint的使用中,经常会遇到某些服务创建失败,某些服务删除不成功的情况.这里,我们就遇到了搜索服务创建失败,然后删除也不成功,使用管理中心的UI无法删除,PowerShell命令也无法删 ...

  8. SmartCoder每日站立会议03

    1.站立会议内容 今天是站立会议第三天,由于我们是做微信小程序,所以很多方面大家都在试验学习阶段,但是经过之前的了解和最近的学习,大家还是有很大进步的.首页简单的css样式已出,正在考虑首页样式再进行 ...

  9. 软件需求规格说明书(spec)

    1.spec 的目标是什么,spec 的目标不包括什么? 我们的目标是对用户发布的各种需求(需要伙伴的需求)进行处理,使别的用户可以看到信息,并且成功找到合适的伙伴一起! 不包括对用户之间的联系. 2 ...

  10. Unity应用架构设计(10)——绕不开的协程和多线程(Part 2)

    在上一回合谈到,客户端应用程序的所有操作都在主线程上进行,所以一些比较耗时的操作可以在异步线程上去进行,充分利用CPU的性能来达到程序的最佳性能.对于Unity而言,又提供了另外一种『异步』的概念,就 ...