🎬 第十一章 SRS搭建直播平台
📄 一句话概括

ingest 让 SRS 主动去拉别人的流,方向和推流正好相反。 它适合「源是一批文件,要当直播播出去」。

📝 本节和前面几节的关系

11.4.2 的主配置管「别人推给我」,这一节管「我去拉别人」。 11.4.4 换回落盘那一侧,讲 HLS 切片。

一、方向是反的

平时是推流端连上来推,ingest 是 SRS 自己发起连接。 配置里那个 url 是「源在哪」,不是「谁来推」。

一份最小的拉流配置:

listen          19350;
exec.ffmpeg     ./objs/ffmpeg/bin/ffmpeg;
ingest {
    enabled     on;
    input { type file; url ./doc/1.mp4; }
    engine { enabled on; }
}

注意 listen 是 19350,不是 1935: 拉流服务和主服务是两个进程,端口要分开。 exec.ffmpeg 指向一个真的 ffmpeg 可执行文件,路径写错启动就报找不到。

二、perfile 怎么排

perfile 的意思是「目录里每个文件各算一路」: 文件名直接变成流名,不用一个一个写 input 块。

这里最容易误判的是循环方式: 它默认是「一个文件播完换下一个」,不是每个文件各自循环。 三个文件分别是 2 秒、4 秒、3 秒,一轮就是 9 秒。 想让单个文件反复播,得靠 loop 那一组参数。

这个机制适合什么场景? 适合「几段宣传片轮流播」这种伪直播。 不适合「一段内容无限循环」——那种情况一轮只有一个文件。

三、循环播不是直播

最需要记住的一点:ingest 播文件不是直播。 观众看到的时间戳是文件里的,不是当前时间。 所以它顶替不了真正的直播源。

按数据算一下这个「循环」有多密: 一轮 9 秒,一天就是 9600 轮。 也就是说这批内容一天会被重复播 9600 遍。 这个量级下,观众随便进都是在看「第几轮的第几秒」。

用它的时候心里要有数: 它是「录像循环播放器」,不是「直播」。 要做真直播,还是得让推流端连上来推。

四、动手 Demo:ingest 的三个源文件——排一轮要多久

造三个长短不同的 mp4,把时长真读出来, 再算一轮多久、一天能播几轮。

for name, nf in (("lesson1.mp4", 50),
                 ("lesson2.mp4", 100),
                 ("lesson3.mp4", 75)):
    path = make_mp4(name, nf)          # 真编一段
    c = av.open(path)
    sec = c.duration / 1000000.0       # 微秒换秒
    c.close()
    print(name, "%.2f 秒" % sec)

total = 2.0 + 4.0 + 3.0
print("一轮", total, "秒")
for label, span in (("1 小时", 3600), ("1 天", 86400)):
    print(label, int(span / total), "轮")

实跑输出:

--------------------------------------------------------------------
ingest.conf——它反过来去拉别人
--------------------------------------------------------------------
**① 方向正好是反的**

  **平时是别人推给 SRS,`ingest` 是 SRS 主动去拉别人。**
  **它适合「源是一批文件,要当直播播出去」这种场合。**

    ingest.conf
    ------------------------------------------------------------
    listen              19350;
    exec.ffmpeg         ./objs/ffmpeg/bin/ffmpeg;
    ingest {
        enabled         on;
        input {
            type        file;
            url         ./doc/1.mp4;
        }
        engine {
            enabled     on;
            perfile {
                audio_enable    on;
            }
        }
    }

  **`perfile` 的意思是「目录里每个文件各算一路」:**
  **文件名直接变成流名,不用一个一个写 input 块。**

**② 真做三个源文件,看 perfile 怎么排**

  **造三个长短不同的 mp4,把时长真读出来。**

  文件            流名        帧数     时长秒     字节
  ---------------------------------------------------------
  lesson1.mp4     lesson1     50       2.00       11328
  lesson2.mp4     lesson2     100      4.00       20677
  lesson3.mp4     lesson3     75       3.00       15961

  **三个文件首尾相接算一轮,一轮 9.00 秒。**

  **这是 `perfile` 最容易误判的地方:它默认是「一个文件播完换下一个」,**
  **不是每个文件各自循环。想让单个文件反复播,得靠 `loop` 那一组参数。**

**③ 一轮之后会怎样**

  时长       轮数       总字节
  ----------------------------------
  1 小时     400        18.3 MB
  1 天       9600       439.1 MB
  30 天      288000     12.9 GB

  **一天 9600 轮,也就是说这批内容会被反复播 9600 遍。**
  **这提醒一件事:`ingest` 播文件不是「直播」,是「录像循环」。**
  **观众看到的时间戳是文件里的,不是当前时间,**
  **所以别拿它顶替真正的直播源。**

  **另一个要注意的是 `exec.ffmpeg`:**
  **它指向一个真的 ffmpeg 可执行文件,路径写错会在启动时报找不到。**
  **SRS 源码包里 `objs/ffmpeg/bin/ffmpeg` 是 `./configure --with-ffmpeg` 编出来的,**
  **没开这个开关的话,这个文件根本不存在。**

三个文件 2 秒、4 秒、3 秒,一轮 9 秒。 一小时 400 轮,一天 9600 轮,这就是「循环」的真实密度。 注意 perfile 是一轮一个文件地走,不是三路同时播。 真读时长要用容器头里的 duration,别按帧数自己乘。

30 秒实验

  1. 把三个文件换成一个 9 秒的文件,猜轮数变不变——不变,一轮还是 9 秒。
  2. 关掉 engine,看还会不会转流——不会,input 只管读,转出去要靠 engine。
  3. 把 exec.ffmpeg 指向不存在的路径,猜什么时候报错——启动就报,比编到一半才发现好查。

常见误区

  1. 「ingest 是别人推给我」——反了,是 SRS 主动去拉。
  2. 「perfile 每个文件各自循环」——是一轮一个文件地走。
  3. 「ingest 播文件就是直播」——时间戳是文件的,不是当前时间。
自测三问(点开对答案) 1. `ingest` 的 `url` 指的是什么? —— **源在哪**,不是谁来推。 2. `perfile` 一轮怎么走? —— **一个文件播完换下一个**,不是各自循环。 3. 为什么说 `ingest` 播文件不是直播? —— **观众看到的时间戳来自文件**,和当前时间无关。

相关笔记