Utilisez CameraX pour prévisualiser, prendre des photos et des vidéos

1. Avantages de CameraX

CameraX est une bibliothèque de support Jetpack conçue pour vous aider à simplifier le développement des applications de caméra. Il fournit une surface API cohérente et facile à utiliser, adaptée à la plupart des appareils Android et rétrocompatible avec Android 5.0 (niveau d'API 21).

Bien qu'il utilise la fonctionnalité de camera2, il utilise une approche plus simple et basée sur des cas d'utilisation qui tient compte du cycle de vie. Il résout également les problèmes de compatibilité des appareils, vous n'avez donc pas besoin d'ajouter de code spécifique à l'appareil à la base de code. Ces fonctionnalités réduisent la quantité de code à écrire lors de l'ajout de fonctions de l'appareil photo à l'application.

2. Ajouter des dépendances

//主要工具类
implementation 'androidx.camera:camera-core:1.0.0-alpha10'
//主要的外部接口
implementation 'androidx.camera:camera-camera2:1.0.0-alpha10'
//管理相机的生命周期
implementation 'androidx.camera:camera-lifecycle:1.0.0-alpha10'
//预览图层
implementation 'androidx.camera:camera-view:1.0.0-alpha10'
//可选插件,通过该插件,您可以在支持的设备上添加效果。这些效果包括人像、HDR、夜间模式和美颜。
implementation 'androidx.camera:camera-extensions:1.0.0-alpha10'

L'interface de chaque version peut être légèrement différente, mais les fonctions sont fondamentalement les mêmes. De plus, vous devez demander les autorisations de caméra:

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

Si vous souhaitez prendre des photos et enregistrer, vous avez également besoin d'autorisations de stockage:

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

3. Allumez l'appareil photo

private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
private PreviewView previewView;
private ImageCapture imageCapture;
private ProcessCameraProvider cameraProvider;
cameraProviderFuture = ProcessCameraProvider.getInstance(activity);
cameraProviderFuture.addListener(() -> {
    
    
	try {
    
    
		cameraProvider = cameraProviderFuture.get();
		//相机ID CameraSelector.LENS_FACING_FRONT前置;CameraSelector.LENS_FACING_BACK 后置
		bindPreview(cameraProvider, cameraId);
	} catch (ExecutionException | InterruptedException e) {
    
    
		Log.e(TAG, "error:" + e);
	}
}, ContextCompat.getMainExecutor(activity));
private void bindPreview(@NonNull ProcessCameraProvider cameraProvider, int lensFacing) {
    
    
	Preview preview = new Preview.Builder()
			.setTargetAspectRatio(AspectRatio.RATIO_16_9)  //设置宽高比
			.setTargetRotation(Surface.ROTATION_0)         // 设置旋转角度
			.build();
	CameraSelector cameraSelector = new CameraSelector.Builder()
			.requireLensFacing(lensFacing)
			.build();


	/**
	  图像分析可以分为两种模式:阻塞模式和非阻塞模式。通过使用 STRATEGY_BLOCK_PRODUCER 调用 
	  setBackpressureStrategy() 以启用阻塞模式。
	  在此模式下,执行程序会按顺序从相机接收帧;这意味着,如果 analyze() 方法所用的时间超过单帧在当前帧
	  速率下的延迟时间,帧便可能不再是最新的帧,因为新帧已被阻止进入流水线,直到该方法返回为止。
	  通过使用 STRATEGY_KEEP_ONLY_LATEST 调用 setBackpressureStrategy() 以启用非阻塞模式。在此模式
	  下,执行程序会从相机接收调用 analyze() 方法时的最后一个可用帧。如果此方法所用的时间超过单帧在当前
	  帧速率下的延迟时间, 可能会跳过某些帧,以便在下一次 analyze() 接收数据时,它会获取相机流水线中的
	  最后一个可用帧。从 analyze() 返回前,请通过调用 image.close() 关闭图片引用,以避免阻塞其他图像的
	  生成(导致预览停顿)并避免可能出现的图像丢失。 此方法必须完成分析或创建副本,而不是将图像引用传递
	  到分析方法以外。*/
	//设置宽高比
	// 设置旋转角度
	ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
			.setTargetAspectRatio(AspectRatio.RATIO_16_9)  //设置宽高比
			.setTargetRotation(Surface.ROTATION_0)         // 设置旋转角度
			.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
			.build();

	imageAnalysis.setAnalyzer(executors, imageProxy -> {
    
    
		//预览过程中,如果需要录制视频,则在这里获取。
		//将图片转换成yuv(格式YUV_420_888)数据,再进行编码。
		//如果处理数据太慢,导致造成阻塞,可以设置监听器,把数据发送到其他线程进行处理
		ImageProxy.PlaneProxy[] planes = imageProxy.getPlanes();
		byte[] mYuvBytes = new byte[imageProxy.getWidth() * imageProxy.getHeight() * 3 / 2];
		// YUV_420_888
		ByteBuffer yBuffer = planes[0].getBuffer();
		int yLen = imageProxy.getWidth() * imageProxy.getHeight();
		yBuffer.get(mYuvBytes, 0, yLen);
		ByteBuffer uBuffer = planes[1].getBuffer();
		ByteBuffer vBuffer = planes[2].getBuffer();


		int pixelStride = planes[1].getPixelStride(); // pixelStride = 2
		for (int i = 0; i <= uBuffer.remaining(); i += pixelStride) {
    
    
			mYuvBytes[yLen++] = uBuffer.get(i);
			mYuvBytes[yLen++] = vBuffer.get(i);
		}
		imageProxy.close();
	});


	//拍摄图像的配置
	imageCapture =
			new ImageCapture.Builder()
					//CAPTURE_MODE_MAXIMIZE_QUALITY 拍摄高质量图片,图像质量优先于延迟,可能需要更长的时间
					//CAPTURE_MODE_MINIMIZE_LATENCY
					.setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
					.setTargetAspectRatio(AspectRatio.RATIO_16_9)  //设置宽高比
					.setTargetRotation(Surface.ROTATION_0)         // 设置旋转角度
					.build();

	cameraProvider.unbindAll();
	Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner) activity, cameraSelector, imageCapture, preview, imageAnalysis);
	
	//这里previewView是预览图层,需要在布局中实现,然后在这里使用
	preview.setSurfaceProvider(previewView.createSurfaceProvider(camera.getCameraInfo()));
}

