whycxzp
2024-07-24 06327334203607e2e77d43407fbbdbcfd5a700a3
双摄-主摄预览拍照,副摄录像
1个文件已修改
296 ■■■■■ 已修改文件
app/src/main/java/com/whyc/widget/Camera2TextureView2.java 296 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/whyc/widget/Camera2TextureView2.java
@@ -4,14 +4,12 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.ImageFormat;
import android.graphics.Rect;
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.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
@@ -26,7 +24,7 @@
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Range;
import android.util.Size;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
@@ -46,19 +44,29 @@
import static android.content.ContentValues.TAG;
import static android.os.Environment.DIRECTORY_DOCUMENTS;
/**这个采用TEMPLATE_RECORD和TEMPLATE_VIDEO_SNAPSHOT模板,TEMPLATE_RECORD模板是录制视频*/
/**
 * 这个采用TEMPLATE_RECORD和TEMPLATE_VIDEO_SNAPSHOT模板,TEMPLATE_RECORD模板是录制视频
 * 改为:
 * 副摄 ->录像
 * 主摄-> 拍照
 * */
public class Camera2TextureView2 extends TextureView {
    private Context mContext;
    private CameraDevice mCameraDevice;
    private CaptureRequest.Builder captureBuilder = null;
    private CameraCaptureSession mCaptureSession;
    //主摄,后摄
    private CameraDevice mainCameraDevice;
    //副摄,前摄
    private CameraDevice subCameraDevice;
    private CaptureRequest.Builder captureCaptureBuilder = null;
    private CaptureRequest.Builder videoCaptureBuilder = null;
    private CaptureRequest.Builder previewCaptureBuilder = null;
    private CameraCaptureSession mainCaptureSession;
    private CameraCaptureSession subCaptureSession;
    private MediaRecorder mMediaRecorder;
    private Surface previewSurface;
    private ImageReader mImageReader;
    private Surface surfaceForStream;
    CaptureRequest.Builder recordRequest;
    private Handler mHandler;
    private Handler mainHandler = new Handler(Looper.getMainLooper());
@@ -70,12 +78,12 @@
    private LinearLayout llUpText;
    private TextView tvDevice;
    private int weight = 128;
    private int height = 72;
    private int weight = 3840;
    private int height = 2160;
    private int imageWeight = 1920;
    private int imageHeight = 1080;
    Range<Integer> rangeMin;
    private int videoWidth = 1920;
    private int videoHeight = 1080;
    Size outputSizes;
    public Camera2TextureView2(Context context) {
        super(context,null);
@@ -83,7 +91,7 @@
    public Camera2TextureView2(Context context, AttributeSet attrs) {
        super(context, attrs);
        executorService = Executors.newScheduledThreadPool(4);
//        executorService = Executors.newScheduledThreadPool(4);
        /*String url = "http://192.168.10.79:8919/fg/server/timestamp";
        executorService.execute(()-> {
                HttpReqData httpReqData = new HttpReqData(url);
@@ -95,6 +103,11 @@
        mThreadHandler = new HandlerThread("camera2");
        mThreadHandler.start();
        mHandler = new Handler(mThreadHandler.getLooper());
        startBackgroundThread();
    }
    public void init(LinearLayout llUpText, TextView tvDevice) {
@@ -106,6 +119,10 @@
    private SurfaceTextureListener mSurfaceTextureListener = new SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
            //预览surface
            SurfaceTexture surfaceTexture = getSurfaceTexture();
            surfaceTexture.setDefaultBufferSize(videoWidth, videoHeight);
            previewSurface = new Surface(surfaceTexture);
            initCamera2();
        }
        @Override
@@ -128,30 +145,32 @@
//        ActivityCompat.requestPermissions(Camera2TextureViewActivity.this, permissionArray, 1);
        CameraManager cm = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
        try {
            String cameraId = cm.getCameraIdList()[0];
            CameraCharacteristics cameraCharacteristics = cm.getCameraCharacteristics(cameraId);
            StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            Range<Integer>[] availableFpsRanges = cameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
            rangeMin = availableFpsRanges[0];
            cm.openCamera(cameraId,mDeviceStateCallback,null);
            //获取前摄像头
            String[] cameraIds = cm.getCameraIdList();
            for (int i = 0; i < cameraIds.length; i++) {
                String cameraId = cameraIds[i];
                CameraCharacteristics cameraCharacteristics = cm.getCameraCharacteristics(cameraId);
                if(cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT){
                    cm.openCamera(cameraId,subDeviceStateCallback,null);
                }else if(cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK){
                    StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                    outputSizes = new Size(weight,height);
                    cm.openCamera(cameraId,mainDeviceStateCallback,null);
                }
            }
            //拍照的接收器
            mImageReader = ImageReader.newInstance(outputSizes.getWidth(), outputSizes.getHeight(), ImageFormat.JPEG, 1);
            mImageReader.setOnImageAvailableListener(mImageReaderListener, null);
            surfaceForStream = mImageReader.getSurface();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    private CameraDevice.StateCallback mDeviceStateCallback = new CameraDevice.StateCallback() {
    private CameraDevice.StateCallback subDeviceStateCallback = new CameraDevice.StateCallback() {
            @Override
            public void onOpened(CameraDevice cameraDevice) {
                mCameraDevice = cameraDevice;
                SurfaceTexture surfaceTexture = getSurfaceTexture();
                surfaceTexture.setDefaultBufferSize(weight, height);
                previewSurface = new Surface(surfaceTexture);
                try {
                    createPreviewSession();
                }catch (Exception e){
                    e.printStackTrace();
                }
                subCameraDevice = cameraDevice;
            }
            @Override
@@ -165,13 +184,54 @@
            }
    };
    private CameraDevice.StateCallback mainDeviceStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(CameraDevice cameraDevice) {
            mainCameraDevice = cameraDevice;
            //初始化主摄像头的会话
            try {
                mainCameraDevice.createCaptureSession(Arrays.asList(previewSurface, surfaceForStream), new CameraCaptureSession.StateCallback() {
                    @Override
                    public void onConfigured(@NonNull CameraCaptureSession session) {
                        mainCaptureSession = session;
                    }
                    @Override
                    public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                    }
                }, null);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {
        }
        @Override
        public void onError(@NonNull CameraDevice camera, int error) {
        }
    };
    private void createPreviewSession() {
        try {
            mCameraDevice.createCaptureSession(Arrays.asList(previewSurface), new CameraCaptureSession.StateCallback() {
            mainCameraDevice.createCaptureSession(Arrays.asList(previewSurface,surfaceForStream), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    mCaptureSession = session;
                    startPreview(mCameraDevice);
                    mainCaptureSession = session;
                    try {
                        previewCaptureBuilder = mainCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                    previewCaptureBuilder.addTarget(previewSurface);
                    startPreview();
                }
                @Override
@@ -183,36 +243,16 @@
            e.printStackTrace();
        }
    }
    private void startPreview(CameraDevice cameraDevice) {
    private void startPreview() {
        //启动预览
        try {
            captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            captureBuilder.addTarget(previewSurface);
            /*设置预览的界面*/
            //设置帧率
            captureBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
                    rangeMin);
            /*//设置自动对焦模式
            captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                    CaptureRequest.CONTROL_AF_MODE_AUTO);
            // 设置自动曝光模式
            captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                    CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
            // 开始对焦
            captureBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
                    CameraMetadata.CONTROL_AF_TRIGGER_START);*/
            captureBuilder.set(CaptureRequest.JPEG_ORIENTATION,  90);
            mCaptureSession.setRepeatingRequest(captureBuilder.build(), null, mHandler);
            mainCaptureSession.setRepeatingRequest(previewCaptureBuilder.build(), null, mHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
    private Surface recorderSurface;
    private int videoWidth = 1280;
    private int videoHeight = 720;
    private File recorderFile;
    private String recorderPath;
    private boolean isRecording = false;
@@ -228,8 +268,6 @@
        recorderPath = recorderFile.getAbsolutePath()+File.separator + System.currentTimeMillis() + ".mp4";
        Log.e(TAG, "视频路径:" + recorderPath);
        mMediaRecorder = new MediaRecorder();
//        recorderSurface = MediaCodec.createPersistentInputSurface();
//        mMediaRecorder.setInputSurface(recorderSurface);
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
@@ -239,26 +277,29 @@
        mMediaRecorder.setVideoSize(videoWidth, videoHeight);
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
    }
        // 开始录制
        /*try {
            mMediaRecorder.prepare();
        } catch (IOException e) {
    private Handler backgroundHandler;
    private HandlerThread backgroundThread;
    private void startBackgroundThread() {
        backgroundThread = new HandlerThread("Camera Background");
        backgroundThread.start();
        backgroundHandler = new Handler(backgroundThread.getLooper());
    }
    private void stopBackgroundThread() {
        backgroundThread.quitSafely();
        try {
            backgroundThread.join();
            backgroundThread = null;
            backgroundHandler = null;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        }
    }
    public void createRecorderSession(){
        //关闭预览请求,启动录像相关
        try {
            mCaptureSession.stopRepeating();
        }catch (Exception e){
            e.printStackTrace();
        }
        mImageReader = ImageReader.newInstance(imageWeight, imageHeight, ImageFormat.JPEG, 1);
        surfaceForStream = mImageReader.getSurface();
        mImageReader.setOnImageAvailableListener(mImageReaderListener, mainHandler);
        if(mMediaRecorder!=null) {
            mMediaRecorder.reset();
        }
@@ -270,34 +311,20 @@
            e.printStackTrace();
        }
        try {
            mCameraDevice.createCaptureSession(Arrays.asList(previewSurface,mMediaRecorder.getSurface(),surfaceForStream), new CameraCaptureSession.StateCallback() {
//            mCameraDevice.createCaptureSession(Arrays.asList(mMediaRecorder.getSurface(),surfaceForStream), new CameraCaptureSession.StateCallback() {
            subCameraDevice.createCaptureSession(Arrays.asList(mMediaRecorder.getSurface()), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    mCaptureSession = session;
                    subCaptureSession = session;
                    try {
                        //camera2 视频录制模式
                        recordRequest = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
                        videoCaptureBuilder = subCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
                        recordRequest.addTarget(previewSurface);
                        recordRequest.addTarget(mMediaRecorder.getSurface());
                        videoCaptureBuilder.addTarget(mMediaRecorder.getSurface());
                        mCaptureSession.setRepeatingRequest(recordRequest.build(), null, mHandler); // 开始录制视频
                        //camera2 捕捉视频快照,1秒钟1次的定时任务
                        CaptureRequest.Builder snapshotBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_VIDEO_SNAPSHOT);
                        snapshotBuilder.addTarget(surfaceForStream);
                        scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
                        scheduledExecutorService.scheduleAtFixedRate(() -> {
                            try {
                                session.capture(snapshotBuilder.build(), null, null);
                            }catch (Exception e){
                                e.printStackTrace();
                            }
                        }, 1, 3, TimeUnit.SECONDS);
                    } catch (Exception e) {                        e.printStackTrace();
                        // 开始录制视频
                        subCaptureSession.setRepeatingRequest(videoCaptureBuilder.build(), null, backgroundHandler);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
@@ -306,51 +333,53 @@
                }
            }, null);
//            CaptureRequest.Builder recordRequest = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
            //camera2 3秒钟1次的定时任务
            //对焦并拍照
            scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
            scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    takePhoto();
                }
            }, 2, 2, TimeUnit.SECONDS);
//            focus();
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
    private void takePhoto() {
        try {
            // 对焦完成,开始拍照
            /*==========摄像头的模式设置==========*/
            // 设置自动白平衡
            //            captureCaptureBuilder.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_AUTO);
            // 设置对焦模式
            //            captureCaptureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            try {
                CaptureRequest.Builder captureRequest = mainCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
                captureRequest.addTarget(surfaceForStream);
                captureRequest.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
                mainCaptureSession.capture(captureRequest.build(),null, mHandler);
                Log.d("Camera2", "拍照成功");
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    private ImageReader.OnImageAvailableListener mImageReaderListener = reader -> {
        /*long now = System.currentTimeMillis();
        SharedPreferences camera2Time = mContext.getSharedPreferences("camera2Time", Context.MODE_PRIVATE);
        long lastTime = camera2Time.getLong("time", 0);
        if (lastTime == 0 || now-lastTime > 1000) {
            //这里只是演示test
            llUpText.setVisibility(View.VISIBLE);
            tvDevice.setText("这是测试的动态赋值");
            camera2Time.edit().putLong("time", now).apply();
            // 获取到拍照的图像数据
            Image image = reader.acquireNextImage();
            // 获取图片的字节数组
            ByteBuffer buffer = image.getPlanes()[0].getBuffer();
            byte[] data = new byte[buffer.remaining()];
            buffer.get(data);
            // 释放图像资源
            image.close();
            // 保存图片到相册
            saveImageToGallery(data);
        }else{
            // 获取到拍照的图像数据
            Image image = reader.acquireNextImage();
            image.close();
        }*/
            // 获取到拍照的图像数据
            Image image = reader.acquireNextImage();
            //这里只是演示test
            llUpText.setVisibility(View.VISIBLE);
            tvDevice.setText("这是测试的动态赋值");
            // 保存图片到相册
            executorService.execute(() -> {
                saveImageToGallery(image);
            });
            saveImageToGallery(image);
    };
@@ -385,18 +414,23 @@
    }
    public void stopRecording() {
        stopBackgroundThread();
        try {
            // 停止录制视频,关闭录像请求
            mMediaRecorder.stop();
            //关闭定时视频快照
            scheduledExecutorService.shutdownNow();
            mCaptureSession.stopRepeating();
            //关闭录制视频会话
            subCaptureSession.close();
            //关闭拍照会话
            mainCaptureSession.close();
            //停止画面图片监听
            mImageReader.close();
           //这里只是演示test
            llUpText.setVisibility(View.GONE);
            //启动预览
            createPreviewSession();
//            createPreviewSession();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {