【Android RTMP】Android Camera 视频数据采集预览 ( 视频采集相关概念 | 摄像头预览参数设置 | 摄像头预览数据回调接口 )

文章目录

安卓直播推流专栏博客总结

一、 Android 端数据采集涉及到的相关概念

二、 Camera 预览图像尺寸设置

三、 获取摄像头采集的数据格式





安卓直播推流专栏博客总结


Android RTMP 直播推流技术专栏 :



0 . 资源和源码地址 :


资源下载地址 : 资源下载地址 , 服务器搭建 , x264 , faac , RTMPDump , 源码及交叉编译库 , 本专栏 Android 直播推流源码 ;

GitHub 源码地址 : han1202012 / RTMP_Pusher


1. 搭建 RTMP 服务器 : 下面的博客中讲解了如何在 VMWare 虚拟机中搭建 RTMP 直播推流服务器 ;


【Android RTMP】RTMP 直播推流服务器搭建 ( Ubuntu 18.04.4 虚拟机 )

2. 准备视频编码的 x264 编码器开源库 , 和 RTMP 数据包封装开源库 :


【Android RTMP】RTMPDumb 源码导入 Android Studio ( 交叉编译 | 配置 CMakeList.txt 构建脚本 )


【Android RTMP】Android Studio 集成 x264 开源库 ( Ubuntu 交叉编译 | Android Studio 导入函数库 )


3. 讲解 RTMP 数据包封装格式 :


【Android RTMP】RTMP 数据格式 ( FLV 视频格式分析 | 文件头 Header 分析 | 标签 Tag 分析 | 视频标签 Tag 数据分析 )


【Android RTMP】RTMP 数据格式 ( FLV 视频格式分析 | AVC 序列头格式解析 )


4. 图像数据采集 : 从 Camera 摄像头中采集 NV21 格式的图像数据 , 并预览该数据 ;


【Android RTMP】Android Camera 视频数据采集预览 ( 视频采集相关概念 | 摄像头预览参数设置 | 摄像头预览数据回调接口 )


【Android RTMP】Android Camera 视频数据采集预览 ( NV21 图像格式 | I420 图像格式 | NV21 与 I420 格式对比 | NV21 转 I420 算法 )


【Android RTMP】Android Camera 视频数据采集预览 ( 图像传感器方向设置 | Camera 使用流程 | 动态权限申请 )


5. NV21 格式的图像数据编码成 H.264 格式的视频数据 :


【Android RTMP】x264 编码器初始化及设置 ( 获取 x264 编码参数 | 编码规格 | 码率 | 帧率 | B帧个数 | 关键帧间隔 | 关键帧解码数据 SPS PPS )


【Android RTMP】x264 图像数据编码 ( Camera 图像数据采集 | NV21 图像数据传到 Native 处理 | JNI 传输字节数组 | 局部引用变量处理 | 线程互斥 )


【Android RTMP】x264 图像数据编码 ( NV21 格式中的 YUV 数据排列 | Y 灰度数据拷贝 | U 色彩值数据拷贝 | V 饱和度数据拷贝 | 图像编码操作 )


6. 将 H.264 格式的视频数据封装到 RTMP 数据包中 :


【Android RTMP】RTMPDump 封装 RTMPPacket 数据包 ( 封装 SPS / PPS 数据包 )


【Android RTMP】RTMPDump 封装 RTMPPacket 数据包 ( 关键帧数据格式 | 非关键帧数据格式 | x264 编码后的数据处理 | 封装 H.264 视频数据帧 )


【Android RTMP】RTMPDump 推流过程 ( 独立线程推流 | 创建推流器 | 初始化操作 | 设置推流地址 | 启用写出 | 连接 RTMP 服务器 | 发送 RTMP 数据包 )


7. 阶段总结 : 阿里云服务器中搭建 RTMP 服务器 , 并使用电脑软件推流和观看直播内容 ;


【Android RTMP】RTMP 直播推流 ( 阿里云服务器购买 | 远程服务器控制 | 搭建 RTMP 服务器 | 服务器配置 | 推流软件配置 | 直播软件配置 | 推流直播效果展示 )


【Android RTMP】RTMP 直播推流阶段总结 ( 服务器端搭建 | Android 手机端编码推流 | 电脑端观看直播 | 服务器状态查看 )


8. 处理 Camera 图像传感器导致的 NV21 格式图像旋转问题 :


【Android RTMP】NV21 图像旋转处理 ( 问题描述 | 图像顺时针旋转 90 度方案 | YUV 图像旋转细节 | 手机屏幕旋转方向 )


【Android RTMP】NV21 图像旋转处理 ( 图像旋转算法 | 后置摄像头顺时针旋转 90 度 | 前置摄像头顺时针旋转 90 度 )


9. 下面这篇博客比较重要 , 里面有一个快速搭建 RTMP 服务器的脚本 , 强烈建议使用 ;


