作者:郭孝星
微博:郭孝星的新浪微博
邮箱:[email protected]
博客:http://blog.csdn.net/allenwells
Github:https://github.com/AllenWells
一 启用相机
1.1 请求相机权限
<manifest ... > <uses-feature android:name="android.hardware.camera" android:required="true" /> ...</manifest>
如果我们的App使用相机,但相机并不是应用的正常运行所必不可少的组件,可以将android:required 设置为false。这样的话,Google Play也会允许没有相机的设备下载该应用。当然在有必要在使用相机之前通过调用以下方法:
hasSystemFeature(PackageManager.FEATURE_CAMERA);
来检查设备上是否有相机。如果没有,我们应该禁用和相机相关的功能。
1.2 创建Intent对象
利用一个描述了做什么的Intent对象,Android可以将某些执行任务委托给其他应用。整个过程包含三部分:
- Intent本身
- 一个函数调用来启动外部的 Activity
- 当焦点返回到你的Activity时,处理返回图像数据的代码。
举例
发送一个Intent来录制视频
static final int REQUEST_VIDEO_CAPTURE = 1;private void dispatchTakeVideoIntent() { Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);//注意在调用startActivityForResult()方法之前,先调用resolveActivity(),这个方法会返回能处理该Intent的第一个Activity,即即检查有没有能处理这个Intent的Activity。执行这个检查是必要的,因为如果你调用startActivityForResult()时,没有应用能处理该Intent,应用将会崩溃。所以只要返回结果不为null,使用该Intent就是安全的。 if (takeVideoIntent.resolveActivity(getPackageManager()) != null) { startActivityForResult(takeVideoIntent, REQUEST_VIDEO_CAPTURE); }}
1.3 查看视频
Android的相机程序会把指向视频存储地址的Uri添加到Intent中,并传送给onActivityResult())方法。
举例
获取该视频并显示到一个VideoView当中。
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == RESULT_OK) { Uri videoUri = intent.getData(); mVideoView.setVideoURI(videoUri); }}
二 控制相机
2.1 打开相机对象
获取一个Camera对象是直接控制相机的第一步。正如Android自带的相机程序一样,访问相机推荐的方式是在onCreate())方法里面另起一个线程来打开相机。这种办法可以避免因为启动时间较长导致UI线程被阻塞。还有一种更好的方法,可以把打开相机的操作延迟到onResume())方法里面去执行,这样使得代码更容易重用,并且保持控制流程简单。
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; }}
2.2 创建相机预览界面
拍照通常需要向用户提供一个预览界面来显示待拍摄的事物,我们可以使用SurfaceView来展现照相机采集的图像。
//为了显示一个预览界面,我们需要创建一个Preview类。这个类需要实现 android.view.SurfaceHolder.Callback接口,用这个接口把相机硬件获取的数据传递给程序,该Preview类必须在图像实时预览开始之前传递给Camera对象。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创建后,接下来我们就可以设置和启动Preview。Camera实例与它相关的Preview必须以特定的顺序来创建,其中Camera对象首先被创建。
举例
将初始化Canera的动作封装起来
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(); }}
2.3 修改相机设置
相机设置可以改变拍照的方式。
举例
改变预览大小,如下所示:
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及以下版本的系统,在改变方向之前,必须先停止预览,然后再去重启它。
2.4 拍摄照片
预览开始之后,可以进行照片的拍摄。
拍摄照片:调用Camera.takePicture(),将创建的Camera.PictureCallback与Camera.ShutterCallback对象传递到该方法内。
连续拍摄照片:调用Camera.takePicture(),创建一个Camera.PreviewCallback并实现onPreviewFrame()方法。我们可以拍摄选中的预览帧,或是为调用takePicture())建立一个延迟。
在拍摄好图片后,你必须在用户拍下一张图片之前重启预览。
举例
利用快门来实现重启,如下所示:
@Overridepublic 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();}
2.5 停止预览并释放相机
当程序使用相机完毕后,有必要做清理的动作。特别地,必须释放Camera对象,不然可能会引起其他应用崩溃,包括我们自己应用的新实例。在预览的Surface被销毁之后,可以做停止预览并释放相机的动作。
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; }}
版权声明:本文为博主原创文章,未经博主允许不得转载。