音视频 系列文章
Android 音视频开发(一) – 使用AudioRecord 录制PCM(录音);AudioTrack播放音频
Android 音视频开发(二) – Camera1 实现预览、拍照功能
Android 音视频开发(三) – Camera2 实现预览、拍照功能
Android 音视频开发(四) – CameraX 实现预览、拍照功能
Android 音视频开发(五) – 使用 MediaExtractor 分离音视频,并使用 MediaMuxer合成新视频(音视频同步)
音视频工程

一. Camerax 简介

在前面两章中,我们已经学习了 Camera1 Android 音视频开发(二) – Camera1 实现预览、拍照功能 和 Camera2 Android 音视频开发(三) – Camera2 实现预览、拍照功能,但从上面两章可以看出来,API 的调用还是比较繁琐的,而且像一些最佳尺寸,角度等还得自己算,从 Camera2 的开发流程就可以知道:

真的很难记住这些流程;google 也意识到这个问题,所以推出了 Camerax ,它虽然底层也是利用了 Camera2 的功能,但它的使用却更加简洁,它的主要优势如下:

  1. 更加简洁的 API 调用,基本十几行代码就能实现预览
  2. Camerax 为 Jetpack 的支持库,所以也具备感知生命周期的功能,即你无需自己释放 生命周期
  3. 更好兼容性
  4. 更多功能,比如图片分析等

注意,Camerax 也只支持 API21 及以上,本次效果如下:

二. Camerax 使用说明

Camerax 的使用非常简单,首先,添加关联库

def camerax_version = "1.0.0-beta06"// CameraX 核心库implementation "androidx.camera:camera-camera2:$camerax_version"// CameraX 生命周期implementation "androidx.camera:camera-lifecycle:$camerax_version"// CameraX view 集合,比如 cameraview,preview等implementation "androidx.camera:camera-view:1.0.0-alpha10"

权限

   

2.1 预览

首先,先通过

  ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this);

返回当前可以绑定生命周期的 ProcessCameraProvider,ProcessCameraProvider 它会和宿主绑定生命周期,这样就不用担心打开相机和关闭的问题了。

接着,向 cameraProviderFuture 注册一个监听,第一个参数是一个 runnable,第二个参数是线程池,即runnable 运行在哪个线程中:

cameraProviderFuture.addListener(Runnable {}, ContextCompat.getMainExecutor(this))

上面我们让它运行在主线程的线程池中,这样,在这个 runnable 中,就可以配置我们的 capture 了:

        //创建相机进程监听        ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(this);        cameraProviderFuture.addListener(new Runnable() {            @SuppressLint("RestrictedApi")            @Override            public void run() {                try {                    //将相机的生命周期和activity的生命周期绑定,camerax 会自己释放,不用担心了                    ProcessCameraProvider cameraProvider = cameraProviderFuture.get();                    //预览的 capture,它里面支持角度换算                    Preview preview = new Preview.Builder().build();                    //创建图片的 capture                    mImageCapture = new ImageCapture.Builder()                            .setFlashMode(ImageCapture.FLASH_MODE_AUTO)                            .build();                                       //选择后置摄像头                    CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build();                    //预览之前先解绑                    cameraProvider.unbindAll();                    //将数据绑定到相机的生命周期中                    Camera camera = cameraProvider.bindToLifecycle(CameraxActivity.this, cameraSelector, preview, mImageCapture);                    //将previewview 的 surface 给相机预览                    preview.setSurfaceProvider(mViewFinder.createSurfaceProvider(camera.getCameraInfo()));                } catch (Exception e) {                    e.printStackTrace();                }            }        },ContextCompat.getMainExecutor(this));

可以看到,使用 ProcessCameraProvider.getInstance(this) 获取当前的 ProcessCameraProvider 去监听宿主的生命周期。

创建并确认 CameraProvider 后,执行步骤如下

  1. 创建 Preview,使用 new Preview.Builder().build() 创建Preview,它是相机预览的数据流,图像数据会通过它来输出,比如输出到 Surface 中
  2. 创建 ImageCapture 用于拍照,这里的 builder 都可以设置参数,比如大小,曝光等
  3. 指定所需的相机 LensFacing 选项,这里直接使用后置即可
  4. 将所选相机和任意用例绑定到生命周期,通过 cameraProvider.bindToLifecycle,将宿主的生命周期,与 cameraSelector,preview和mImageCapture判定起来。
  5. 将 Preview 连接到 PreviewView,preview.setSurfaceProvider() 设置要预览的 surface

上面的的 mViewFinder 其实是一个 PreviewView ,这是一种可以剪裁、缩放和旋转以确保正确显示的 View,即不用你自己去设置预览的角度等问题了。

    

2.2. 拍照

上面已经设置了 mImageCapture,拍照呢,在 Camerax 中也很简单,使用 takePicture 即可,如下

 public void takePhoto(View view) {        if (mImageCapture != null) {            File dir = new File(Constants.PATH);            if (!dir.exists()) {                dir.mkdirs();            }            //创建文件            File file = new File(Constants.PATH,"testx.jpg");            if (file.exists()) {                file.delete();            }            //创建包文件的数据,比如创建文件            ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(file).build();            //开始拍照            mImageCapture.takePicture(outputFileOptions, ContextCompat.getMainExecutor(this), new ImageCapture.OnImageSavedCallback() {                @Override                public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {                //    Uri savedUri = outputFileResults.getSavedUri();                    Toast.makeText(CameraxActivity.this, "保存成功: ", Toast.LENGTH_SHORT).show();                }                @Override                public void onError(@NonNull ImageCaptureException exception) {                    Toast.makeText(CameraxActivity.this, "保存失败", Toast.LENGTH_SHORT).show();                }            });        }    }

注释已经很清楚了,注意我们可以使用 ImageCapture.OutputFileOptions 让 Camerax 去帮我们保存图片文件。

参考:
https://codelabs.developers.google.com/codelabs/camerax-getting-started/#0

更多相关文章

  1. Activity全解(一)
  2. Android之碎片Fragment的生命周期
  3. 阿里云面试(android)
  4. Android(安卓)修改Camera拍照的默认保存路径
  5. Android——拍照、剪切、得到图片/从相册中选择照片(api19以上和
  6. android头像设置:从本地照片库或拍照获取并剪裁
  7. Android(安卓)调用系统拍照 笔记 - 会说话的哑巴的个人页面 - 开
  8. Android后台开启服务默默拍照
  9. Android中的骨架加载预览(Skeleton),RecycleView加载数据前的预览

随机推荐

  1. JDK ANT ANDROID Configure
  2. Android(安卓)点击back键两次退出程序
  3. Android之生成桌面快捷方式(二)
  4. 最受欢迎的文章汇总
  5. Android键盘映射
  6. android使用notifyDataSetChanged()方法,a
  7. Android(安卓)封装自己的工具Jar
  8. Android(安卓)P 系统启动-System Server
  9. android设置Webview的滚动条属性
  10. sdut 2162:The Android(安卓)University