消息格式
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编码的命令,负责用户与服务器之间的交互,比如播放,暂停
载荷
载荷中消息中包含的真实数据。例如,它可以是音频样本或压缩的视频数据。
消息是rtmp协议的基本数据单元,在网络传输时,消息会被重新封装成块进行传输,每个块都有固定的大小,如果消息大小大于块的大小,消息就会被拆分成几个块发送。
块格式
块由头和载荷组成
块头结构
值 | 长度 | 含义 |
---|---|---|
basic header | 1byte或2byte或3byte | 块基本头 |
chunk msg header | 11byte或2byte或3byte | 块消息头 |
extended timestamp | 4byte | 扩展时间戳 |
基本头第一个字节的结构:
值 | 长度 | 含义 |
---|---|---|
fmt | 2bit | 块格式 |
cs id | 6bit | 块流ID |
类型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,消息长度,时间戳都不出现。这种类型的块使用与先前块相同的数据。当一个消息被分成多个块,除了第一块以外,所有的块都应使用这种类型。
rtmp的消息类型可分为三大类:协议控制消息、用户控制消息、RTMP命令消息
(Message Type=4)
RTMP使用消息类型ID 4表示用户控制消息。这些消息包含RTMP流传输层所使用的信息。协议控制消息使用的ID为 1、2、3、5 和 6 (前面已经介绍过了)。
用户控制消息应该使用消息流ID 0 (以被认为是控制流),并且以RTMP块流发送时以块流ID为2。协议控制消息接收立即生效;解析时,时间戳字段被忽略。
客户端或服务端通过本消息向对方发送元数据和用户数据。元数据包括数据的创建时间、时长、主题等细节。消息类型为18的用AMF0编码,消息类型为15的用AMF3编码。
共享对象是跨多个客户端,实例同步的FLASH对象(名值对的集合)。消息类型kMsgContainer=19用AMF0编码,kMsgContainerEx=16用AMF3编码,这两个消息用于共享对象事件。每个消息可包含多个事件。
(2)服务端在接收到C0后发送S0,S1块。
(3)客户端接收到S0,S1块后,发送C2块,服务端接收到C0,C1块后发送S2块。
(4)当客户端接收到S2,服务端接受到C2,分别校验后握手成功
(1)客户端发送"connect消息"请求连接。
(2)服务收到"connect"请求后,发送一个"确认窗口大小消息"。
(3)服务端发送"设置带宽消息"到客户端。
(4)客户端处理"设置带宽消息"后,发送"确认窗口大小消息"到服务端(设置带宽消息的值与窗口大小不相同才会发送此消息)。
(5)服务器发送用户控制消息中的“流开始(Stream Begin)消息“到客户端。
(6)服务器发送“命令消息”中的”结果“(_result),通知客户端连接的状态。
(1)客户端发送"命令消息"中的"创建流命令(createStream)"到服务端。
(2)服务端接受到消息之后,发送"命令消息"中的"结果(_result)"。
(2)服务端接受到消息之后发送用户控制消息中的“streambegin”。
(3)客户端开始发送音视频数据
需要实现RTMP网络推流一般需要三个部分。
分为RTMP服务器进行数据分发,拉流部分与推流部分。
在这里我用树莓派作为一个网络摄像头,当然最简单的方法是运用x264 ffmpeg直接拉流usb摄像头,同时进行编码与推流。
当然为了方便,必须对WIFI的连接与程序的启动进行一些配置,使树莓派可以在没有接屏幕的情况下自动接到WIFI中,然后启动推流。
当然为了实现在不同的局域网内,都可以进行拉流,你当然要有一个具有公网IP的服务器,这里我买了一个云服务器进行部署。这里需要移植一个SRS的RTMP服务器。这里需要考虑到SRS的编译移植问题。
至于拉流部分,有很多方法,包括PC端,网页,IOS,
Android等情况,这里只采用最简单的使用VLC直接拉流。
准备工作
git clone https://github.com/ossrs/srs
cd srs/trunk
./configure --full --without-utest --use-sys-ssl && make
cd srs-master/trunk // 先进入trunk目录。
./objs/srs -c conf/srs.conf
检查SRS是否启动成功:
ps -ef | grep srs
进入需要放置文件的目录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/sh
PREFIX=/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