利用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() {
        @Override
        public void onOpened(CameraDevice camera) {
            Log.d("CameraCallback", "Camera Opened");
            cameraDevice = camera;
            takePreview();
        }

        @Override
        public void onDisconnected(CameraDevice cameraDevice) {
            Log.d("CameraCallback", "Camera Disconnected");
            closeCameraDevice();
        }

        @Override
        public 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(),
                imageReader.getSurface()), new CameraCaptureSession.StateCallback() {
            @Override
            public 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();
                }
            }

            @Override
            public 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() {
            @Override
            public void onImageAvailable(ImageReader imageReader) {
                Image image = null;
                try {
                    image = imageReader.acquireLatestImage();
                    Log.d("PreviewListener", "GetPreviewImage");
                    if (image == null) {
                        return;
                    }
                    byte[] bytes = ImageUtil.imageToByteArray(image);
                    if (pushFlag == false)
                        uploadImg(bytes);
                } finally {
                    if (image != null) {
                        image.close();
                    }
                }

            }
        }, mainHandler);

ImageReader是一个可以让我们对绘制到surface的图像进行直接操作的类。在这里我们从摄像设备中传入了连续的预览图片,也就是我们在屏幕上看到的画面,它们的格式都是未经压缩的YUV_420_888类型的(同样的如果要操作拍摄后的图片,就要设置成jpeg格式)。我们调用imageReader.acquireLatestImage或者acquireNextImage来获取图像队列中的图片。并进行操作。在这里我利用一个函数将图像压缩后转化成byte[]格式,并调用uploadImg函数上传至服务器。这样,整个摄像头的调用到预览图像的处理也就完成了。想要实现拍照功能也是大同小异,在这里我就不一一贴出了。

欢迎更多安卓开发者一同交流。

时间: 2024-11-05 13:38:34

利用Android Camera2 的照相机api 实现 实时的图像采集与预览的相关文章

Android 手势检测实战 打造支持缩放平移的图片预览效果(下)

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/39480503,本文出自:[张鸿洋的博客] 上一篇已经带大家实现了自由的放大缩小图片,简单介绍了下Matrix:具体请参考:Android 手势检测实战 打造支持缩放平移的图片预览效果(上):本篇继续完善我们的ImageView~~ 首先加入放大后的移动~~ 1.自由的进行移动 我们在onTouchEvent里面,加上移动的代码,当然了,必须长或宽大于屏幕才可以移动~~~ @Ov

Android图片上传,可以选择多张图片,缩放预览,拍照上传等

仿照微信,朋友圈分享图片功能 .可以进行图片的多张选择,拍照添加图片,以及进行图片的预览,预览时可以进行缩放,并且可以删除选中状态的图片 .很不错的源码,大家有需要可以下载看看 . 微信 微信 微信 微信 下载地址 : 微信上传图片源码 //部分代码如下 [java] view plaincopy package com.king.photo.activity; import android.annotation.SuppressLint; import android.app.Activity

Android开发实践:掌握Camera的预览方向和拍照方向

Android的Camera相关应用开发中,有一个必须搞清楚的知识点,就是Camera的预览方向和拍照方向,本文就重点讨论一下这个问题. 图像的Sensor方向:手机Camera的图像数据都是来自于摄像头硬件的图像传感器(Image Sensor),这个Sensor被固定到手机之后是有一个默认的取景方向的,这个方向如下图所示,坐标原点位于手机横放时的左上角: Camera的预览方向:由于手机屏幕可以360度旋转,为了保证用户无论怎么旋转手机都能看到"正确"的预览画面(这个"正

Android Camera API/Camera2 API 相机预览及滤镜、贴纸等处理

Android Lollipop 增加了Camera2 API,并将原来的Camera API标记为废弃了.相对原来的Camera API来说,Camera2是重新定义的相机 API,也重构了相机 API 的架构.初看之下,可能会感觉Camera2使用起来比Camera要复杂,然而使用过后,你也许就会喜欢上使用Camera2了.无论是Camera还是Camera2,当相机遇到OpenGL就比较好玩了. 问题及思路 Camera的预览比较常见的是使用SurfaceHolder来预览,Camera2

用 grunt-contrib-connect 构建实时预览开发环境 实时刷新

本文基本是参照着 用Grunt与livereload构建实时预览的开发环境 实操了一遍,直接实现能实时预览文件列表,内容页面.不用刷新页面了,这比以前开发网页程序都简单. 这里要用到的 Grunt 插件有 grunt-contrib-connect , 用来充当一个静态文件服务器,本身集成了 livereload 功能 grunt-contrib-watch , 监视文件的改变,然后执行指定任务,这里用来刷新  grunt serve 打开的页面 以下是个辅助的插件 load-grunt-tas

Android实战技巧之四十七:不用预览拍照与图片缩放剪裁

副标题:Take Picture without preview Android Google出于对隐私的保护,制定了一条门槛,即在Android应用开发中编写拍照程序是必需要有图像预览的.这会对那些恶意程序比如Android中泛滥的Service在后台偷偷记录手机用户的行为与周边信息.这样的门槛还包括手机厂商自带的相机软件在拍照时必须是有声音,这样要避免一些偷拍的情况. 处于技术调研与一些特殊无害场景的使用,我们要用到不用预览的拍照.此文就是以此为背景,做的一些调研.只是用不多与五款手机测试,

重建“巴别塔”,Skype推出Windows10实时语音翻译预览版

据<圣经·创世记>第 11 章记载,曾经有一个时代,人类之间并没有语言沟通障碍,于是他们联合起来兴建希望塔顶通天能传扬后人的高塔.为了阻止人类的计划,上帝让人类说不同的语言,使人类相互之间不能沟通,计划因此失败,人类自此各散东西.那个导致了灾难的建筑叫做"巴别塔",而人们曾经口音言语想通的日子也成为了传说中的"巴别塔时代". 而如今科技可以让人们打破地域和语言的界限,有望重新建造巴别塔. Skype 官方近期宣布推出实时语言翻译的预览版.在帮助用户跨越了

利用 Android 系统原生 API 实现分享功能

利用 Android 系统原生 API 实现分享功能 这篇文章提供一个封装好的 Share2 库供大家参考. GitHub 项目地址:Share2 大家知道,要调用 Android 系统内建的分享功能,主要有三步流程: 创建一个 Intent ,指定其 Action 为 Intent.ACTION_SEND,表示要创建一个发送指定内容的隐式意图. 然后指定需要发送的内容和类型,设置分享的文本内容或文件的Uri,以及文件的类型,便于是支持该类型内容的应用打开. 最后向系统发送隐式意图,开启系统分享

phonegap的照相机 API

一. Camera Api 简单介绍 Camera 选择使用摄像头拍照,或从设备相册中获取一张照片.图片以 base64 编码的 字符串或图片 URI 形式返回. 方法: 1. camera.getPicture 拍照获取相册图片 navigator.camera.getPicture( cameraSuccess, cameraError, [ cameraOptions ] ); cameraSuccess:提供图像数据的 onSuccess 回调函数. cameraError:提供错误信息