zoukankan      html  css  js  c++  java
  • 如何实现RTMP推送Android Camera2数据

    Camera2简介

    在Google 推出Android 5.0的时候, Android Camera API 版本升级到了API2(android.hardware.camera2), 之前使用的API1(android.hardware.camera)就被标为 Deprecated 了。

    Camera API2相较于API1有很大不同, 并且API2是为了配合HAL3进行使用的, API2有很多API1不支持的特性, 比如:

    1. 更先进的API架构;
    2. 可以获取更多的帧(预览/拍照)信息以及手动控制每一帧的参数;
    3. 对Camera的控制更加完全(比如支持调整focus distance, 剪裁预览/拍照图片);
    4. 支持更多图片格式(yuv/raw)以及高速连拍等。

    在API架构方面, Camera2和之前的Camera有很大区别, APP和底层Camera之前可以想象成用管道方式连接, 如下图:

    fig.1

    这里引用了管道的概念将安卓设备和摄像头之间联通起来,系统向摄像头发送 Capture 请求,而摄像头会返回 CameraMetadata。这一切建立在一个叫作 CameraCaptureSession 的会话中。

    下面是 camera2包中的主要类:

    fig.2

    其中 CameraManager 是那个站在高处统管所有摄像投设备(CameraDevice)的管理者,而每个 CameraDevice 自己会负责建立 CameraCaptureSession 以及建立 CaptureRequest。

    CameraCharacteristics 是 CameraDevice 的属性描述类,非要做个对比的话,那么它与原来的 CameraInfo 有相似性。

    Camera2 API调用基础流程:

    1. 通过context.getSystemService(Context.CAMERA_SERVICE) 获取CameraManager;
    2. 调用CameraManager .open()方法在回调中得到CameraDevice;
    3. 通过CameraDevice.createCaptureSession() 在回调中获取CameraCaptureSession;
    4. 构建CaptureRequest, 有三种模式可选 预览/拍照/录像.;
    5. 通过 CameraCaptureSession发送CaptureRequest, capture表示只发一次请求, setRepeatingRequest表示不断发送请求;
    6. 拍照数据可以在ImageReader.OnImageAvailableListener回调中获取, CaptureCallback中则可获取拍照实际的参数和Camera当前状态。

    获取数据后对接RTMP推送:

    通过OnImageAvailableListenerImpl 获取到原始数据,推送端以大牛直播SDK https://github.com/daniulive/SmarterStreaming/ 的万能推送接口为例,获取数据后,调用SmartPublisherOnImageYUV420888() 完成数据传送,底层进行二次处理后,编码后传输即可。

    接口描述:

    	/*
    	*  专门为android.media.Image的android.graphics.ImageFormat.YUV_420_888格式提供的接口
    	*
        * @param   必须是8的倍数
    	*
        * @param  height: 必须是8的倍数
    	*
    	* @param  crop_left: 剪切左上角水平坐标, 一般根据android.media.Image.getCropRect() 填充
    	*
    	* @param  crop_top: 剪切左上角垂直坐标, 一般根据android.media.Image.getCropRect() 填充
    	*
        * @param  crop_ 必须是8的倍数, 填0将忽略这个参数, 一般根据android.media.Image.getCropRect() 填充
    	*
        * @param  crop_height: 必须是8的倍数, 填0将忽略这个参数,一般根据android.media.Image.getCropRect() 填充
        *
        * @param y_plane 对应android.media.Image.Plane[0].getBuffer()
        *
        * @param y_row_stride 对应android.media.Image.Plane[0].getRowStride()
    	*
    	* @param u_plane 对应android.media.Image.Plane[1].getBuffer()
    	*
    	* @param v_plane 对应android.media.Image.Plane[2].getBuffer()
    	*
    	* @param uv_row_stride 对应android.media.Image.Plane[1].getRowStride()
    	*
    	* @param uv_pixel_stride 对应android.media.Image.Plane[1].getPixelStride()
    	*
        * @param  rotation_degree: 顺时针旋转, 必须是0, 90, 180, 270
    	*
        * @param  is_vertical_flip: 是否垂直翻转, 0不翻转, 1翻转
    	*
        * @param  is_horizontal_flip:是否水平翻转, 0不翻转, 1翻转
    	*
        * @param  scale_ 缩放宽,必须是8的倍数, 0不缩放
    	*
        * @param  scale_height: 缩放高, 必须是8的倍数, 0不缩放
    	*
    	* @param  scale_filter_mode: 缩放质量, 范围必须是[1,3], 传0使用默认速度
    	*
    	* @return {0} if successful
        */
    	public native int SmartPublisherOnImageYUV420888(long handle, int width, int height,
    													 int crop_left, int crop_top, int crop_width, int crop_height,
    													 ByteBuffer y_plane, int y_row_stride,
    													 ByteBuffer u_plane, ByteBuffer v_plane, int uv_row_stride, int uv_pixel_stride,
    													 int rotation_degree, int is_vertical_flip, int is_horizontal_flip,
    													 int scale_width, int scale_height, int scale_filter_mode);
        private class OnImageAvailableListenerImpl implements ImageReader.OnImageAvailableListener {
    
            @Override
            public void onImageAvailable(ImageReader reader) {
                Image image = reader.acquireLatestImage();
    
                if ( image != null )
                {
                    if ( camera2Listener != null )
                    {
                        camera2Listener.onCameraImageData(image);
                    }
    
                    image.close();
                }
            }
        }
        @Override
        public void onCameraImageData(Image image) {
    
            synchronized(this)
            {
                Rect crop_rect = image.getCropRect();
    
                if(isPushingRtmp || isRTSPPublisherRunning) {
                    if(libPublisher != null)
                    {
                        Image.Plane[] planes = image.getPlanes();
    
                        //  crop_rect.left, crop_rect.top, crop_rect.width(), crop_rect.height(),
                        //  这里缩放宽高可以填0,使用原视视频宽高都可以的
                        libPublisher. SmartPublisherOnImageYUV420888(publisherHandle, image.getWidth(), image.getHeight(),
                                crop_rect.left, crop_rect.top, crop_rect.width(), crop_rect.height(),
                                planes[0].getBuffer(), planes[0].getRowStride(),
                                planes[1].getBuffer(), planes[2].getBuffer(), planes[1].getRowStride(), planes[1].getPixelStride(),
                                displayOrientation, 0, 0,
                                videoWidth, videoHeight, 1);
                    }
                }
            }
        }

    以上就是基础的Android Camera2介绍,和RTMP调用流程,感兴趣的可以自行学习。

  • 相关阅读:
    什么样的代码称得上是好代码?
    九年程序人生 总结分享
    Docker入门 第一课 --.Net Core 使用Docker全程记录
    阿里云 Windows Server 2012 r2 部署asp.net mvc网站 平坑之旅
    Visual studio 2015 Community 安装过程中遇到问题的终极解决
    Activiti6.0 spring5 工作流引擎 java SSM流程审批 项目框架
    java 进销存 库存管理 销售报表 商户管理 springmvc SSM crm 项目
    Leetcode名企之路
    24. 两两交换链表中的节点
    21. 合并两个有序链表
  • 原文地址:https://www.cnblogs.com/daniulivesdk/p/12636260.html
Copyright © 2011-2022 走看看