Utilisation de PreviewView

<androidx.camera.view.PreviewView
	android:id="@+id/preview"
	android:layout_width="match_parent"
	android:layout_height="match_parent"/>

4. Prenez des photos

Il existe deux façons de prendre des photos de rappel:
1. Rappelez l'image, si vous devez enregistrer, vous pouvez transférer vers Bitmap, puis enregistrer
2. Configurer directement le chemin de sauvegarde, puis recevoir le rappel du succès et de l'échec du image.

public void takePicture() {
    
    
	imageCapture.takePicture(executors, new ImageCapture.OnImageCapturedCallback() {
    
    
		@Override
		public void onCaptureSuccess(@NonNull ImageProxy imageProxy) {
    
    
			ImageProxy.PlaneProxy[] planes = imageProxy.getPlanes();
			ByteBuffer buffer = planes[0].getBuffer();
			buffer.position(0);
			byte[] bytes = new byte[buffer.capacity()];
			buffer.get(bytes);
			imageProxy.close();
			super.onCaptureSuccess(imageProxy);
		}
	});


	/*ImageCapture.Metadata metadata = new ImageCapture.Metadata();
	if (mCurrentCameraId == CameraSelector.LENS_FACING_FRONT) {
		metadata.setReversedHorizontal(true);
	} else {
		metadata.setReversedHorizontal(false);
	}

	File file = new File(Environment.getExternalStorageState(), new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS",
			Locale.US).format(System.currentTimeMillis()) + ".jpg");
	ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.
			Builder(file).setMetadata(metadata).build();
	imageCapture.takePicture(outputFileOptions, executors, new ImageCapture.OnImageSavedCallback() {
		@Override
		public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
			Log.e(TAG, "outputFileResults:" + outputFileResults.getSavedUri());
		}

		@Override
		public void onError(@NonNull ImageCaptureException exception) {
			Log.e(TAG, "exception:" + exception.toString());
		}
	});*/
}

Les étudiants qui ont besoin de l'extension du fournisseur peuvent la vérifier sur le site officiel.

PS: La description officielle de CameraX

https://developer.android.google.cn/training/camerax

Je suppose que tu aimes

Origine blog.csdn.net/mozushixin_1/article/details/108075167
conseillé
Classement