乐趣区

关于android:基于CameraX完成拍照和拍视频

背景:最近在做一个 APP 视频上传的我的项目,因为应用的是自家的服务器,内存有肯定的限度,而目前的手机大多分辨率较大,拍进去的视频几秒钟就好几兆,如何让压缩录制的视频,跟微信一样,因而查阅了一些材料,特此记下,避免本人忘记!

我之前大多应用 Camera1 和 Camera2 开发相机性能的时候须要调用非常复杂的 API,而且因为 Android 手机的碎片化重大,不同手机对相机性能的反对度也不一样,因而很多做相机相干利用的公司都会封装本人的相机库来简化相机的应用步骤和解决兼容性问题。

之后谷歌为简化相机 API 的应用,推出了 CameraX。最多兼容到 Android 5.0,底层调用的也是 Camera2,不过比 Camera2 用起来更简略,而且能够绑定生命周期,从而能够主动的解决相机的开启开释等工作。

dependencies {
   // CameraX 外围库应用 camera2 实现
    implementation "androidx.camera:camera-camera2:1.0.0-beta03"
    // 能够应用 CameraView
    implementation "androidx.camera:camera-view:1.0.0-alpha10"
    // 能够应用供应商扩大
    implementation "androidx.camera:camera-extensions:1.0.0-alpha10"
    //camerax 的生命周期库
    implementation "androidx.camera:camera-lifecycle:1.0.0-beta03"
    }

配置状态
预览配置:Preview 用于相机预览的时候显示预览画面。

Preview preview = new Preview.Builder()
                // 设置宽高比
                .setTargetAspectRatio(screenAspectRatio)
                // 设置以后屏幕的旋转
                .setTargetRotation(rotation)
                .build();

照相配置:ImageCapture 用于拍照,并将图片保留

ImageCapture imageCapture = new ImageCapture.Builder()
                // 优化捕捉速度,可能升高图片品质
                .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                // 设置宽高比
                .setTargetAspectRatio(screenAspectRatio)
                // 设置初始的旋转角度
                .setTargetRotation(rotation)
                .build();

录制视频设置:VideoCapture 用来录制视频和保留视频,宽高比和分辨率设置一个就能够了,不要同时设置否则报错。依据理论的需要来设置,如果对宽高比要求高就设置宽高比,反之就设置分辨率

这个中央是重点,录制视频的时候能够设置分辨率、帧率和 bit 率进行批改录制视频的大小

VideoCapture videoCapture = new VideoCaptureConfig.Builder()
                // 设置以后旋转
                .setTargetRotation(rotation)
                // 设置宽高比
                .setTargetAspectRatio(screenAspectRatio)
                // 分辨率
                //.setTargetResolution(resolution)
                // 视频帧率  越高视频体积越大
                .setVideoFrameRate(25)
                //bit 率  越大视频体积越大
                .setBitRate(3 * 1024 * 1024)
                .build();

绑定到生命周期:ProcessCameraProvider 是一个单例类,能够把相机的生命周期绑定到任何 LifecycleOwner 类中。AppCompatActivity 和 Fragment 都是 LifecycleOwner

//Future 示意一个异步的工作,ListenableFuture 能够监听这个工作,当工作实现的时候执行回调
 ListenableFuture<ProcessCameraProvider> cameraProviderFuture =
                ProcessCameraProvider.getInstance(this);
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();

// 从新绑定之前必须先勾销绑定
cameraProvider.unbindAll();

Camera camera = cameraProvider.bindToLifecycle(CameraActivity.this,
                cameraSelector,preview,imageCapture,videoCapture);

OK 预览,照相,录视频的配置和绑定到生命周期的工作就实现了

预览的时候须要显示到一个 View 控件上吧,CameraX 中提供了一个 PreviewView 用来显示预览画面。其外部封装了 TextureView 和 SurfaceView,能够依据不同的模式来抉择其外部应用 TextureView 还是 SurfaceView 来显示。

xml 中增加 PreviewView,并在代码中将其附加到后面创立进去的 Preview 这个实例上

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

preview.setSurfaceProvider(mPreviewView.createSurfaceProvider(camera .getCameraInfo()));
这样当咱们进入该页面的时候就能够看到相机的预览成果呢,接下来就是执行拍照和录制的性能了

当初咱们就一起看看如何实现拍照

// 创立图片保留的文件地址
  File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsolutePath(),
          System.currentTimeMillis() + ".jpeg");
  ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(file).build();
  mImageCapture.takePicture(outputFileOptions,mExecutorService , new ImageCapture.OnImageSavedCallback() {
      @Override
      public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {Uri savedUri = outputFileResults.getSavedUri();
          if(savedUri == null){savedUri = Uri.fromFile(file);
          }
          outputFilePath = file.getAbsolutePath();
          onFileSaved(savedUri);
      }

      @Override
      public void onError(@NonNull ImageCaptureException exception) {Log.e(TAG, "Photo capture failed:"+exception.getMessage(), exception);
      }
  });
// 将后面保留的文件增加到媒体中
private void onFileSaved(Uri savedUri) {if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {sendBroadcast(new Intent(android.hardware.Camera.ACTION_NEW_PICTURE, savedUri));
        }
        String mimeTypeFromExtension = MimeTypeMap.getSingleton().getMimeTypeFromExtension(MimeTypeMap
                .getFileExtensionFromUrl(savedUri.getPath()));
        MediaScannerConnection.scanFile(getApplicationContext(),
                new String[]{new File(savedUri.getPath()).getAbsolutePath()},
                new String[]{mimeTypeFromExtension}, new MediaScannerConnection.OnScanCompletedListener() {
                    @Override
                    public void onScanCompleted(String path, Uri uri) {Log.d(TAG, "Image capture scanned into media store: $uri"+uri);
                    }
                });
        PreviewActivity.start(this, outputFilePath, !takingPicture);
    }

1、调用 ImageCapture 的 takePicture 办法来拍照
2、传入一个文件地址用来保留拍好的照片
3、onImageSaved 办法是照片曾经拍好并存好之后的回调
4、onFileSaved 办法中将后面保留的文件增加到媒体中,最初跳转到预览界面。

录制视频
和拍照相似

// 创立视频保留的文件地址
File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsolutePath(),
        System.currentTimeMillis() + ".mp4");
mVideoCapture.startRecording(file, Executors.newSingleThreadExecutor(), new VideoCapture.OnVideoSavedCallback() {
    @Override
    public void onVideoSaved(@NonNull File file) {outputFilePath = file.getAbsolutePath();
        onFileSaved(Uri.fromFile(file));
    }

    @Override
    public void onError(int videoCaptureError, @NonNull String message, @Nullable Throwable cause) {Log.i(TAG,message);
    }
});

1、应用 VideoCapture 的 startRecording 办法来录视频
2、传入一个 File 文件用来保留视频,
3、录制实现之后回调 onVideoSaved 办法,并返回该文件的实例。
4、调用 onFileSaved 办法将后面保留的文件增加到媒体中,最初跳转到预览界面。
5、达到录制工夫的时候,须要调用 videoCapture.stopRecording(); 办法来进行录像。

当初根本就实现了拍照和录制视频的性能了,下一篇再记录一下 CameraView 的应用常识!

注:本文章常识大部分都采集于大佬们的博客,我只是在此做常识笔记,避免本人忘记!不用于任何商业用途!
原著地址:https://zhuanlan.zhihu.com/p/…

退出移动版