文章目录

  • 安卓直播推流专栏博客总结
  • 一、 NV21 图像数据中的 YUV 数据简介
  • 二、向 x264 编码图片
  • 三、 提取 NV21 数据中的灰度数据 Y
  • 四、 提取 NV21 数据中的饱和度数据 U 和 色彩值数据 V
  • 五、 图像编码操作
  • 六、 x264 视频数据编码代码示例

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


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 服务器中 ;

本篇博客中介绍如下内容 , Java 层将 Camera 采集的 NV21 格式的数据传入 JNI 层 , 在 JNI 中使用 x264 编码器将 NV21 图像数据编码为 H.264 视频数据 ;

一、 NV21 图像数据中的 YUV 数据简介


Camera 采集的数据是 NV21 格式的 ;

NV21 是 YUV 格式中的一种 , Y 代表灰度 , U 代表色彩值 , V 代表色彩的饱和度 ;

NV21 格式数据在内存中的表示 : 以 4×44 \times 44×4 大小的图片为例 , 先存放 161616 个像素的灰度值 Y 数据 , 然后 444 组色彩值 V 数据和饱和度 U 数据交替存放 ;

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 ,
}

【Android RTMP】Android Camera 视频数据采集预览 ( NV21 图像格式 | I420 图像格式 | NV21 与 I420 格式对比 | NV21 转 I420 算法 ) 博客中详细介绍了 NV21 数据中的 YUV 数据格式 ;

二、向 x264 编码图片


1 . x264 编码图片引入 : x264 编码器对图像数据进行编码 , 要先将 NV21 的图像数据中的 YUV 数据分别存储到 x264 编码图片中 ;

2 . x264_picture_t 结构体 : 该结构体代表了 x264 编码图片 , 该结构体定义在 x264.h 中 ;

typedef struct x264_picture_t
{// ...// 存储要编码的图片数据x264_image_t img;// ...
} x264_picture_t;

3 . x264 编码图片使用 :

① 声明 x264_picture_t 指针变量 : C++ 堆内存中的对象必须使用指针接收 ;

// x264 需要编码的图片
x264_picture_t *x264EncodePicture = 0;

② 初始化 x264_picture_t 对象 : 首先创建 x264_picture_t 对象 , 设置编码方式为 I420 , 以及图片的宽度 x264Param.i_width , 和图片高度 x264Param.i_height ;

// 初始化 x264 编码图片
x264EncodePicture = new x264_picture_t;
// 为 x264 编码图片分配内存
x264_picture_alloc(x264EncodePicture, X264_CSP_I420, x264Param.i_width, x264Param.i_height);

③ 释放 x264_picture_t 对象 : 调用 x264_picture_clean 方法释放资源 , 然后销毁对象 ;

// 只要调用该方法, x264_picture_t 必须重新进行初始化
// 因为图片大小改变了, 那么对应的图片不能再使用原来的参数了
// 释放原来的 x264_picture_t 图片, 重新进行初始化
// 析构函数中也要进行释放
if (x264EncodePicture) {x264_picture_clean(x264EncodePicture);delete x264EncodePicture;x264EncodePicture = 0;
}

三、 提取 NV21 数据中的灰度数据 Y


1 . 计算灰度数据的个数 : 灰度数据的个数 , 就是像素的个数 , 每个像素点都有一个灰度数据 ;

// 灰色值的个数, 单位字节
YByteCount = width * height;

2 . 将灰度数据存储到 x264_picture_t 中 : 在 NV21 格式的图像数据中 , 前 YByteCount 个数据是 YByteCount 个像素点的灰度数据 , 将这些灰度数据拷贝到 x264 编码图像中 ;

3 . 数据接收方 : x264_picture_t* x264EncodePicture 图像的 img 成员的 plane[0] 指针指向的地址 , 接收 YByteCount 个灰度数据 ;

4 . 代码示例 :

    // 从 Camera 采集的 NV21 格式的 data 数据中// 将 YUV 中的 Y 灰度值数据, U 色彩值数据, V 色彩饱和度数据提取出来memcpy(x264EncodePicture->img.plane[0], data, YByteCount);

四、 提取 NV21 数据中的饱和度数据 U 和 色彩值数据 V


1 . 计算饱和度数据 U 的个数 : 饱和度数据 U 的个数 , 与色彩值数据 V 的个数相同 , 是灰度值数据 Y 个数的 14\cfrac{1}{4}41​ ;

// 灰色值的个数, 单位字节
YByteCount = width * height;
// U 色彩值, V 饱和度 个数
UVByteCount = YByteCount / 4;

2 . 将灰度数据存储到 x264_picture_t 中 : 在 NV21 格式的图像数据中 , 色彩值数据 V , 饱和度数据 U , 交替存储 , V 在前 ( 偶数位置 ), U 在后 ( 奇数位置 ) ;

① U 色相 / 色彩值数据 : 存储在 YByteCount 后的奇数索引位置

