whycxzp
2024-07-26 263432ae8c0f6f6dc5cc214772f1863389184add
优化线程和释放资源
1个文件已修改
244 ■■■■■ 已修改文件
app/src/main/java/com/whyc/widget/Camera2TextureView2.java 244 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/whyc/widget/Camera2TextureView2.java
@@ -3,6 +3,7 @@
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
@@ -11,7 +12,6 @@
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.MediaRecorder;
@@ -27,16 +27,19 @@
import android.util.Size;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.whyc.util.BitmapUtil;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -68,21 +71,35 @@
    private ImageReader mImageReader;
    private Surface surfaceForStream;
    private Handler mHandler;
    /**线程处理器 分别处理 录像,预览,拍照*/
    private Handler mainHandler = new Handler(Looper.getMainLooper());
    private HandlerThread mThreadHandler;
    private HandlerThread videoThread;
    private HandlerThread previewThread;
    private HandlerThread captureThread;
    private HandlerThread imageThread;
    private Handler videoThreadHandler;
    private Handler previewThreadHandler;
    private Handler captureThreadHandler;
    private Handler imageThreadHandler;
    ScheduledExecutorService scheduledExecutorService;
    //主页面的视图
    private LinearLayout llUpText;
    private TextView tvDevice;
    private int weight = 3840;
    private int wight = 3840;
    private int height = 2160;
//    private int wight = 1920;
//    private int height = 1080;
    private int videoWidth = 1920;
    private int videoHeight = 1080;
    Size outputSizes;
    Size outputSizes = new Size(wight,height);
    public Camera2TextureView2(Context context) {
        super(context,null);
@@ -99,14 +116,6 @@
            });*/
        mContext = context;
        mThreadHandler = new HandlerThread("camera2");
        mThreadHandler.start();
        mHandler = new Handler(mThreadHandler.getLooper());
        startBackgroundThread();
    }
    public void init(LinearLayout llUpText, TextView tvDevice) {
@@ -120,8 +129,10 @@
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
            //预览surface
            SurfaceTexture surfaceTexture = getSurfaceTexture();
            surfaceTexture.setDefaultBufferSize(videoWidth, videoHeight);
            surfaceTexture.setDefaultBufferSize(outputSizes.getWidth(), outputSizes.getHeight());
            previewSurface = new Surface(surfaceTexture);
            //页面加载后初始化线程处理器
            initPreviewThreadHandler();
            initCamera2();
        }
        @Override
@@ -152,15 +163,9 @@
                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();
        }
@@ -187,23 +192,10 @@
        @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();
            }*/
            //拍照的接收器
            mImageReader = ImageReader.newInstance(outputSizes.getWidth(), outputSizes.getHeight(), ImageFormat.YUV_420_888, 2);
            //            mImageReader = ImageReader.newInstance(outputSizes.getWidth(), outputSizes.getHeight(), ImageFormat.JPEG, 4);
            //创建主摄像头会话并预览
            createPreviewSession();
        }
