Camera2 和CameraX 从入门到精通 java实现

此文章我会用Camera2 和CameraX 分别实现预览拍照录制视频

目录

此文章我会用Camera2 和CameraX 分别实现预览拍照录制视频

Camera2

APP实现 Camera2 需要提前声明

相机方向

Camera层级架构

API2流程

废话不多说 实战开始

CameraX

CameraX api

CameraX demo


Camera2

APP实现 Camera2 需要提前声明

相机方向

相机相对于手机屏幕默认方向不一致:

        前置摄像头(指向与显示屏方向相同的摄像头)的传感器相对于手机旋转 270 度(顺时针),以符合 Android 兼容性定义

手机的传感器是顺时针旋转的 左横屏就是90度 

 手机的传感器是顺时针旋转的 右横屏就是270度或者-90度 

Camera层级架构

Camera 只是Android的一部分  所以框架层级整体跟Android一样为

Applications 应用层            -----------------------------对应camera APP

Framework层                      -----------------------------对应Java Framework

Libraries 系统运行库层       -----------------------------对应Native Framework (CameraService)

Hardwre Abstraction layer HAL硬件抽象层-----------------------------对应Camera Provider

Linux Kernel 内核层           -----------------------------对应Camera Driver

Camera根据Android 架构从上至下可分为

    1)Applications: 最上层的应用,编译后生成Camera  APK

    2)Application Framework: 主要为Applications提供API;

    3)JNI: 使Application FrameworkLibraries可交互;

    4)Libraries: 包括Camera FrameworkCamera Service(camera servicecamera client);

    5)HAL: 硬件抽象层用来链接driver Camera Service;

    6)Kernel: image sensor driver的实作.

API2流程

 解释下来 其实就是CameraManager调用openCamera 下发open指令到底层,然后在CameraDevice.StateCallbackonOpened 中 拿到底层返回来的CameraDevice 通过CameraDevice去创建Session(createCaptureSession) 创建Session是需要添加对应的surface 预览的surface 有TextureView SurfaceView 拍照对应的Surface 为ImageReader 然后在Session的状态回调的onConfigured里(CameraCaptureSession.StateCallback)拿到CameraCaptureSession对象  通过CameraCaptureSession 可以申请预览 setRepeatingRequest 或者是 拍照 Capture 录制视频 需要配置 MediaRecorder 

废话不多说 实战开始

首先利用AndroidStudio 创建工程

 

Next

 Finish

打开布局文件

 一步步实现 就慢慢来,activity_main.xml布局文件代码

<?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:background="#000000"
    >

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

    <ImageButton
        android:id="@+id/takePictureButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="70dp"
        android:background="@drawable/shape_white_ring"
        android:src="@drawable/shape_take_photo" />

</RelativeLayout>

看到我放了两个控件一个TextureView 用来预览的控件 SurfaceView 等等也可以 还有一个拍照按钮 ImageButton  

首先我们实现预览 预览是一切的基础

package com.example.camera2demo;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.TextureView;
import android.view.View;
import android.widget.ImageButton;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    //预览画面控件
    private TextureView mTextureView;
    //拍照按钮
    private ImageButton mTakePictureButton;
    //日志的tag
    private final String TAG = "Camera2Demo" ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化预览控件
        mTextureView = findViewById(R.id.previewSurfaceView);
        //初始化拍照按钮
        mTakePictureButton = findViewById(R.id.takePictureButton);

    }

    @Override
    protected void onStart() {
        super.onStart();
        //设置拍照按钮监听
        mTakePictureButton.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.takePictureButton:
                takePicture();
                break;
        }
    }

    private void takePicture() {
        Log.d(TAG,"-----takePicture");
    }

}

可以看到 就是在onCreate 里去 初始化 预览控件和拍照按钮 并在 onStart 里去设置按钮 监听

在点击时间里 写了空函数 takePicture 基本框架已经实现 

要实现预览 我们是需要 申请Camera权限的 所以接下来我们先申请权限

Android 6.0 之前只需要在 AndroidManifest.xml 中加入 就OK  6.0 之后需要加入并且动态申请权限

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

 代码 块如下

package com.example.camera2demo;

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