② V 色彩饱和度数据 : 存储在 YByteCount 后的偶数索引位置

3 . 代码示例 :

    // 取出 NV21 数据中交替存储的 VU 数据// V 在前 ( 偶数位置 ), U 在后 ( 奇数位置 ), 交替存储for(int i = 0; i < UVByteCount; i ++){// U 色相 / 色彩值数据, 存储在 YByteCount 后的奇数索引位置*(x264EncodePicture->img.plane[1] + i) = *(data + YByteCount + i * 2 + 1);// V 色彩饱和度数据, 存储在 YByteCount 后的偶数索引位置*(x264EncodePicture->img.plane[2] + i) = *(data + YByteCount + i * 2);}

五、 图像编码操作


1 . 图片编码 :

① 普通帧 : 一般情况下, 一张图像编码出一帧数据 , pp_nal 是一帧数据, pi_nal 表示帧数为 1

② 关键帧 : 如果这个帧是关键帧, 那么 pp_nal 将会编码出 3 帧数据 , pi_nal 表示帧数为 3

③ 关键帧数据 : SPS 帧, PPS 帧, 画面帧 ;

2 . 编码方法函数原型 :

int x264_encoder_encode( x264_t *, x264_nal_t **pp_nal, int *pi_nal, x264_picture_t *pic_in, x264_picture_t *pic_out );

① x264_t * 参数 : x264 视频编码器

② x264_nal_t **pp_nal 参数 : 编码后的帧数据, 可能是 1 帧, 也可能是 3 帧

③ int *pi_nal 参数 : 编码后的帧数, 1 或 3

④ x264_picture_t *pic_in 参数 : 输入的 NV21 格式的图片数据

⑤ x264_picture_t *pic_out 参数 : 输出的图片数据

3 . 图像编码代码示例 :

    // 编码后的数据, 这是一个帧数据, 1 帧或 3帧x264_nal_t *pp_nal;// 编码后的数据个数, 帧的个数, 1 或 3int pi_nal;// 输出的图片数据x264_picture_t pic_out;// 编码核心操作x264_encoder_encode(x264VedioCodec, &pp_nal, &pi_nal, x264EncodePicture, &pic_out);

六、 x264 视频数据编码代码示例


x264 编码器将 NV21 图像数据编码为 H.264 代码 :

