宁夏成城建设集团网站,贵州网络科技有限公司,市场推广的方法和规划,建设一个游戏网站需要多少钱最近在做自定义相机相关的项目#xff0c;网上查了资料都是有关android.hardware.Camera的资料#xff0c;开始使用的才发现这个类已经废弃了。Android 5.0(21)之后android.hardware.Camera就被废弃了#xff0c;取而代之的是全新的android.hardware.Camera2 。Android 5.0对…最近在做自定义相机相关的项目网上查了资料都是有关android.hardware.Camera的资料开始使用的才发现这个类已经废弃了。Android 5.0(21)之后android.hardware.Camera就被废弃了取而代之的是全新的android.hardware.Camera2 。Android 5.0对拍照API进行了全新的设计新增了全新设计的Camera v2 API这些API不仅大幅提高了Android系统拍照的功能还能支持RAW照片输出甚至允许程序调整相机的对焦模式、曝光模式、快门等。Camera2主要的类说明CameraManager摄像头管理器。这是一个全新的系统管理器专门用于检测系统摄像头、打开系统摄像头。除此之外调用CameraManager的getCameraCharacteristics(String)方法即可获取指定摄像头的相关特性。CameraCharacteristics摄像头特性。该对象通过CameraManager来获取用于描述特定摄像头所支持的各种特性。CameraDevice代表系统摄像头。该类的功能类似于早期的Camera类。CameraCaptureSession这是一个非常重要的API当程序需要预览、拍照时都需要先通过该类的实例创建Session。而且不管预览还是拍照也都是由该对象的方法进行控制的其中控制预览的方法为setRepeatingRequest()控制拍照的方法为capture()。CameraRequest和CameraRequest.Builder当程序调用setRepeatingRequest()方法进行预览时或调用capture()方法进行拍照时都需要传入CameraRequest参数。CameraRequest代表了一次捕获请求用于描述捕获图片的各种参数设置比如对焦模式、曝光模式……总之程序需要对照片所做的各种控制都通过CameraRequest参数进行设置。CameraRequest.Builder则负责生成CameraRequest对象。开启相机预览开启相机请一定添加相关的相机权限判断6.0以后添加动态权限的获取。如果相机预览出现黑屏多半就是因为没有相机权限而导致的首页我们要设置相机相关的参数CameraManager manager (CameraManager) ctx.getSystemService(Context.CAMERA_SERVICE);try {//获取可用摄像头列表for (String cameraId : manager.getCameraIdList()) {//获取相机的相关参数CameraCharacteristics characteristics manager.getCameraCharacteristics(cameraId);// 不使用前置摄像头。Integer facing characteristics.get(CameraCharacteristics.LENS_FACING);if (facing ! null facing CameraCharacteristics.LENS_FACING_FRONT) {continue;}StreamConfigurationMap map characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);if (map null) {continue;}// 检查闪光灯是否支持。Boolean available characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);mFlashSupported available null ? false : available;mCameraId cameraId;Log.e(TAG, 相机可用 );return;}} catch (CameraAccessException e) {e.printStackTrace();} catch (NullPointerException e) {//不支持Camera2API}}通过getSystemService(Context.CAMERA_SERVICE);拿到了CameraManager 返回当前可用的相机列表在这里你可以选择使用前置还是后置摄像头。CameraCharacteristics characteristics manager.getCameraCharacteristics(cameraId);可以拿到当前相机的相关参数在这里你可以进行相关的参数检查例如检查闪光灯是否支持等。在这里我们拿到当前相机的cameraId后面使用。拿到cameraId我们就可以调用CameraManager的openCamera(String cameraId, CameraDevice.StateCallback callback, Handler handler)打开相机了CameraManager manager (CameraManager) ctx.getSystemService(Context.CAMERA_SERVICE);try {//打开相机预览manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);} catch (CameraAccessException e) {e.printStackTrace();} catch (InterruptedException e) {throw new RuntimeException(Interrupted while trying to lock camera opening., e);}添加 CameraDevice.StateCallback 监听我们需要对相机状态就行监听以便在相机状态发生改变的时候做相应的操作。openCamera(String cameraId, CameraDevice.StateCallback callback, Handler handler)中CameraDevice.StateCallback就是对相机的状态改变的Callbackprivate final CameraDevice.StateCallback mStateCallback new CameraDevice.StateCallback() {Overridepublic void onOpened(NonNull CameraDevice cameraDevice) {mCameraDevice cameraDevice;//创建CameraPreviewSessioncreateCameraPreviewSession();}Overridepublic void onDisconnected(NonNull CameraDevice cameraDevice) {cameraDevice.close();mCameraDevice null;}Overridepublic void onError(NonNull CameraDevice cameraDevice, int error) {cameraDevice.close();mCameraDevice null;}};创建 CameraCaptureSession在onOpened()中我们可以拿到CameraDevice对象在相机打开后需要创建CameraCaptureSession。CameraCaptureSession是什么呢由于Camera2是一套全新的API所以它引用了管道的概念将安卓设备和摄像头之间联通起来系统向摄像头发送 Capture 请求而摄像头会返回 CameraMetadata。这一切建立在一个叫作 CameraCaptureSession的会话中。如下图2086682-e68d187e1240bfc5.png这里我们需要预览相机的内容就需要创建CameraCaptureSession向相机发送Capture请求预览相机内容/*** 为相机预览创建新的CameraCaptureSession*/private void createCameraPreviewSession() {try {//设置了一个具有输出Surface的CaptureRequest.Builder。mPreviewRequestBuilder mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);mPreviewRequestBuilder.addTarget(mSurfaceHolder.getSurface());//创建一个CameraCaptureSession来进行相机预览。mCameraDevice.createCaptureSession(Arrays.asList(mSurfaceHolder.getSurface()),new CameraCaptureSession.StateCallback() {Overridepublic void onConfigured(NonNull CameraCaptureSession cameraCaptureSession) {// 相机已经关闭if (null mCameraDevice) {return;}// 会话准备好后我们开始显示预览mCaptureSession cameraCaptureSession;try {// 自动对焦应mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);// 闪光灯setAutoFlash(mPreviewRequestBuilder);// 开启相机预览并添加事件mPreviewRequest mPreviewRequestBuilder.build();//发送请求mCaptureSession.setRepeatingRequest(mPreviewRequest,null, mBackgroundHandler);Log.e(TAG, 开启相机预览并添加事件);} catch (CameraAccessException e) {e.printStackTrace();}}Overridepublic void onConfigureFailed(NonNull CameraCaptureSession cameraCaptureSession) {Log.e(TAG, onConfigureFailed 开启预览失败);}}, null);} catch (CameraAccessException e) {Log.e(TAG, CameraAccessException 开启预览失败);e.printStackTrace();}}首先我们创建了一个CaptureRequest 上面说过了我们需要跟相机通信只有通过CameraCaptureSession。而要和CameraCaptureSession通信就是发送请求。这里我们相当于在创建请求的一些参数。createCaptureRequest(int); 也有很多参数可选。这里我们发送的是CameraDevice.TEMPLATE_PREVIEW也就是告诉相机我们只需要预览。更多参数如下详细信息可以参考官网的API文档。调用创建方法createCaptureSession(List outputs, CameraCaptureSession.StateCallback callback, Handler handler) 第一参数就是我们需要输出到的Surface列表这里我们可以输出到一个SurfaceView中或者TextureView中。第二参数是对创建过程的一个回调方法当onConfigured回调的时候说明CameraCaptureSession创建成功了。现在我们可以向CameraCaptureSession发送前面创建的好的预览相机请求了。调用mCaptureSession.setRepeatingRequest(mPreviewRequest,null, mBackgroundHandler); 这样我们就开启的相机的预览在刚才添加的输出Surface对应的控件中我们可以看到摄像头的预览内容了。拍照当我们需要拍照并且得到相应的照片数据的时候和开启相机预览相同的操作我们只需要向CameraCaptureSession发送我们创建好的请求就行就像我们请求网络数据一样封装好参数直接告诉CameraCaptureSession需要做什么由它去和相机建立通信并执行相应的操作。对焦/*** 将焦点锁定为静态图像捕获的第一步。(对焦)*/private void lockFocus() {try {// 相机对焦mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,CameraMetadata.CONTROL_AF_TRIGGER_START);// 修改状态mState STATE_WAITING_LOCK;mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,mBackgroundHandler);} catch (CameraAccessException e) {e.printStackTrace();}}向CameraCaptureSession发送对焦请求并且对对焦是否成功进行监听在mCaptureCallback中对回调进行处理/*** 处理与JPEG捕获有关的事件*/private CameraCaptureSession.CaptureCallback mCaptureCallback new CameraCaptureSession.CaptureCallback() {//处理private void process(CaptureResult result) {switch (mState) {case STATE_PREVIEW: {//预览状态break;}case STATE_WAITING_LOCK: {//等待对焦Integer afState result.get(CaptureResult.CONTROL_AF_STATE);if (afState null) {captureStillPicture();} else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED afState ||CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED afState) {// CONTROL_AE_STATE can be null on some devicesInteger aeState result.get(CaptureResult.CONTROL_AE_STATE);if (aeState null || aeState CaptureResult.CONTROL_AE_STATE_CONVERGED) {mState STATE_PICTURE_TAKEN;//对焦完成captureStillPicture();} else {runPrecaptureSequence();}}break;}}}}拍摄图片对焦完成后我们就可以向CameraCaptureSession发送请求可以拍照了/**** 拍摄静态图片。*/private void captureStillPicture() {try {if ( null mCameraDevice) {return;}// 这是用来拍摄照片的CaptureRequest.Builder。final CaptureRequest.Builder captureBuilder mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);captureBuilder.addTarget(mImageReader.getSurface());// 使用相同的AE和AF模式作为预览。captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);setAutoFlash(captureBuilder);// 方向int rotation this.getWindowManager().getDefaultDisplay().getRotation();captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));CameraCaptureSession.CaptureCallback CaptureCallback new CameraCaptureSession.CaptureCallback() {Overridepublic void onCaptureCompleted(NonNull CameraCaptureSession session,NonNull CaptureRequest request,NonNull TotalCaptureResult result) {showToast(Saved: mFile);Log.d(TAG, mFile.toString());unlockFocus();}};//停止连续取景mCaptureSession.stopRepeating();//捕获图片mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);} catch (CameraAccessException e) {e.printStackTrace();}}相信看到这里代码已经不复杂了组装好我们的请求然后用CameraCaptureSession发送这个请求就可以了。这里需要注意的是我们怎么拿到图片数据呢 这里要说回在创建CameraCaptureSession时参数不是有一个输出的Surface列表么在列表中添加一个ImageReader的Surface用户获取图片数据mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),null).....在ImageReader中对图片获取就行监听mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);private final ImageReader.OnImageAvailableListener mOnImageAvailableListener new ImageReader.OnImageAvailableListener() {Overridepublic void onImageAvailable(ImageReader reader) {//当图片可得到的时候获取图片并保存mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));}};调用reader.acquireNextImage()我们就可以拿到当前的图片数据了。拍完后我们需要解锁焦点让相机回到预览状态同样的我们发送请求就可以了/*** 解锁焦点*/private void unlockFocus() {try {// 重置自动对焦mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);setAutoFlash(mPreviewRequestBuilder);mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,mBackgroundHandler);// 将相机恢复正常的预览状态。mState STATE_PREVIEW;// 打开连续取景模式mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,mBackgroundHandler);} catch (CameraAccessException e) {e.printStackTrace();}}效果GIF.gif之前看了鸿神推送的Android 仿火萤视频桌面 神奇的LiveWallPaper 一文中提到了用相机来做壁纸也就是透明屏幕项目地址https://github.com/songixan/Wallpaper 查看源码发现还是用的旧的CameraAPI所以我在Demo中用Camera2API做了透明屏幕有兴趣的可以去看下。 PS后来在同事的小米2S(5.1.1)中测试发现出错了初步猜测是分辨率的原因目前正在解决中。有问题大家可以私信我 谢谢~到此Camera2的学习就结束了同样的如果你想用相机就行拍摄视频也是如此用CameraCaptureSession发送相应的请求了就可以了大家有兴趣可以做一做视频的拍摄。现在做微信的小10秒小视频拍摄也很简单了思路很简单当用户按下拍摄按钮用CameraCaptureSession发送拍摄视频的请求松开手指的时候相机恢复到预览状态。so easy~ 大家有兴趣可以尝试下。作者_小河马链接http://www.jianshu.com/p/73fed068a795來源简书著作权归作者所有。商业转载请联系作者获得授权非商业转载请注明出处。