import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.TextureView;
import android.view.View;
import android.widget.ImageButton;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    //预览画面控件
    private TextureView mTextureView;
    //拍照按钮
    private ImageButton mTakePictureButton;
    //日志的tag
    private final String TAG = "Camera2Demo";
    //权限字符串数组 因为还需要其他 便于添加权限 选择字符串数组的形式
    private final String[] REQUIRED_PERMISSIONS = new String[]{
            "android.permission.CAMERA",
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化预览控件
        mTextureView = findViewById(R.id.previewSurfaceView);
        //初始化拍照按钮
        mTakePictureButton = findViewById(R.id.takePictureButton);

    }

    @Override
    protected void onResume() {
        super.onResume();
        //检查权限申请权限
        if (allPermissionsGranted()) {
            Log.d(TAG, "权限已授予");
        } else {
            Log.d(TAG, "申请权限");
            ActivityCompat.requestPermissions(MainActivity.this, REQUIRED_PERMISSIONS, 1);
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        //设置拍照按钮监听
        mTakePictureButton.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.takePictureButton:
                takePicture();
                break;
        }
    }

    private boolean allPermissionsGranted() {
        Log.d(TAG, "----- 检查权限");
        for (String permission : REQUIRED_PERMISSIONS) {
            if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    //权限回调 申请完权限之后 返回的结果在这里接收
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        //这个1 是申请权限时的第三个参数
        if (requestCode == 1) {
            if (allPermissionsGranted()) {
                openCamera();
            } else {
                ActivityCompat.requestPermissions(MainActivity.this, REQUIRED_PERMISSIONS, 1);
            }
        }
    }

    private void openCamera() {
        Log.d(TAG,"----------openCamera");
    }

    private void takePicture() {
        Log.d(TAG,"-----takePicture");
    }

}

在刚刚 的基础之上加了三个函数 一个检查权限的函数 一个权限回调函数 一个 openCamera的空函数 权限获取之后我们就正式进入openCamera

package com.example.camera2demo;

import static java.lang.String.valueOf;

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

import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.util.Size;
import android.view.TextureView;
import android.view.View;
import android.widget.ImageButton;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    //预览画面控件
    private TextureView mTextureView;
    //拍照按钮
    private ImageButton mTakePictureButton;
    //日志的tag
    private final String TAG = "Camera2Demo";
    //权限字符串数组 因为还需要其他 便于添加权限 选择字符串数组的形式
    private final String[] REQUIRED_PERMISSIONS = new String[]{
            "android.permission.CAMERA",
    };
    //处理回调函数的线程
    private HandlerThread mCameraThread;
    private Handler mCameraHandler;
    
    //具体的相机设备
    private CameraDevice mCameraDevice;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化预览控件
        mTextureView = findViewById(R.id.previewSurfaceView);
        //初始化拍照按钮
        mTakePictureButton = findViewById(R.id.takePictureButton);

        //开启线程 用于处理回调函数 可开可不开
        startCameraThread();
    }

    @Override
    protected void onResume() {
        super.onResume();
        //检查权限申请权限
        if (allPermissionsGranted()) {
            Log.d(TAG, "权限已授予");
        } else {
            Log.d(TAG, "申请权限");
            ActivityCompat.requestPermissions(MainActivity.this, REQUIRED_PERMISSIONS, 1);
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        //设置拍照按钮监听
        mTakePictureButton.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.takePictureButton:
                takePicture();
                break;
        }
    }

    private boolean allPermissionsGranted() {
        Log.d(TAG, "----- 检查权限");
        for (String permission : REQUIRED_PERMISSIONS) {
            if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    //权限回调 申请完权限之后 返回的结果在这里接收
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        //这个1 是申请权限时的第三个参数
        if (requestCode == 1) {
            if (allPermissionsGranted()) {
                openCamera();
            } else {
                ActivityCompat.requestPermissions(MainActivity.this, REQUIRED_PERMISSIONS, 1)
  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要使用 CameraX 在 Java实现切换前后置摄像头,可以通过以下步骤: 1. 获取 CameraSelector 对象:通过调用 `CameraSelector.DEFAULT_BACK_CAMERA` 或 `CameraSelector.DEFAULT_FRONT_CAMERA` 方法获取后置或前置摄像头的 CameraSelector 对象。 2. 关闭当前摄像头:在切换摄像头之前,需要先关闭当前正在使用的摄像头。可以通过调用 CameraProvider.unbindAll() 方法,来关闭当前的摄像头。 3. 绑定新的摄像头:使用 CameraProvider.bindToLifecycle() 方法,将新的 CameraSelector 对象绑定到生命周期中。 下面是一个简单的 Java 代码示例,可以实现切换前后置摄像头: ```java private void switchCamera() { CameraSelector cameraSelector = null; if (lensFacing == CameraSelector.LENS_FACING_BACK) { cameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA; } else { cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA; } CameraProvider cameraProvider = cameraProviderFuture.get(); cameraProvider.unbindAll(); Preview preview = new Preview.Builder().build(); ImageAnalysis imageAnalysis = new ImageAnalysis.Builder().build(); ImageCapture imageCapture = new ImageCapture.Builder().build(); Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, preview, imageAnalysis, imageCapture); preview.setSurfaceProvider(previewView.createSurfaceProvider(camera.getCameraInfo())); lensFacing = camera.getCameraInfo().getLensFacing(); } ``` 在这个示例中,我们首先根据当前正在使用的摄像头的 LensFacing 属性,来获取要切换到的摄像头的 CameraSelector 对象。然后,我们通过 CameraProvider.unbindAll() 方法,关闭当前正在使用的摄像头。接着,我们使用 CameraProvider.bindToLifecycle() 方法,将新的 CameraSelector 对象绑定到生命周期中。最后,我们将 preview 设置为新摄像头的 SurfaceProvider,并更新当前正在使用的摄像头的 LensFacing 属性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值