参考:
https://developer.android.google.cn/training/camerax
https://codelabs.developers.google.com/codelabs/camerax-getting-started/#0
代码Github:https://github.com/345166018/HxJetpack/tree/master/HxCameraX
添加Gradle依赖
//material组件
implementation 'com.google.android.material:material:1.1.0-alpha10'
//camera
implementation 'androidx.camera:camera-core:1.0.0-alpha04'
implementation 'androidx.camera:camera-camera2:1.0.0-alpha04'
implementation 'androidx.camera:camera-view:1.0.0-alpha01'
implementation 'androidx.camera:camera-extensions:1.0.0-alpha01'
//gesture imageview
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
//图片加载
implementation 'com.github.bumptech.glide:glide:4.9.0'
implementation 'jp.wasabeef:glide-transformations:4.0.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
//视频播放组件
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'
CameraX需要一些Java 8的方法,app的build.gradle的buildTypes之后添加以下内容:
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
权限
<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()) {
bindCameraX();
} 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();
CaptureActivity.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(CaptureActivity.this, deniedPermission.toArray(denied), PERMISSION_CODE);
}
}).create().show();
}
}
}
配置CameraX
@SuppressLint("RestrictedApi")
private void bindCameraX() {
CameraX.unbindAll();
PreviewConfig config = new PreviewConfig.Builder()
//前后摄像头
.setLensFacing(mLensFacing)
//旋转角度
.setTargetRotation(rotation)
//分辨率
.setTargetResolution(resolution)
//宽高比
.setTargetAspectRatio(rational)
.build();
preview = new Preview(config);
imageCapture = new ImageCapture(new ImageCaptureConfig.Builder()
.setTargetAspectRatio(rational)
.setTargetResolution(resolution)
.setLensFacing(mLensFacing)
.setTargetRotation(rotation).build());
videoCapture = new VideoCapture(new VideoCaptureConfig.Builder()
.setTargetRotation(rotation)
.setLensFacing(mLensFacing)
.setTargetResolution(resolution)
.setTargetAspectRatio(rational)
//视频帧率
.setVideoFrameRate(25)
//bit率
.setBitRate(10440).build());
preview.setOnPreviewOutputUpdateListener(new Preview.OnPreviewOutputUpdateListener() {
@Override
public void onUpdated(Preview.PreviewOutput output) {
textureView = mBinding.textureView;
ViewGroup parent = (ViewGroup) textureView.getParent();
parent.removeView(textureView);
parent.addView(textureView, 0);
textureView.setSurfaceTexture(output.getSurfaceTexture());
}
});
CameraX.unbindAll();
CameraX.bindToLifecycle(this, preview, imageCapture, videoCapture);
}
@Override
protected void onDestroy() {
CameraX.unbindAll();
super.onDestroy();
}
拍照和录像
@Override
public void onClick() {
takingPicture = true;
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), System.currentTimeMillis() + ".jpeg");
mBinding.captureTips.setVisibility(View.INVISIBLE);
imageCapture.takePicture(file, new ImageCapture.OnImageSavedListener() {
@Override
public void onImageSaved(@NonNull File file) {
onFileSaved(file);
}
@Override
public void onError(@NonNull ImageCapture.UseCaseError useCaseError, @NonNull String message, @Nullable Throwable cause) {
showErrorToast(message);
}
});
}
@SuppressLint("RestrictedApi")
@Override
public void onLongClick() {
takingPicture = false;
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), System.currentTimeMillis() + ".mp4");
videoCapture.startRecording(file, new VideoCapture.OnVideoSavedListener() {
@Override
public void onVideoSaved(File file) {
onFileSaved(file);
}
@Override
public void onError(VideoCapture.UseCaseError useCaseError, String message, @Nullable Throwable cause) {
showErrorToast(message);
}
});
}
保存和预览
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);
PreviewActivity.startActivityForResult(this, outputFilePath, !takingPicture, "完成");
}
预览照片和录像
private void previewImage(String previewUrl) {
mPreviewBinding.photoView.setVisibility(View.VISIBLE);
Glide.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);
}