【Android RTMP】NV21 图像旋转处理 ( 快速搭建 RTMP 服务器 Shell 脚本 | 创建 RTMP 服务器镜像 | 浏览器观看直播 | 前置 / 后置摄像头图像旋转效果展示 )

10. 编码 AAC 音频数据的开源库 FAAC 交叉编译与 Android Studio 环境搭建 :


【Android RTMP】音频数据采集编码 ( 音频数据采集编码 | AAC 高级音频编码 | FAAC 编码器 | Ubuntu 交叉编译 FAAC 编码器 )


【Android RTMP】音频数据采集编码 ( FAAC 头文件与静态库拷贝到 AS | CMakeList.txt 配置 FAAC | AudioRecord 音频采样 PCM 格式 )


11. 解析 AAC 音频格式 :


【Android RTMP】音频数据采集编码 ( AAC 音频格式解析 | FLV 音频数据标签解析 | AAC 音频数据标签头 | 音频解码配置信息 )

12 . 将麦克风采集的 PCM 音频采样编码成 AAC 格式音频 , 并封装到 RTMP 包中 , 推流到客户端 :


【Android RTMP】音频数据采集编码 ( FAAC 音频编码参数设置 | FAAC 编码器创建 | 获取编码器参数 | 设置 AAC 编码规格 | 设置编码器输入输出参数 )


【Android RTMP】音频数据采集编码 ( FAAC 编码器编码 AAC 音频解码信息 | 封装 RTMP 音频数据头 | 设置 AAC 音频数据类型 | 封装 RTMP 数据包 )


【Android RTMP】音频数据采集编码 ( FAAC 编码器编码 AAC 音频采样数据 | 封装 RTMP 音频数据头 | 设置 AAC 音频数据类型 | 封装 RTMP 数据包 )






Android 直播推流流程 : 手机采集视频 / 音频数据 , 视频数据使用 H.264 编码 , 音频数据使用 AAC 编码 , 最后将音视频数据都打包到 RTMP 数据包中 , 使用 RTMP 协议上传到 RTMP 服务器中 ;



Android 端中主要完成手机端采集视频数据操作 , 并将视频数据传递给 JNI , 在 NDK 中使用 x264 将图像转为 H.264 格式的视频 , 最后将 H.264 格式的视频打包到 RTMP 数据包中 , 上传到 RTMP 服务器中 ;



本篇博客中主要讲解 Android 端数据采集 , Camera 摄像头设置 ;






一、 Android 端数据采集涉及到的相关概念


1 . 图像采集显示组件 : 布局文件中添加 SurfaceView , 用于在该 SurfaceView 组件中预览 Camera 采集的图像数据 ;




2 . Android 摄像头常量 : Android 中使用特定的常量指定使用哪个摄像头 ;



① 指定后摄像头 : 使用 Camera.CameraInfo.CAMERA_FACING_BACK 常量 , 指定后摄像头 ;


② 指定前摄像头 : 使用 Camera.CameraInfo.CAMERA_FACING_FRONT 常量 , 指定前摄像头 ;




3 . 码率 与 帧率 :



① 码率 : 单位时间内 , 传输的视频数据的位数 , 单位是 BPS ;


② 码率与视频质量 : 码率与视频编码后的数据量成正比 , 码率越高 , 允许的数据量大小越高 , 视频越清晰 , 数据量随之变大 ;


③ 码率极限值 : 码率不是越大越好 , 码率有一个极限值 , 固定的宽高的视频码率有一个最大值 , 高于该最大值 , 没有任何意义 , 不能提升视频质量 ;


④ 帧率 : FPS , 界面刷新频率 , 单位 赫兹 Hz , 每秒刷新的画面次数 ;






二、 Camera 预览图像尺寸设置


Camera 采集图像数据时 , 会通过指定的回调函数返回图像数据 , 这些图像数据称为预览数据 , 图像肯定有对应的尺寸 , 这些尺寸是 Camera 启动时设置的 , 称为预览尺寸 PreviewSize ;




1 . Camera 预览图像尺寸设置 :



① 用户设置测图像预览尺寸 : 用户设置 Camera 参数时 , 会设置一个 Camera 摄像头预览图像宽高参数 , 这个值用户可以随意设置 ;


② 系统预置的 Camera 预览尺寸 : 但是实际上 , Android 系统中的 Camera 摄像头的尺寸参数必须从几个预置的预览尺寸中选择 , 这些预览尺寸是厂家设定好的 , 用户无法设置 Camera 的语言尺寸 ;



厂家为该 Camera 预置了若干个预览尺寸 , 需要选择一个用户设置的尺寸与系统预置尺寸差距最小的那个 , 才能更好的实现用户意图 ;




2 . 预览尺寸选择方法 :



① 用户设置像素总数 : 用户设置的宽高像素值相乘, 就是用户设置像素总数 ;


② 系统支持像素总数 : 屏幕支持的 宽 高 像素值相乘, 就是系统支持的某个宽高的像素总数 ;


