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





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



Android RTMP 直播推流技术专栏 :


0 . 资源和源码地址 :


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

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

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

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

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

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

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

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

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

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

11. 解析 AAC 音频格式 :

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






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


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


本篇博客中主要讲解 Android 端数据采集 , Camera 摄像头获取 NV21 数据后 , 将 NV21 数据转为 x264 需要的 I420 数据 , 然后将 I420 数据编码成 H.264 格式的数据 ;





一、 NV21 与 I420 数据格式转换



1 . 采集数据 :


① Camera 采集的数据 : 上面讲解了 Camera 摄像头采集图像数据之后 , 会回调 PreviewCallback 接口的 onPreviewFrame 方法 , onPreviewFrame 方法的 byte[] data 参数 , 就是 Camera 采集的图像数据 ;

② 采集的数据格式 : Camera 采集的图像数据是 NV21 格式的 ;



2 . x264 接收的格式 :


① RTMP 推流过程 : 在 RTMP 推流过程中 , 手机 Camera 采集到数据后 , 需要先使用 x264 将数据编码成 H.264 格式的 , 然后将 H.264 数据打包成 RTMP 数据 ;

② x264 接收格式 : x264 开源库的输入数据类型必须是 I420 格式 , 这里就涉及到了将 Camera 采集的 NV21 格式的数据 , 转为 x264 开源库需要的 I420 格式的数据 ;



3 . YUV420 格式 :


① 两个分支格式 : NV21 图像格式I420 图像格式都属于 YUV420 图像格式的分支 ;

② YUV 说明 : YUV 各种中的 Y 表示明亮度和灰度 , UV 表示色度和饱和度 ;

③ 黑白图片 : 如果只有 Y 数据 , 那么就是灰度图片 , 这张图片是黑白的 ; UV 数据表示的是图像的色彩 ;

④ 存储原理 : 灰度数据 Y 保证全部满足 , 多个灰度数据公用 UV 色彩数据 , 这样就可以减少图像数据的大小 ;





二、 NV21 数据格式



NV21 图像格式数据排列 :4×44 \times 4 像素的图片为例 , 其有 1616 个 Y 数据 , UV 数据只有 44 组 , 共 88 个 ;


① 数据的排列格式如下矩阵 :

[y1y2y3y4y5y6y7y8y9y10y11y12y13y14y15y16v1u1v2u2v3u3v4u4]\begin{bmatrix} y1 & y2 & y3 & y4 \\\\ y5 & y6 & y7 & y8 \\\\ y9 & y10& y11& y12 \\\\ y13& y14& y15& y16 \\\\ v1 & u1 & v2 & u2 \\\\ v3 & u3 & v4 & u4\\ \end{bmatrix}


② 内存中的数据表示 : 这也是 NV21 数据中的数组排列方式 , 每个 YUV 数据各占 11 字节 , 如 11 个 Y 数据占 11 字节 ;

byte[] data = {
	y1 , y2 , y3 , y4 ,
	y5 , y6 , y7 , y8 ,
	y9 , y10, y11, y12,
	y13, y14, y15, y16,
	v1 , u1 , v2 , u2 , 
	v3 , u3 , v4 , u4 , 
}

③ 数据使用情况 :

  • 灰度数据 y1 , y2 , y5 , y6 使用的是 v1 , u1 色彩数据 ;
  • 灰度数据 y3 , y4 , y7 , y8 使用的是 v2 , u2 色彩数据 ;
  • 灰度数据 y9 , y10, y13, y14 使用的是 v3 , u3 色彩数据 ;
  • 灰度数据 y11, y12, y15, y16 使用的是 v4 , u5 色彩数据 ;




三、 I420 数据格式



I420 图像格式数据排列 :4×44 \times 4 像素的图片为例 , 其有 1616 个 Y 数据 , UV 数据只有 44 组 , 共 88 个 ;


① 数据的排列格式如下矩阵 :

