Camera2 实现重力感应四个方向调试相机预览
Camera2API 实现重力感应四个方向调试相机预览
文章目录
- 需求
- 场景
- 需求实现
- setAspectRatio 设置显示长宽
- postScale postRotate 设置缩放和旋转
- manager.openCamera 打开相机
- startPreview
- getPreviewRequestBuilder 设置预览参数:
- createCaptureSession 预览准备工作
- setRepeatingRequest 请求预览
- 总结
需求
Camera2 相机预览实现四个重力感应方向预览方向正常
场景
- 实际有个客户需求,用到了四个方向的重力感应,但是之前的工程代码只有两个方向,导致屏幕无法四个方向正常显示
- 相机预览两个重力感应方向已经满足了需求,但是客户重力感应模块、板卡 实际物理装配时候不可能按照要求装配的,不同厂家的磨具不一样导致板卡方向装配不一样。基于这样的实际情况,软件就需要适配四个方向,两个重力感应预览方向就无法满足实际要求了。
- 实际产品案例:监控、HDMIN、车载Camera…
需求实现
setAspectRatio 设置显示长宽
设置显示组件长宽
textureView.setAspectRatio(width, height)
private void setupCamera(int width, int height) {CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);try {for (String cameraId : manager.getCameraIdList()) {...............int orientation = getResources().getConfiguration().orientation;if (orientation == Configuration.ORIENTATION_LANDSCAPE) {Log.d(TAG, "setupCamera: ORIENTATION_LANDSCAPE " + mPreviewSize.getWidth() + " x " + mPreviewSize.getHeight());textureView.setAspectRatio(1920, 1080);} else {textureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());Log.d(TAG, "setupCamera: ORIENTATION_PORT " + mPreviewSize.getWidth() + " x " + mPreviewSize.getHeight());}break;}} catch (CameraAccessException e) {e.printStackTrace();}}
使用位置:在View 组件流传递过来时候, onSurfaceTextureAvailable 方法中,去设置 setupCamera
TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {@Overridepublic void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {setupCamera(width, height);configureTransform(width, height);openCamera();}@Overridepublic void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {configureTransform(width, height);}@Overridepublic boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {return false;}@Overridepublic void onSurfaceTextureUpdated(SurfaceTexture surface) {}};
postScale postRotate 设置缩放和旋转
比如长宽肯定是1920*1080,根据实际产品长宽进行设置,但是如果是竖屏状态下,还是需要这个图像输出流的比例数出来,那么就必须进行缩放,才能完全显示出来的。
补充下基本知识点:
Matrix的操作,总共分为translate(平移),rotate(旋转),scale(缩放)和skew(倾斜)四种,每一种变换在Android的API里都提供了set, post和pre三种操作方式,除了translate,其他三种操作都可以指定中心点。
set是直接设置Matrix的值,每次set一次,整个Matrix的数组都会变掉,这也就意味着你对同一个矩阵先调用setScale,再调用setTranslate,那么矩阵只会执行Translate的操作,前面的scale操作是无效的。
post是后乘,当前的矩阵乘以参数给出的矩阵。可以连续多次使用post,来完成所需的整个变换。例如,要将一个图片先缩放,再平移则可以通过:
同样的道理,如上面设置显示长宽的后面就需要又缩放和旋转逻辑了, 输出流的地方是不会变的,那么接收的地方就需要根据实际情况如重力感应和物理场景【竖屏-横屏】进行流显示的变化了->缩放、旋转操作
onSurfaceTextureAvailable -> configureTransform(width, height) -> Configuration config = getResources().getConfiguration()【根据重力感应方向,计算缩放比例和旋转角度及选择方向了】核心代码如下:
private void configureTransform(int viewWidth, int viewHeight) {if (null == textureView || null == mPreviewSize) {return;}int rotation = getWindowManager().getDefaultDisplay().getRotation();Configuration config = getResources().getConfiguration();if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {Log.d(TAG, "configureTransform: ORIENTATION_PORTRAIT");if(Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation){isRotation = true;}} else if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {Log.d(TAG, "configureTransform: ORIENTATION_LANDSCAPE");if(Surface.ROTATION_0 == rotation || Surface.ROTATION_180 == rotation){isRotation = true;}}Log.d(TAG, "configureTransform: isRotation = "+isRotation);if(isRotation){rotation = rotation + 1;if(rotation > 3){rotation = rotation - 3;}}Log.d(TAG," aaaaaaaaaaaa rotation:"+rotation);Matrix matrix = new Matrix();RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());float centerX = viewRect.centerX();float centerY = viewRect.centerY();if (Surface.ROTATION_90 == rotation) {bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);float scale = Math.max((float) viewHeight / mPreviewSize.getHeight(),(float) viewWidth / mPreviewSize.getWidth());matrix.postScale(scale, scale, centerX, centerY);matrix.postRotate(90 * (rotation - 2), centerX, centerY);Log.d(TAG," 00000000000000 ");}else if ( Surface.ROTATION_270 == rotation) {bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);float scale = Math.max((float) viewHeight / mPreviewSize.getHeight(),(float) viewWidth / mPreviewSize.getWidth());matrix.postScale(scale, scale, centerX, centerY);matrix.postRotate(270, centerX, centerY);Log.d(TAG," bbbbbbbbbbbbbbbb ");} else if (Surface.ROTATION_180 == rotation) {float scale = (float)1080/ 1920;Log.d(TAG, "configureTransform: rizhi xianshi port state scale:"+scale+" centerX:"+centerX+" centerY:"+centerY);matrix.postScale(scale, scale, centerX, centerY);textureView.setRotation(270f);Log.d(TAG, "configureTransform: "+" centerX:"+centerX+" centerY:"+centerY);Log.d(TAG," 111111111111111 ");}else if(Surface.ROTATION_0 == rotation){float scale = (float)1080/ 1920;Log.d(TAG, "configureTransform: rizhi xianshi port state scale:"+scale+" centerX:"+centerX+" centerY:"+centerY);matrix.postScale(scale, scale, centerX, centerY);textureView.setRotation(270f);Log.d(TAG," 222222222222222222 ");}textureView.setTransform(matrix);}
manager.openCamera 打开相机
打开相机就是一个比较常规操作了,如上显示组件 已经准备好,进行了算转和缩放操作,就是显示组件已经设置好了参数,接下来就打开相机,让流数据进来。
打开相机基本代码如下:
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {setupCamera(width, height);configureTransform(width, height);openCamera();
}private void openCamera() {CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);int i = 0;try {i = manager.getCameraIdList().length;} catch (CameraAccessException e) {e.printStackTrace();}if (getDevVideoList()) {i = i - 1;}if (i == 2) {mCameraId = "9";} else {mCameraId = "0";}try {if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {Log.d(TAG," has no CAMERA permission");return;}manager.openCamera(mCameraId, stateCallback, null);} catch (CameraAccessException e) {e.printStackTrace();}}
startPreview
在相机打开操作中,如果相机打开成功,回调地方就需要设置预览了,这个是相机Camera 相关的操作了。 不要和预览组件textureView 搞混淆了。
这里用到的是Camera2 API 实现的
private void startPreview() {setupImageReader();SurfaceTexture mSurfaceTexture = textureView.getSurfaceTexture();Log.d(TAG, "startPreview: setDefaultBufferSize : width:"+mPreviewSize.getWidth()+" x "+mPreviewSize.getHeight()+" shiji xiesi 1920 x 1080");mSurfaceTexture.setDefaultBufferSize(1920, 1080);mPreviewSurface = new Surface(mSurfaceTexture);try {getPreviewRequestBuilder();mCameraDevice.createCaptureSession(Arrays.asList(mPreviewSurface, mImageReader.getSurface()), new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(CameraCaptureSession session) {mCaptureSession = session;repeatPreview();}@Overridepublic void onConfigureFailed(CameraCaptureSession session) {}}, null);} catch (CameraAccessException e) {e.printStackTrace();}}
getPreviewRequestBuilder 设置预览参数:
private void getPreviewRequestBuilder() {try {mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);} catch (CameraAccessException e) {e.printStackTrace();}mPreviewRequestBuilder.addTarget(mPreviewSurface);MeteringRectangle[] meteringRectangles = mPreviewRequestBuilder.get(CaptureRequest.CONTROL_AF_REGIONS);if (meteringRectangles != null && meteringRectangles.length > 0) {Log.d(TAG, "PreviewRequestBuilder: AF_REGIONS=" + meteringRectangles[0].getRect().toString());}mPreviewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE);}
createCaptureSession 预览准备工作
这里完全找找Camera2 API 开发的流程要求,先进行预览准备工作,可以理解为参数设置。mCameraDevice.createCaptureSession(Arrays.asList(mPreviewSurface, mImageReader.getSurface()), new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(CameraCaptureSession session) {mCaptureSession = session;repeatPreview();}@Overridepublic void onConfigureFailed(CameraCaptureSession session) {}}, null);
setRepeatingRequest 请求预览
这里只是一个请求操作,前面参数设置了为预览,所以这里局势预览操作
private void repeatPreview() {mPreviewRequestBuilder.setTag(TAG_PREVIEW);mPreviewRequest = mPreviewRequestBuilder.build();try {mCaptureSession.setRepeatingRequest(mPreviewRequest, mPreviewCaptureCallback, null);} catch (CameraAccessException e) {e.printStackTrace();}}
总结
- Camera2 实现基本API操作
- 重力感应四个方向适配,注意显示UI组件几个必备操作:显示大小、缩放、旋转、旋转位置x、y
- 作为一个笔记篇,使用地方蛮多的,简单总结
核心基本代码如下
public class MainActivity extends Activity {private static final String TAG = "MainActivity";private static final String TAG_PREVIEW = "dddd";private static final SparseIntArray ORIENTATION = new SparseIntArray();static {ORIENTATION.append(Surface.ROTATION_0, 90);ORIENTATION.append(Surface.ROTATION_90, 0);ORIENTATION.append(Surface.ROTATION_180, 270);ORIENTATION.append(Surface.ROTATION_270, 180);}private String mCameraId;private Size mPreviewSize;private ImageReader mImageReader;private CameraDevice mCameraDevice;private CameraCaptureSession mCaptureSession;private CaptureRequest mPreviewRequest;private CaptureRequest.Builder mPreviewRequestBuilder;private AutoFitTextureView textureView;private Surface mPreviewSurface;private String hdmiPlug = "0";private boolean isRotation = false;Handler mHandler = new Handler();Runnable mRun = new Runnable() {@Overridepublic void run() {Log.d("dddd", "mHandler =" + hdmiPlug);plugHandler.removeCallbacks(plugRun);sendHdmiInSpk("0");finish();}};Handler plugHandler = new Handler();Runnable plugRun = new Runnable() {@Overridepublic void run() {Log.d("dddd", "plugHandler =" + hdmiPlug);getHdmiInPlug();}};TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {@Overridepublic void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {setupCamera(width, height);configureTransform(width, height);openCamera();}@Overridepublic void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {configureTransform(width, height);}@Overridepublic boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {return false;}@Overridepublic void onSurfaceTextureUpdated(SurfaceTexture surface) {}};private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {@Overridepublic void onOpened(CameraDevice camera) {mCameraDevice = camera;startPreview();}@Overridepublic void onDisconnected(CameraDevice camera) {Log.i(TAG, "CameraDevice Disconnected");}@Overridepublic void onError(CameraDevice camera, int error) {Log.e(TAG, "CameraDevice Error = " + error);if (error == 4) {Toast.makeText(MainActivity.this, MainActivity.this.getString(R.string.fise_error_title), Toast.LENGTH_SHORT).show();sendHdmiInPlug();plugHandler.removeCallbacks(plugRun);mHandler.postDelayed(mRun, 1000);}}};private CameraCaptureSession.CaptureCallback mPreviewCaptureCallback = new CameraCaptureSession.CaptureCallback() {@Overridepublic void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {}@Overridepublic void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult) {}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);int uiFlags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION| View.SYSTEM_UI_FLAG_FULLSCREEN| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;getWindow().getDecorView().setSystemUiVisibility(uiFlags);getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);// 添加标志以强制Activity全屏显示getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);}}@Overrideprotected void onStart() {super.onStart();Permission.checkPermission(this);}private void setupCamera(int width, int height) {CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);try {for (String cameraId : manager.getCameraIdList()) {CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);if (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT)continue;StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);mPreviewSize = getOptimalSize(map.getOutputSizes(SurfaceTexture.class), width, height);Log.d(TAG, "getOptimalSize: ORIENTATION_PORT " + width + " x " + height);int orientation = getResources().getConfiguration().orientation;if (orientation == Configuration.ORIENTATION_LANDSCAPE) {Log.d(TAG, "setupCamera: ORIENTATION_LANDSCAPE " + mPreviewSize.getWidth() + " x " + mPreviewSize.getHeight());textureView.setAspectRatio(1920, 1080);} else {textureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());Log.d(TAG, "setupCamera: ORIENTATION_PORT " + mPreviewSize.getWidth() + " x " + mPreviewSize.getHeight());}break;}} catch (CameraAccessException e) {e.printStackTrace();}}private boolean getDevVideoList() {File file = new File("/dev/video3");if (file.exists()) {Log.d("huanghb", "video3 true");return true;}Log.d("huanghb", "video3 false");return false;}private void openCamera() {CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);int i = 0;try {i = manager.getCameraIdList().length;} catch (CameraAccessException e) {e.printStackTrace();}if (getDevVideoList()) {i = i - 1;}if (i == 2) {mCameraId = "9";} else {mCameraId = "0";}try {if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {Log.d(TAG," has no CAMERA permission");return;}manager.openCamera(mCameraId, stateCallback, null);} catch (CameraAccessException e) {e.printStackTrace();}}private void closeCamera() {Log.d(TAG, "closeCamera");if (null != mCaptureSession) {mCaptureSession.close();mCaptureSession = null;}if (null != mCameraDevice) {mCameraDevice.close();mCameraDevice = null;}if (null != mImageReader) {mImageReader.close();mImageReader = null;}}private void configureTransform(int viewWidth, int viewHeight) {if (null == textureView || null == mPreviewSize) {return;}int rotation = getWindowManager().getDefaultDisplay().getRotation();Configuration config = getResources().getConfiguration();if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {Log.d(TAG, "configureTransform: ORIENTATION_PORTRAIT");if(Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation){isRotation = true;}} else if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {Log.d(TAG, "configureTransform: ORIENTATION_LANDSCAPE");if(Surface.ROTATION_0 == rotation || Surface.ROTATION_180 == rotation){isRotation = true;}}Log.d(TAG, "configureTransform: isRotation = "+isRotation);if(isRotation){rotation = rotation + 1;if(rotation > 3){rotation = rotation - 3;}}Log.d(TAG," aaaaaaaaaaaa rotation:"+rotation);Matrix matrix = new Matrix();RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());float centerX = viewRect.centerX();float centerY = viewRect.centerY();if (Surface.ROTATION_90 == rotation) {bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);float scale = Math.max((float) viewHeight / mPreviewSize.getHeight(),(float) viewWidth / mPreviewSize.getWidth());matrix.postScale(scale, scale, centerX, centerY);matrix.postRotate(90 * (rotation - 2), centerX, centerY);Log.d(TAG," 00000000000000 ");}else if ( Surface.ROTATION_270 == rotation) {bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);float scale = Math.max((float) viewHeight / mPreviewSize.getHeight(),(float) viewWidth / mPreviewSize.getWidth());matrix.postScale(scale, scale, centerX, centerY);matrix.postRotate(270, centerX, centerY);Log.d(TAG," bbbbbbbbbbbbbbbb ");} else if (Surface.ROTATION_180 == rotation) {float scale = (float)1080/ 1920;Log.d(TAG, "configureTransform: rizhi xianshi port state scale:"+scale+" centerX:"+centerX+" centerY:"+centerY);matrix.postScale(scale, scale, centerX, centerY);textureView.setRotation(270f);Log.d(TAG, "configureTransform: "+" centerX:"+centerX+" centerY:"+centerY);Log.d(TAG," 111111111111111 ");}else if(Surface.ROTATION_0 == rotation){float scale = (float)1080/ 1920;Log.d(TAG, "configureTransform: rizhi xianshi port state scale:"+scale+" centerX:"+centerX+" centerY:"+centerY);matrix.postScale(scale, scale, centerX, centerY);textureView.setRotation(270f);Log.d(TAG," 222222222222222222 ");}textureView.setTransform(matrix);}private void startPreview() {setupImageReader();SurfaceTexture mSurfaceTexture = textureView.getSurfaceTexture();Log.d(TAG, "startPreview: setDefaultBufferSize : width:"+mPreviewSize.getWidth()+" x "+mPreviewSize.getHeight()+" shiji xiesi 1920 x 1080");mSurfaceTexture.setDefaultBufferSize(1920, 1080);mPreviewSurface = new Surface(mSurfaceTexture);try {getPreviewRequestBuilder();mCameraDevice.createCaptureSession(Arrays.asList(mPreviewSurface, mImageReader.getSurface()), new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(CameraCaptureSession session) {mCaptureSession = session;repeatPreview();}@Overridepublic void onConfigureFailed(CameraCaptureSession session) {}}, null);} catch (CameraAccessException e) {e.printStackTrace();}}private void repeatPreview() {mPreviewRequestBuilder.setTag(TAG_PREVIEW);mPreviewRequest = mPreviewRequestBuilder.build();try {mCaptureSession.setRepeatingRequest(mPreviewRequest, mPreviewCaptureCallback, null);} catch (CameraAccessException e) {e.printStackTrace();}}private void setupImageReader() {mImageReader = ImageReader.newInstance(mPreviewSize.getWidth(), mPreviewSize.getHeight(), ImageFormat.JPEG, 1);mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {@Overridepublic void onImageAvailable(ImageReader reader) {Log.i(TAG, "Image Available!");Image image = reader.acquireLatestImage();new Thread(new ImageSaver(image)).start();}}, null);}private Size getOptimalSize(Size[] sizeMap, int width, int height) {for(Size size:sizeMap){Log.d(TAG, ": size "+size.getWidth()+" "+size.getHeight());}List<Size> sizeList = new ArrayList<>();for (Size option : sizeMap) {if (width > height) {if (option.getWidth() > width && option.getHeight() > height) {sizeList.add(option);}} else {if (option.getWidth() > height && option.getHeight() > width) {sizeList.add(option);}}}if (sizeList.size() > 0) {return Collections.min(sizeList, new Comparator<Size>() {@Overridepublic int compare(Size lhs, Size rhs) {return Long.signum(lhs.getWidth() * lhs.getHeight() - rhs.getWidth() * rhs.getHeight());}});}Log.d(TAG, "getOptimalSize: zuizhong sizeMap[0]: width:"+sizeMap[0].getWidth()+" height:"+sizeMap[0].getHeight());return sizeMap[0];}private void getPreviewRequestBuilder() {try {mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);} catch (CameraAccessException e) {e.printStackTrace();}mPreviewRequestBuilder.addTarget(mPreviewSurface);MeteringRectangle[] meteringRectangles = mPreviewRequestBuilder.get(CaptureRequest.CONTROL_AF_REGIONS);if (meteringRectangles != null && meteringRectangles.length > 0) {Log.d(TAG, "PreviewRequestBuilder: AF_REGIONS=" + meteringRectangles[0].getRect().toString());}mPreviewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE);}public static class ImageSaver implements Runnable {private Image mImage;public ImageSaver(Image image) {mImage = image;}@Overridepublic void run() {ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();byte[] data = new byte[buffer.remaining()];buffer.get(data);File imageFile = new File(Environment.getExternalStorageDirectory() + "/DCIM/myPicture.jpg");FileOutputStream fos = null;try {fos = new FileOutputStream(imageFile);fos.write(data, 0, data.length);} catch (IOException e) {e.printStackTrace();} finally {if (fos != null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}}}}@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_BACK) {plugHandler.removeCallbacks(plugRun);sendHdmiInSpk("0");finish();return true;}else if (keyCode == KeyEvent.KEYCODE_HOME) {plugHandler.removeCallbacks(plugRun);sendHdmiInSpk("0");finish();return true;}return super.onKeyDown(keyCode, event);}@Overrideprotected void onPause() {super.onPause();Log.d(TAG, "onPause");plugHandler.removeCallbacksAndMessages(null); closeCamera();sendHdmiInSpk("0");super.onPause();}@Overrideprotected void onDestroy() {super.onDestroy();sendHdmiInSpk("0");Log.d("huanghb","onDestroy=");}@Overrideprotected void onResume() {super.onResume();Log.d(TAG," onREsume");if(Permission.isPermissionGranted(this)) {setContentView(R.layout.activity_main);sendHdmiInPlug();textureView = findViewById(R.id.textureView);textureView.setSurfaceTextureListener(textureListener);Log.d(TAG," 权限申请成功,走正常逻辑...");plugHandler.removeCallbacksAndMessages(null);plugHandler.postDelayed(plugRun, 2000);Log.d(TAG, "onResume: ");sendHdmiInSpk("1");}else{Log.d(TAG," 未授权成功..");}}public void sendHdmiInSpk(String spk) {Log.d(TAG, "sendHdmiInSpk: cmdParam:" + spk);Intent intent =new Intent();intent.setAction("com.fise.hdmiin.spk");intent.putExtra("hdmiinSpk", spk);sendBroadcast(intent);}public void sendHdmiInPlug(){Intent intent = new Intent();intent.setAction("com.fise.hdmiin.plug");sendBroadcast(intent);}private void getHdmiInPlug(){hdmiPlug = Uitls.read("/sys/class/fise_hdmiin_state_irq/fise_hdmiin_state_irq_enable");Log.d(TAG,"getHdmiInPlug ="+hdmiPlug);if(hdmiPlug == null || hdmiPlug.toString().trim().equals("")){return;}if(hdmiPlug.equals("1")){Toast.makeText(MainActivity.this, MainActivity.this.getString(R.string.fise_error_title), Toast.LENGTH_SHORT).show();sendHdmiInPlug();plugHandler.removeCallbacks(plugRun);mHandler.postDelayed(mRun, 1000);}else{plugHandler.postDelayed(plugRun, 1000);}}@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);if (requestCode == Permission.REQUEST_CODE) {for (int grantResult : grantResults) {if (grantResult != PackageManager.PERMISSION_GRANTED) {Log.e("Permission","授权失败!");Toast.makeText(MainActivity.this," Please grant permission",Toast.LENGTH_LONG);this.finish();return;}}}}}
相关文章:
Camera2 实现重力感应四个方向调试相机预览
Camera2API 实现重力感应四个方向调试相机预览 文章目录 需求场景 需求实现setAspectRatio 设置显示长宽postScale postRotate 设置缩放和旋转manager.openCamera 打开相机startPreviewgetPreviewRequestBuilder 设置预览参数:createCaptureSession 预览准备工作set…...
C++::多态
目录 一.多态的概念 二.多态的定义及实现 二.1多态的构成条件 二.2虚函数 1.虚函数的写法 2.虚函数的重写/覆盖 3.协变 二.3析构函数的重写 二.4override和final关键字 编辑二.5重载/重写/隐藏的对比 三.多态的运行原理(一部分) 四.多态的常…...
278.缀点成线
1232. 缀点成线 - 力扣(LeetCode) class Solution {public boolean checkStraightLine(int[][] coordinates) {if(coordinates.length2){return true;}int xcoordinates[1][0]-coordinates[0][0];int ycoordinates[1][1]-coordinates[0][1];for(int i1;i…...
xssgame第8关注入详解
1.SVG利用实现xss攻击 1.代码如下: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>tes…...
《数据库原理》SQLServer期末复习_题型+考点
目录 题型: 一. 概况分析题(5小题,每小题2分,共10分) 二. 计算题(3小题,每小题5分,共15分) 三. 数据库设计(2小题,每小题10分,共2…...
RK3588开发笔记-RTL8852wifi6模块驱动编译报错解决
目录 前言 一、问题背景 二、驱动编译 总结 前言 在基于 RK3588 进行开发,使用 RTL8852 WiFi6 模块时,遇到了一个让人头疼的驱动编译报错问题:“VFs_internal_I_am_really_a_filesystem_and_am_NoT_a_driver, but does”。经过一番摸索和尝试,最终成功解决了这个问题,在…...
机器学习算法实战——天气数据分析(主页有源码)
✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ 1. 引言 天气数据分析是气象学和数据科学交叉领域的一个重要研究方向。随着大数据技术的发展,气象数据的采集、存储和分…...
java项目之基于ssm的毕业论文管理系统(源码+文档)
项目简介 毕业论文管理系统实现了以下功能: 本毕业论文管理系统主要实现的功能模块包括学生模块、导师模块和管理员模块三大部分,具体功能分析如下: (1)导师功能模块:导师注册登录后主要功能模块包括个人…...
【Vue3入门1】02- vue3的基本操作(上)
本文介绍vue3中的一些方法的操作。 目录 1. 绑定事件 v-on 2. 按键修饰符 3. 显示和隐藏 v-show 4. 条件渲染 v-if 5. 条件渲染if-else 1. 绑定事件 v-on 点击事件 v-on:click" 发生事件 " <body><div id"app">{{ msg }} <h2&g…...
Redis集群搭建和高可用方案(Java实现)
Redis集群搭建和高可用方案(Java实现) 我将详细介绍如何使用Java技术搭建Redis集群并实现高可用方案。 1. Redis集群架构概述 Redis集群可以通过以下几种方式实现: 主从复制Sentinel哨兵模式Redis Cluster集群模式2. 使用Java实现Redis集群连接 2.1 使用Jedis客户端 Je…...
【大模型算法工程】大模型应用工具化、忠诚度以及知识库场景下PDF双栏解析问题的讨论
1. 大模型时代应用工具化以及无忠诚度现象讨论 接触大模型久了,也慢慢探到一些大模型能力表现非常自然和突出的场景,比如AI搜索(依赖大模型的理解总结能力)、AI对话(即chat,依赖大模型的生成能力࿰…...
Rust语言学习
Rust语言学习 通用编程概念所有权所有权引用和借用slice struct(结构体)定义并实例化一个结构体使用结构体方法语法 枚举 enums定义枚举match控制流运算符if let 简单控制流 使用包、Crate和模块管理不断增长的项目(模块系统)包和crate定义模块来控制作用…...
AI比人脑更强,因为被植入思维模型【16】反脆弱
毛选中就有言,不经历困难,我们就不会掌握战胜困难的方法。 这个世界纷繁复杂,不是强者总是运气好,而是他们能够失败后快速复原,不断找到战胜困难的方法。 定义 马斯洛需求层次模型是一种将人类需求从低到高按层次进…...
系统架构设计知识体系总结
1.技术选型 1.什么是技术选型? 技术选型是指评估和选择在项目或系统开发中使用的最合适的技术和工具的过程。这涉及考虑基于其能力、特性、与项目需求的兼容性、可扩展性、性能、维护和其他因素的各种可用选项。技术选型的目标是确定与项目目标相符合、能够有效解…...
计算机视觉的多模态模型
计算机视觉的多模态模型 是指能够同时处理和理解 多种类型数据(模态) 的模型。这些模态可以包括图像、文本、音频、视频、深度信息等。多模态模型的核心目标是利用不同模态之间的互补信息,提升模型的性能和泛化能力。 1. 多模态模型的核心思想…...
Scrapy 入门教程
Scrapy 入门教程 Scrapy 是一个用于爬取网站数据的 Python 框架,功能强大且易于扩展。本文将介绍 Scrapy 的基本概念、安装方法、使用示例,并展示如何编写一个基本的爬虫。 1. 什么是 Scrapy? Scrapy 是一个开源的、用于爬取网站数据的框架…...
Oracle OCP认证是否值得考?
Oracle OCP(Oracle Certified Professional)认证是数据库领域的传统权威认证,但随着云数据库和开源技术的崛起,其价值正面临分化。是否值得考取,需结合你的职业定位、行业需求及长期规划综合判断。以下是关键分析&…...
OpenCV中距离公式
一、各类距离公式总结 常见距离公式 欧氏距离: 曼哈顿距离(L1): 切比雪夫距离(Chessboard): 1、点与点距离(欧氏距离) 二维空间 设两点坐标为 P1(x1,y1)、P2(x2,y2),其距离…...
DeepSeek自学手册:《从理论(模型训练)到实践(模型应用)》|73页|附PPT下载方法
导 读INTRODUCTION 今天分享是由ai呀蔡蔡团队带来的DeepSeek自学手册:《从理论(模型训练)到实践(模型应用)》,这是一篇关于DeepSeek模型训练、应用场景及替代方案的综合指南文章,主要介绍了Deep…...
Doris官网上没有的一些Fe参数了,都在源码中
一、FE配置源码 apache-doris-src\fe\fe-common\src\main\java\org\apache\doris\common\Config.java 二、BE配置源码 apache-doris-src\be\src\common\config.cpp 三、FE源码 package org.apache.doris.common;public class Config extends ConfigBase {ConfField(descri…...
(一)丶Windows安装RabbitMQ可能会遇到的问题
一丶可能会忘了配置ERLang的环境变量 二丶执行命令时报错 第一步 rabbitmq-plugins enable rabbitmq_management 第二部 rabbitmqctl status 三丶修改.erlang.cookie 文件 1.找到C盘目下的.erlang.cookie文件 C:\Users\admin\.erlang.cookie C:\Windows\System32\config\sys…...
stm32g030移植RT-Thread
移植流程 移植前需要安装Keil.STM32G0xx_DFP.1.2.0.pack组件,大致的移植过程: CubeMX配置RT-Thread组件配置工程模板配置 参考例程配置:拷贝仓库原有的stm32g070-st-nucleo工程,然后另起一个名字,目录结构如下 完整…...
Parsing error: Unexpected token, expected “,“
今天在使用Trae AI 编程工具开发大文件切片上传功能,使用的是VUE3,TS技术栈,开发完成运行时,编译报错(Parsing error: Unexpected token, expected ","),让AI自行修复此问题多次后还是没有解决&a…...
Day23: 数组中数字出现的次数
整数数组 sockets 记录了一个袜子礼盒的颜色分布情况,其中 sockets[i] 表示该袜子的颜色编号。礼盒中除了一款撞色搭配的袜子,每种颜色的袜子均有两只。请设计一个程序,在时间复杂度 O(n),空间复杂度O(1) 内找到这双撞色搭配袜子的…...
目标检测——清洗数据
清洗VOC格式数据集代码示例 import os import xml.etree.ElementTree as ETdef process_annotations(image_folder, annotation_folder):# 遍历标签文件夹中的所有XML文件for xml_file in os.listdir(annotation_folder):if not xml_file.endswith(.xml):continuexml_path os…...
嵌入式基础知识学习:UART是什么?
UART(Universal Asynchronous Receiver/Transmitter,通用异步收发传输器)是一种广泛应用于嵌入式系统和通信设备的异步串行通信协议。它通过两根数据线(TX和RX)实现设备间的全双工数据传输,无需共享时钟信号…...
SpringBoot项目实战(初级)
目录 一、数据库搭建 二、代码开发 1.pom.xml 2.thymeleaf模块处理的配置类 3.application配置文件 4.配置(在启动类中) 5.编写数据层 ②编写dao层 ③编写service层 接口 实现类 注意 补充(注入的3个注解) 1.AutoWir…...
合成层优化
以下是关于 合成层(Composite Layer)优化 的系统梳理,涵盖基础原理、触发条件、优化策略及进阶实践,帮助深入理解如何通过分层渲染提升页面性能: 一、合成层基础概念 1. 什么是合成层? 定义:浏览器将页面元素提升为独立的图形层(Graphics Layer),由 GPU 单独处理,避…...
什么是MCP|工作原理是什么|怎么使用MCP|图解MCP
写在前面 Manus的爆火似乎推动了MCP的出圈,虽然Manus没有用MCP。这篇文章我们就讲讲MCP,当然我也是最近才学习到MCP的,如果理解有误的地方,欢迎评论区指出! 1. 为什么需要MCP? 1.1 LLM 现状 我们都知道…...
《Partial-label learning with a guided Prototypical classifier》23年CVPR 文献速读
论文地址 1. 引言 本文介绍了一种用于部分标签学习(Partial-Label Learning, PLL)的新框架 PaPi(Partial-label learning with a guided Prototypical classifier),旨在提高在视觉任务中处理部分标签数据时的性能。部…...
GitLens with `Commit Graph`
文章目录 GitLens with Commit Graph GitLens with Commit Graph 自己打包的 GitLens,能够查看 commit graph。 GitLens 持续更新中 下载之后,通过 VSCode 插件直接安装即可使用。...
python每日十题(6)
】函数定义:函数是指一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需要调用其函数名即可。函数能提高应用的模块性和代码的重复利用率 在Python语言中,用关键字class来定义类 在Python语…...
UniRel论文复现过程中的问题解决办法(全)
注解写在前面:本文仅为解决各位同学在复现时面对的问题,有问题可以评论,看见会回复!!! [顶刊论文]UniRel:Unified Representation and Interaction for Joint Relational Triple Extraction2022.11.16&…...
js逆向之断点调试
1.XHR/提取断点用法 当刷新页面时候,有大量请求,并且你无法定位参数信息的时候,或者参数被混淆无法搜到,可以用该方法,该方法是会捕获所有请求连接,然后我们通过连接过滤出自己想要的请求,然后…...
Unity Shader编程】之渲染流程之深度及pass详解
关于透明物体的渲染,首先需要了解以下部分 深度缓冲区深度写入深度测试pass渲染和深度测试的过程深度测试和颜色混合过程 ** 一,深度缓冲区 ** 深度即物体距离相机的距离,深度写入即是把物体的距离相机信息记录下来,写入一个名…...
【算法笔记】图论基础(一):建图、存图、树和图的遍历、拓扑排序、最小生成树
目录 何为图论图的概念 图的一些基本概念有向图和无向图带权图连通图和非连通图对于无向图对于有向图 度对于无向图对于有向图一些结论 环自环、重边、简单图、完全图自环重边简单图 稀疏图和稠密图子图、生成子图同构 图的存储直接存边邻接矩阵存边邻接表存边链式前向星存边 图…...
Compose 原理解析
Compose 的组件都是放在 setContent() 之后才能显示的,那需要先看看这个函数的作用。 先看 ComponentActivity 的扩展函数 setContent(): /*** 将给定的可组合项合成到给定的 Activity 中。[content] 将成为给定 Activity 的根视图。* 这大致相当于使用…...
pyspark学习rdd处理数据方法——学习记录
python黑马程序员 """ 文件,按JSON字符串存储 1. 城市按销售额排名 2. 全部城市有哪些商品类别在售卖 3. 上海市有哪些商品类别在售卖 """ from pyspark import SparkConf, SparkContext import os import jsonos.environ[PYSPARK_P…...
个人学习编程(3-22) leetcode刷题
连续子数组:(难) 示例 1: 输入: nums [0,1] 输出: 2 说明: [0, 1] 是具有相同数量 0 和 1 的最长连续子数组。 示例 2: 输入: nums [0,1,0] 输出: 2 说明: [0, 1] (或 [1, 0]) 是具有相同数量0和1的最长连续子数组。 需要理解的知识&a…...
RabbitMQ八股文
RabbitMQ 核心概念与组件 1. RabbitMQ 核心组件及其作用 1.1 生产者(Producer) 作用:创建并发送消息到交换机。特点:不直接将消息发送到队列,而是通过交换机路由。 1.2 交换机(Exchange) 作…...
运维面试题(七)
1.statefulset用来管理有状态的应用程序,有状态是什么意思? 每一个pod都有一个固定的网络标识符,在整个生命周期中不会改变。每个实例都可以拥有自己的持久化存储卷,即使容器被删除并重新创建,存储卷仍然存在。Statef…...
【项目设计】网页版五子棋
文章目录 一、项目介绍1.项目简介2.开发环境3.核心技术4.开发阶段 二、Centos-7.6环境搭建1.安装wget工具2.更换软件源(yum源)3.安装scl工具4.安装epel软件源5.安装lrzsz传输工具6.安装高版本gcc/g编译器7.安装gdb调试器8.安装git9.安装cmake10.安装boost库11.安装Jsoncpp库12.…...
Netty——BIO、NIO 与 Netty
文章目录 1. 介绍1.1 BIO1.1.1 概念1.1.2 工作原理1.1.3 优缺点 1.2 NIO1.2.1 概念1.2.2 工作原理1.2.3 优缺点 1.3 Netty1.3.1 概念1.3.2 工作原理1.3.3 优点 2. Netty 与 Java NIO 的区别2.1 抽象层次2.2 API 易用性2.3 性能优化2.4 功能扩展性2.5 线程模型2.6 适用场景 3. 总…...
Docker 安装 Mysql
以下是安装Docker版MySQL 8.0.25并实现目录挂载的步骤: docker仓库:https://hub.docker.com/_/mysql 1. 拉取Mysql镜像文件 docker pull mysql:8.0.252. 创建mysql临时容器服务 docker run -d \--name mysql \-p 3306:3306 \-e MYSQL_ROOT_PASSWORD123…...
Electron打包文件生成.exe文件打开即可使用
1 、Electron 打包,包括需要下载的内容和环境配置步骤 注意:Electron 是一个使用 JavaScript、HTML 和 CSS 构建跨平台桌面应用程序的框架 首先需要电脑环境有Node.js 和 npm我之前的文章有关nvm下载node的说明也可以去官网下载 检查是否有node和npm环…...
线程和协程的区别了解
1.资源消耗 调度方式:线程由操作系统内核调度(抢占式),协程由程序自己控制调度(协作式)。切换开销:线程切换涉及内核态与用户态的转换,开销大;协程只在用户态切换上下文…...
楼宇自控系统的结构密码:总线与分布式结构方式的差异与应用
在现代建筑中,为了实现高效、智能的管理,楼宇自控系统变得越来越重要。它就像建筑的 智能管家,可自动控制照明、空调、通风等各种机电设备,让建筑运行更顺畅,还能节省能源成本。而在楼宇自控系统里,有两种关…...
算法及数据结构系列 - 滑动窗口
系列文章目录 算法及数据结构系列 - 二分查找 算法及数据结构系列 - BFS算法 算法及数据结构系列 - 动态规划 算法及数据结构系列 - 双指针 算法及数据结构系列 - 回溯算法 算法及数据结构系列 - 树 文章目录 滑动窗口框架思路经典题型76. 最小覆盖子串567. 字符串的排列438. …...
【江协科技STM32】软件SPI读写W25Q64芯片(学习笔记)
SPI通信协议及S为5Q64简介:【STM32】SPI通信协议&W25Q64Flash存储器芯片(学习笔记)-CSDN博客 STM32与W25Q64模块接线: SPI初始化: 片选SS、始终SCK、MOSI都是主机输出引脚,输出引脚配置为推挽输出&…...
2025.3.23机器学习笔记:文献阅读
2025.3.23周报 题目信息摘要Abstract创新点网络架构实验不足以及展望 题目信息 题目: Enhancement of Hydrological Time Series Prediction with Real-World Time Series Generative Adversarial Network-Based Synthetic Data and Deep Learning Models期刊&…...