🎬 第十三章 FFmpeg直播综合案例实战
📄 一句话概括

一条直播链就是五段:采集、编码、封装、推流、分发。 前三段这本书已经讲完了,剩下的两段要靠服务器。

📝 本节和前面几节的关系

第十二章做完「采集」,这一章把后面几段接起来。 这是全书最后一章,也是把前面十二章拼成一件事的一章。

一、五段各归哪一层

先看全景,再一段一段对回前面学过的库。 段 做什么 归哪一层


一 采集:拿画面与声音 AVDevice 二 编码:压成码流 AVCodec 三 封装:装进容器 AVFormat 四 推流:送到服务器 AVIO 协议 五 分发:转给观众 流媒体服务器

前三段这本书已经全讲完了:采集在第十二章、编码在第八章、封装在第七章。 第四段是协议层,第五段根本不归 FFmpeg 管。 「不归 FFmpeg 管」这句话要点明:服务器是别人的程序,FFmpeg 只负责把码流送到它的门口。 所以这一章的一半篇幅在讲「门口之外」,而不是 API。

二、逐段问本机能不能做

真跑之前先问一遍,省得写到一半发现没有这条路。 段 用什么 结果


一 采集 gdigrab 能 二 编码 libx264 能 三 封装 flv 能 四 推流 rtmp 不能 五 分发 服务器 没有,本机没装

五段里四段能真跑,只有第四段的 rtmp 协议与第五段整段做不了。 这个结果是这一章的写法依据:能做到的做到极致,做不到的写清原因并给替代验证。 「替代验证」这个词很重要: 不能推 RTMP,但可以把「要推的那串字节」亲手生成出来、再亲手用 TCP 送到对面。 这就把「不知道对不对」变成了「只差最后一段协议封装」。

三、四种协议各管一段场景

没有一个协议能通吃,选型看场景。 协议 延迟量级 典型场景


RTMP 1~3 秒 主播上行推流(最常用) HTTP-FLV 1~3 秒 国内网页低延迟播放 HLS 6~30 秒 跨平台、可回看、能过 CDN WebRTC 0.2~1 秒 连麦、会议、超低延迟

延迟差在哪:RTMP 与 HTTP-FLV 是「收到就转」, HLS 要把画面切成几秒一个的 ts 片、再写一个索引,才能播——切片这件事本身就决定了它快不了。 WebRTC 快是因为它换了传输层:走 UDP,丢包不重传,宁可糊一下也不等。 代价是它需要一整套信令与穿透,工程复杂度高一个量级。 所以行业里的常规组合是「上行 RTMP、下行 HLS 或 HTTP-FLV」: 推流端只挑一个协议,播放端按观众设备挑。 服务器在中间做转协议,这一层叫「转推」。

四、延迟是从哪攒起来的

直播的延迟不是一个数,是好几个缓冲加起来的。 环节 攒多少 能不能省


采集缓冲 一帧到几帧 能,但会卡顿 编码缓冲 B 帧越多越久 能,关 B 帧 服务器缓存 一个 GOP 能,改 gop cache 播放器缓冲 几秒 能,但要防抖

第三行那个「一个 GOP」是很多人不知道的: 服务器为了让新观众一进来就能播,会缓存一个关键帧间隔的码流。 这个缓存对延迟的贡献等于一个 GOP 的时长,两秒一个 GOP 就白等两秒。 这条与第八章接上了:GOP 越长压得越好、延迟越大。 所以「清晰又低延迟」是个取舍,直播里常把 GOP 定在两秒,点播才敢定十秒。

五、这一章六节怎么排

按「能不能真跑」来排,不是按教材顺序的难度。 节 讲什么 能不能真跑


13.2 流媒体服务器与握手 能,自己扮一次 13.3 RTMP 推流 能,手工分块推 13.4 两个 C++ 封装类 不能,只讲设计 13.5 OpenCV 磨皮 能,全真跑 13.6 磨皮接进推流 能,全真跑

99 篇里唯一「只讲设计不跑代码」的是 13.4,因为沙箱里没有任何 C++ 编译器, 这一点到那一节会明说。 其余五节都有实测数据,包括最像「只能讲概念」的 13.2。 那一节用两个 socket 把 RTMP 握手真的走一遍,收到的字节数与回抄校验都是真跑出来的。

六、动手 Demo:把直播链拆成五段,逐段问本机能不能做

五段逐段试一遍:抓一帧桌面、建一个 x264 编码器、查 flv 与 rtmp 在不在表里。

import av

def can_capture():
    try:
        av.open("desktop", format="gdigrab",
                options={"framerate": "5", "video_size": "32x24"}).close()
        return "能"
    except Exception as e:
        return type(e).__name__