@@ -222,7 +214,7 @@
    private void createPreviewSession() {
        try {
            mainCameraDevice.createCaptureSession(Arrays.asList(previewSurface,surfaceForStream), new CameraCaptureSession.StateCallback() {
            mainCameraDevice.createCaptureSession(Arrays.asList(previewSurface, mImageReader.getSurface()), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    mainCaptureSession = session;
@@ -247,13 +239,12 @@
    private void startPreview() {
        //启动预览
        try {
            mainCaptureSession.setRepeatingRequest(previewCaptureBuilder.build(), null, mHandler);
            mainCaptureSession.setRepeatingRequest(previewCaptureBuilder.build(), null, previewThreadHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
    private Surface recorderSurface;
    private File recorderFile;
    private String recorderPath;
    private boolean isRecording = false;
@@ -280,31 +271,14 @@
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
    }
    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(){
        if(mMediaRecorder!=null) {
            mMediaRecorder.reset();
        }
        initRecorder();
        //线程开启
        initThreadHandlerForRecording();
        mImageReader.setOnImageAvailableListener(mImageReaderListener, imageThreadHandler);
        try{
            mMediaRecorder.prepare();
            mMediaRecorder.start();
@@ -323,7 +297,7 @@
                        videoCaptureBuilder.addTarget(mMediaRecorder.getSurface());
                        // 开始录制视频
                        subCaptureSession.setRepeatingRequest(videoCaptureBuilder.build(), null, backgroundHandler);
                        subCaptureSession.setRepeatingRequest(videoCaptureBuilder.build(), null, videoThreadHandler);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
@@ -342,7 +316,7 @@
                public void run() {
                    takePhoto();
                }
            }, 2, 2, TimeUnit.SECONDS);
            }, 5, 2, TimeUnit.SECONDS);
//            focus();
        } catch (CameraAccessException e) {
            e.printStackTrace();
@@ -358,11 +332,13 @@
            // 设置对焦模式
            //            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", "拍照成功");
                if(captureCaptureBuilder == null) {
                    captureCaptureBuilder = mainCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
                    captureCaptureBuilder.addTarget(mImageReader.getSurface());
                    captureCaptureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
                }
                mainCaptureSession.capture(captureCaptureBuilder.build(),null, captureThreadHandler);
                Log.d("Camera2", "拍照成功:");
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
@@ -371,18 +347,65 @@
        }
    }
    private ImageReader.OnImageAvailableListener mImageReaderListener = reader -> {
            // 获取到拍照的图像数据
            Image image = reader.acquireNextImage();
        Log.d("Camera2", "获取到图像数据:");
        try {
            // 获取到拍照的图像数据
            //这里只是演示test
            llUpText.setVisibility(View.VISIBLE);
            tvDevice.setText("这是测试的动态赋值");
            // 保存图片到相册
            saveImageToGallery(image);
            //            llUpText.setVisibility(View.VISIBLE);
            //            tvDevice.setText("这是测试的动态赋值");
            // 保存图片到相册-这种方式是JEPG格式
            //            saveImageToGallery(image);
            //YUV420
            //            int I420size = image.getWidth()*image.getHeight()*3/2;
            //            byte[] nv21 = new byte[I420size];
            //            YUVUtil.YUVToNV21_NV12(image,nv21,outputSizes.getWidth(),outputSizes.getHeight(),"NV21");
            List<byte[]> planetBytes = getPlanetBytes(image);
            byte[] nv21 = byteMergerAll(planetBytes.get(0), planetBytes.get(1));
            Bitmap bitmap = BitmapUtil.nv21ToBitmap(nv21, outputSizes.getWidth(), outputSizes.getHeight());
            BitmapUtil.saveBitmapToFile(bitmap);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            image.close();
        }
    };
    private List<byte[]> getPlanetBytes(Image image) {
        Image.Plane[] planes = image.getPlanes();
        int remaining0 = planes[0].getBuffer().remaining();
//        int remaining1 = planes[1].getBuffer().remaining();
        int remaining2 = planes[2].getBuffer().remaining();
        //分别准备三个数组接收YUV分量。
        byte[] yRawSrcBytes = new byte[remaining0];
//        byte[] uRawSrcBytes = new byte[remaining1];
        byte[] vRawSrcBytes = new byte[remaining2];
        planes[0].getBuffer().get(yRawSrcBytes);
//        planes[1].getBuffer().get(uRawSrcBytes);
        planes[2].getBuffer().get(vRawSrcBytes);
        List<byte[]> yuvBytes = new ArrayList<>();
        yuvBytes.add(yRawSrcBytes);
        yuvBytes.add(vRawSrcBytes);
        return yuvBytes;
    }
    private static byte[] byteMergerAll(byte[]... values) {
        int length_byte = 0;
        for (int i = 0; i < values.length; i++) {
            length_byte += values[i].length;
        }
        byte[] all_byte = new byte[length_byte];
        int countLength = 0;
        for (int i = 0; i < values.length; i++) {
            byte[] b = values[i];
            System.arraycopy(b, 0, all_byte, countLength, b.length);
            countLength += b.length;
        }
        return all_byte;
    }
    private void saveImageToGallery(Image image) {
        // 定义图片的保存路径和文件名
@@ -415,22 +438,20 @@
    }
    public void stopRecording() {
        stopBackgroundThread();
        try {
            // 停止录制视频,关闭录像请求
            mMediaRecorder.stop();
            //关闭录制视频会话
            subCaptureSession.close();
            subCaptureSession.stopRepeating();
            //关闭拍照会话
            scheduledExecutorService.shutdown();
            mainCaptureSession.close();
            scheduledExecutorService.shutdownNow();
            //停止画面图片监听
            mImageReader.close();
            mImageReader.setOnImageAvailableListener(null, null);
            //终止线程
            stopThreadHandlerForRecording();
           //这里只是演示test
            llUpText.setVisibility(View.GONE);
            //启动预览
            createPreviewSession();
//            llUpText.setVisibility(View.GONE);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
@@ -452,4 +473,61 @@
                    Toast.makeText(mContext, "视频已保存至相册", Toast.LENGTH_SHORT).show();
                });
    }
    private void initPreviewThreadHandler(){
        //预览的处理线程
        previewThread = new HandlerThread("camera2Preview");
        previewThread.start();
        previewThreadHandler = new Handler(previewThread.getLooper());
        //图像监测的处理线程
        imageThread = new HandlerThread("camera2Image");
        imageThread.start();
        imageThreadHandler = new Handler(imageThread.getLooper());
    }
    /**
     *  录像      一个线程处理器
     *  拍照      一个线程处理器
     *  图像监测  一个线程处理器
     */
    private void initThreadHandlerForRecording() {
        //录像的处理线程
        videoThread = new HandlerThread("Camera2Video");
        videoThread.start();
        videoThreadHandler = new Handler(videoThread.getLooper());
        //拍照的处理线程
        captureThread = new HandlerThread("camera2Capture");
        captureThread.start();
        captureThreadHandler = new Handler(captureThread.getLooper());
        //图像监测的处理线程
        if(imageThreadHandler == null) {
            imageThread = new HandlerThread("camera2Image");
            imageThread.start();
            imageThreadHandler = new Handler(imageThread.getLooper());
        }
    }
    private void stopThreadHandlerForRecording() {
        try {
            videoThread.quitSafely();
            videoThread.join();
            videoThread = null;
            videoThreadHandler = null;
            captureThread.quitSafely();
            captureThread.join();
            captureThread = null;
            captureThreadHandler = null;
            imageThread.quitSafely();
            imageThread.join();
            imageThread = null;
            imageThreadHandler = null;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}