用ChatGPT写Camera2在录制视频中拍照且不中断录制问题

提问记录

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

调试代码

从回答的问题中可以看到,核心的代码已基本都给出来。这里我们可以根据经验补全XML代码或继续问细节代码都行(当然也可以直接贴报错代码进行提问)。
在这里插入图片描述

调整后代码

xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextureView
        android:id="@+id/textureview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <Button
            android:id="@+id/start"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="startRtmp"
            android:text="开始推流"/>
        <Button
            android:id="@+id/stop"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="stopRtmp"
            android:text="关闭推流"/>
        <Button
            android:id="@+id/take_photo"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="takePhoto"
            android:text="拍照"/>
    </LinearLayout>
</RelativeLayout>

Activity代码

package runde.mark.demo;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaCodec;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;

/**
 * Created by 玉念聿辉.
 * User: 吴明辉
 * Date: 2023/5/4
 * Time: 10:02
 */
public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    private Size videoSize;
    private Size previewSize;

    private CameraDevice cameraDevice;
    private CameraCaptureSession cameraCaptureSession;
    private CaptureRequest.Builder captureRequestBuilder;
    private MediaRecorder mediaRecorder;
    private TextureView textureView;
    private Surface previewSurface;
    private Surface recordSurface;
    private ImageReader imageReader;

    private Handler mHandler;
    private boolean isTakePhoto = false;


    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.camera);
        Button start = findViewById(R.id.start);
        start.setText("开始录制");
        Button stop = findViewById(R.id.stop);
        stop.setText("关闭录制");

        HandlerThread mThreadHandler = new HandlerThread("CAMERA2");
        mThreadHandler.start();
        mHandler = new Handler(mThreadHandler.getLooper());

        // 初始化 MediaRecorder
        startRecordingVideo();

        // 创建 ImageReader,并设置监听器
        imageReader = ImageReader.newInstance(1920, 1080, ImageFormat.JPEG, 1);
        imageReader.setOnImageAvailableListener(imageReader -> {
            // 获取最新的图片
            Image image = imageReader.acquireLatestImage();

            // 将图片保存为文件
            if (isTakePhoto) {
                FileOutputStream output = null;
                try {
                    // 创建保存图片的文件
                    File pictureFile = new File(getExternalFilesDir(null), System.currentTimeMillis() + ".jpg");
                    Log.e(TAG, "onImageAvailable  图片地址: " + pictureFile.getAbsolutePath());
                    output = new FileOutputStream(pictureFile);
                    ByteBuffer buffer = image.getPlanes()[0].getBuffer();
                    byte[] bytes = new byte[buffer.remaining()];
                    buffer.get(bytes);
                    output.write(bytes);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (output != null) {
                        try {
                            output.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    isTakePhoto = false;
                }
            }
            if (image != null) {
                image.close();
            }
        }, mHandler);

        // 设置监听器,并打开相机并启动预览
        textureView = findViewById(R.id.textureview);
        textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surfaceTexture, int i, int i1) {
                // 打开相机并启动预览
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    openCamera();
                }
            }

            @Override
            public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surfaceTexture, int i, int i1) {

            }

            @Override
            public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surfaceTexture) {
                return false;
            }

            @Override
            public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surfaceTexture) {

            }
        });

    }

    // 打开相机
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void openCamera() {
        CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
        try {
            // 获取可用的摄像头列表
            String[] cameraIds = cameraManager.getCameraIdList();

            // 选择后置摄像头作为默认摄像头
            String cameraId = null;
            for (String id : cameraIds) {
                CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(id);
                if (cameraCharacteristics.get(CameraCharacteristics.LENS_FACING)
                        == CameraCharacteristics.LENS_FACING_BACK) {
                    cameraId = id;
                    break;
                }
            }

            // 获取相机支持的预览尺寸和视频尺寸
            CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
            StreamConfigurationMap streamConfigurationMap = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            previewSize = streamConfigurationMap.getOutputSizes(SurfaceTexture.class)[0];
            videoSize = chooseVideoSize(streamConfigurationMap.getOutputSizes(MediaRecorder.class));

            // 打开相机并启动预览
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
            cameraManager.openCamera(cameraId, new CameraDevice.StateCallback() {
                @RequiresApi(api = Build.VERSION_CODES.M)
                @Override
                public void onOpened(CameraDevice cameraDevice) {
                    MainActivity.this.cameraDevice = cameraDevice;

                    try {
                        // 创建预览请求,以及对应的 Surface
                        captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
                        SurfaceTexture surfaceTexture = textureView.getSurfaceTexture();
                        surfaceTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
                        previewSurface = new Surface(surfaceTexture);
                        captureRequestBuilder.addTarget(previewSurface);

                        // 创建录制请求,以及对应的 Surface
                        captureRequestBuilder.addTarget(recordSurface);

                        // 添加拍照 Surface
                        captureRequestBuilder.addTarget(imageReader.getSurface());

                        // 创建 CameraCaptureSession
                        cameraDevice.createCaptureSession(Arrays.asList(previewSurface, recordSurface, imageReader.getSurface()),
                                new CameraCaptureSession.StateCallback() {
                                    @Override
                                    public void onConfigured(CameraCaptureSession cameraCaptureSession) {
                                        MainActivity.this.cameraCaptureSession = cameraCaptureSession;

                                        try {
                                            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                                                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                                            cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(),
                                                    null, mHandler);
                                        } catch (CameraAccessException e) {
                                            Log.e(TAG, "Failed to start preview", e);
                                        }
                                    }

                                    @Override
                                    public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
                                        Log.e(TAG, "Failed to create capture session");
                                    }
                                }, mHandler);
                    } catch (CameraAccessException e) {
                        Log.e(TAG, "Failed to create capture request", e);
                    }
                }

                @Override
                public void onDisconnected(CameraDevice cameraDevice) {
                    cameraDevice.close();
                    MainActivity.this.cameraDevice = null;
                }

                @Override
                public void onError(CameraDevice cameraDevice, int error) {
                    cameraDevice.close();
                    MainActivity.this.cameraDevice = null;
                }
            }, mHandler);
        } catch (CameraAccessException e) {
            Log.e(TAG, "Failed to get camera id list", e);
        }
    }

    // 选择视频尺寸
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private Size chooseVideoSize(Size[] sizes) {
        for (Size size : sizes) {
            if (size.getWidth() ==
                    size.getHeight() * 16 / 9 &&
                    size.getWidth() <= 1920) {
                return size;
            }
        }
        return sizes[0];
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void updateView() {
        try {
            captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
            captureRequestBuilder.addTarget(previewSurface);

            // 创建录制请求,以及对应的 Surface
            captureRequestBuilder.addTarget(recordSurface);

            // 添加拍照 Surface
            captureRequestBuilder.addTarget(imageReader.getSurface());
            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, mHandler);
            Log.e(TAG, "updateView");
        } catch (CameraAccessException e) {
            Log.e(TAG, "Failed to start preview", e);
        }
    }


    // 启动录制视频
    private void startRecordingVideo() {
        try {
            // 配置 MediaRecorder
            if (mediaRecorder == null) {
                mediaRecorder = new MediaRecorder();
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    recordSurface = MediaCodec.createPersistentInputSurface();
                }
            } else {
                mediaRecorder.reset();
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                mediaRecorder.setInputSurface(recordSurface);
            }
            mediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
            mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
            mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_2_TS);
            mediaRecorder.setOutputFile(getOutputFile());
            mediaRecorder.setVideoEncodingBitRate(5 * 1024 * 1024);
            mediaRecorder.setVideoFrameRate(30);
            mediaRecorder.setVideoSize(1920, 1080);
            mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
            mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
            mediaRecorder.prepare();
            mediaRecorder.start();

            //再次录制时刷新预览
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && cameraCaptureSession != null) {
                updateView();
            }
        } catch (IOException e) {
            Log.e(TAG, "Failed to start recording video", e);
        }
    }

    // 停止录制视频
    private void stopRecordingVideo() {
        if (mediaRecorder != null) {
            mediaRecorder.stop();
            mediaRecorder.reset();
        }
    }

    // 获取输出文件路径
    private String getOutputFile() {
        File file = new File(this.getExternalFilesDir(null), System.currentTimeMillis() + ".ts");
        Log.e(TAG, "getOutputFile  视频路径: " + file.getAbsolutePath());
        return file.getAbsolutePath();
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public void startRtmp(View view) {
        Log.e(TAG, "startRtmp: 开始录制");
        startRecordingVideo();
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public void stopRtmp(View view) {
        Log.e(TAG, "stopRtmp: 关闭录制");
        stopRecordingVideo();
    }

    public void takePhoto(View view) {
        Log.e(TAG, "takePhoto: 拍照");
        isTakePhoto = true;
    }
}

记得添加权限

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

运行效果

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_35350654/article/details/130485177
今日推荐