Android Camera2预览流程

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

最近一直在学习Android 操作Camera的流程,由于camera1已经废弃,直接学习了Camera2 API的使用流程,Camera2 API相对于Camera1来讲增加了许多功能,使得对于相机的可操作性更高,让傻瓜式相机向专业相机转变,可以手动控制许多参数(曝光、对焦等)。


一、Camera2相关API介绍

1.Camera2流程

Camera2流程
由上面这种谷歌官方的图我们可以看到几个关键的类:

  • CameraManager
  • CameraCharacteristic
  • CameraDevice
  • CaptureRequest
  • CaptureResult
  • CameraCaptureSession

2.Camera2 API介绍

2.1 CameraManager

CameraManager见名知意,相当于是一个相机的管理者,通过CameraManager构建的对象,我们可以知道一些相机的基本信息,这个信息就存储在CameraCharacteristic对象中。我们可以这样获取到相机的一些基本信息,就是一个CameraInfo类

CameraCharacteristics cameraInfo = mCameraManager.getCameraCharacteristics(cameraId);

除了获取Camera的属性信息外,CameraManager对象扮演的最重要的角色就是打开相机(openCamera),通过CameraManager这个管理者我们才能真正的拿到CameraDevice对象去操作相机。

/*这里的三个参数分别是
cameraId:需要打开的摄像头的id
mCameraDeviceStateCallback:一个CameraDevice的状态回调类,在这个类回调方法里,会告知Camera设备的打开状态,成功还是失败
Handler:openCamera的操作在哪个线程执行,null即为在主线程执行
*/
mCameraManager.openCamera(cameraId, mCameraDeviceStateCallback, null);
2.2 CameraCharacteristic

描述相机设备的属性类,获取方式通过CameraManager对象获得(见上),具体的属性可见官方链接,这里不多赘述
https://developer.android.google.cn/reference/android/hardware/camera2/CameraCharacteristics

2.3 CameraDevice

代表Camera设备,有了CameraDevice对象,就可以创建上层与Camera设备之间的一个会话,在Camera2中即为CameraCaptureSession

/*
List<Surface> outputs:Arrays.asList(mPreviewSurface,mMediaRecorder.getSurface()):代表要配置的流的数量(这里是一个预览流和拍照流)不理解的可以先看下SurafceView、Surface的介绍
mCaptureSessionStateCallback:CameraCaptureSession创建的对象的状态回调
Handler:createCaptureSession的操作在哪个线程执行,null即为在主线程执行
*/
mCameraDevice.createCaptureSession(Arrays.asList(mPreviewSurface,mImagerReader.getSurface()),mCaptureSessionStateCallback,null);
2.4 CaptureCaptureSession

代表上层与底层之间的一个会话,通过这个会话我们可以下发指令给相机,让相机执行预览、拍照录像等操作,在mCameraDevice.createCaptureSession的回调中获得

private CameraCaptureSession.StateCallback mCaptureSessionStateCallback = new CameraCaptureSession.StateCallback() {
        @Override
        public void onConfigured(@NonNull CameraCaptureSession session) {
            mCameraCaptureSession = session;
            Log.i(TAG, "onConfigured: ");
        }

        @Override
        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
            Log.i(TAG, "onConfigureFailed: ");

        }
    };
2.5 CaptureRequest和CaptureResult

CaptureRequest代表相机捕获请求,当CaptureCaptureSession创建好之后,我们就可以使用这个会话来下发指令,表明我当前是需要预览、拍照、还是录像,CaptureRequest对象可以携带我们所需要设置的参数,比如是否自动对焦、自动曝光、自动白平衡等。CaptureRequest对象的创建使用了建造者模式,需要通过CaptureRequest.Builder来创建,通过调用build方法,

PreviewRequest = mCaptureRequestBuilder.build();

mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);               mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);//自动连续对焦
mCaptureRequestBuilder.addTarget(mPreviewSurface); //预览流,底层回来的数据放在哪里
mCaptureRequestBuilder.addTarget(mImageReader.getSurface());拍照流
PreviewRequest = mCaptureRequestBuilder.build();
//这里是下发预览,如果是拍照可以调用capture()方法
mCameraCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureSessionCaptureCallback, null);

CaptureResut代表捕获请求返回的一些结果信息,从里面可以获取一些Metadata数据信息

二、Camera2操作相机预览步骤

1.添加相机、存储使用权限

在AndroidManifest.xml清单文件中添加权限

    <uses-permission android:name="android.permission.CAMERA"></uses-permission>

2.打开相机(openCamera)

在这里插入图片描述

mCameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
        //权限检查
            return;
        }
        try {
        //这里直接打开后摄
            mCameraManager.openCamera("0", mStateCallback, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
//CameraDevice打开状态的回调
mStateCallback = new CameraDevice.StateCallback() {
            @Override
            public void onOpened(@NonNull CameraDevice camera) {
                mCameraDevice = camera;
                createCameraPreviewSession();//获取CamearDevice对象后,就可以创建Session
            }

            @Override
            public void onDisconnected(@NonNull CameraDevice camera) {
                camera.close();
                mCameraDevice = null;
            }

            @Override
            public void onError(@NonNull CameraDevice camera, int error) {
                camera.close();
                mCameraDevice = null;

            }
        };

3.创建相机捕获会话(CreateCaptureSession)

在这里插入图片描述
在上面获得了CameraDevice对象之后,调用了createCameraPreviewSession()的方法

mCameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {

                @Override
                public void onConfigured(CameraCaptureSession cameraCaptureSession) {
                    mCaptureSession = cameraCaptureSession;
                    try {
						//下发预览请求
                        mCaptureSession.setRepeatingRequest(mPreviewRequest, null, null);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
                    Log.e("MainActivity", "onConfigureFailed");
                }
            }, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

上面创建Session时的Arrays.asList(surface)代表要配置一条预览流,这里的surface对象可以通过我们在xml文件中使用TextureView获得:
在这里插入图片描述
这里的TextureView实际就是我们的预览窗口

        mTextureView = findViewById(R.id.preview);
        mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surfaceTexture, int width, int height) {
                //在SurfaceTexture可以用的时候,利用SurfaceTexture创建Surface对象
                SurfaceTexture texture = mTextureView.getSurfaceTexture();
            	texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
            	surface = new Surface(texture);
            	//这边要注意,上面的创建session的动作一定要在SurfaceTexture可用之后,所以我们可以把openCamera的操作放在这个回调里
            	//ToDo openCamera
            }

            @Override
            public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {

            }

            @Override
            public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
                return false;
            }

            @Override
            public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {

            }
        });

4.下发预览请求

下发预览请求我们放在创建Session的回调onConfigured中,
在这里插入图片描述
不过在这之前需要构建一个CaptureRequest对象

final CaptureRequest.Builder previewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
previewRequestBuilder.addTarget(surface);
previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                        mPreviewRequest = previewRequestBuilder.build();

至此,就可以完成Camera的预览了

完整代码

package com.example.camerademo;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;

import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.SurfaceTexture;
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.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.view.TextureView;

import java.util.Arrays;
import java.util.concurrent.Executor;

public class MainActivity extends AppCompatActivity {

    private CameraManager mCameraManager;
    private CameraDevice.StateCallback mStateCallback;
    private CameraDevice mCameraDevice;
    private TextureView mTextureView;
    private CameraCaptureSession mCaptureSession;
    private Size mPreviewSize;
    private CaptureRequest mPreviewRequest;
    private Surface surface;


    TextureView.SurfaceTextureListener surfaceTextureListener = new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surfaceTexture, int width, int height) {
            SurfaceTexture texture = mTextureView.getSurfaceTexture();
            texture.setDefaultBufferSize(1280, 720);
            surface = new Surface(texture);
            openCamera();

        }

        @Override
        public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {

        }

        @Override
        public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
            return false;
        }

        @Override
        public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {

        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextureView = findViewById(R.id.preview);
        mTextureView.setSurfaceTextureListener(surfaceTextureListener);
        applyForPermission();
        initCamera();

    }

    private void applyForPermission() {
        if (Build.VERSION.SDK_INT > 22) {
            if (ContextCompat.checkSelfPermission(MainActivity.this,
                    android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(MainActivity.this,
                        new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
            } else {
                //说明已经获取到摄像头权限了
                Log.i("MainActivity", "已经获取了权限");
            }
        } else {

            Log.i("MainActivity", "这个说明系统版本在6.0之下,不需要动态获取权限。");
        }
    }

    private void initCamera() {

        mStateCallback = new CameraDevice.StateCallback() {
            @Override
            public void onOpened(@NonNull CameraDevice camera) {
                mCameraDevice = camera;
                createCameraPreviewSession();

            }

            @Override
            public void onDisconnected(@NonNull CameraDevice camera) {
                camera.close();
                mCameraDevice = null;
            }

            @Override
            public void onError(@NonNull CameraDevice camera, int error) {
                camera.close();
                mCameraDevice = null;

            }
        };
    }

    public void openCamera(){
        mCameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return;
        }
        try {
            mCameraManager.openCamera("0", mStateCallback, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private void createCameraPreviewSession() {
        try {

            final CaptureRequest.Builder previewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            previewRequestBuilder.addTarget(surface);
            previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            mPreviewRequest = previewRequestBuilder.build();
            mCameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {

                @Override
                public void onConfigured(CameraCaptureSession cameraCaptureSession) {
                    mCaptureSession = cameraCaptureSession;
                    try {
                        mCaptureSession.setRepeatingRequest(mPreviewRequest, null, null);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }

                    
                }

                @Override
                public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
                    Log.e("MainActivity", "onConfigureFailed");
                }
            }, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        closeCamera();
    }

    private void closeCamera() {
        if (mCaptureSession != null) {
            mCaptureSession.close();
            mCaptureSession = null;
        }
        if (mCameraDevice != null) {
            mCameraDevice.close();
            mCameraDevice = null;
        }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextureView
        android:id="@+id/preview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </TextureView>

</LinearLayout>
  • 0
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值