Android 用 camera2 API 自定义相机

Android 用 camera2 API 自定义相机,第1张

概述前言笔者因为项目需要自定义相机,所以了解了一下Android关于camera这块的API。AndroidSDK21(LOLLIPOP)开始已经弃用了之前的Camera类,提供了camera2相关API,目前网上关于camera2API介绍的资料比较少,笔者搜集网

前言

笔者因为项目需要自定义相机,所以了解了一下 AndroID 关于 camera 这块的 API。AndroID SDK 21(LolliPOP) 开始已经弃用了之前的 Camera 类,提供了 camera2 相关 API,目前网上关于 camera2 API 介绍的资料比较少,笔者搜集网上资料,结合自己的实践,在这里做一个总结。

流程

因为 camera2 提供的接口比较多,虽然很灵活,但是也增加了使用的复杂度。首先来大致了解一下调用 camera2 的流程,方便我们理清思路。

要显示相机捕捉的画面,只需要三步:初始化相机,预览,更新预览。也就是上图中左侧的部分。要实现这三步,需要用到的主要接口类和它们的作用步骤如上图右侧部分所示。下面就用代码来详解一下。

案例

首先创建一个相机界面:

activity_camera.xml

<linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" androID:layout_wIDth="match_parent" androID:layout_height="wrap_content" androID:orIEntation="vertical"> <TextureVIEw  androID:ID="@+ID/camera_texture_vIEw"  androID:layout_wIDth="match_parent"  androID:layout_height="match_parent" /> <Imagebutton  androID:ID="@+ID/capture_ib"  androID:layout_wIDth="60dp"  androID:layout_height="60dp"  androID:layout_marginBottom="10dp"  androID:layout_gravity="bottom|center"  androID:background="@drawable/send_pres"/></linearLayout>

界面很简单,只有一个 TexureVIEw 和一个按钮。

接下来在 Activity 中初始化并显示相机捕捉的画面。

首先要解决的一个问题就是画面拉伸的问题。

要解决这个问题,首先要从 TextureVIEw 下手。

CameraActivity.java

mTextureVIEw.setSurfaceTextureListener(new TextureVIEw.SurfaceTextureListener() {  @OverrIDe  public voID onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,int wIDth,int height) {  mWIDth = wIDth;  mHeight = height;  getCameraID();  openCamera();  }  @OverrIDe  public voID onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,int i,int i1) {  }  @OverrIDe  public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {  return false;  }  @OverrIDe  public voID onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {  } });

在 onSurfaceTextureAvailable 中初始化相机。通过 CameraManager 对象 openCamera,这正是流程图中 Init 步骤中的第一步。openCamera 有三个参数,第一个是 String 类型的 cameraID,第二个是 CameraDevice.StateCallback,第三个是 Handler。这里我们要声明一个 StateCallback:

private CameraDevice.StateCallback mCameraDeviceStateCallback = new CameraDevice.StateCallback() { @OverrIDe public voID onopened(CameraDevice cameraDevice) {  mCameraDevice = cameraDevice;  createCameraPrevIEw(); } @OverrIDe public voID ondisconnected(CameraDevice cameraDevice) {  mCameraDevice.close();  mCameraDevice = null; } @OverrIDe public voID onError(CameraDevice cameraDevice,int i) {  mCameraDevice.close();  mCameraDevice = null; } };

可以看到,在 camera 准备完毕之后就可以创建预览界面了。解决画面拉伸的问题就是要为预览界面设置一个合适比例的 SurfaceTexture buffer size。

private voID createCameraPrevIEw() { try {  SurfaceTexture texture = mTextureVIEw.getSurfaceTexture();  assert texture != null;  Cameracharacteristics characteristics = mCameraManager.getCameracharacteristics(mCameraID);  StreamConfigurationMap map = characteristics.get(Cameracharacteristics.SCALER_STREAM_CONfigURATION_MAP);  int deviceOrIEntation = getwindowManager().getDefaultdisplay().getorIEntation();  int totalRotation = sensorToDeviceRotation(characteristics,deviceOrIEntation);  boolean swapRotation = totalRotation == 90 || totalRotation == 270;  int rotateDWIDth = mWIDth;  int rotatedHeight = mHeight;  if (swapRotation) {  rotateDWIDth = mHeight;  rotatedHeight = mWIDth;  }  mPrevIEwSize = getPreferredPrevIEwSize(map.getoutputSizes(SurfaceTexture.class),rotateDWIDth,rotatedHeight);  texture.setDefaultBufferSize(mPrevIEwSize.getWIDth(),mPrevIEwSize.getHeight());  Log.e("CameraActivity","OptimalSize wIDth: " + mPrevIEwSize.getWIDth() + " height: " + mPrevIEwSize.getHeight());  ...

这里根据当前设备及传感器的旋转角度来判断是否交换宽高值,然后通过 Cameracharacteristics 来得到最适合当前大小比例的宽高,然后把这个宽高设置给 SurfaceTexture 。

private Size getPreferredPrevIEwSize(Size[] sizes,int height) { List<Size> collectorSizes = new ArrayList<>(); for (Size option : sizes) {  if (wIDth > height) {  if (option.getWIDth() > wIDth && option.getHeight() > height) {   collectorSizes.add(option);  }  } else {  if (option.getHeight() > wIDth && option.getWIDth() > height) {   collectorSizes.add(option);  }  } } if (collectorSizes.size() > 0) {  return Collections.min(collectorSizes,new Comparator<Size>() {  @OverrIDe  public int compare(Size s1,Size s2) {   return Long.signum(s1.getWIDth() * s1.getHeight() - s2.getWIDth() * s2.getHeight());  }  }); } return sizes[0]; }这里 Sizes 是相机返回的支持的分辨率,从我们传递的参数找找到一个最接近的分辨率。接下来就要通过 CaptureRequest.Builder以及 CameraCaptureSession.StateCallback 来创建及更新预览界面:...Surface surface = new Surface(texture);  mBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);  // 设置预览对象  mBuilder.addTarget(surface);  mCameraDevice.createCaptureSession(Arrays.asList(surface),new CameraCaptureSession.StateCallback() {  @OverrIDe  public voID onConfigured(CameraCaptureSession cameraCaptureSession) {   if (null == mCameraDevice) {   return;   }   mSession = cameraCaptureSession;   mBuilder.set(CaptureRequest.CONTRol_MODE,CameraMetadata.CONTRol_MODE_auto);   try {   // 不停地将捕捉的画面更新到 TextureVIEw   mSession.setRepeatingRequest(mBuilder.build(),mSessionCaptureCallback,mBackgroundHandler);   } catch (CameraAccessException e) {   e.printstacktrace();   }  }  @OverrIDe  public voID onConfigureFailed(CameraCaptureSession cameraCaptureSession) {   Toast.makeText(CameraActivity.this,"Camera configuration change",Toast.LENGTH_SHORT).show();  }  },null); } catch (CameraAccessException e) {  e.printstacktrace(); }

这样就完成了自定义相机第一步,源码地址请戳这里。下载地址:http://xiazai.jb51.net/201704/yuanma/camera2-master_jb51.rar

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持编程小技巧!

总结

以上是内存溢出为你收集整理的Android 用 camera2 API 自定义相机全部内容,希望文章能够帮你解决Android 用 camera2 API 自定义相机所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1146482.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存