Audio and video learning

Audio and video learning

Camera2

Learning and using Camera

  1. Create a Camera instance through Camera.open()
  2. Then release the lock through camera.unlock, otherwise it cannot be used
  3. Then use MediaCorder.setCamera to make settings

Because camera is out of date, Google now launches Camera2 and CameraX

Study and use of Camera2

  1. Get the CameraManager through context.getSystemService(Context.CAMERA_SERVICE)

  2. Gets the currently selected CameraID

     private void selectCamera() {
            if (mCameraManager != null) {
                Log.e(TAG, "selectCamera: CameraManager is null");
    
            }
            try {
                String[] cameraIdList = mCameraManager.getCameraIdList();   //Gets the collection of all camera IDs of the current device
                if (cameraIdList.length == 0) {
                    Log.e(TAG, "selectCamera: cameraIdList length is 0");
                }
                for (String cameraId : cameraIdList) { //Traverse all cameras
                    CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId);//Get the camera description feature of the current id
                    Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING); //Obtain the directional feature information of the camera
                    if (facing == CameraCharacteristics.LENS_FACING_BACK) { //The rear camera is selected here
                        mCurrentSelectCamera = cameraId;
                    }
                }
    
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }
    
  3. Set the Handler for child thread operations

  4. Call the cameramanager. Opencamera() method. The parameters are the CameraID just obtained, call back CameraDevice.StateCallback() and Handler, and get CameraDevice

  5. Get CameraCaptureSession. In the callback through CameraDevice.createCaptureSession()

  6. Use Device to call createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW) to build PreviewCaptureRequest. There are three modes: preview / photo / video

  7. Send createcapturesession through mCameraDevice. Capture means to send the request only once, and setRepeatingRequest means to send the request continuously

During use, Camera2 needs permission declarative confirmation. The first parameter of createCaptureSession needs two surfaces, one for preview and the other for recording

MediaRecorder

  1. First declare permissions

        <uses-permission android:name="android.permission.CAMERA"/>
        <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    
  2. Create through new MediaRecorder() to obtain the MediaRecorder instance

  3. Set the audio source through setAudioSource

  4. Set video source through setVideoSource

  5. Set the output format through setOutputFormat

  6. Set the audio coding format through setAudioEncoder. Compatibility needs to be considered in the project. AAC should be selected

  7. Set the video coding format through setVideoEncoder. Compatibility needs to be considered in the project. H264 should be selected

  8. Set the bit rate through setvideoencoding bitrate, which generally fluctuates between 1 resolution and 10 resolution. The higher the bit rate, the clearer the video, but the larger the video file.

  9. Set the number of frames through setVideoFrameRate, generally 30

  10. Set the width and height through setVideoSize. If the width and height are not appropriate, preview deformation and video playback failure will occur

    /adopt CameraManager.getCameraCharacteristics(Currently selected CameraID)obtain cameraCharacteristics Object, and then get size
        private Size getMathSize() {
            Size selectSize = null;
            try {
                CameraCharacteristics cameraCharacteristics = mCameraManager.getCameraCharacteristics(mCurrentSelectCamera);
                StreamConfigurationMap streamConfigurationMap = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                Size[] sizes = streamConfigurationMap.getOutputSizes(ImageFormat.JPEG);
                //Because I spread the preview all over the screen, I get the screen resolution directly
                DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
                int deviceWidth = displayMetrics.widthPixels; //Wide screen resolution
                int deviceHeight = displayMetrics.heightPixels; //High screen resolution
                /**
                 * Cycle 40 times to gradually increase the width range from the minimum to find the resolution that best matches the screen width,
                 * ,However, the larger the loop, the more mismatched the resolution obtained
                 */
                for (int j = 1; j < 41; j++) {
                    for (int i = 0; i < sizes.length; i++) { //Traverse all sizes
                        Size itemSize = sizes[i];
                        Log.e(TAG, "current itemSize wide=" + itemSize.getWidth() + "high=" + itemSize.getHeight());
                        //Judge that the current Size height is less than the screen width + J * 5 & & judge that the current Size height is greater than the screen width - J * 5 & & judge that the current Size width is less than the current screen height
                        if (itemSize.getHeight() < (deviceWidth + j * 5) && itemSize.getHeight() > (deviceWidth - j * 5)) {
                            if (selectSize != null) { //If a matching width has been found before
                                if (Math.abs(deviceHeight - itemSize.getWidth()) < Math.abs(deviceHeight - selectSize.getWidth())) { //Find the absolute value and calculate the dimension closest to the height of the equipment
                                    selectSize = itemSize;
                                    continue;
                                }
                            } else {
                                selectSize = itemSize;
                            }
    
                        }
                    }
                    if (selectSize != null) { //If it is not equal to null, the jump out loop has been found
                        break;
                    }
                }
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
            Log.e(TAG, "getMatchingSize2: Selected resolution width=" + selectSize.getWidth());
            Log.e(TAG, "getMatchingSize2: Selected resolution height=" + selectSize.getHeight());
            return selectSize;
        }
    
  11. Use setOrientationHint to rotate the video, otherwise the video preview is inverted, and the recorded video is the same

  12. Set the video preview through setPreviewDisplay

  13. Set the output file location through setOutputFile

  14. Prepare through MediaRecorder.prepare

  15. Start recording with MediaRecorder.Start

  16. Stop recording through MediaRecorder.Stop and MediaRecorder.reset, or release resources through MediaRecorder.release

MediaPlayer

  1. Create an instance of MediaPlayer through new MediaPlayer()

  2. Prepare to listen by setting

    mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mediaPlayer) {
            mMediaPlayer.start();
        }
    });
    
  3. Set video end settings

    mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                        @Override
                        public void onCompletion(MediaPlayer mediaPlayer) {
                            mMediaPlayer.stop();
                            mMediaPlayer.release();
                        }
                    });
    
  4. Set video resources through setDataSource

  5. Controls to set playback through setSurface

  6. Asynchronous preparation via prepareAsync

