文章目录
安卓直播推流专栏博客总结
一、 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 格式图片 }