音视频基础(网络传输): RTMP封包

简介: RTMP 概念与 HTTP(超文本传输协议)同样是一个基于 TCP 的 Real Time Messaging Protocol(实时消息传输协议)。由 Adobe Systems 公司为 Flash 播放器和服务器之间音频、视频和数据传输开发的一种开放协议 。在国内被广泛的应用于直播 领域。HTTP 默认端口为 80,RTMP 则为 1935。

改不完的 Bug,写不完的矫情。公众号 杨正友 现在专注移动基础开发 ,涵盖音视频和 APM,信息安全等各个知识领域;只做全网最 Geek 的公众号,欢迎您的关注!

RTMP 基础

RTMP 概念

与 HTTP(超文本传输协议)同样是一个基于 TCP 的 Real Time Messaging Protocol(实时消息传输协议)。由 Adobe Systems 公司为 Flash 播放器和服务器之间音频、视频和数据传输开发的一种开放协议 。在国内被广泛的应用于直播 领域。HTTP 默认端口为 80,RTMP 则为 1935。


我们通过阅读 Adobe 的协议规范,通过与服务器建立 TCP 通信,根据协议格式生成与解析数据即可使用 RTMP 进行 直播。当然我们也可以借助一些实现了 RTMP 协议的开源库来完成这一过程。

RTMPDump

RTMPDump 是一个用来处理 RTMP 流媒体的开源工具包。它能够单独使用进行 RTMP 的通信,也可以集成到 FFmpeg 中通过 FFmpeg 接口来使用 RTMPDump。 RTMPDump源码下载

交叉编译

在 Android 中可以直接借助 NDK 在 JNI 层调用 RTMPDump 来完成 RTMP 通信。但是首先必须得进行交叉编译。 RTMPDump 源码结构如下:

1681565752147.png

在根目录下提供了一个 Makefile 与一些 源文件。这里的源文件将会编译出一系列的可执行文件。然后我们需 要的并不是可执行文件,真正的对 RTMP 的实现都在 librtmp 子目录中。


在这个子目录中同样包含了一个 Makefile 文件。通过阅读 发现,它的源码并不多: OBJS=rtmp.o log.o amf.o hashswf.o parseurl.o 。因此我们 不进行预编译,即直接放入 AS 中借助 CMakeLists.txt 来进行编译。


这么做可以让我们方便的对库本身进行调试或 修改(实际上我们确实会稍微修改这个库的源码)。 在 AS 中复制 librtmp 置于: ,并为其编写 CMakeLists.txt


# 预编译宏
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_CRYPTO" )
# 所有源文件放入 rtmp_source 变量
file(GLOB rtmp_source *.c)
# 编译静态库
add_library(rtmp STATIC ${rtmp_source} )

在 中导入这个 CMakeLists.txt

cmake_minimum_required(VERSION 3.4.1)
# 导 入 其 他 目 录
cmakelist add_subdirectory(src/main/cpp/librtmp) add_library(XXX SHARED ...)
#XXX需要链接rtmp库
target_link_libraries(XXX rtmp ...)

RTMP 视频数据

RTMP 视频流格式与 FLV 很相似,通过查看 FLV 的格式文档,就能够知道 RTMP 视频数据应该怎么拼接。

RTMP 中的数据就是由 FLV 的 TAG 中的数据区构成。
1681565830266.png

FLV tags 结构

字段 字节 描述
类型 1 0x08:音频
0x09:视频
0x12: 脚本(描述信息)
数据大小 3 数据区的大小,不包括包头。
时间戳 3 当前帧相对时间戳,单位是毫秒。相对于第一个 TAG 时戳。
时戳扩展 1 如果时戳大于 0xFFFFFF,将会存在字节。
流 ID 3 总是 0
数据区 n 音、视频包

1681565862056.png