SoundPool

  1. Create an instance through the new SoundPool.Builder().setMaxStreams(5).build() builder pattern

  2. Play through the following code

    mSoundPool.play(sound.getSoundId(),0.5f,0.5f,1,0,1.0f);
    
  3. When closing, use SoundPool.unload and SoundPool.release() to release resources

CameraX

Through the above study of Camera2, we can see that the configuration of Camera2 is relatively complex, so CameraX is officially released for use to simplify user operations

Add dependency

    // CameraX core library using the camera2 implementation
    def camerax_version = "1.0.1"
    // The following line is optional, as the core library is included indirectly by camera-camera2
    implementation "androidx.camera:camera-core:${camerax_version}"
    implementation "androidx.camera:camera-camera2:${camerax_version}"
    // If you want to additionally use the CameraX Lifecycle library
    implementation "androidx.camera:camera-lifecycle:${camerax_version}"
    // If you want to additionally use the CameraX View class
    implementation "androidx.camera:camera-view:1.0.0-alpha27"
    // If you want to additionally use the CameraX Extensions library
    implementation "androidx.camera:camera-extensions:1.0.0-alpha27"

add permission

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

Create layout file

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".CameraXFragment">

        <androidx.camera.view.PreviewView
            android:id="@+id/preview_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <Button
            android:id="@+id/btn_take_photo"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="photograph"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent" />

        <Button
            android:id="@+id/btn_take_video"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="videotape"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/btn_jump"
            app:layout_constraintStart_toEndOf="@+id/btn_take_photo" />

        <Button
            android:id="@+id/btn_jump"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Jump"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
   </layout>

Create preview interface

