欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

FFMPEG对摄像头进行RTP推流,以及RTP转发服务

程序员文章站 2022-07-01 15:40:39
...

RTP在流媒体传输中是广为应用的一种协议,包括大家熟知的GB28181协议以及很多视频会议的应用,都是采用RTP。常用的RTSP协议实际上也是在RTP基础上实现的。RTP并不复杂,本质上可以理解为RAW数据加上一些头,封装以后进行UDP传输。报文结构是这样的:

0 1 2 3
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
V P X CC(4bit) M PT(7bit) Sequence Number(16bit)
timestamp(32bit)
SSRC标识符(32bit)
CSRC标识符(n个32bit)
playload

每个字段具体的含义可查阅相关资料。RTP传输的时候,并不保证数据包按序号传送,即使下层网络提供可靠性传送,也不能保证数据包的顺序到达,包含在RTP中的***就是供接收方重新对数据包排序之用。与RTP对应的,还有RTCP是控制协议。正常情况下,RTP和RTCP是使用配套的两个端口,RTP都是使用偶数端口,例如,要给目标地址的30010端口发送RTP数据,则30011端口会发送RTCP数据。
 

使用FFMPEG可以进行RTP的推流测试,接收端可以用VLC,也可以用FFPLAY。以下命令行使用内置摄像头采集实时视频,h.264编码,帧率25fps,GOP为25,低延时,以RTP推送到本机的30010端口,并生成一个sdp文件用于播放使用:

ffmpeg -f dshow -i video="Integrated Camera" -b:v 500k  -r 25 -g 25 -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -f rtp rtp://127.0.0.1:30010 > v.sdp

摄像头的名字每个电脑不一定相同,可以用ffmpeg命令查看,也可以在电脑属性里面看设备名称。如果要播放,可以把生成的这个sdp文件拷贝下来,用VLC打开播放。但是注意生成的文件第一行有SDP这几个字母,要把这行删掉,不然VLC播放出错。用ffplay也可以播放,命令行如下:

ffplay -protocol_whitelist "file,udp,rtp" -i v.sdp

类似地,也可以采集麦克风数据,推送AAC音频,命令行如下:

ffmpeg -f dshow -i audio="Microphone Array (Realtek High " -acodec aac -ar 32000 -b:a 128k -f rtp rtp://127.0.0.1:30012 > a.sdp

麦克风的名字同样自己去查。

以上的命令行推流,都是用的RTP裸流,也有一些场景是要求对数据采用PS或TS进行封装以后再推送的。此外,视频音频也可以在一个命令行进行推送,,播放方式类似:

ffmpeg -fflags +genpts -f dshow -i video="Integrated Camera":audio="Microphone Array (Realtek High " -an -s 720x576 -b:v 500k -r 25 -g 25 -bufsize 2000k -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -f rtp rtp://127.0.0.1:30010 -vn -acodec aac -ar 32000 -b:a 128k -f rtp rtp://127.0.0.1:30012 > av.sdp

实际使用的时候,很多情况下是需要一个发送端,多个接收端,这个时候就需要有RTP的转发服务器。自己写代码的话,有两种方式,一种是直接UDP接收,数据放在队列里,开一个线程把队列里面的UDP数据发出去。因为RTP实际上就是UDP的数据,所以这种方式也是能转发的,但是丢包情况很感人,实测发现播放经常花屏、乱序。另外一种方式,可以使用开源的jrtplib,收到数据放到队列以后,调用jrtplib的接口重新对裸数据封装rtp包,打时间戳,加序号以后再发送。这样的效果就非常好。两个程序都写了,做了对比,最后用rtp的这种形式,封装了接口,很好用。目前还欠缺的是srtp的加密数据有点问题,还在研究中。