/*** 视频数据编码* 接收 int8_t 类型的原因是, 这里处理的是 jbyte* 类型参数* jbyte 类型就是 int8_t 类型* @param data 视频数据指针*/
void VedioChannel::encodeCameraData(int8_t *data) {// 加锁, 设置视频编码参数 与 编码互斥pthread_mutex_lock(&mMutex);// 参数中的 data 是 NV21 格式的// 前面 YByteCount 字节个 Y 灰度数据// 之后是 UVByteCount 字节个 VU 数据交替存储// UVByteCount 字节 V 数据, UVByteCount 字节 U 数据// 从 Camera 采集的 NV21 格式的 data 数据中// 将 YUV 中的 Y 灰度值数据, U 色彩值数据, V 色彩饱和度数据提取出来memcpy(x264EncodePicture->img.plane[0], data, YByteCount);// 取出 NV21 数据中交替存储的 VU 数据// V 在前 ( 偶数位置 ), U 在后 ( 奇数位置 ), 交替存储for(int i = 0; i < UVByteCount; i ++){// U 色相 / 色彩值数据, 存储在 YByteCount 后的奇数索引位置*(x264EncodePicture->img.plane[1] + i) = *(data + YByteCount + i * 2 + 1);// V 色彩饱和度数据, 存储在 YByteCount 后的偶数索引位置*(x264EncodePicture->img.plane[2] + i) = *(data + YByteCount + i * 2);}// 下面两个是编码时需要传入的参数, 这两个参数地址, x264 编码器会想这两个地址写入值// 编码后的数据, 这是一个帧数据x264_nal_t *pp_nal;// 编码后的数据个数, 帧的个数int pi_nal;// 输出的图片数据x264_picture_t pic_out;/*int x264_encoder_encode( x264_t *, x264_nal_t **pp_nal, int *pi_nal,x264_picture_t *pic_in, x264_picture_t *pic_out );函数原型 :x264_t * 参数 : x264 视频编码器x264_nal_t **pp_nal 参数 : 编码后的帧数据, 可能是 1 帧, 也可能是 3 帧int *pi_nal 参数 : 编码后的帧数, 1 或 3x264_picture_t *pic_in 参数 : 输入的 NV21 格式的图片数据x264_picture_t *pic_out 参数 : 输出的图片数据普通帧 : 一般情况下, 一张图像编码出一帧数据, pp_nal 是一帧数据, pi_nal 表示帧数为 1关键帧 : 如果这个帧是关键帧, 那么 pp_nal 将会编码出 3 帧数据, pi_nal 表示帧数为 3关键帧数据 : SPS 帧, PPS 帧, 画面帧*/x264_encoder_encode(x264VedioCodec, &pp_nal, &pi_nal, x264EncodePicture, &pic_out);// 后续还有操作, 本博客中暂时省略 ... // 解锁, 设置视频编码参数 与 编码互斥pthread_mutex_unlock(&mMutex);
}

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

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

    文章目录 安卓直播推流专栏博客总结 一. NV21 数据传入 Native 层 二. jbyte * 数据类型 ( Java 中的 byte[] 数组传入 JNI 处理方式 ) 三. 局部引用处理 四 ...

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

    文章目录 安卓直播推流专栏博客总结 一. 编写快速搭建 RTMP 服务器 Shell 脚本 二. RTMP 快速搭建方法 三.创建阿里云 RTMP 服务器镜像 四.浏览器查看直播内容 五.前置 / 后 ...

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

    文章目录 安卓直播推流专栏博客总结 一. 后置摄像头顺时针旋转 90 度 二. 前置摄像头顺时针旋转 90 度 三. NV21 格式图像旋转代码 安卓直播推流专栏博客总结 Android RTMP 直 ...

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

    文章目录 安卓直播推流专栏博客总结 一. NV21 图像格式与 Camera图像传感器方向问题 二. NV21 图像格式视频旋转 1. 图像旋转问题及解决方案 ( 顺时针旋转 90 度 ) 2. NV ...

  5. 【Android RTMP】安卓直播推流总结 ( 直播服务器搭建 | NV21 图像采集 | H.264 视频编码 | PCM 音频采集 | AAC 音频编码 | RTMP 包封装推流 )

    文章目录 一. 安卓直播推流专栏博客总结 二. 相关资源介绍 三. GitHub 源码地址 四. 整体 Android 直播推流数据到服务器并观看直播演示过程 Android 直播推流流程 : 手机采 ...

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

    文章目录 安卓直播推流专栏博客总结 一. AAC 音频格式解析 二. FLV 音频数据标签解析 1. 分析 FLV 格式中的 AAC 音频格式数据 2. AAC 音频特殊配置 3. AAC 音频数据标 ...

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

    文章目录 安卓直播推流专栏博客总结 一. FAAC 头文件与静态库拷贝到 Android Studio 二. CMakeList.txt 构建脚本配置 三. Java 层 AudioRecord 音频 ...

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

    文章目录 安卓直播推流专栏博客总结 一. x264 编码后的 H.264 数据帧 二. RTMP 协议中 关键帧 / 非关键帧 数据格式 说明 三. 判定 H.264 帧数据分隔符 四. 初始化 RT ...

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

    文章目录 安卓直播推流专栏博客总结 一. x264 编码器参数设置引入 二. 获取 x264 编码器参数 三. 设置 x264 编码器编码规格 四. 设置 x264 编码器编码图像数据格式 五. 设置 ...

最新文章

  1. python控制结构实训_《python 从入门到精通》§5 控制结构
  2. Nature封面:每天工作21.5小时的AI化学家,8天内完成688个实验,已自主发现一种全新催化剂...
  3. 11月14日云栖精选夜读 | 动画+原理+代码,解读十大经典排序算法
  4. excel查找窗口被拉边上_你会做 Excel目录 吗?这个奇葩方法100%的人不知道
  5. c#与科学计算之一:发掘 C# 特性赋予科学计算项目以威力(转贴)
  6. 安装linux_linux安装mysql
  7. Linux 性能分析工具总结
  8. 老鼠怕猫是鼻子决定的?!
  9. 【Qt】Qt登录对话框(设计器实现)
  10. 『设计模式』撩妹秘籍竟是使用设计模式的抽象工厂模式
  11. C++基础02-C++对c的拓展
  12. 域外计算机访问域内共享,域外用户如何拥有让其他电脑加域或退域的权限
  13. [转][进阶]-Python3 异步编程详解
  14. 如何在C++中调用C程序?(讲的比较清楚)
  15. T-Sql 创建全文索引
  16. ipython notebook使用教程
  17. 《Java编程思想》读后感
  18. 亚马逊运营实用教程 上线前三个月如何做
  19. 分布式事务介绍以及几种方式对比
  20. 股票买卖明细接口是怎样实现查询交易数据的?

热门文章

  1. python web shell
  2. Mysql优化之开山篇
  3. listalias - 列出用户和系统别名
  4. Python学习---协程 1226
  5. 计划程序:拒绝重复工作,让效率翻倍!
  6. UESTC 电子科大专题训练 数据结构 J
  7. HDU 2896 病毒侵袭 AC自动机
  8. android5.0(Lollipop) BLE Peripheral深入理解系统篇之提高篇
  9. cocos2d-x 3.2 listview scorllview 等容器在小米华为等部分手机显示泛白解决
  10. SAP EWM Table Overview [转]