//The ProcessCameraProvider of the life cycle can be bound
        // It binds the life cycle to the host so that you don't have to worry about turning the camera on and off
        mProviderListenableFuture
                = ProcessCameraProvider.getInstance(requireContext());
        //Register listening. The first parameter is a runnable, and the second parameter is a thread pool
        mProviderListenableFuture.addListener(() -> {
            try {
                // //Bind the camera life cycle to the activity life cycle, and camerax will release itself. Don't worry
                mProcessCameraProvider = mProviderListenableFuture.get();
            } catch (ExecutionException | InterruptedException e) {
                e.printStackTrace();
            }
            //Create preview to support angle conversion
            mPreview = new Preview.Builder().build();
            //Connect Preview to PreviewView to Preview
            mPreview.setSurfaceProvider(mCameraXBinding.previewView.getSurfaceProvider());
            //Create a capture of a picture
            mImageCapture = new ImageCapture.Builder()
                    .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
                    .setTargetResolution(new Size(1920, 1080))
                    .build();
            //Create a video capture
            mVideoCapture = new VideoCapture.Builder()
                    .setTargetRotation(mCameraXBinding.previewView.getDisplay().getRotation())
                    .setVideoFrameRate(30)
                    .setBitRate(5 * 1024 * 1024)
                    .build();

            ImageAnalysis imageAnalysis = new ImageAnalysis.Builder().build();
            imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(requireContext()),
                    image -> image.close());
            //Unbound
            mProcessCameraProvider.unbindAll();
            //Bind data to the camera's lifecycle
            mCamera = mProcessCameraProvider.bindToLifecycle(requireActivity(),
                    CameraSelector.DEFAULT_BACK_CAMERA //Select rear camera
                    , mVideoCapture, mPreview);
            //Click focus
            mCameraXBinding.previewView.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View view, MotionEvent motionEvent) {
                    float x = motionEvent.getX();
                    float y = motionEvent.getY();
                    FocusMeteringAction focusMeteringAction = new FocusMeteringAction.Builder(
                            mCameraXBinding.previewView.getMeteringPointFactory()
                                    .createPoint(x, y)).build();
                    mCamera.getCameraControl().startFocusAndMetering(focusMeteringAction);
                    return true;
                }
            });
        }, ContextCompat.getMainExecutor(requireContext()));

Start taking pictures

File file = new File(requireActivity().getExternalFilesDir("").getAbsoluteFile(), "camerax.jpg");
        if (file.exists()) {
            file.delete();
        }
        //Create data for picture files
        ImageCapture.OutputFileOptions outputFileOptions =
                new ImageCapture.OutputFileOptions.Builder(file).build();
        mProcessCameraProvider.bindToLifecycle(requireActivity(), CameraSelector.DEFAULT_BACK_CAMERA
                , mImageCapture);
        //Start taking pictures
        mImageCapture.takePicture(outputFileOptions, ContextCompat.getMainExecutor(requireActivity()),
                new ImageCapture.OnImageSavedCallback() {
                    @Override
                    public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
                        Uri savedUri = outputFileResults.getSavedUri();
                        if (savedUri == null) {
                            savedUri = Uri.fromFile(file);
                        }
                        Toast.makeText(requireActivity(), "????,???" + savedUri
                                , Toast.LENGTH_SHORT).show();
                    }

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

Start recording

File file = new File(requireActivity().getExternalFilesDir("").getAbsoluteFile(), "camerax.mp4");
        if (file.exists()) {
            file.delete();
        }
        //Data for creating video files, such as creating files
        VideoCapture.OutputFileOptions fileOptions = new VideoCapture.OutputFileOptions
                .Builder(file).build();
        if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        //Permission confirmation is required before taking photos
        mVideoCapture.startRecording(fileOptions, ContextCompat.getMainExecutor(requireActivity())
                , new VideoCapture.OnVideoSavedCallback() {
                    //Save video
                    @Override
                    public void onVideoSaved(@NonNull VideoCapture.OutputFileResults outputFileResults) {
                        Toast.makeText(requireActivity(), "Video saved"
                                + outputFileResults.getSavedUri().getPath(), Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onError(int videoCaptureError, @NonNull String message, @Nullable Throwable cause) {
                        Log.e("TAG", "onError: ");
                        //The video will come here in less than a second, but the video is still generated, so it has to be deleted
                        file.delete();
                    }
                });

Stop recording

//Judge whether the video Capture is empty
if (mVideoCapture != null){
            //Stop recording
            mVideoCapture.stopRecording();
        }

Full code address

https://gitee.com/thereisnoif/media-recorder-demo

Tags: Java Android

Posted on Mon, 20 Sep 2021 20:04:35 -0400 by Aebx