From 263432ae8c0f6f6dc5cc214772f1863389184add Mon Sep 17 00:00:00 2001
From: whycxzp <glperry@163.com>
Date: 星期五, 26 七月 2024 14:36:22 +0800
Subject: [PATCH] 优化线程和释放资源

---
 app/src/main/java/com/whyc/widget/Camera2TextureView2.java |  244 ++++++++++++++++++++++++++++++++----------------
 1 files changed, 161 insertions(+), 83 deletions(-)

diff --git a/app/src/main/java/com/whyc/widget/Camera2TextureView2.java b/app/src/main/java/com/whyc/widget/Camera2TextureView2.java
index bd959f9..80f2920 100644
--- a/app/src/main/java/com/whyc/widget/Camera2TextureView2.java
+++ b/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 {
             // 鑾峰彇鍒版媿鐓х殑鍥惧儚鏁版嵁
-            Image image = reader.acquireNextImage();
             //杩欓噷鍙槸婕旂ずtest
-            llUpText.setVisibility(View.VISIBLE);
-            tvDevice.setText("杩欐槸娴嬭瘯鐨勫姩鎬佽祴鍊�");
-            // 淇濆瓨鍥剧墖鍒扮浉鍐�
-            saveImageToGallery(image);
+            //            llUpText.setVisibility(View.VISIBLE);
+            //            tvDevice.setText("杩欐槸娴嬭瘯鐨勫姩鎬佽祴鍊�");
+            // 淇濆瓨鍥剧墖鍒扮浉鍐�-杩欑鏂瑰紡鏄疛EPG鏍煎紡
+            //            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();
+        }
+    }
 }

--
Gitblit v1.9.1