package com.whyc.widget; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; 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.MediaRecorder; import android.media.MediaScannerConnection; import android.net.Uri; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.support.annotation.NonNull; import android.util.AttributeSet; import android.util.Log; 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 java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import static android.content.ContentValues.TAG; import static android.os.Environment.DIRECTORY_DOCUMENTS; /** * 这个采用TEMPLATE_RECORD和TEMPLATE_VIDEO_SNAPSHOT模板,TEMPLATE_RECORD模板是录制视频 * 改为: * 副摄 ->录像 * 主摄-> 拍照 * */ public class Camera2TextureView2 extends TextureView { private Context mContext; //主摄,后摄 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; private Handler mHandler; private Handler mainHandler = new Handler(Looper.getMainLooper()); private HandlerThread mThreadHandler; ScheduledExecutorService scheduledExecutorService; //主页面的视图 private LinearLayout llUpText; private TextView tvDevice; private int weight = 3840; private int height = 2160; private int videoWidth = 1920; private int videoHeight = 1080; Size outputSizes; public Camera2TextureView2(Context context) { super(context,null); } public Camera2TextureView2(Context context, AttributeSet attrs) { super(context, attrs); // executorService = Executors.newScheduledThreadPool(4); /*String url = "http://192.168.10.79:8919/fg/server/timestamp"; executorService.execute(()-> { HttpReqData httpReqData = new HttpReqData(url); HttpRespData data = HttpRequestUtil.getData(httpReqData); System.out.println("-------------------------------------------heirong wei---"+data.content); });*/ mContext = context; mThreadHandler = new HandlerThread("camera2"); mThreadHandler.start(); mHandler = new Handler(mThreadHandler.getLooper()); startBackgroundThread(); } public void init(LinearLayout llUpText, TextView tvDevice) { this.llUpText = llUpText; this.tvDevice = tvDevice; setSurfaceTextureListener(mSurfaceTextureListener); } 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 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { } }; @SuppressLint("MissingPermission") private void initCamera2() { //获取权限 // ActivityCompat.requestPermissions(Camera2TextureViewActivity.this, permissionArray, 1); CameraManager cm = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE); try { //获取前摄像头 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 subDeviceStateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice cameraDevice) { subCameraDevice = cameraDevice; } @Override public void onDisconnected(@NonNull CameraDevice camera) { } @Override public void onError(@NonNull CameraDevice camera, int error) { } }; 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(); }*/ //创建主摄像头会话并预览 createPreviewSession(); } @Override public void onDisconnected(@NonNull CameraDevice camera) { } @Override public void onError(@NonNull CameraDevice camera, int error) { } }; private void createPreviewSession() { try { mainCameraDevice.createCaptureSession(Arrays.asList(previewSurface,surfaceForStream), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { mainCaptureSession = session; try { previewCaptureBuilder = mainCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); } catch (CameraAccessException e) { e.printStackTrace(); } previewCaptureBuilder.addTarget(previewSurface); startPreview(); } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { } }, null); }catch (Exception e){ e.printStackTrace(); } } private void startPreview() { //启动预览 try { mainCaptureSession.setRepeatingRequest(previewCaptureBuilder.build(), null, mHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } private Surface recorderSurface; private File recorderFile; private String recorderPath; private boolean isRecording = false; private void initRecorder() { // recorderFile = new File(Camera2Activity.this.getExternalFilesDir(null).getAbsolutePath() + "/video/"); // recorderFile = new File(mContext.getExternalFilesDir(null).getAbsolutePath() + "/video/"); // recorderFile = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM); recorderFile = new File(Environment.getExternalStoragePublicDirectory(DIRECTORY_DOCUMENTS).getAbsolutePath() + "/yc_test/"); if (!recorderFile.exists()) { recorderFile.mkdirs(); } recorderPath = recorderFile.getAbsolutePath()+File.separator + System.currentTimeMillis() + ".mp4"; Log.e(TAG, "视频路径:" + recorderPath); mMediaRecorder = new MediaRecorder(); mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mMediaRecorder.setOutputFile(recorderPath); mMediaRecorder.setVideoEncodingBitRate(10000000); mMediaRecorder.setVideoFrameRate(20); mMediaRecorder.setVideoSize(videoWidth, videoHeight); mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); 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(); try{ mMediaRecorder.prepare(); mMediaRecorder.start(); }catch (Exception e){ e.printStackTrace(); } try { subCameraDevice.createCaptureSession(Arrays.asList(mMediaRecorder.getSurface()), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { subCaptureSession = session; try { //camera2 视频录制模式 videoCaptureBuilder = subCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD); videoCaptureBuilder.addTarget(mMediaRecorder.getSurface()); // 开始录制视频 subCaptureSession.setRepeatingRequest(videoCaptureBuilder.build(), null, backgroundHandler); } catch (Exception e) { e.printStackTrace(); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { } }, null); //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 -> { // 获取到拍照的图像数据 Image image = reader.acquireNextImage(); //这里只是演示test llUpText.setVisibility(View.VISIBLE); tvDevice.setText("这是测试的动态赋值"); // 保存图片到相册 saveImageToGallery(image); }; private void saveImageToGallery(Image image) { // 定义图片的保存路径和文件名 String fileName = "IMG_" + System.currentTimeMillis() + ".jpg"; String filePath = Environment.getExternalStoragePublicDirectory(DIRECTORY_DOCUMENTS).getAbsolutePath() + "/yc_test"+ File.separator + fileName; // 获取图片的字节数组 ByteBuffer buffer = image.getPlanes()[0].getBuffer(); byte[] data = new byte[buffer.remaining()]; buffer.get(data); // 创建文件输出流 try { FileOutputStream fos = new FileOutputStream(filePath); fos.write(data); fos.close(); image.close(); // 通知图库更新 MediaScannerConnection.scanFile(mContext, new String[]{filePath}, null, null); // 在某些设备上,可能需要发送广播通知才能使图片立即出现在相册中 mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(new File(filePath)))); // 显示保存成功的提示 // Toast.makeText(this, "图片保存成功", Toast.LENGTH_SHORT).show(); } catch (IOException e) { e.printStackTrace(); // 显示保存失败的提示 // Toast.makeText(this, "图片保存失败", Toast.LENGTH_SHORT).show(); } } public void stopRecording() { stopBackgroundThread(); try { // 停止录制视频,关闭录像请求 mMediaRecorder.stop(); //关闭录制视频会话 subCaptureSession.close(); //关闭拍照会话 scheduledExecutorService.shutdown(); mainCaptureSession.close(); //停止画面图片监听 mImageReader.close(); //这里只是演示test llUpText.setVisibility(View.GONE); //启动预览 createPreviewSession(); } catch (Exception e) { e.printStackTrace(); } finally { mMediaRecorder.reset(); // mMediaRecorder.release(); // mMediaRecorder = null; //图库更新 addToGallery(recorderPath); isRecording = false; } } private void addToGallery(String videoFilePath) { // 发送广播通知图库更新 MediaScannerConnection.scanFile(mContext, new String[]{videoFilePath}, null, (path, uri) -> { // 添加到相册成功的回调 Toast.makeText(mContext, "视频已保存至相册", Toast.LENGTH_SHORT).show(); }); } }