利用Android Camera2 的照相机api 实现 实时的图像采集与预览
最近想要做一个客户端往服务器推送实时画面的功能,首先可以考虑到两种思路,一种是在客户端进行视频流的推送,主要利用RTSP等流媒体协议进行传输,而另外一种是通过摄像头获取当前画面,将每一帧作为对象单独传输。
项目想要实现的功能最终目的是对实时画面的每一帧进行处理,可以考虑客户端推流到服务器,再在服务器进行帧解析的操作,但由于目前很多的流媒体推送框架在推流端或者服务端都或多或少存在限制,很少有完全开源的项目,再加上传送画面的同时需要附带部分的数据,仍然需要另外建立连接进行传输,所以暂时搁置这一方案。选择第二种思路,获取每一帧的画面,单独传输。
要想获取实时画面,我们必须通过对安卓设备上的摄像头进行调用。
从API21开始,安卓引入了android.hardware.camera2这个包,来替代原有的camera类,原有的camera类已经不再建议使用了。camera2中最重要的变化是,摄像头的调用不再是简单地进行实例化,而是用一种类似服务申请的方式来进行调用。通过CameraManager来管理摄像服务,需要通过建立CameraCaptureSession来建立一个调用摄像设备CameraDevices的会话,来实现对摄像头的调用。而CaptureRequest.Builder类用于建立实际的调用请求,具体的参数设置也可以通过这个类来实现(而不是对camera设备进行直接设置),这样做的目的是把对摄像头的控制与摄像头本身分离开来,用户可以通过不同的session根据不同的配置来使用摄像头。
我们可以结合具体的代码来分析新api中摄像头调用的过程。
首先我们想要对摄像设备进行操作,需要获得CameraManager的实例
CameraManager cameraManager;cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
我们可以调用openCamera函数打开摄像头设备
cameraManager.openCamera(cameraId, cameraCallback, mainHandler);
这里需要传入三个参数,cameraId是设备编号,cameraCallback控制摄像服务的回调,最后一个参数指定HandlerThread对象
cameraId = Integer.toString(CameraCharacteristics.LENS_FACING_FRONT);private CameraDevice.StateCallback cameraCallback = new CameraDevice.StateCallback() {@Overridepublic void onOpened(CameraDevice camera) {Log.d("CameraCallback", "Camera Opened");cameraDevice = camera;takePreview();}@Overridepublic void onDisconnected(CameraDevice cameraDevice) {Log.d("CameraCallback", "Camera Disconnected");closeCameraDevice();}@Overridepublic void onError(CameraDevice cameraDevice, int i) {Log.d("CameraCallback", "Camera Error");Toast.makeText(PusherSurface.this, "摄像头开启失败", Toast.LENGTH_SHORT).show();}};
回调函数用于指定连接摄像头设备时不同状态的操作。在这里,我们在摄像头成功连接的时候调用 takePreview()函数开启摄像头画面的预览。
private void takePreview() {try {final CaptureRequest.Builder previewRequestBuilder= cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);previewRequestBuilder.addTarget(surfaceHolder.getSurface());previewRequestBuilder.addTarget(previewReader.getSurface());cameraDevice.createCaptureSession(Arrays.asList(surfaceHolder.getSurface(),previewReader.getSurface(),p_w_picpathReader.getSurface()), new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(CameraCaptureSession cameraCaptureSession) {if (cameraDevice == null) return;mCameraCaptureSession = cameraCaptureSession;try {previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.CONTROL_AE_MODE_OFF);CaptureRequest previewRequest = previewRequestBuilder.build();mCameraCaptureSession.setRepeatingRequest(previewRequest, null, childHandler);} catch (CameraAccessException e) {e.printStackTrace();}}@Overridepublic void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {Toast.makeText(PusherSurface.this, "配置失败", Toast.LENGTH_SHORT).show();}}, childHandler);} catch (CameraAccessException e) {e.printStackTrace();}
}
要从摄像设备中获取图像,我们首先需要建立一个camera capture session。函数
createCaptureSession(List, CameraCaptureSession.StateCallback, Handler)的第一个参数传入了我们想要绘制的视图列表,第二个参数传入的是建立摄像会话的状态回调函数,第三个参数传入相应的handler处理器。然后,我们需要利用capturerequest来定义摄像头捕获图像时候的具体参数,比如是否开启摄像头,是否自动对焦等。最后通过CamraCaptureSession.setRepeatingRequest来开启请求。这样我们就可以从capturesession传入的list中的surface列表获得连续的图像。留意到
previewRequestBuilder.addTarget(surfaceHolder.getSurface());
previewRequestBuilder.addTarget(previewReader.getSurface());
这里除了传入xml界面布局中的surfaceHolder的surface外,还传入了一个previewReader的surface。
previewReader是一个自定义的ImageReader对象。
previewReader = ImageReader.newInstance(1080, 1920, ImageFormat.YUV_420_888, 2);previewReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {@Overridepublic void onImageAvailable(ImageReader p_w_picpathReader) {Image p_w_picpath = null;try {p_w_picpath = p_w_picpathReader.acquireLatestImage();Log.d("PreviewListener", "GetPreviewImage");if (p_w_picpath == null) {return;}byte[] bytes = ImageUtil.p_w_picpathToByteArray(p_w_picpath);if (pushFlag == false)uploadImg(bytes);} finally {if (p_w_picpath != null) {p_w_picpath.close();}}}}, mainHandler);
ImageReader是一个可以让我们对绘制到surface的图像进行直接操作的类。在这里我们从摄像设备中传入了连续的预览图片,也就是我们在屏幕上看到的画面,它们的格式都是未经压缩的YUV_420_888类型的(同样的如果要操作拍摄后的图片,就要设置成jpeg格式)。我们调用p_w_picpathReader.acquireLatestImage或者acquireNextImage来获取图像队列中的图片。并进行操作。在这里我利用一个函数将图像压缩后转化成byte[]格式,并调用uploadImg函数上传至服务器。这样,整个摄像头的调用到预览图像的处理也就完成了。想要实现拍照功能也是大同小异,在这里我就不一一贴出了。
欢迎更多安卓开发者一同交流。
转载于:https://blog.51cto.com/davidwillo/1908166
利用Android Camera2 的照相机api 实现 实时的图像采集与预览相关推荐
- Android Camera使用OpenGL ES 2.0和GLSurfaceView对预览进行实时二次处理(黑白滤镜)
第一篇 Android Camera使用OpenGL ES 2.0和GLSurfaceView对预览进行实时二次处理(黑白滤镜) 第二篇 Android Camera使用OpenGL ES 2.0和T ...
- Android Camera使用OpenGL ES 2.0和TextureView对预览进行实时二次处理(黑白滤镜)
本系列教程会有三篇文章讲解Android平台滤镜的实现方式,希望在阅读本文之前先阅读下述第一篇文档,因为第一篇讲过的知识,本文并不会细讲了. 第一篇 Android Camera使用OpenGL ES ...
- android 相机手动对焦,使用android camera2进行手动对焦API
我想为自己开发一款适用于自己的Android相机应用程序(如果有兴趣的人可以分享它),在录制视频时需要手动对焦.使用android camera2进行手动对焦API 我已经添加了一个SeekBar到谷 ...
- 利用Gulp实现JSDoc 3的文档编写过程中的实时解析和效果预览
### 利用Gulp实现JSDoc 3的文档编写过程中的实时解析和效果预览 http://segmentfault.com/a/1190000002583569 转载于:https://www.cnb ...
- android surfaceview 大小,Android设置SurfaceView任意大小、任意位置、保持预览宽高比与屏...
Android设置SurfaceView任意大小.任意位置.保持预览宽高比与屏 Android设置SurfaceView任意大小.任意位置.保持预览宽高比与屏显一致 一.任意大小.任意位置 1) 代码 ...
- OpenGL.ES在Android上的简单实践:20-水印录制(预览+透明水印 表情 弹幕 gl_blend)
OpenGL.ES在Android上的简单实践:20-水印录制(预览 gl_blend) 1.继续画出预览帧 紧接着上篇文章,既然是要画出预览帧,按照之前其他项目的架构组成.我们是通过模型FrameR ...
- Android 手势检测实战 打造支持缩放平移的图片预览效果(下)
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/39480503,本文出自:[张鸿洋的博客] 上一篇已经带大家实现了自由的放大缩小图 ...
- android camera移动方向_Android Camera开发系列:调整Camera预览方向
有时候我们想根据自己的需要调整下Camera的预览方向,那么是调用哪个API可以达到我们的目的呢? 我们看下下图拍的几张小可爱的照片,分别是正常方向.旋转180度.90度拍的照片. 正常方向 旋转 ...
- Android设置SurfaceView任意大小、任意位置、保持预览宽高比与屏显一致
一.任意大小.任意位置 1) 代码 public void init() {// FrameLayoutViewGroup.LayoutParams framelayout_params =new V ...
最新文章
- Github 的 Pull Request 教程
- vscode打造golang开发环境以及golang的debug单元测试
- PySide2 基础入门-创建实例窗口(详细解释)
- python 余弦距离_距离公式汇总以及Python实现
- css --- 应用媒介查询制作响应式导航栏
- Windows Server 2008 R2 搭建FTP服务
- Ansible(四)ansible roles实现(apache+haproxy+keepalived)负载均衡+高可用
- linux命令:FTP服务
- do{} while(0)
- 教训:LINUX复制文件到U盘丢失
- c语言windows停止工作,win7系统一打开便签就提示停止工作的解决方法
- 《Microsoft Word》进阶技巧:如何设置文档视图
- SLAM常见面试题集锦
- Graph Neural Controlled Differential Equations for Traffic Forecasting(AAAI2022)
- Excel:sumifs函数
- 嵌入式开发工程师需要掌握哪些知识呢?
- 如果编程语言是一门武功绝学,那么汇编、C语言······
- 主引导记录MBR详解
- 【测试】功能测试用例设计方法总结
- Redis高级项目实战,西安java程序员工资