如上图,第一个字节 0x09 表示此段数据为视频,数据大小为 0x00,0x00,0x2F 即 47,时间戳为 0x00,0x00,0x00,时间戳扩展也为 0x00。(第二行)流 ID:0x00,0x00,0x00。


接下来就是视频数据,通过此处的 数据大小字段得知,数据长为 47 字节。


则从 0x17 开始,一直到最后一行的 0xC0,就是数据区域,而最后的 0x00,0x00,0x00,0x3A 即 58,表示的是这个数据块除最后 4 个字节的总大小。


本处为视频数据,那么从 0x17 开始,数据内容则为下面的部分。

视频数据

字段 占位 描述
帧类型 4 1:关键帧
2:普通帧
......
编码 ID 4 7: 高级视频编码 AVC......
视频数据 n AVC 则需要下面的 AVCVIDEOPACKET
AVCVIDEOPACKET
字段 字节 描述
类型 1 0:AVC 序列头(指导播放器如何解码)
1:其他单元(其他 NALU)
合成时间 3 对于 AVC 序列头,全为 0
数据 n 类型不同,数据不同

1681565899166.png

视频数据中 0x17 则表示了 1:关键帧与 7:高级视频编码 AVC,如果是普通帧,则此数据为 0x27。


而类型为: 0x00 表示这段数据为 AVC 序列头(avc sequence header)。


最后三个字节为合成时间。


而如果类型为 AVC 序列 头接下来的数据就是下面的内容:

AVC 序列头

在 AVCVIDEOPACKET 中如果类型为 0,则后续数据为:

类型 字节 说明
版本 1 0x01
编码规格 3 sps[1]+sps[2]+sps3
几个字节表示 NALU 的长度 1 0xFF,包长为 (0xFF& 3) + 1,也就是 4 字节表示
SPS 个数 1 0xE1,个数为 0xE1 & 0x1F 也就是 1
SPS 长度 2 整个 sps 的长度
sps 的内容 n 整个 sps
pps 个数 1 0x01,不用计算就是 1
pps 长度 2 整个 pps 长度
pps 内容 n 整个 pps 内容

1681565933454.png

0x01 为版本,后续数据按照上表记录,最后四字节上面说过:为这个数据块除最后 4 个字节的总大小。其中 SPS 与 PPS 是编码器在编码 H.264 视频时,在关键帧前会编码出的关于这个关键帧与需要参考该关键帧的 B/P 帧如何解码的内容,如:宽、高等信息。

其他
类型 字节 说明
包长 由 AVC 序列头中定义 后续长度
数据 n H.264 数据

一般情况下,组装的 RTMPPacket(RTMPDump 中的结构体)为:

1681565971856.png

这里的 sps 与 pps 表示 AVC 序列头

1681566004461.png

所以对于视频的数据封装,AVC 序列头为:

1681566033242.png

H.264 数据

H.264 码流在网络中传输时实际是以 NALU 的形式进行传输的。


NALU 就是 NAL UNIT,NAL 单元。


NAL 全称 Network Abstract Layer, 即网络抽象层。在 H.264/AVC 视频编码标准中,整个系统框架被分为了两个层面:视频编码层面 (VCL)和网络抽象层面(NAL)。


其中,前者负责有效表示视频数据的内容,而后者则负责格式化数据并提供头 信息,以保证数据适合各种信道和存储介质上的传输。


我们平时的每帧数据就是一个 NAL 单元。


往 RTMP 包中填充的就是 NAL 数据,但不是直接将编码出来的数据填充进去。


一段包含了 N 个图像的 H.264 裸数据,每个 NAL 之间由: 00 00 00 01 或者 00 00 01 进行分割。


在分割符之后的第一个字节,就是表示这个 nal 的类型。

  • 0x67:sps
  • 0x68: pps
  • 0x65: IDR 在将数据加入 RTMPPacket 的时候是需要去除分割符的。


1681566083927.png

所以完整的封包代码为:

1681566126305.png

