Android CameraX实现摄像头预览拍照录制视频

Posted 殇神马

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android CameraX实现摄像头预览拍照录制视频相关的知识,希望对你有一定的参考价值。

一、前言

从Camera1到Camera2,再到现在的Jetpack中的CameraX,Google一直在致力于让android应用开发者更加方便的去使用摄像头相关的API,更加简单快速的实现摄像头相关的应用功能;下面就来学习一下使用CameraX实现拍照和录制视频功能;

二、CameraX概述

CameraX是Android Jetpack中的组件,旨在简化相机相关的应用开发工作,但是要注意的是CameraX向下最低兼容到Android 5.0(API 21);CameraX利用了Camera2的功能,但采取了一种具有生命周期感知能力且基于用例(UseCase)的更简单的方式,它还解决了设备兼容性问题。

三、CameraX使用

添加依赖:

在Module的build.gradle中添加CameraX相关的依赖

dependencies 
    .....
    def camerax_version = "1.0.0-beta07"
    // CameraX core library using camera2 implementation
    implementation "androidx.camera:camera-camera2:$camerax_version"
    // CameraX Lifecycle Library
    implementation "androidx.camera:camera-lifecycle:$camerax_version"
    // CameraX View class
    implementation "androidx.camera:camera-view:1.0.0-alpha14"

同时CameraX需要一些属于java8的方法,因此我们需要相应地设置编译选项。在build.gradle文件中android块的末尾,buildTypes之后,添加以下内容:

android 
  ...
 compileOptions 
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    
  

添加相关权限

添加相机权限,这里因为我们还要实现照片拍摄,视频录制所以除了相机权限,还需要录音权限,以及存储的读写权限;

     <uses-feature android:name="android.hardware.camera.any" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

相机预览

相机预览我们肯定是要有一个显示摄像头画面的View,在使用Camera1或Camera2时我们一般都是使用SurfaceView来显示摄像头画面,CameraX中提供PreviewView
作为显示摄像头画面的View

所以我么在布局中添加一个PreviewView

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

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

</FrameLayout>

并且使用Preview相关的API实现摄像头画面的预览

    @SuppressLint("RestrictedApi")
    private void preview() 
        ListenableFuture<ProcessCameraProvider> listenableFuture = ProcessCameraProvider.getInstance(mActivity);
        try 
            mProcessCameraProvider = listenableFuture.get();
            mProcessCameraProvider = listenableFuture.get();

            mPreview = new Preview.Builder()
                    .setTargetResolution(new Size(640, 480))
                    .build();
            mPreview.setSurfaceProvider(mPreviewView.createSurfaceProvider());
            ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
                    .build();
            imageAnalysis
                    .setAnalyzer(ContextCompat.getMainExecutor(mActivity),
                            new ImageAnalysis.Analyzer() 
                                @Override
                                public void analyze(@NonNull ImageProxy image) 
                                    Log.e(TAG, "analyze: " + image);
                                    image.close();
                                
                            
                    );
            mProcessCameraProvider.bindToLifecycle((LifecycleOwner) mActivity, CameraSelector.DEFAULT_BACK_CAMERA,
                    mPreview,
                    imageAnalysis
            );
         catch (Exception e) 
            e.printStackTrace();
        

    

我们这里在实现摄像头画面预览的同时,还添加了一ImageAnalysis 图像分析用例,ImageAnalysis设置一个ImageAnalysis.Analyzer分析器,这个用例是用来实现每一帧画面的数据分析的,每一帧画面都会回调到analyze(ImageProxy image)方法
我们可以从IamgeProxy中拿到每一帧画面的图像数据;

这里要注意在回调方法中使用完IamgeProxy后,一定要调用IamgeProxy.close()方法关闭,否则analyze(ImageProxy image)这个方法只会回调一次,这是个坑一定要注意关闭;

拍摄照片

