Android相机的使用
在Android手机中,相机应该算是每部智能手机的标准配置了,google为了方便开发者开发,提供了一套供开发者使用的api,作为软件开发者基本上只要调用这些接口就可以进行Android相机方面的功能开发了(这里指的只是基本功能,比如预览、拍照等)!
在本篇博客中将想你展示如何使用google提供的接口(Camera1,后面还会说到,google在后期的版本中推出了Camera2接口,在下一篇博客中在介绍如何使用Camera2接口)开发自己的相机。在这里使用到的类不多,主要包含:Camera、SurfaceView、SurfaceHolder等!
google在相机预览、拍照包括人脸识别中都提供了一个接口,直接调用就可以实现相应的功能,是不是感觉很简单,下面我们就来实现一个Camera(具有预览拍照功能,拍照的图片储存在这里就不实现了)!
先看一下布局文件吧:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v4.widget.DrawerLayout android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:background="@android:color/transparent" android:layout_width="match_parent" android:layout_height="match_parent"> <SurfaceView android:background="@android:color/transparent" android:id="@id/camera_preview" android:layout_width="match_parent" android:layout_height="match_parent" /> FrameLayout> <LinearLayout android:layout_width="150dp" android:layout_height="300dp" android:layout_gravity="start|center_vertical" android:background="@color/colorPrimary" /> android.support.v4.widget.DrawerLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:background="@android:color/transparent"> <ImageView android:onClick="onCapturePhoto" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:background="@android:color/transparent" android:src="@drawable/photo_button" /> RelativeLayout>RelativeLayout>
写的有点啰嗦,其实要做demo的话,只需要一个SurfaceView即可,其他的即可抛弃!!!
再来看一下java代码的实现:
package com.example.administrator.beercamera;import android.app.Activity;import android.graphics.ImageFormat;import android.graphics.Paint;import android.hardware.camera2.CameraAccessException;import android.hardware.camera2.CameraCaptureSession;import android.hardware.camera2.CameraDevice;import android.hardware.camera2.CameraManager;import android.hardware.camera2.CaptureRequest;import android.hardware.camera2.CaptureResult;import android.hardware.camera2.TotalCaptureResult;import android.media.Image;import android.media.ImageReader;import android.os.Bundle;import android.support.annotation.NonNull;import android.util.Log;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import android.view.Window;import android.view.WindowManager;import java.util.Arrays;public class Camera2Activity extends Activity { private SurfaceView mSurfaceView; private SurfaceHolder mSurfaceHolder; private CameraManager mCameraManager; private CameraDevice mCameraDeivce; private CameraCaptureSession mCameraSession; private CaptureRequest.Builder mRequestBuilder; private ImageReader mImageReader; private SavePhotoListener mSaveListener; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().requestFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.activity_main); mCameraManager = (CameraManager) getSystemService(CAMERA_SERVICE); mSurfaceView = (SurfaceView) findViewById(R.id.camera_preview); mSurfaceHolder = mSurfaceView.getHolder(); mSurfaceHolder.addCallback(new SurfaceViewCallBack()); mSaveListener = new SavePhotoListener(); } @Override protected void onDestroy() { super.onDestroy(); if(mCameraDeivce != null){ mCameraDeivce.close(); } } public void onCapturePhoto(View view) { try { final CaptureRequest.Builder mBuilder = mCameraDeivce.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); mBuilder.addTarget(mImageReader.getSurface()); mBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); mBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); mBuilder.set(CaptureRequest.CONTROL_AWB_MODE,CaptureRequest.CONTROL_AWB_MODE_AUTO);// mImageReader.setOnImageAvailableListener(mSaveListener,null); mCameraSession.stopRepeating(); mCameraSession.capture((mBuilder.build()),new CameraResultCallBack(),null); } catch (CameraAccessException e) { e.printStackTrace(); } } private boolean CheckPermission(){ return true; } private class SurfaceViewCallBack implements SurfaceHolder.Callback{ @Override public void surfaceCreated(SurfaceHolder holder) { try { mCameraManager.openCamera("0",new CameraCallBack(),null); } catch (CameraAccessException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { } } private class CameraCallBack extends CameraDevice.StateCallback{ @Override public void onOpened(@NonNull CameraDevice camera) { Log.e("zyq","onOpened"); mCameraDeivce = camera; try { mImageReader = ImageReader.newInstance(mSurfaceView.getWidth(),mSurfaceView.getHeight(), ImageFormat.JPEG,7); mImageReader.setOnImageAvailableListener(mSaveListener,null); mRequestBuilder = mCameraDeivce.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); mRequestBuilder.addTarget(mSurfaceHolder.getSurface()); mCameraDeivce.createCaptureSession(Arrays.asList(mSurfaceHolder.getSurface(),mImageReader.getSurface()),new CameraCaptureConfig(),null); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onDisconnected(@NonNull CameraDevice camera) { } @Override public void onError(@NonNull CameraDevice camera, int error) { if(camera != null){ camera.close(); } } } private class CameraCaptureConfig extends CameraCaptureSession.StateCallback{ @Override public void onConfigured(@NonNull CameraCaptureSession session) { mCameraSession = session; mRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); mRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); mRequestBuilder.set(CaptureRequest.CONTROL_AWB_MODE,CaptureRequest.CONTROL_AWB_MODE_AUTO); try { mCameraSession.setRepeatingRequest(mRequestBuilder.build(),null,null); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { } } private class CameraResultCallBack extends CameraCaptureSession.CaptureCallback{ @Override public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) { super.onCaptureProgressed(session, request, partialResult); Log.e("zyq","onCaptureProgressed"); } @Override public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { super.onCaptureCompleted(session, request, result); mCameraSession = session; Log.e("zyq","onCaptureCompleted"); try { mCameraSession.setRepeatingRequest(mRequestBuilder.build(),null,null); } catch (CameraAccessException e) { Log.e("zyq","onCaptureCompleted e="+e.getMessage()); e.printStackTrace(); } } } private class SavePhotoListener implements ImageReader.OnImageAvailableListener{ @Override public void onImageAvailable(ImageReader reader) { Log.e("zyq","save photo"); Image image = reader.acquireLatestImage(); if(image != null){ Log.e("zyq","iamge = "+image.getHeight()+" , "+image.getWidth()); } } }}
具体预览的效果图就不给出了,给一下拍照时的log吧,log如下;
06-03 14:29:47.689 21208-21208/com.example.administrator.beercamera E/zyq: save photo06-03 14:29:47.690 21208-21208/com.example.administrator.beercamera E/zyq: iamge = 1280 , 72006-03 14:29:47.700 21208-21208/com.example.administrator.beercamera E/zyq: onCaptureCompleted
在ImageReader回调函数中,即使你不打算存储图片也需要调用获取Image的方法,不然的话,下一次点击拍照会出现不执行回调函数的情况,有兴趣的朋友可以自己试一下,使用Camera2刚开始可能会不太习惯,但是认真看一下之后,你会觉的Camera2的架构更容易理解。
下面大致说一下,具体的我也没有追过Camera2的架构代码:
使用Camera2的api,你会发现一切的操作基本上都是通过请求完成,而对请求结果的处理都是通过回调接口完成:
比如我们需要拍摄照片,那么就需要构建一个新的请求,在请求中指定请求的类型为抓取照片,请求放回数据的输出目标为ImageReader中的Surface,然后在请求中添加一系列camera的参数等,然后通过会话传递这个请求基本上就可以达到获取照片的目的了,详细的还是看一下上面的代码!!!
现在来看一下Camera1的API接口的使用:
package com.example.administrator.beercamera;import android.app.Activity;import android.hardware.Camera;import android.os.Bundle;import android.support.annotation.Nullable;import android.util.Log;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import java.io.IOException;/** * Created by Administrator on 2017/5/28 0028. */@Deprecatedpublic class Camera1Activity extends Activity { private SurfaceView mSurfaceView; private SurfaceHolder mSurfaceHolder; private Camera mCamera; private SavePhotoListener mSavePhotoListener; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mSurfaceView = (SurfaceView) findViewById(R.id.camera_preview); mSurfaceHolder = mSurfaceView.getHolder(); mSurfaceHolder.addCallback(new PreviewCallBack()); mSavePhotoListener = new SavePhotoListener(); } public void onCapturePhoto(View view){ mCamera.takePicture(null,null,mSavePhotoListener); } private class PreviewCallBack implements SurfaceHolder.Callback{ @Override public void surfaceCreated(SurfaceHolder holder) { mCamera = Camera.open(0); try { mCamera.setPreviewDisplay(holder); } catch (IOException e) { e.printStackTrace(); } mCamera.setDisplayOrientation(90); mCamera.startPreview(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { mCamera.stopPreview(); } } @Override protected void onDestroy() { super.onDestroy(); if(mCamera != null){ mCamera.release(); } } private class SavePhotoListener implements Camera.PictureCallback{ @Override public void onPictureTaken(byte[] data, Camera camera) { Log.i("zyq","data length = "+data.length); mCamera.startPreview(); } }}
使用Camera1的时候,所有的操作都是一步接着一步的,首先打开相机,设置相关参数,开始预览、拍照等,这种思路很像我们平常操作手机中相机的步骤,感觉更符合我做事时思考的方式,但是Camera2肯定也有着它的优势,不然google没什么事干嘛推出Camera2呢!!
两者的区别主要是架构的不同,对于开发者来说,除了需要知道架构的不同外,我们还需要了解一下Camera2相关API的使用,不然还是不能很好的利用Camera2的接口进行相机编程的!!
好了关于Android相机这一块就说到这吧,其实要编写一个很好的Camera很是很难的,你需要考虑相机的各个方面的东西,兼容、设置、图片/视频的存储等,有条件的话可以看一下系统相机的源码,或者是MTK的相机,阅读源码还是很有收获的!!!有兴趣的朋友可以以关注我,遇到问题大家一起讨论一下!!
这是我的微信公众号,如果可以的话,希望您可以帮忙关注一下,这将是对我最大的鼓励了,谢谢!!
更多相关文章
- Android(安卓)面向接口编程
- App ReLoad:用Android(安卓)来控制单反相机
- Android实现自定义listview上拉刷新下拉加载以及侧滑编辑、删除
- Android中三种超实用的滑屏方式汇总
- 万能前端框架uni app初探01:搭建开发环境
- Android照相和录音功能的使用
- Android远程service aidl的用法
- 腾讯微博java(android) sdk 话题相关api详细介绍
- iPhone与Android谁更能倾倒开发者?