此文章我会用Camera2 和CameraX 分别实现预览拍照录制视频
目录
此文章我会用Camera2 和CameraX 分别实现预览拍照录制视频
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 Framework和Libraries可交互;
4)Libraries: 包括Camera Framework和Camera Service(camera service和camera client);
5)HAL: 硬件抽象层, 用来链接driver和 Camera Service;
6)Kernel: image sensor driver的实作.
API2流程
解释下来 其实就是CameraManager调用openCamera 下发open指令到底层,然后在CameraDevice.StateCallback 的onOpened 中 拿到底层返回来的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)