使用IamgeCapture相关的API实现照片拍摄功能

 private void takePhoto() 
        ImageCapture imageCapture = new ImageCapture.Builder()
                //优化捕获速度,可能降低图片质量
                .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                //设置宽高比
                .setTargetResolution(new Size(640, 480))
                //设置初始的旋转角度
                .build();
        String dirPath = getExternalFilesDir("").getAbsolutePath()
                + File.separator + "TestRecode";
        File dirFile = new File(dirPath);
        if (!dirFile.exists()) 
            boolean mkdir = dirFile.mkdir();
            Log.e(TAG, "takePhoto: mkdir:" + mkdir);
        
        File file = new File(dirFile, System.currentTimeMillis() + ".jpg");
        if (!file.exists()) 
            try 
                boolean newFile = file.createNewFile();
                Log.e(TAG, "takePhoto: newFile:" + newFile);
             catch (IOException e) 
                e.printStackTrace();
            
        
        ImageCapture.OutputFileOptions outputFileOptions = new ImageCapture.OutputFileOptions.Builder(file).build();


        mProcessCameraProvider.bindToLifecycle((LifecycleOwner) mActivity, CameraSelector.DEFAULT_BACK_CAMERA,
                imageCapture
        );

        imageCapture.takePicture(outputFileOptions, ContextCompat.getMainExecutor(mActivity), new ImageCapture.OnImageSavedCallback() 
            @Override
            public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) 
                Log.e(TAG, "onImageSaved: " + outputFileResults);
                Uri savedUri = outputFileResults.getSavedUri();
                Log.e(TAG, "onImageSaved: " + savedUri);
                if (savedUri == null) 
                    savedUri = Uri.fromFile(file);
                
                Toast.makeText(mActivity, "拍摄成功", Toast.LENGTH_SHORT).show();
            

            @Override
            public void onError(@NonNull ImageCaptureException exception) 
                Log.e(TAG, "onError: " + exception);
            
        );
    

录制视频

使用VideoCapture相关的API实现视频录制的功能

  @SuppressLint("RestrictedApi")
    private void startRecorder() 

        mVideoCapture = new VideoCapture.Builder()
                .build();

        String dirPath = getExternalFilesDir("").getAbsolutePath()
                + File.separator + "TestRecode";
        File dirFile = new File(dirPath);
        if (!dirFile.exists()) 
            boolean mkdir = dirFile.mkdir();
            Log.e(TAG, "startRecorder: mkdir:" + mkdir);
        
        File file = new File(dirFile, System.currentTimeMillis() + ".mp4");
        if (!file.exists()) 
            try 
                boolean newFile = file.createNewFile();
                Log.e(TAG, "startRecorder: newFile:" + newFile);
             catch (IOException e) 
                e.printStackTrace();
            
        

        mProcessCameraProvider.bindToLifecycle(
                this, CameraSelector.DEFAULT_BACK_CAMERA, mPreview,
                mVideoCapture);

        mVideoCapture.startRecording(file, ContextCompat.getMainExecutor(mActivity),
                new VideoCapture.OnVideoSavedCallback() 
                    @Override
                    public void onVideoSaved(@NonNull File file) 
                        Log.e(TAG, "onVideoSaved: " + file);
                        Toast.makeText(mActivity, "录制结束", Toast.LENGTH_SHORT).show();
                    

                    @Override
                    public void onError(int videoCaptureError, @NonNull String message, @Nullable Throwable cause) 
                        Log.e(TAG, "onError: " + videoCaptureError + "," + message);
                        Toast.makeText(mActivity, "录制出错:code:" + videoCaptureError + "," + message, Toast.LENGTH_SHORT).show();
                        mIsRecording = false;
                    
                
        );
    

    @SuppressLint("RestrictedApi")
    private void stopRecorder() 
        if (mVideoCapture != null) 
            mVideoCapture.stopRecording();
        
    

一开始的时候回调到onError中,videoCaptureError是2,message是MediaMuxer creation failed!,百度也没有找到解决方法,后来发现是视频文件File没有创建成功,所以要注意检查视频文件File有没有创建成功;

当然别忘记了在程序中先要动态申请相关权限;

以上就是使用CameraX实现摄像头预览、拍照、视频录制功能;

Demo源码地址:https://github.com/maqing-programmer/CameraXDemo


欢迎扫码订阅公众号,公众号主要分享原创或转载移动开发技术文章,和广大移动开发者一起学习成长!

以上是关于Android CameraX实现摄像头预览拍照录制视频的主要内容,如果未能解决你的问题,请参考以下文章

使用CameraX几行代码实现摄像头预览和拍照

Android CameraX 仿一甜相机(录像拍照可调节尺寸聚焦照明网格线),最全的CameraX教程

Android CameraX使用,预览拍照获取静态图像

Android 使用CameraX拍照预览

Android 使用CameraX拍照预览

Android的camerax预览拍照