Android相机的使用

在Android手机中,相机应该算是每部智能手机的标准配置了,google为了方便开发者开发,提供了一套供开发者使用的api,作为软件开发者基本上只要调用这些接口就可以进行Android相机方面的功能开发了(这里指的只是基本功能,比如预览、拍照等)!

在本篇博客中将想你展示如何使用google提供的接口(Camera1,后面还会说到,google在后期的版本中推出了Camera2接口,在下一篇博客中在介绍如何使用Camera2接口)开发自己的相机。在这里使用到的类不多,主要包含:Camera、SurfaceView、SurfaceHolder等!

google在相机预览、拍照包括人脸识别中都提供了一个接口,直接调用就可以实现相应的功能,是不是感觉很简单,下面我们就来实现一个Camera(具有预览拍照功能,拍照的图片储存在这里就不实现了)!
先看一下布局文件吧:


<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 photo
06-03 14:29:47.690 21208-21208/com.example.administrator.beercamera E/zyq: iamge = 1280 , 720
06-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.
 */

@Deprecated
public 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相机的使用_第1张图片

你可能感兴趣的:(Android)