把最后一环从写文件换成写网络,前面一环不动。 RTP 送数据、RTSP 下指令、SDP 描述内容,三样凑齐才能看。 判断协议在不在只有一招:真开一次,看报错长相。
4.5.2 讲的是本地两条路,这一节把输出端换成网络。 下一篇 4.5.4 把 4.5 的三篇汇成一张账。
一、只换最后一环
边转边推的结构与本地转码只差一个输出对象。 环节 本地转码 边转边推
输入 文件 文件或摄像头 输出 文件 网络地址 最后一步 写磁盘 发 UDP 包 能否回看 能 不能
「不能回看」是本质区别。 文件写完了就在那儿,流过去了就没了。所以直播系统必须另有录制环节。 这也解释了直播为什么怕断网:断了那一段就是永久丢失,不像点播能重连续传。
二、RTP、RTSP、SDP 三者的分工
这三个缩写经常被混着说,其实各管一段。 协议 管什么 打个比方
RTP 把音视频包按序号发出去 送快递的车 RTSP 让对方「开始、暂停、跳转」 打电话下指令 SDP 描述「我发的是什么」 随车的货物清单
三者合作才凑出一个能看的流:RTSP 建会话,SDP 说清编码与地址,RTP 送数据。 缺一样,播放器就不知道该怎么接。 只用 RTP 也行,那就得手工把 SDP 给对方。 这就是为什么有些推流配置里要填一个 sdp 文件路径。
三、判断协议在不在的唯一办法
先拆一个容易踩的坑:av.formats_available 不是协议表。
它列的是容器格式名。rtsp、rtp 查得到,是因为它们同时也是容器格式;
http、file 查不到,可它们明明都能用。
名字 在格式表里 真能不能用
rtsp 有 能 rtp 有 能 rtmp 没有 能 http 没有 能 file 没有 能
五行里有三行的「没有」是假阴性。 所以别查表,唯一可靠的招是拿真地址开一次,看它抛什么异常。 异常类型就是答案,比任何自查表都准。下一篇 Demo 把四个真地址加一个瞎编地址并排开一遍。
四、报错长相分三种
同样是「打不开」,背后可能是三件完全不同的事。 抛的异常 说明 接着查什么
ProtocolNotFoundError 协议没编进来 换构建 ExitError 一类 协议在,连不上 查对端 HTTP 类异常 协议在,也连上了 看状态码
这三行是本节最值钱的东西。 看到第一种才可以说「不支持」;看到后两种,都得先往「对端」上想。
为了让这套判法自己站得住,Demo 里放了一个瞎编的协议 foo:// 当阴性对照,它报的正是第一种。
这也正是本节标题的意思:转码讲得清,推流能讲到哪一层,靠的不是嘴,是靠报错。
五、把边界说清楚
这一节在沙箱里只能讲到「协议在、对端没有」这一层。 任何「推流成功」的结论都得有一台在跑的 RTSP 服务器做对端。没有对端就说成功,那是编的。 教材这一节的代码要落地,需要三样东西:一台跑着 RTSP 服务的机器、一张能收到流的播放器、 以及两端能通的网络。 这种老实交代不丢人。 把「能验证的」验证到位,把「不能验证的」标清楚, 比含糊写一句「运行成功」有用得多。第十三章的直播综合案例也会照这个规矩写。
六、动手 Demo:基于 RTP 的转码应用——能讲到哪一层
五个地址各开一次,最后一个协议是瞎编的,当阴性对照。
import av
urls = [
"http://example.com/a.mp4",
"rtp://127.0.0.1:5004",
"rtsp://127.0.0.1:8554/x",
"rtmp://127.0.0.1:1935/live/x",
"foo://1.2.3.4/x",
]
for url in urls:
try:
av.open(url, timeout=3).close()
print(url, "开成功")
except Exception as e:
print(url, type(e).__name__)
实跑输出:
--------------------------------------------------------------------
基于 RTP 的转码应用——能讲到哪一层
--------------------------------------------------------------------
**① 教材这一节讲的是「转完直接推出去,不落盘」**
把链的最后一环从「写文件」换成「写网络」,前面的环一个不动。这就是流媒体服务器的基本形态。
环节 本地转码 边转边推
----------------------------------------------
输入 文件 文件或摄像头
输出 文件 网络地址
最后一步 写磁盘 发 UDP 包
能否回看 能 不能,过去就没了
**② RTP 与 RTSP 是两件事,必须分清**
协议 管什么 打个比方
------------------------------------------------------------
RTP 把音视频包按序号发出去 送快递的车
RTSP 告诉对方「开始、暂停、跳转」 打电话下指令
SDP 描述「我发的是什么」 随车的货物清单
**三者合作的方式**:RTSP 建会话,SDP 描述内容,RTP 送数据。
摄像头能用 VLC 打开,靠的就是这三样凑齐。
**③ 判断协议在不在,只有一个办法:真开一次看报什么错**
**别用 formats_available 判断。** 它列的是容器格式名,不是协议名。
rtsp 与 rtp 能查到,是因为它们同时是容器格式;http 与 file 查不到,但它们明明能用。
下面四个地址各开一次,看抛什么异常:
地址 抛的异常 读出来的意思
---------------------------------------------------------------------------------------
http://example.com/a.mp4 HTTPNotFoundError 协议在,服务器说没这文件
rtp://127.0.0.1:5004 ExitError 协议在,连接建不起来
rtsp://127.0.0.1:8554/x ExitError 协议在,连接建不起来
rtmp://127.0.0.1:1935/live/x ExitError 协议在,连接建不起来
foo://1.2.3.4/x ProtocolNotFoundError 协议不在
**http 那个抛的是 HTTP 类异常,说明它收到了服务器回复。**
所以协议在,网络也通。
报的不是「没这个文件」就是别的 HTTP 状态,都属于「连上了但对方不接受」,跟协议在不在无关。
**关键是最后一行那个瞎编的协议。** 它报 ProtocolNotFoundError,这才是「协议不在」的标准长相。
**有了这个对照,rtp、rtsp、rtmp 三个的性质就定死了**:它们报的不是 ProtocolNotFoundError,
说明协议都编进来了,只是连不上——因为本机没有对端。
**换句话说,这一版构建是能推 rtmp 的**,缺的只是一台在跑的服务器。
这跟「构建里没编进 rtmp」是两件完全不同的事,报错长相也不一样。
**④ 所以这一节能验证到哪一层,要说清楚**
能验证的 不能验证的
---------------------------------------------------------
协议编进来了(http 已证) 真推出去对面收得如何
地址格式对了(错了报解析错) 长时间推流的稳定性
缺对端时抛什么异常 对端存在时的握手细节
**这不是含糊过去,是把边界划清楚。** 本机没有 RTSP 服务器,任何「推流成功」的结论都是编的。
教材这一节的代码要落地,得有一台在跑的 RTSP 服务器当对端。
**第四章后面不再碰推流**,第十三章的直播综合案例也一样:能讲清链路与参数,跑不通的部分会明说。
只有 foo 那个报了 ProtocolNotFoundError。 其余四个报的都是「协议在、事情没办成」,不是「没这协议」。 所以推流推不出去,缺的是对端,不是构建。
30 秒实验
- 再挑十个协议名逐个
av.open,看有几个报 ProtocolNotFoundError。 - 在另一台机器上起一个 RTSP 服务器,再跑这段,看结果怎么变。
- 把地址改成
rtp://239.0.0.1:5004(组播),看报错是否相同。
常见误区
- 把「开不了」当协议不支持。 协议在,缺的是对端。
- 以为 RTP 与 RTSP 是一回事。 一个送数据,一个下指令。
- 拿
formats_available判断协议。 它列的是容器格式名,不是协议名。
自测三问(点开对答案)
1. RTP 与 RTSP 各管什么? —— RTP 送音视频数据包,RTSP 下发播放控制指令(开始、暂停、跳转)。 2. 为什么不能拿 formats_available 判断协议在不在? —— 它列的是容器格式名。http 与 file 查不到却能用,rtmp 查不到也能用。 3. 哪种异常才算「协议不在」? —— ProtocolNotFoundError。其余异常都说明协议在,问题出在对端或网络。- ☐ (本节完,下一节 4.5.4 FFmpeg 转码流程小结)