
本文共 5398 字,大约阅读时间需要 17 分钟。
文章目录
(一) 预备知识
关于RTMP推流
1、消息
消息格式
RTMP消息头和载荷两部分。
消息头
值 | 长度 | 含义 |
---|---|---|
message type | 1byte | 表示消息类型 |
payload length | 3byte | 表示载荷的字节数,big-endian格式 |
timestamp | 4byte | 表示消息的时间戳,big-endian格式 |
stream id | 3byte | 表示消息流ID,big-endian格式 |
消息类型:1-7的消息ID用于协议控制消息8、9的消息分别用于传输音频和视频数据15-20的消息用于发送AMF编码的命令,负责用户与服务器之间的交互,比如播放,暂停
载荷
载荷中消息中包含的真实数据。例如,它可以是音频样本或压缩的视频数据。
2、块
消息是rtmp协议的基本数据单元,在网络传输时,消息会被重新封装成块进行传输,每个块都有固定的大小,如果消息大小大于块的大小,消息就会被拆分成几个块发送。
块格式
块由头和载荷组成
块头结构
值 | 长度 | 含义 |
---|---|---|
basic header | 1byte或2byte或3byte | 块基本头 |
chunk msg header | 11byte或2byte或3byte | 块消息头 |
extended timestamp | 4byte | 扩展时间戳 |
a、块基本头(basic header)
基本头第一个字节的结构:
值 | 长度 | 含义 |
---|---|---|
fmt | 2bit | 块格式 |
cs id | 6bit | 块流ID |
b、块消息头(chunk msg header)
类型0
总共11byte,格式如下:
值 | 长度 | 含义 |
---|---|---|
timestamp | 3byte | 时间戳 |
message length | 3byte | 载荷的长度 |
message type id | 1byte | 消息类型id |
message stream id | 4byte | 消息流id |
类型1
类型1总共7byte,格式如下:
值 | 长度 | 含义 |
---|---|---|
timestamp | 3byte | 时间戳 |
message length | 3byte | 载荷的长度 |
message type id | 1byte | 消息类型id |
类型2
类型2总共3byte,格式如下:
值 | 长度 | 含义 |
---|---|---|
timestamp | 3byte | 时间戳 |
类型3
类型3的块没有头。流ID,消息长度,时间戳都不出现。这种类型的块使用与先前块相同的数据。当一个消息被分成多个块,除了第一块以外,所有的块都应使用这种类型。
3、rtmp的消息类型
rtmp的消息类型可分为三大类:协议控制消息、用户控制消息、RTMP命令消息
协议控制消息
- 设置块大小消息(Message Type=1)
- 终止消息(Message Type=2)
- 确认消息(Message Type=3)
- 确认窗口大小消息(Message Type=5)
- 设置对端带宽消息(Message Type=6)
用户控制消息
(Message Type=4)
RTMP使用消息类型ID 4表示用户控制消息。这些消息包含RTMP流传输层所使用的信息。协议控制消息使用的ID为 1、2、3、5 和 6 (前面已经介绍过了)。
用户控制消息应该使用消息流ID 0 (以被认为是控制流),并且以RTMP块流发送时以块流ID为2。协议控制消息接收立即生效;解析时,时间戳字段被忽略。
RTMP命令消息
数据消息(Message Type=18或15)
客户端或服务端通过本消息向对方发送元数据和用户数据。元数据包括数据的创建时间、时长、主题等细节。消息类型为18的用AMF0编码,消息类型为15的用AMF3编码。
共享对象消息 (Message Type=19或16)
共享对象是跨多个客户端,实例同步的FLASH对象(名值对的集合)。消息类型kMsgContainer=19用AMF0编码,kMsgContainerEx=16用AMF3编码,这两个消息用于共享对象事件。每个消息可包含多个事件。
4、实例分析rtmp传输过程
- 握手
- 建立网络连接
- 建立流
- 播放
(1)握手
(1)握手开始于客户端发送C0,C1块。
(2)服务端在接收到C0后发送S0,S1块。
(3)客户端接收到S0,S1块后,发送C2块,服务端接收到C0,C1块后发送S2块。
(4)当客户端接收到S2,服务端接受到C2,分别校验后握手成功
(2)建立连接
(1)客户端发送"connect消息"请求连接。
(2)服务收到"connect"请求后,发送一个"确认窗口大小消息"。
(3)服务端发送"设置带宽消息"到客户端。
(4)客户端处理"设置带宽消息"后,发送"确认窗口大小消息"到服务端(设置带宽消息的值与窗口大小不相同才会发送此消息)。
(5)服务器发送用户控制消息中的“流开始(Stream Begin)消息“到客户端。
(6)服务器发送“命令消息”中的”结果“(_result),通知客户端连接的状态。
(3)建立流
(1)客户端发送"命令消息"中的"创建流命令(createStream)"到服务端。
(2)服务端接受到消息之后,发送"命令消息"中的"结果(_result)"。
(4)发布音视频
(1)客户端发送"命令消息"中的"publish命令"。
(2)服务端接受到消息之后发送用户控制消息中的“streambegin”。
(3)客户端开始发送音视频数据
(二)构建思路
需要实现RTMP网络推流一般需要三个部分。
分为RTMP服务器进行数据分发,拉流部分与推流部分。
在这里我用树莓派作为一个网络摄像头,当然最简单的方法是运用x264 ffmpeg直接拉流usb摄像头,同时进行编码与推流。
当然为了方便,必须对WIFI的连接与程序的启动进行一些配置,使树莓派可以在没有接屏幕的情况下自动接到WIFI中,然后启动推流。
当然为了实现在不同的局域网内,都可以进行拉流,你当然要有一个具有公网IP的服务器,这里我买了一个云服务器进行部署。这里需要移植一个SRS的RTMP服务器。这里需要考虑到SRS的编译移植问题。
至于拉流部分,有很多方法,包括PC端,网页,IOS,
Android等情况,这里只采用最简单的使用VLC直接拉流。
(三)编译部署SRS
准备工作
1. 创建文件夹 mkdir srs,将我们的项目存放在该目录下
2. 下载SRS源码,这里是去github上下载,使用
git clone https://github.com/ossrs/srs
3. 编译与安装
cd srs/trunk
./configure --full --without-utest --use-sys-ssl && make
4. 运行
cd srs-master/trunk // 先进入trunk目录。
./objs/srs -c conf/srs.conf
检查SRS是否启动成功:
ps -ef | grep srs
(四)树莓派编译FFmpeg
进入需要放置文件的目录git安装ffmpeg:git clone git://source.ffmpeg.org/ffmpeg.git
安装 libx264-dev
sudo apt-get install libx264-dev
另外ffmpeg中的播放器程序ffplay依赖sdl来显示视频,sdl是一个图形显示库,安装命令:
sudo apt-get install libsdl2-dev
ffmpeg 配置脚本 ffmpeg_rpi.sh ,放进 ffmpeg 目录
#!/bin/shPREFIX=/usr/local./configure \--enable-gpl --enable-version3 --enable-nonfree \--enable-static --disable-shared \\--prefix=$PREFIX \\--disable-opencl \--disable-thumb \--disable-pic \--disable-stripping \\--enable-small \\--enable-ffmpeg \--enable-ffplay \--enable-ffprobe \\--disable-doc \--disable-htmlpages \--disable-podpages \--disable-txtpages \--disable-manpages \\--disable-everything \\--enable-libx264 \--enable-encoder=libx264 \--enable-decoder=h264 \--enable-encoder=aac \--enable-decoder=aac \--enable-encoder=ac3 \--enable-decoder=ac3 \--enable-encoder=rawvideo \--enable-decoder=rawvideo \--enable-encoder=mjpeg \--enable-decoder=mjpeg \\--enable-demuxer=concat \--enable-muxer=flv \--enable-demuxer=flv \--enable-demuxer=live_flv \--enable-muxer=hls \--enable-muxer=segment \--enable-muxer=stream_segment \--enable-muxer=mov \--enable-demuxer=mov \--enable-muxer=mp4 \--enable-muxer=mpegts \--enable-demuxer=mpegts \--enable-demuxer=mpegvideo \--enable-muxer=matroska \--enable-demuxer=matroska \--enable-muxer=wav \--enable-demuxer=wav \--enable-muxer=pcm* \--enable-demuxer=pcm* \--enable-muxer=rawvideo \--enable-demuxer=rawvideo \--enable-muxer=rtsp \--enable-demuxer=rtsp \--enable-muxer=rtsp \--enable-demuxer=sdp \--enable-muxer=fifo \--enable-muxer=tee \\--enable-parser=h264 \--enable-parser=aac \\--enable-protocol=file \--enable-protocol=tcp \--enable-protocol=rtmp \--enable-protocol=cache \--enable-protocol=pipe \--enable-protocol=srtp \\--enable-filter=aresample \--enable-filter=allyuv \--enable-filter=scale \--enable-libfreetype \\--enable-indev=v4l2 \--enable-indev=alsa \\--enable-omx \--enable-omx-rpi \--enable-encoder=h264_omx \\--enable-mmal \--enable-hwaccel=h264_mmal \--enable-decoder=h264_mmal \\
测试ffmpeg
采集mjpeg格式视频
ffplay -f video4linux2 -input_format mjpeg -framerate 25 -video_size 640x480 -i /dev/video0
采集yuyv422格式视频
ffplay -f video4linux2 -input_format yuyv422 -framerate 25 -video_size 640x480 -i /dev/video0
推送mjpeg视频流
ffmpeg -f video4linux2 -input_format mjpeg -framerate 25 -video_size 1280x720 -i /dev/video0 -vcodec copy -rtsp_transport tcp -f rtsp rtsp://172.17.6.213/test
然后配置开机运行 (/etc/rc.local)
添加
sleep 10
#这里需要延时,因为WIFI连接可能需要较长的时间
ffmpeg -framerate 15 -video_size 640x480 -i /dev/video0 -vcodec h264_omx -f flv rtmp://123.57.93.3/live/livestream
发表评论
最新留言
关于作者