def can_encode():
    av.codec.Codec("libx264", "w")
    return "能"

tab = av.formats_available
print("采集", can_capture())
print("编码", can_encode())
print("封装 flv", "能" if "flv" in tab else "不能")
print("推流 rtmp", "能" if "rtmp" in tab else "不能")
print("分发 服务器", "本机没装")

实跑输出:

--------------------------------------------------------------------
把直播链拆成五段,逐段问本机能不能做
--------------------------------------------------------------------

**① 一条直播链就五段**

  段     做什么                 归哪一层
  ----------------------------------------------
  一     采集:拿画面与声音     AVDevice
  二     编码:压成码流         AVCodec
  三     封装:装进容器         AVFormat
  四     推流:送到服务器       AVIO 协议
  五     分发:转给观众         流媒体服务器

**前三段这一本书已经全讲完了**,第四段是协议层,第五段根本不归 FFmpeg 管。

**② 本机逐段验一遍**

  段          用什么      结果
  ------------------------------------------
  一 采集     gdigrab     **能**
  二 编码     libx264     **能**
  三 封装     flv         **能**
  四 推流     rtmp        **不能**
  五 分发     服务器      没有,本机没装

**五段里四段能真跑,只有第四段的 rtmp 与第五段整段做不了。**
**这一章的重点就在「四段怎么接起来」与「做不到的那段怎么交代」。**

**③ 四种直播协议各管一段场景**

  协议         延迟量级     典型场景
  ------------------------------------------------------
  RTMP         1~3 秒       主播上行推流(最常用)
  HTTP-FLV     1~3 秒       国内网页低延迟播放
  HLS          6~30 秒      跨平台、可回看、能过 CDN
  WebRTC       0.2~1 秒     连麦、会议、超低延迟

**延迟差在哪**:RTMP 与 HTTP-FLV 是「收到就转」,
**HLS 要把画面切成几秒一个的 ts 片、写一个索引,才能播**——**切片这件事本身就决定了它快不了。**

**所以行业里的常规组合是「上行 RTMP、下行 HLS 或 HTTP-FLV」**:
**推流端只挑一个协议,播放端按观众设备挑。**

**④ 延迟是从哪攒起来的**

  环节           攒多少           能不能省
  ------------------------------------------------------------
  采集缓冲       一帧到几帧       能,但要冒卡顿风险
  编码缓冲       B 帧越多越久     能,关 B 帧
  服务器缓存     GOP 一个         能,改服务器的 gop cache
  播放器缓冲     几秒             能,但要防抖

**第四段那个「GOP 一个」是很多人不知道的**:
**服务器为了让新观众一进来就能播,会缓存一个关键帧间隔的码流。**
**这个缓存对延迟的贡献等于一个 GOP 的时长**,两秒一个 GOP 就白等两秒。

**⑤ 这一章怎么讲**

  节       讲什么                 能不能真跑
  --------------------------------------------------
  13.2     流媒体服务器与握手     能,自己扮一次
  13.3     RTMP 推流              能,手工分块推
  13.4     两个 C++ 封装类        不能,只讲设计
  13.5     OpenCV 磨皮            能,全真跑
  13.6     磨皮接进推流           能,全真跑

**28 篇里唯一「只讲设计不跑代码」的是 13.4**,**因为沙箱里没有任何 C++ 编译器**,
这一点到那一节会明说。

五段里四段能跑,只有 rtmp 协议与流媒体服务器做不了。 rtmp 不在格式表这件事就是整章写法的依据:能做的做到底,做不到的说清原因。

30 秒实验

  1. 把 gdigrab 换成 dshow,看结果变成什么(提示:OSError)。
  2. 打印 av.formats_available 里含 rt 的所有名字,看 rtsp 在不在。
  3. 用 av.codec.Codec("libx264","w") 读 long_name,看它是哪家的实现。

常见误区

  1. 以为直播链是 FFmpeg 一个人干完的。 第五段是别人的服务器。
  2. 以为延迟只有一个来源。 采集、编码、服务器、播放器四处都在攒。
  3. 以为 HLS 慢是协议写得差。 它要先切片,天生就慢。
自测三问(点开对答案) 1. 直播链的五段是什么? —— 采集、编码、封装、推流、分发。 2. 为什么 HLS 比 RTMP 慢一个量级? —— 它要把画面切成几秒一个的 ts 片再写索引,切片本身就要等。 3. 服务器缓存为什么会加延迟? —— 它缓存一个 GOP 好让新观众立刻能播,代价就是一个关键帧间隔的等待。

相关笔记