[y1y2y3y4y5y6y7y8y9y10y11y12y13y14y15y16u1u2u3u4v1v2v3v4]\begin{bmatrix} y1 & y2 & y3 & y4 \\\\ y5 & y6 & y7 & y8 \\\\ y9 & y10& y11& y12 \\\\ y13& y14& y15& y16 \\\\ u1 & u2 & u3 & u4 \\\\ v1 & v2 & v3 & v4\\ \end{bmatrix}


② 内存中的数据表示 : 这也是 NV21 数据中的数组排列方式 , 每个 YUV 数据各占 11 字节 , 如 11 个 Y 数据占 11 字节 ;

byte[] data = {
	y1 , y2 , y3 , y4 ,
	y5 , y6 , y7 , y8 ,
	y9 , y10, y11, y12,
	y13, y14, y15, y16,
	u1 , u2 , u3 , u4 , 
	v1 , v2 , v3 , v4
}

③ 数据使用情况 :

  • 灰度数据 y1 , y2 , y5 , y6 使用的是 v1 , u1 色彩数据 ;
  • 灰度数据 y3 , y4 , y7 , y8 使用的是 v2 , u2 色彩数据 ;
  • 灰度数据 y9 , y10, y13, y14 使用的是 v3 , u3 色彩数据 ;
  • 灰度数据 y11, y12, y15, y16 使用的是 v4 , u5 色彩数据 ;




四、 NV21 格式与 I420 格式对比



NV21 格式与 I420 格式对比 :


① 数据量 : 相同像素点数的图像 , 其数据大小是相同的 ;

② Y 灰度值排列 : 其灰度值排列方式是相同的 , 都是在 1 ~ 16 位置依次排列 16 个像素点数 ;

③ UV 色彩值排列 : 其色彩值排列是不同的 ,

  • NV21 格式中 , UV 色彩值是交替排序的 , v1 , u1 , v2 , u2 , v3 , u3 , v4 , u4 ;

  • I420 格式中 , UV 色彩值是 44 个 u 先排列 , 然后排 44 个 v 数据 , u1 , u2 , u3 , u4 , v1 , v2 , v3 , v4 ;





五、 NV21 与 I420 图像大小



NV21 与 I420 图像大小 :


① 推导过程 :

  • 44 像素值数据 : 44 个像素值 , 有 44 个 Y 灰度数据 , 占 44 字节 ; 11 个 Y 和 11 个 U 数据 , 占 22 字节 ;

  • 44 像素值数据大小 :总共有 4+1+1=64 + 1 + 1 = 6 字节 ;

  • 44 个像素对应 66 个字节 ;

  • 归纳 : nn 个像素对应 n×32\cfrac{n \times 3}{2} 个字节数据 ;


② 计算公式为 : 已知图像像素的宽度和高度 ;

()=××32图像大小 ( 字节 ) = \cfrac{宽度 \times 高度 \times 3}{2}





六、 NV21 格式转为 I420 格式算法



NV21 格式与 I420 格式的区别只是 UV 色彩值的排列方式不一样 , NV21图像转为 I420 图像 , 只需要将 NV21 格式图像交替排列的 UV 数据 , 按照 I420 格式图像的先 U 后 V 的顺序重新进行排列即可完成图像格式转换 ;


先将 NV21 格式数据中的 Y 灰度数据拷贝出来放在一个数组中 , 再将 NV21 数据中的 V 数据 , 和 U 数据分别拷贝出来 , 这里得到三个数组 , 分别存储 Y 数据 , U 数据 , V 数据 ;


将 NV21 数据中的 V 数据 , 和 U 数据分别拷贝出来的方式时 , 读取 Y 数据完毕后 , 取下一个数据就是 V 数据 , 放入 V 数组 , 再取下一个数据就是 U 数据 , 放入 U 数组 , 之后继续获取数据 , 交替放入 V 数组 / U 数组 , 最终就得到了 33 个数组 , 即 Y 数组 , U 数组 , V 数组 ;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章