NALU

NALU 就是 NAL UNIT,nal 单元。NAL 全称 Network Abstract Layer, 即网络抽象层,H.264 在网络上传输的结构。一 帧图片经过 H.264 编码器之后,就被编码为一个或多个片(slice),而装载着这些片(slice)的载体,就是 NALU 了 。

音频数据

RTMP 的音频数据相对视频比较简单,只需要根据是否为音频 audio specific config(记录音频的格式)。


如果为 audio specific config 拼接 0xAF,0x00,否则就只需要添加 0xAF,0x00。

1681566178494.png

0xAF 的由来:

1681566223862.png

我们的编码为:

  • 10:AAC,3:44100 采样率
  • 1:采样长度
  • 1:声道。
  • 按照位数表示数据就为:0xAF
  • 1681566257130.png而 audio specific config 只需要在发起推流时,发送音频数据之前发起一次即可。其数据为两字节:

1681566296234.png
1681566319220.png

  • 第一个数据:AAC-LC 值为 2,占用 5 位,则数据为: 0001 0
  • 第二个数据:采样率 44100 值为 4,占用 4 位,则数据为:0100
  • 第三个数据:声道,双声道为 2,单声道为 1,则数据为:0010(双声道),0001(单声道) 最后三位为 0,这样组成的数据 5+4+4+3=16 位,两字节。
  • 双声道:0x12 ,0x10
  • 单声道:0x12 ,0x08

1681566353375.png

Nginx-RTMP 服务器搭建

Linux 操作:


下载 nginx wget http://nginx.org/download/nginx-1.15.3.tar.gz


解压


tar xvf nginx-1.15.3.tar.gz


下载 nginx rtmp 模块


wget https://codeload.github.com/arut/nginx-rtmp-module/tar.gz/v1.2.1


解压


tar xvf v1.2.1


进入 nginx 目录


cd nginx-1.15.3


执行:

1681566393675.png

在这个过程中可能因为环境不同而出现不同错误,比如缺少 pcre、openssl 等,这时候就需要安装这些库。

https://blog.csdn.net/z920954494/article/details/52132125

编译完成后,安装在当前目录的 bin 目录下。

cd bin/conf

vim nginx.conf 修改为:

1681566428532.png

1681566455363.png

其实就是从 nginx-rtmp-module-1.2.1/test/nginx.conf 中拷贝

端口占用检查: lsof -i:8080

需要注意的是目录与端口是否被占用,比如 8080 端口被占用,可以改为了 8081,然后需要开放端口。

如果使用的阿里云服务器可以进入阿里云控制台开放

1681566495434.png

然后点击 配置规则 ,在新页面点击添加 安全组规则 ,开放 8081 端口,然后确定,就可以了。

1681566532524.png

配置完成后,就可以启动 nginx 了


在 nginx-1.15.3 目录 执行 bin/sbin/nginx 即可启动


bin/sbin/nginx -s stop 停止


一定要在 nginx-1.15.3 目录启动,因为上面的配置 error_log logs/error.log debug; 会去执行命令的目录下查找 logs。


如果 error_log 改成一个绝对路径 那就没关系了。


在浏览器输入 【IP】:8081/stat ,能访问就表示配置完成了。


此时一旦有播放器或者推流器连接到搭建的服务器刷新 此界面就能够看到如下界面:(手机推流,ffplay、网页、potplayer 播放)

1681567318478.png

