| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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()); |
| | |
| | | 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); |
| | |
| | | |
| | | 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); |
| | |
| | | mThreadHandler = new HandlerThread("camera2"); |
| | | mThreadHandler.start(); |
| | | mHandler = new Handler(mThreadHandler.getLooper()); |
| | | |
| | | startBackgroundThread(); |
| | | |
| | | |
| | | |
| | | } |
| | | |
| | | public void init(LinearLayout llUpText, TextView tvDevice) { |
| | |
| | | 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 |
| | |
| | | // 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 |
| | |
| | | } |
| | | }; |
| | | |
| | | 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 |
| | |
| | | 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; |
| | |
| | | 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); |
| | |
| | | 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(); |
| | | } |
| | |
| | | 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(); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | } |
| | | }, 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); |
| | | |
| | | }; |
| | | |
| | |
| | | } |
| | | |
| | | 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 { |