工作流程和原理 实现代码
AspectRatioTextureView是一个封装过的TextureView,提供了控制宽高比,快捷获取Surface的功能
ChainLinkList是一个封装过的LinkedList,使用了链式调用风格,方便使用
LoginActivity是核心逻辑代码,上面两个文件只是简单的辅助文件
//LoginActivity.java
@SuppressWarnings("all")
public class LoginActivity extends CommonActivity {
@BindView(R.id.v_texture_view)
AspectRatioTextureView textureView;
@BindView(R.id.bt1)
View bt1;
@BindView(R.id.bt2)
View bt2;
HandlerThread backgroundThread;
Handler backgroundHandler;
CameraManager cameraManager;
CameraDevice cameraDevice;
CameraCaptureSession session;
ImageReader imageReader;
String cameraId;
Size previewSize;
long lastPictureCaptureTime;
protected void create() {
setContentView(R.layout.activity_main);
ButterKnife.bind(this, ctx);
requestAllPermissionWithCallback();
}
@Override
protected void onPermissionOk() {
init();
}
@SneakyThrows
private void init() {
//获取相机管理器
cameraManager = (CameraManager) ctx.getSystemService(Context.CAMERA_SERVICE);
//获取后置摄像机
for (String cameraId : cameraManager.getCameraIdList()) {
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (facing == CameraCharacteristics.LENS_FACING_BACK) {
ctx.cameraId = cameraId;
//获取最大支持的图片大小
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
previewSize = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)), (l, r) -> {
return l.getWidth() * l.getHeight() - r.getWidth() * r.getHeight();
});
}
}
//创建一个HandlerThread,用来处理后台任务,如写出图片等
backgroundThread = new HandlerThread("CameraBackgroundThread");
backgroundThread.start();
backgroundHandler = new Handler(backgroundThread.getLooper());
//创建ImageReader,用于缓存和抓取帧图像
imageReader = ImageReader.newInstance(previewSize.getWidth(), previewSize.getHeight(), ImageFormat.JPEG, 1);
imageReader.setOnImageAvailableListener(ctx::writeOutImage, backgroundHandler);
//监听TextureView初始化完成
textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
@Override
@SneakyThrows
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
cameraManager.openCamera(cameraId, new CameraDevice.StateCallback() {
@Override
@SneakyThrows
public void onOpened(CameraDevice cameraDevice) {
ctx.cameraDevice = cameraDevice;
//创建关联TextureView和ImageReader的Surface
Surface textureSurface = textureView.getSurface(previewSize.getWidth(), previewSize.getHeight());
Surface imageSurface = imageReader.getSurface();
//开启CaptureSession
ChainLinkList surfaceList = ChainLinkList.create(Surface.class).add(textureSurface, imageSurface);
cameraDevice.createCaptureSession(surfaceList.baseList, new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
ctx.session = session;
startVideoPreview();
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {}
}, backgroundHandler);
}
@Override
public void onDisconnected(CameraDevice cameraDevice) {
ctx.session = null;
ctx.cameraDevice = null;
}
@Override
public void onError(CameraDevice camera, int errorCode) {}
}, backgroundHandler);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { return false; }
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {}
});
//截取图片
bt1.setOnClickListener(v -> {
startImageCapture();
});
}
//视频预览
@SneakyThrows
void startVideoPreview() {
//发起CaptureRequest
CaptureRequest.Builder captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
captureRequestBuilder.addTarget(textureView.getSurface(previewSize.getWidth(), previewSize.getHeight()));
CaptureRequest captureRequest = captureRequestBuilder.build();
session.setRepeatingRequest(captureRequest, null, backgroundHandler);
}
//抓拍图片
@SneakyThrows
void startImageCapture() {
//发起CaptureRequest
CaptureRequest.Builder captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureRequestBuilder.addTarget(textureView.getSurface(previewSize.getWidth(), previewSize.getHeight()));
captureRequestBuilder.addTarget(imageReader.getSurface());
CaptureRequest captureRequest = captureRequestBuilder.build();
lastPictureCaptureTime = 0;
session.stopRepeating();
session.abortCaptures();
session.capture(captureRequest, null, backgroundHandler);
}
//写出图片
@SneakyThrows
void writeOutImage(ImageReader reader) {
//每5秒保存一次图片
long now = Times.millisOfNow();
if (now - lastPictureCaptureTime
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?