相关文章
|
3月前
|
监控 网络协议 安全
|
3月前
|
缓存 算法 物联网
基于AODV和leach协议的自组网络平台matlab仿真,对比吞吐量,负荷,丢包率,剩余节点个数,节点消耗能量
本系统基于MATLAB 2017b,对AODV与LEACH自组网进行了升级仿真,新增运动节点路由测试,修正丢包率统计。AODV是一种按需路由协议,结合DSDV和DSR,支持动态路由。程序包含参数设置、消息收发等功能模块,通过GUI界面配置节点数量、仿真时间和路由协议等参数,并计算网络性能指标。 该代码实现了节点能量管理、簇头选举、路由发现等功能,并统计了网络性能指标。
170 73
|
1月前
|
网络协议 安全 算法
网络空间安全之一个WH的超前沿全栈技术深入学习之路(9):WireShark 简介和抓包原理及实战过程一条龙全线分析——就怕你学成黑客啦!
实战:WireShark 抓包及快速定位数据包技巧、使用 WireShark 对常用协议抓包并分析原理 、WireShark 抓包解决服务器被黑上不了网等具体操作详解步骤;精典图示举例说明、注意点及常见报错问题所对应的解决方法IKUN和I原们你这要是学不会我直接退出江湖;好吧!!!
网络空间安全之一个WH的超前沿全栈技术深入学习之路(9):WireShark 简介和抓包原理及实战过程一条龙全线分析——就怕你学成黑客啦!
|
3月前
|
存储 弹性计算 测试技术
阿里云服务器实例规格vCPU、内存、网络带宽、网络收发包PPS、连接数等性能指标详解
阿里云服务器ECS实例可以分为多种实例规格族。根据CPU、内存等配置,一种实例规格族又分为多种实例规格。而实例规格又包含vCPU、处理器、内存、vTPM、本地存储、网络带宽、网络收发包PPS、连接数、弹性网卡、云盘带宽、云盘IOPS等指标,本文为大家详细介绍实例规格的这些指标,以供大家了解和选择。
156 14
阿里云服务器实例规格vCPU、内存、网络带宽、网络收发包PPS、连接数等性能指标详解
|
1月前
|
网络协议 安全 算法
网络空间安全之一个WH的超前沿全栈技术深入学习之路(9-2):WireShark 简介和抓包原理及实战过程一条龙全线分析——就怕你学成黑客啦!
实战:WireShark 抓包及快速定位数据包技巧、使用 WireShark 对常用协议抓包并分析原理 、WireShark 抓包解决服务器被黑上不了网等具体操作详解步骤;精典图示举例说明、注意点及常见报错问题所对应的解决方法IKUN和I原们你这要是学不会我直接退出江湖;好吧!!!
|
7月前
|
SQL Oracle Java
实时计算 Flink版产品使用合集之网络包大小与配置不符该如何处理
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStreamAPI、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
3月前
|
网络协议 网络虚拟化
接收网络包的过程——从硬件网卡解析到IP
【9月更文挑战第18天】这段内容详细描述了网络包接收过程中机制。当网络包触发中断后,内核处理完这批网络包,会进入主动轮询模式,持续处理后续到来的包,直至处理间隙返回其他任务,从而减少中断次数,提高处理效率。此机制涉及网卡驱动初始化时注册轮询函数,通过软中断触发后续处理,并逐步深入内核网络协议栈,最终到达TCP层。整个接收流程分为多个层次,包括DMA技术存入Ring Buffer、中断通知CPU、软中断处理、以及进入内核网络协议栈等多个步骤。
|
4月前
|
存储 缓存 网络协议
网络丢包排查方法
网络丢包排查方法
|
4月前
|
内存技术
思科TAC专家分享的内嵌抓包法,真是网络大神必备技能啊!
思科TAC专家分享的内嵌抓包法,真是网络大神必备技能啊!
|
4月前
|
移动开发 网络协议 算法
(十)Netty进阶篇:漫谈网络粘包、半包问题、解码器与长连接、心跳机制实战
在前面关于《Netty入门篇》的文章中,咱们已经初步对Netty这个著名的网络框架有了认知,本章的目的则是承接上文,再对Netty中的一些进阶知识进行阐述,毕竟前面的内容中,仅阐述了一些Netty的核心组件,想要真正掌握Netty框架,对于它我们应该具备更为全面的认知。
228 2