| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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); |
| | |
| | | });*/ |
| | | |
| | | mContext = context; |
| | | mThreadHandler = new HandlerThread("camera2"); |
| | | mThreadHandler.start(); |
| | | mHandler = new Handler(mThreadHandler.getLooper()); |
| | | |
| | | startBackgroundThread(); |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | public void init(LinearLayout llUpText, TextView tvDevice) { |
| | |
| | | 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 |
| | |
| | | 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(); |
| | | } |
| | |
| | | @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(); |
| | | } |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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(); |
| | |
| | | videoCaptureBuilder.addTarget(mMediaRecorder.getSurface()); |
| | | |
| | | // 开始录制视频 |
| | | subCaptureSession.setRepeatingRequest(videoCaptureBuilder.build(), null, backgroundHandler); |
| | | subCaptureSession.setRepeatingRequest(videoCaptureBuilder.build(), null, videoThreadHandler); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | } |
| | |
| | | public void run() { |
| | | takePhoto(); |
| | | } |
| | | }, 2, 2, TimeUnit.SECONDS); |
| | | }, 5, 2, TimeUnit.SECONDS); |
| | | // focus(); |
| | | } catch (CameraAccessException e) { |
| | | e.printStackTrace(); |
| | |
| | | // 设置对焦模式 |
| | | // 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(); |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | 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) { |
| | | // 定义图片的保存路径和文件名 |
| | |
| | | } |
| | | |
| | | 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 { |
| | |
| | | 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(); |
| | | } |
| | | } |
| | | } |