【Android Developers Training】 50. 控制相机
注:本文翻译自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.PictureCallback和Camera.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. 控制相机的更多相关文章
- 【Android Developers Training】 65. 应用投影和相机视图
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 44. 控制你应用的音量和播放
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 45. 控制音频焦点
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 47. 序言:拍摄照片
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 83. 实现高效网络访问来优化下载
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 64. 绘制形状
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 61. 序言:使用OpenGL ES显示图像
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 25. 保存文件
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 【Android Developers Training】 108. 使用模拟定位进行测试
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
随机推荐
- [刷题]算法竞赛入门经典 3-1/UVa1585 3-2/UVa1586 3-3/UVa1225
书上具体所有题目:http://pan.baidu.com/s/1hssH0KO(我也是在网上找到的pdf,但不记得是从哪里搜刮到的了,就重新上传了一遍) PS:第一次写博客分享我的代码,不知道我对c ...
- CachedRowSet使用
public interface CachedRowSet extends RowSet,Joinable 所有标准 CachedRowSet 实现都必须实现的接口.Sun Microsystems ...
- Node.js入门第一天
一.Node.js简介 1.1 简介 V8引擎本身就是用于Chrome浏览器的JS解释部分,但是Ryan Dahl这哥们,鬼才般的,把这个V8搬到了服务器上,用于做服务器的软件. Node.js是一个 ...
- Linux常用网络测试命令
Linux常用网络测试命令 1. ifconfig 可以使用ifconfig命令来配置并查看网络接口的配置情况. 例如: (1) 配置eth0的IP地址, 同时激活该设备. #ifcon ...
- koa-router中路由/后面不填参数就会报404的解决办法
koa-router 中使用路由参数时会遇到一个问题,就是像下面的代码在没有传入 id 是会报 404 错误 router.get('/:id', (err, ctx, next) => { / ...
- 观《IT培训行业揭秘》触发北大青鸟回忆
在园子里看到这篇文章<IT培训行业解密(六)>时,挺有感触,回忆顿时涌上心头: 我想起了当年单纯的我们因为各自的原因来到北大青鸟,或因前途迷茫而选择想找一条出路,或因父母的信息闭塞而想给我 ...
- Oracle数据库------体系结构
ORACLE体系结构包括:实例(Instance),数据库文件,用户进程(User process),服务器进程以及其他文件. 1.ORACLE实例(instance) 1).要访问数据库必须 ...
- jquery中html、text、val回调函数
先扫盲: 摘自菜鸟教程:jQuery 方法:text().html() 以及 val()拥有回调函数. 回调函数有两个参数:被选元素列表中当前元素的下标,以及原始(旧的)值.然后以函数新值返回您希望使 ...
- JDBC连接数据库程序
废话少说,看了尚学堂的视频以及某大神的博客,总结出以下.(本文以oracle数据库为例) 创建一个JDBC连接数据库的程序,需要着手做以下几件事情: 注意,这里边使用了java.sql.Stateme ...
- 如何按内容筛选dom
有时候我们需要按照dom的text内容去筛选,那么可以用jQuery的contains筛选 写法 $("div:contains(aaa)") 筛选出内容包含aaa的div 另外 ...