package com.whyc.widget; import android.Manifest; import android.annotation.SuppressLint; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; 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.CameraMetadata; import android.hardware.camera2.CaptureRequest; import android.media.Image; import android.media.ImageReader; import android.media.MediaCodec; 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.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; import android.util.AttributeSet; import android.util.Log; 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.Camera2Activity; import com.whyc.Camera2TextureViewActivity; 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; public class Camera2TextureView extends TextureView { private Context mContext; private CameraDevice mCameraDevice; private CaptureRequest.Builder captureBuilder = null; private CameraCaptureSession mCaptureSession; private MediaRecorder mMediaRecorder; private Surface previewSurface; private ImageReader mImageReader; private Surface surfaceForStream; CaptureRequest.Builder recordRequest; private Handler mHandler; private HandlerThread mThreadHandler; //主页面的视图 private LinearLayout llUpText; private TextView tvDevice; public Camera2TextureView(Context context) { super(context,null); } public Camera2TextureView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; mThreadHandler = new HandlerThread("camera2"); mThreadHandler.start(); mHandler = new Handler(mThreadHandler.getLooper()); } 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) { 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 cameraId = cm.getCameraIdList()[0]; cm.openCamera(cameraId,mDeviceStateCallback,null); }catch (Exception e){ e.printStackTrace(); } } private CameraDevice.StateCallback mDeviceStateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice cameraDevice) { mCameraDevice = cameraDevice; SurfaceTexture surfaceTexture = getSurfaceTexture(); surfaceTexture.setDefaultBufferSize(1920, 1080); previewSurface = new Surface(surfaceTexture); try { createPreviewSession(); }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() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { mCaptureSession = session; startPreview(mCameraDevice); } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { } }, null); }catch (Exception e){ e.printStackTrace(); } } private void startPreview(CameraDevice cameraDevice) { //启动预览 try { captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); captureBuilder.addTarget(previewSurface); /*设置预览的界面*/ //设置自动对焦模式 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); } catch (CameraAccessException e) { e.printStackTrace(); } } private Surface recorderSurface; private int videoWidth = 1920; private int videoHeight = 1080; 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(); // recorderSurface = MediaCodec.createPersistentInputSurface(); // mMediaRecorder.setInputSurface(recorderSurface); mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); mMediaRecorder.setOutputFile(recorderPath); mMediaRecorder.setVideoEncodingBitRate(10000000); mMediaRecorder.setVideoFrameRate(30); mMediaRecorder.setVideoSize(videoWidth, videoHeight); mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); // 开始录制 /*try { mMediaRecorder.prepare(); } catch (IOException e) { e.printStackTrace(); }*/ } public void createRecorderSession(){ mImageReader = ImageReader.newInstance(1920, 1080, ImageFormat.JPEG, 1); surfaceForStream = mImageReader.getSurface(); mImageReader.setOnImageAvailableListener(mImageReaderListener, null); if(mMediaRecorder!=null) { mMediaRecorder.reset(); } initRecorder(); try{ mMediaRecorder.prepare(); }catch (Exception e){ e.printStackTrace(); } try { // mCameraDevice.createCaptureSession(Arrays.asList(previewSurface,mMediaRecorder.getSurface(), surfaceForStream), new CameraCaptureSession.StateCallback() { mCameraDevice.createCaptureSession(Arrays.asList(mMediaRecorder.getSurface(), surfaceForStream), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { mCaptureSession = session; try { recordRequest = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); // recordRequest.addTarget(previewSurface); recordRequest.addTarget(mImageReader.getSurface()); recordRequest.addTarget(mMediaRecorder.getSurface()); mCaptureSession.setRepeatingRequest(recordRequest.build(), null, mHandler); // 开始录制视频 mMediaRecorder.start(); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { } }, null); // CaptureRequest.Builder recordRequest = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD); } catch (CameraAccessException 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(); }*/ SharedPreferences camera2Time = mContext.getSharedPreferences("camera2Time", Context.MODE_PRIVATE); long lastTime = camera2Time.getLong("time", 0); // 获取到拍照的图像数据 Image image = reader.acquireNextImage(); long now = image.getTimestamp()/1000000000; if (lastTime == 0 || now-lastTime > 5) { camera2Time.edit().putLong("time", now).apply(); //这里只是演示test llUpText.setVisibility(View.VISIBLE); tvDevice.setText("这是测试的动态赋值"); // 获取图片的字节数组 ByteBuffer buffer = image.getPlanes()[0].getBuffer(); byte[] data = new byte[buffer.remaining()]; buffer.get(data); // 释放图像资源 image.close(); // 保存图片到相册 saveImageToGallery(data); }else{ image.close(); } }; private void saveImageToGallery(byte[] data) { // 定义图片的保存路径和文件名 String fileName = "IMG_" + System.currentTimeMillis() + ".jpg"; String filePath = Environment.getExternalStoragePublicDirectory(DIRECTORY_DOCUMENTS).getAbsolutePath() + "/yc_test"+ File.separator + fileName; // 创建文件输出流 try { FileOutputStream fos = new FileOutputStream(filePath); fos.write(data); fos.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() { //这里只是演示test llUpText.setVisibility(View.GONE); //停止画面图片监听 mImageReader.close(); // 停止录制视频 try { mMediaRecorder.stop(); // createPreviewSession(); } catch (IllegalStateException e) { e.printStackTrace(); } finally { // mMediaRecorder.reset(); // mMediaRecorder.release(); // mMediaRecorder = null; } isRecording = false; // 关闭相机预览会话 // if (captureSession != null) { // captureSession.close(); // captureSession = null; // } //图库更新 addToGallery(recorderPath); } private void addToGallery(String videoFilePath) { // 发送广播通知图库更新 MediaScannerConnection.scanFile(mContext, new String[]{videoFilePath}, null, (path, uri) -> { // 添加到相册成功的回调 Toast.makeText(mContext, "视频已保存至相册", Toast.LENGTH_SHORT).show(); }); } }