【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 ...
随机推荐
- WinRAR5.01注册码附注册机
把下面的注册码复制到"记事本"中,另存为"rarreg.key"文件,放到WinRAR安装目录即完成注册.RAR registration datakjcy8U ...
- 从C++ int类型的变量范围谈起
从学习C语言开始,int类型所占字节数,以及数值范围就是一个挥之不去的问题.一开始会死记硬背一个char 1个字节,一个字节8个bit.64位机器上面一个int 4个字节,32位机器上面不一样.那时候 ...
- JAVA的节点流和处理流
节点流:可以从或向一个特定的地方(节点)读写数据.如FileReader. 处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写.如BufferedReader.处理流的构造方 ...
- 【LR11】Error -27796: Failed to connect to server"server:port": [10060] Connection timed out错误解决办法
场景描述:被测系统是发布在远程服务器上的,假设IP是10.10.10.10,端口是8066,那么访问地址是http://10.10.10.10:8066/,在control机器上我设置了IP欺骗. ...
- cuda学习1-初始庐山真面目
cuda作为gpu计算中的代表,拥有着超级高的计算效率,其原因是gpu实际相当与一台超级并行机组,使用过MPI做并行计算的人们可能知道,所谓的并行计算,简单讲就是用多个U(计算单元)来完成一个U的计算 ...
- vue组件之间的通信以及如何在父组件中调用子组件的方法和属性
在Vue中组件实例之间的作用域是孤立的,以为不能直接在子组件上引用父组件的数据,同时父组件也不能直接使用子组件的数据 一.父组件利用props往子组件传输数据 父组件: <div> < ...
- python中xrange用法分析
本文实例讲述了python中xrange用法.分享给大家供大家参考.具体如下: 先来看如下示例: >>> x=xrange(0,8) >>> print x xra ...
- CommonsChunkPlugin并不是分离第三方库的好办法(DllPlugin科学利用浏览器缓存)
webpack算是个磨人的小妖精了.之前一直站在glup阵营,使用browserify打包,发现webpack已经火到爆炸,深怕被社区遗落,赶紧拿起来把玩一下.本来只想玩一下的.尝试打包了以后,就想启 ...
- 禅道---Bug管理模块
禅道官网:http://www.cnezsoft.com/ 简介: 开源免费的项目管理软件.集产品管理.项目管理.测试管理一体以及事物管理组织管理的功能 使用原因: 开源 方便跟踪管理Bug 使用简单 ...
- 用hmmlearn学习隐马尔科夫模型HMM
在之前的HMM系列中,我们对隐马尔科夫模型HMM的原理以及三个问题的求解方法做了总结.本文我们就从实践的角度用Python的hmmlearn库来学习HMM的使用.关于hmmlearn的更多资料在官方文 ...