③ 选择尺寸 : 找出一个系统预置的预览尺寸的 系统支持像素总数 , 该数值与 用户设置像素总数 最接近即可 , 该预览尺寸就是要设置给 Camera 的预览尺寸 ;



3 . 代码示例 : 根据用户设置的尺寸 , 选择最接近的 Camera 支持的预览尺寸值 ;


/**
     * 用户设置的高度
     */
    private int mHeight;
    /**
     * 用户设置的宽度
     */
    private int mWidth;
    /**
     * 设置 Camera 摄像头的参数
     * 宽度, 高度
     *
     * 摄像头支持的宽高值是固定的, 不能人为的随意设置
     * 手机给出一组支持的宽高值, 可以选择其中的某一个进行设置
     *
     * 用户虽然设置了一个宽高值, 这个宽高值肯定不能直接设置给 Camera 摄像头
     * 需要对比 Camera 支持的一组宽高值, 哪一个与用户设置的最接近
     * 这个最相似的宽高值就是我们要设置的值
     *
     * 对比方法 : 对比像素总数
     * 用户设置像素总数 : 用户设置的 宽 高 像素值相乘, 就是用户设置像素总数
     * 系统支持像素总数 : 屏幕支持的 宽 高 像素值相乘, 就是系统支持的某个宽高的像素总数
     *
     * 找出上述 用户设置像素总数 和 系统支持像素总数 最接近的的那个 系统支持像素总数
     *      对应的 屏幕支持的 宽 高 值
     *
     * @param parameters
     */
    private void setPreviewSize(Camera.Parameters parameters) {
        // 1. 获取摄像头参数中的预览图像大小参数
        List<Camera.Size> supportedPreviewSizes = parameters.getSupportedPreviewSizes();
        // 2. 下面开始遍历获取与用户设置的宽高值最接近的, Camera 支持的宽高值
        // 获取系统 Camera 摄像头支持的最低的摄像头
        //      Camera.Size 中有宽度和高度参数
        Camera.Size currentSupportSize = supportedPreviewSizes.get(0);
        // 对比第 0 个系统支持的像素总数 与 用户设置的像素总数 差值
        //      之后会逐个对比, 每个系统支持的像素总数 与 用户设置像素总数 差值
        //      选择差值最小的那个像素值
        int minDeltaOfPixels = 
            Math.abs(currentSupportSize.height * currentSupportSize.width - mWidth * mHeight);
        // 对比完成之后, 删除像素值
        //supportedPreviewSizes.remove(0);
        // 遍历系统支持的宽高像素集合, 如果
        Iterator<Camera.Size> iterator = supportedPreviewSizes.iterator();
        while (iterator.hasNext()) {
            // 当前遍历的的系统支持的像素宽高
            Camera.Size tmpSupportSize = iterator.next();
            // 计算当前的设备支持宽高与用户设置的宽高的像素点个数差值
            int tmpDeltaOfPixels = 
                Math.abs(tmpSupportSize.height * tmpSupportSize.width - mWidth * mHeight);
            // 如果当前的差分值 小于 当前最小像素差分值, 那么使用当前的数据替代
            if (tmpDeltaOfPixels < minDeltaOfPixels) {
                minDeltaOfPixels = tmpDeltaOfPixels;
                currentSupportSize = tmpSupportSize;
            }
        }
        // 3. 选择出了最合适的 Camera 支持的宽高值
        mWidth = currentSupportSize.width;
        mHeight = currentSupportSize.height;
        // 4. 为 Camera 设置最合适的像素值
        parameters.setPreviewSize(mWidth, mHeight);
    }






三、 获取摄像头采集的数据格式


1 . 设置数据预览回调接口 :



① 设置方法 : Android 中的摄像头 Camera 通过调用 setPreviewCallbackWithBuffer 函数 , 传递一个回调接口对象 ;


② 调用的 setPreviewCallbackWithBuffer 方法原型 :


public final void setPreviewCallbackWithBuffer(PreviewCallback cb)

1

③ 传递的接口参数 :


public interface PreviewCallback{
    void onPreviewFrame(byte[] data, Camera camera);
}



2 . PreviewCallback 回调接口的作用 : PreviewCallback 接口中定义了 onPreviewFrame 方法 , 该方法中的 byte[] data 参数就是摄像头采集的数据 ;



3 . 采集到的图像数据 : 这是摄像头采集的图像数据 , Android 中的 Camera 摄像头采集数据成功后 , 就会回调该 PreviewCallback 接口中的 onPreviewFrame 方法 , 可以让用户获取并使用这些图像数据 ;



这是数据的格式是 NV21 格式的 ;


// 设置 Camera 预览数据回调接口
    mCameraHelper.setPreviewCallback(this);
    // ....
    /**
     * Camera 摄像头采集数据完毕, 通过回调接口传回数据
     * 数据格式是 nv21 格式的
     * @param data
     * @param camera
     */
    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        // 处理该获取的 Camera 采集的 data 数据, nv21 格式图片
    }


上一篇:自动化运维工具ansible安装及使用


下一篇:HTML5实现刮奖效果