Android Jetpack架构组件(五)CameraX视频录制
添加Gradle依赖
// Use the most recent version of CameraX, currently that is alpha04
def camerax_core_version = "1.0.0-beta03"
def camerax_version = "1.0.0-alpha10"
implementation "androidx.camera:camera-core:${camerax_core_version}"
implementation "androidx.camera:camera-camera2:${camerax_core_version}"
// If you want to use the CameraX View class
implementation "androidx.camera:camera-view:${camerax_version}"
// If you want to use the CameraX Extensions library
implementation "androidx.camera:camera-extensions:${camerax_version}"
// If you want to use the CameraX Lifecycle library
implementation "androidx.camera:camera-lifecycle:${camerax_version}"
//视频播放组件
implementation 'com.google.android.exoplayer:exoplayer-core:2.10.4'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.10.4'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.10.4'
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
权限声明
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
private static final String[] PERMISSIONS = new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO};
private ArrayList<String> deniedPermission = new ArrayList<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_CODE);
...
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_CODE) {
deniedPermission.clear();
for (int i = 0; i < permissions.length; i++) {
String permission = permissions[i];
int result = grantResults[i];
if (result != PackageManager.PERMISSION_GRANTED) {
deniedPermission.add(permission);
}
}
if (deniedPermission.isEmpty()) {
//Toast.makeText(CaptureActivity.this, "all permission allowed", Toast.LENGTH_SHORT).show();
initCamera();
} else {
new AlertDialog.Builder(this)
.setMessage(getString(R.string.capture_permission_message))
.setNegativeButton(getString(R.string.capture_permission_no), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
CameraXCaptureActivity.this.finish();
}
})
.setPositiveButton(getString(R.string.capture_permission_ok), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String[] denied = new String[deniedPermission.size()];
ActivityCompat.requestPermissions(CameraXCaptureActivity.this, deniedPermission.toArray(denied), PERMISSION_CODE);
}
}).create().show();
}
}
}
配置CameraX
private void initCamera() {
executor = ContextCompat.getMainExecutor(this);
cameraProviderFuture = ProcessCameraProvider.getInstance(this);
cameraProviderFuture.addListener(() -> {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
bindPreview(cameraProvider);
} catch (ExecutionException | InterruptedException e) {
// No errors need to be handled for this Future.
// This should never be reached.
}
}, executor);
}
@SuppressLint("RestrictedApi")
private void bindPreview(ProcessCameraProvider cameraProvider) {
CameraX.unbindAll();
cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build();
Preview preview = new Preview.Builder()
.setCameraSelector(cameraSelector) //前后摄像头
.setTargetAspectRatio(AspectRatio.RATIO_16_9) //宽高比
.setTargetRotation(rotation) //旋转角度
//.setTargetResolution(resolution) //分辨率
.build();
imageCapture = new ImageCapture.Builder()
.setCameraSelector(cameraSelector)
.setTargetAspectRatio(AspectRatio.RATIO_16_9)
.setTargetRotation(rotation)
//.setTargetResolution(resolution)
.build();
videoCapture = new VideoCaptureConfig.Builder()
.setCameraSelector(cameraSelector)
.setTargetAspectRatio(AspectRatio.RATIO_16_9)
.setTargetRotation(rotation)
//.setTargetResolution(resolution)
//视频帧率
.setVideoFrameRate(25)
//bit率
.setBitRate(10440).build();
//Caused by: java.lang.IllegalArgumentException: No supported surface combination is found for camera device - Id : 0. May be attempting to bind too many use cases.
//cameraSelector与videoCapture不能同时绑定
//Camera camera = cameraProvider.bindToLifecycle(this, cameraSelector, imageCapture, videoCapture, preview);
//Camera camera = cameraProvider.bindToLifecycle(this, cameraSelector, imageCapture, preview);
Camera camera = cameraProvider.bindToLifecycle(this, cameraSelector, videoCapture, preview);
CameraInfo cameraInfo = camera.getCameraInfo();
preview.setSurfaceProvider(mBinding.previewView.createSurfaceProvider(cameraInfo));
}
若报错:IllegalArgumentException: No supported surface combination is found
,如下:
java.lang.IllegalArgumentException: No supported surface combination is found for camera device - Id : 0. May be attempting to bind too many use cases.
at androidx.camera.camera2.impl.Camera2DeviceSurfaceManager.getSuggestedResolutions(Camera2DeviceSurfaceManager.java:176)
解决:cameraSelector与videoCapture不能同时绑定
参考:https://github.com/android/camera-samples/issues/38
参考:https://stackoverflow.com/questions/57126429/an-error-occurred-by-camerax-bindtolifecycle
拍照和录像
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_camerax_capture);
mBinding.recordView.setOnRecordListener(new RecordView.onRecordListener() {
@Override
public void onClick() {
takingPicture = true;
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), System.currentTimeMillis() + ".jpeg");
ImageCapture.OutputFileOptions outputFileOptions =
new ImageCapture.OutputFileOptions.Builder(file).build();
mBinding.captureTips.setVisibility(View.INVISIBLE);
imageCapture.takePicture(outputFileOptions, executor, new ImageCapture.OnImageSavedCallback() {
@Override
public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
String msg = "图片保存成功: " + file.getAbsolutePath();
Toast.makeText(CameraXCaptureActivity.this, msg, Toast.LENGTH_SHORT).show();
Log.i(CommonConstants.TAG, msg);
onFileSaved(file);
}
@Override
public void onError(@NonNull ImageCaptureException exception) {
String msg = "图片保存失败: " + exception.getMessage();
showErrorToast(msg);
Log.e(CommonConstants.TAG, msg);
}
});
}
@SuppressLint("RestrictedApi")
@Override
public void onLongClick() {
takingPicture = false;
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), System.currentTimeMillis() + ".mp4");
videoCapture.startRecording(file, executor, new VideoCapture.OnVideoSavedCallback() {
@Override
public void onVideoSaved(@NonNull File file) {
onFileSaved(file);
}
@Override
public void onError(int videoCaptureError, @NonNull String message, @Nullable Throwable cause) {
String msg = "图片保存失败: " + message;
showErrorToast(msg);
Log.e(CommonConstants.TAG, msg);
}
});
}
@SuppressLint("RestrictedApi")
@Override
public void onFinish() {
videoCapture.stopRecording();
}
});
}
保存和预览
private void onFileSaved(File file) {
outputFilePath = file.getAbsolutePath();
String mimeType = takingPicture ? "image/jpeg" : "video/mp4";
MediaScannerConnection.scanFile(this, new String[]{outputFilePath}, new String[]{mimeType}, null);
CameraXPreviewActivity.startActivityForResult(this, outputFilePath, !takingPicture, "完成");
}
预览照片和录像
private void previewImage(String previewUrl) {
mPreviewBinding.photoView.setVisibility(View.VISIBLE);
GlideApp.with(this).load(previewUrl).into(mPreviewBinding.photoView);
}
private void previewVideo(String previewUrl) {
mPreviewBinding.playerView.setVisibility(View.VISIBLE);
player = ExoPlayerFactory.newSimpleInstance(this, new DefaultRenderersFactory(this), new DefaultTrackSelector(), new DefaultLoadControl());
Uri uri = null;
File file = new File(previewUrl);
if (file.exists()) {
DataSpec dataSpec = new DataSpec(Uri.fromFile(file));
FileDataSource fileDataSource = new FileDataSource();
try {
fileDataSource.open(dataSpec);
uri = fileDataSource.getUri();
} catch (FileDataSource.FileDataSourceException e) {
e.printStackTrace();
}
} else {
uri = Uri.parse(previewUrl);
}
ProgressiveMediaSource.Factory factory = new ProgressiveMediaSource.Factory(
new DefaultDataSourceFactory(this, Util.getUserAgent(this, getPackageName())));
ProgressiveMediaSource mediaSource = factory.createMediaSource(uri);
player.prepare(mediaSource);
player.setPlayWhenReady(true);
mPreviewBinding.playerView.setPlayer(player);
}
版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/03/25/android-jetpack-architecture-components-camerax-video-recording/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。
THE END
0
二维码
打赏
海报
Android Jetpack架构组件(五)CameraX视频录制
添加Gradle依赖
// Use the most recent version of CameraX, currently that is alpha04
def camerax_core_version = "1.0.0-beta03"
def camerax_……
文章目录
关闭
共有 0 条评论