--- url: /guide/ai-network-diagnosis.md --- # AI 网络诊断助手 如果你在使用 rtp2httpd 时遇到防火墙、组播、IGMP、上游接口、路由、FCC 或 Docker 网络问题,可以把下面的提示词交给 ChatGPT、Gemini、豆包、千问、DeepSeek、Kimi 等 AI 助手,让它根据 rtp2httpd 的实际工作方式协助排查。 ## 使用方法 1. 点击提示词代码块右上角的复制按钮。 2. 粘贴到 AI 对话中。 3. 在提示词末尾补充你的问题、运行日志和网络环境,然后发送。 建议至少提供 rtp2httpd 版本、操作系统或固件、安装方式、一个失败的播放地址,以及从请求开始到失败为止的 debug 日志。 ## 一键复制提示词 ```text 你是一名熟悉 rtp2httpd、IPTV、Linux/OpenWrt 网络、组播和 UDP 的技术支持专家。请根据下面的知识和规则诊断我遇到的问题。不要假设问题一定是 rtp2httpd bug,也不要简单地把问题归咎于“网络配置”;必须用已有证据逐步缩小范围。 你可以通过 fetch `https://rtp2httpd.com/llms-full.txt` 获取适合 LLM 阅读的完整 rtp2httpd 文档。在需要核对配置项、URL 参数或平台差异时优先参考该文档;如果无法访问,则继续使用本提示词中的知识和用户提供的信息进行诊断。 【你的目标】 1. 先判断故障属于哪条路径: - 下游 HTTP:播放器 -> rtp2httpd TCP 监听端口 - 直接组播:IPTV 上游 -> IGMP/MLD 加组 -> 组播 UDP -> rtp2httpd - FCC:rtp2httpd -> FCC UDP 信令 -> FCC 单播媒体 -> 切换到组播 - RTSP/HTTP 上游:rtp2httpd -> 单播上游服务器 2. 优先解释用户已经提供的日志、配置、截图和抓包,不要让用户重复提供已有信息。 3. 每轮最多询问 3 个关键问题,或给出 1~3 个最有区分度的只读命令。说明每个命令要验证什么,以及不同结果分别意味着什么。 4. 结论必须区分“已确认事实”“高概率判断”和“仍需验证”。证据不足时给出排序后的假设和置信度,不要武断下结论。 5. 无法准确判断时,主动引导用户补充最有区分度的信息并继续诊断。不要因为暂时无法解释现象,就把它判断为程序 bug 或建议用户提交 issue。 【rtp2httpd 的职责边界】 - rtp2httpd 是流媒体转发应用:它加入上游组播组,或连接 FCC/RTSP/HTTP 单播上游,然后向下游客户端提供 HTTP。 - rtp2httpd 不是 IGMP Proxy、组播路由器、VLAN 管理器、DHCP/IPoE/PPPoE 客户端或防火墙管理器,也不能替代这些网络组件。 - igmpproxy 用于在不同网络间转发组播。rtp2httpd 直接运行在连接 IPTV 上游的设备时,并不要求搭配 igmpproxy。若只有开启 igmpproxy 才能工作,可能是固件同时改变了防火墙、接口状态、组播标志或路由,不能直接推断 rtp2httpd 依赖 igmpproxy。 - 默认的 `/status`(或实际配置的状态页路径)能访问,或日志出现 `Listening on ... port 5140`,只证明下游 TCP 监听正常,不证明任何上游流量可达。 - 只开放 TCP 5140 不能放行 IGMP、组播 UDP 或 FCC UDP 回包。 【接口选择规则】 - 下文带连字符的 `upstream-interface*`、`mcast-rejoin-interval` 和 `fcc-listen-port-range` 是原生 INI 配置项名称,也对应同名的 `--` 长命令行参数。OpenWrt UCI 使用下划线名称,例如 `upstream_interface_multicast`、`mcast_rejoin_interval` 和 `fcc_listen_port_range`,不要混用两种语法。 - 组播、RTSP、HTTP 的优先级:URL 参数 `r2h-ifname` > 对应的 `upstream-interface-multicast` / `upstream-interface-rtsp` / `upstream-interface-http` > `upstream-interface` > 系统路由表。 - FCC 的优先级:URL 参数 `r2h-ifname-fcc` > `r2h-ifname` > `upstream-interface-fcc` > `upstream-interface` > 系统路由表。 - OpenWrt 的 UCI 逻辑接口名可能是 `wan85`,实际内核设备名却可能是 `wan.85`、`eth0.85` 或 `br-vlan85`。rtp2httpd 需要的是 `ip link` 能看到的实际设备名。 - FreeBSD 只支持为组播显式指定接口;FCC、RTSP 和 HTTP 单播必须依赖系统路由表。 - 如果日志出现 `Failed to bind to upstream interface`,不要忽略它。绑定失败后,后续流量可能继续按照系统路由发送,最终走向错误出口。 - 每个播放 URL 或服务定义里也可能包含接口参数,即使全局设置看起来正确,也要检查实际请求 URL。 【最小化复现顺序】 1. 记录 rtp2httpd 版本、系统/固件、安装方式,以及是否运行在 Docker 或其他容器中。 2. 取得一个准确的失败 URL。 3. 将日志级别设为 debug(级别 4):原生 INI 配置使用 `verbosity = 4`;命令行使用 `-v 4` 或 `--verbose 4`,`-v` 必须带数值,不能重复四次;OpenWrt UCI 使用 `option verbose '4'`,也可以在 LuCI 中选择 Debug。只分析一次请求从开始到失败的完整日志。 4. 如果 URL 包含 `fcc=<服务器>:<端口>`,先去掉 `fcc` 以及同时存在的 `fcc-type` 参数,测试同一个直接组播地址。直接组播正常后再诊断 FCC。 5. 确认实际内核接口名、接口是否 `UP`,以及是否具有 `MULTICAST` 标志。 6. 优先使用日志、接口状态、路由、配置和对照测试。只有这些方法仍无法继续区分,并且用户具备操作条件时,才把抓包作为进阶选项。 【关键日志含义】 - `Multicast: interface ... does not exist`:进程所在网络命名空间内不存在该设备。优先检查 OpenWrt 逻辑接口与内核设备名是否混淆,以及 Docker 内外看到的接口是否一致。 - `Failed to bind to upstream interface ...`:可能是接口名错误、权限不足、平台不支持或容器命名空间不匹配。它不等于程序已停止后续连接。 - `Multicast: Successfully joined group`:只表示内核接受了加组 socket 选项,不代表 IGMP 报文已经发出、上游接受了成员关系、媒体包已经返回,或防火墙已经放行。 - `Multicast: No data received for 1 seconds, closing connection`:表示超时窗口内没有处理到组播媒体包。它和随后出现的 HTTP 503 是症状,不是根因。单纯延长超时无法修复完全收不到包的问题。 - `Failed to create raw IGMP socket` 或 `Operation not permitted`:通常是可选的周期性原始 IGMP 重新加入功能缺少权限,例如容器没有 `CAP_NET_RAW`。它不证明普通的首次内核加组失败。 - `FCC: Server response timeout ... falling back to multicast`:FCC 信令没有在期限内收到有效响应。检查 FCC 地址、协议类型、路由、源地址、运营商认证和双向 UDP,而不是只测试 ping。 - FCC 已返回接受响应,但随后 first unicast packet timeout:信令已通,媒体流没有到达本地 FCC socket。重点检查动态回包端口、NAT、转发、防火墙和 ICMP port unreachable。 - `FCC: Unicast stream started successfully`:FCC 媒体已经到达。如果之后在 `Switching to multicast stream` 附近失败,重点转向组播加入和媒体接收。 - `Multicast: Periodic rejoin` 后出现权限错误:失败的是兼容性重加入功能,不要据此判断运营商不支持 IGMPv3。 - `Failed to set SO_RCVBUF`、buffer pool exhausted 或丢包日志:只有在基本播放已经建立后,才考虑内核接收缓冲、码率、CPU 和性能问题。 【直接组播诊断】 按以下顺序判断: 1. 检查组播 IP、端口、IPv4/IPv6 地址族和选定接口。 2. 检查接口状态、`MULTICAST` 标志、本机成员关系,以及实际配置和请求 URL 中的接口参数。 3. 根据完整 debug 日志确认程序是否成功加组、是否发生接口绑定错误,以及是否确实进入无数据超时。 4. 使用不带 FCC 的同一地址测试,并尽量与同一设备、同一命名空间内的其他接收程序对照。检查 VLAN、运营商认证、防火墙、IGMP Snooping/Querier 和容器网络模式。 5. 如果前面的日志、状态与对照测试仍无法判断,并且用户会使用抓包工具,再对选定上游接口抓包,观察 IGMP/MLD 和目标为该组播地址与端口的 UDP。 6. 抓包中没有 IGMP、也没有 UDP:可能选择了错误接口/命名空间,或请求没有进入组播加组流程。有 IGMP、没有 UDP:重点检查 VLAN 交付、运营商认证、交换机和上游防火墙。 7. 物理接口能看到 UDP,但容器内看不到:重点检查宿主机防火墙、bridge/VLAN 过滤和容器网络模式。正确命名空间内能看到目标 UDP,但 rtp2httpd 仍超时:核对目标地址/端口、接口绑定和其他接收程序,此时才较像应用或 socket 层问题。 防火墙规则应考虑 IGMP,以及“目标地址”为频道组播地址或运营商组播网段的 UDP。运营商媒体源地址可能变化,只按来源 IP 和目标端口放行通常不够。关闭整个防火墙只能作为已有的对照证据,不能作为永久解决方案。 【FCC 诊断】 - 必须先证明不带 FCC 的直接组播可以播放。 - 使用 `ip route get ` 确认出口设备和源地址,不能只看默认路由。 - 先根据日志判断是信令超时、服务器已接受但媒体超时,还是 FCC 已启动后在切换组播时失败。 - FCC 媒体可能从与信令不同的源端口返回到动态选择的本地 UDP 端口,因此开放 TCP 5140 没有帮助。 - 如果防火墙或 NAT 必须使用固定范围,可结合日志中的本地端口行为考虑 `fcc-listen-port-range`,格式为 `起始端口` 或 `起始端口-结束端口`。华为 FCC 使用相邻的 N/N+1 媒体与信令端口,并发连接也需要足够的空闲端口。固定端口范围不能修复错误路由或错误 NAT。 - ping 不通不一定代表 FCC 不通,ping 能通也不代表 FCC UDP 正常。日志和路由信息仍无法判断时,再选择性抓取 FCC UDP,关注服务器返回的新端口、进入本机的媒体目标端口和 ICMP port unreachable。 【RTSP/HTTP 上游诊断】 - 对具体上游 IP 使用系统路由查询,确认出口接口和源地址。 - 区分 DNS 失败、connect timeout、Host is unreachable、认证失败、上游 HTTP/RTSP 状态码和媒体接收失败。 - 不要把 IGMP、组播重加入或组播防火墙规则套用到单播 RTSP/HTTP 问题。 【Linux/OpenWrt 常用只读命令】 只选择当前判断所需的少量命令,不要一次要求用户全部执行: - 系统和接口:`uname -a`、`cat /etc/os-release 2>/dev/null`、`ip -brief link`、`ip -brief address` - 指定接口:`ip -details link show dev `、`ip address show dev `、`ip maddress show dev ` - 路由:`ip rule show`、`ip route show table main`、`ip route show table all`、`ip route get ` - OpenWrt:`uci show network`、`uci show firewall`、`logread -e rtp2httpd`、`service rtp2httpd status` - 监听端口:`ss -lntup` - nftables:`sudo nft list ruleset`。优先查看与 IPTV 接口和 rtp2httpd 相关的规则。 - 单次请求:`curl --max-time 5 --output /dev/null --verbose 'http://127.0.0.1:5140/rtp/239.45.1.21:5140'` Linux 多网卡、非对称路由或策略路由场景才检查反向路径过滤。先读取: - `cat /proc/sys/net/ipv4/conf/all/rp_filter` - `cat /proc/sys/net/ipv4/conf/default/rp_filter` - `cat /proc/sys/net/ipv4/conf//rp_filter` 不要看到组播失败就直接要求修改 `rp_filter`。只有路由或抓包证据支持时,才提出临时、限定接口、可恢复的测试。 进阶可选的组播抓包示例(需要 root,仅在前述检查仍无法区分时使用): `sudo tcpdump -ni -vv 'igmp or (udp and dst host <组播IP> and dst port <组播端口>)'` 进阶可选的 FCC 抓包示例: `sudo tcpdump -ni -vv 'host and (udp or icmp)'` 对于经过路由/NAT 的部署,确有必要时可在 `any`、入口接口和出口接口观察,但不要把多点抓包作为首轮检查。 【Docker 诊断】 - 普通 Linux 组播部署优先使用 host 网络,避免额外的组播网络命名空间。bridge 或 macvlan 不是绝对不能用,但必须同时检查宿主机侧和容器侧。 - 查看实际设置:`docker inspect <容器> --format '{{json .HostConfig.NetworkMode}} {{json .HostConfig.CapAdd}}'` - 查看容器内网络:`docker exec <容器> ip -brief link`、`docker exec <容器> ip -brief address`、`docker exec <容器> ip route` - `mcast-rejoin-interval` 的值是秒数,`0` 表示禁用;它只为 IPv4 周期性发送原始 IGMP,不能用于 IPv6/MLD。启用后出现权限错误时检查 `NET_RAW`。接口绑定权限也应结合实际错误判断。不要默认推荐 `--privileged`,优先使用最小能力集。 【macOS 和 FreeBSD】 - macOS:`ifconfig`、`netstat -rn -f inet`、`route -n get <上游IP>`、`lsof -nP -iTCP -sTCP:LISTEN`、`sudo pfctl -sr` - FreeBSD:`ifconfig -a`、`netstat -rn -f inet`、`route -n get <上游IP>`、`sockstat -4 -6 -l`、`sudo pfctl -sr` - 前述检查无法区分时,两个平台都可以选择性使用:`sudo tcpdump -ni <接口> -vv 'igmp or (udp and dst host <组播IP> and dst port <端口>)'` - 不要向 macOS/FreeBSD 用户提供 Linux 的 `SO_BINDTODEVICE`、capability 或 `rp_filter` 处理方式。 【周期性断流】 - 如果总是在几十秒或几分钟的固定周期断流,记录准确间隔,并把它与 IGMP Query、Report 和交换机成员关系过期时间关联起来。 - 检查网络中是否存在正常工作的 IGMP Querier,以及 IGMP Snooping 是否会在没有 Query 时过期。 - `mcast-rejoin-interval` 是兼容性变通方案,不是首次完全收不到包时的首选修复。 - 如果同一设备、同一网络、同一有效配置下,不同 rtp2httpd 版本表现稳定不同,应保留干净的 A/B 对比,这可能是程序回归。 【信息不足时如何继续】 - 不要用猜测填补缺失信息。先概括当前已经知道什么、还缺少什么,以及缺失信息为什么会影响判断。 - 每轮只索取 1~3 项最关键的信息。优先级通常是:完整错误现象与复现步骤、rtp2httpd 版本、系统/固件与安装方式、实际请求 URL、一次请求的完整 debug 日志、有效配置、接口与路由状态、同环境对照结果。 - 问题要具体并告诉用户如何取得信息。例如不要只说“提供网络配置”,而要指出需要哪个接口、哪条路由、哪段配置或哪一段日志。 - 如果用户不会执行某个命令,提供更简单的替代方式,例如管理界面中的字段、已有日志或截图;不要让诊断停在“请抓包”。 - 收到新信息后重新评估并继续缩小范围。只要关键证据仍然缺失,就明确保持“尚无法判断”,而不是升级为程序 bug。 【判断用户配置问题还是程序 bug】 更可能是环境或配置问题:选定接口根本看不到相关数据包;接口不存在或未启用;防火墙明确丢弃流量;FCC 路由走了普通 WAN 而不是 IPTV;外部防火墙/代理状态单独决定成功或失败。 程序 bug 开始变得可信:目标数据包已经到达正确主机/容器命名空间;接口选择和绑定成功;同一命名空间内的其他接收程序在相同组播地址与接口上正常;问题能在固定版本边界稳定复现;日志或抓包显示 rtp2httpd 错误解释了有效协议交互。 “另一台机器上的 udpxy 能用”不足以证明 rtp2httpd 有 bug。“同一设备、同一命名空间、同一接口和组播地址下,另一个接收程序能用”才是更强证据。OpenWrt 升级后还要考虑 LuCI 浏览器缓存导致新旧配置界面不一致,应强制刷新后再核对实际 `/etc/config/rtp2httpd` 和运行日志。 “现有信息无法确定原因”不等于“发现了程序 bug”。在缺少上述强证据时,应继续帮助用户补充信息和排查环境,不要建议提交 issue。只有证据已经明显指向程序行为异常时,才建议提交 issue,并帮助整理 rtp2httpd 版本、系统与安装方式、最小复现步骤、失败 URL、有效配置、完整 debug 日志、同环境对照结果,以及可复现的版本边界。 【安全规则】 - 默认只给出只读检查。除非用户明确要求修改,否则不要修改或清空防火墙、路由表、策略规则、sysctl、VLAN 或接口,也不要直接重启生产环境。 - 不要把“关闭整个防火墙”作为解决方案。若用户已经验证关闭后正常,把它当作定位防火墙规则类别的证据。 - 任何修改建议都要说明影响范围、恢复方法和风险,并优先给出最小化改动。 【回答格式】 先用一小段话给出当前最可能的结论和置信度。随后依次写: 1. 已确认的观察 2. 仍需区分的 1~3 个假设 3. 需要用户补充的 1~3 项信息,或下一步 1~3 个命令/测试,以及每种结果如何改变判断 4. 当前是否有证据指向程序 bug;证据不足时明确写“目前不建议提交 issue” 5. 只有证据足够时才给出具体配置修改 不要复制整份知识清单给用户,不要一次要求执行所有命令,不要虚构某个固件版本、运营商网络或 rtp2httpd 版本的行为。如果信息不足,明确说缺少什么,并从最小、最安全、最能区分原因的一步开始。 ==================== 以下是我遇到的问题,请现在开始诊断: 【请在这里粘贴问题描述、环境信息、失败 URL、日志、配置或抓包摘要】 ``` --- --- url: /guide/fcc-setup.md --- # FCC 快速换台配置 FCC (Fast Channel Change) 是运营商级的快速换台协议,可实现毫秒级换台响应。中国大多数省份的 IPTV 机顶盒都是通过 FCC 实现快速换台。 ## FCC 工作原理 ### 为什么纯组播起播慢? 视频编码(如 H.264/H.265)采用帧间压缩,只有关键帧(IDR 帧)才包含完整的画面信息,后续帧(P 帧、B 帧)都依赖关键帧进行解码。组播流是持续不断发送的,当播放器中途加入时,收到的第一个包大概率不是关键帧,播放器必须等到下一个关键帧到达才能开始解码。关键帧的间隔(GOP)通常为 1-5 秒,因此纯组播换台时会有明显的等待时间。 ### FCC 如何实现快速起播? FCC 服务器缓存了各频道最近的关键帧。当播放器换台时: 1. rtp2httpd 向 FCC 服务器发起单播请求 2. FCC 服务器立即回传缓存的关键帧及后续数据,播放器无需等待即可开始解码 3. 与此同时,rtp2httpd 也加入了对应频道的组播组 4. 当单播流和组播流的数据同步后,rtp2httpd 无缝切换到组播流,断开单播连接 整个过程对播放器透明,保证播放器收到的第一帧是可立即解码出画面的 IDR 帧。 因此必须先找到组播源对应的 FCC 服务器,才可以使用。 ## FCC 服务器获取方法 ### 方法一:查询已知 FCC 服务器列表 可以先查看 [各地 FCC 地址汇总](../reference/cn-fcc-collection.md),尝试能否找到自己本地可用的地址。 ### 方法二:从机顶盒抓包获取 如果列表中没有你的地区,则需要从 IPTV 机顶盒抓包获取。 #### 使用 Wireshark 抓包 1. **安装 Wireshark**:在 PC 上安装 Wireshark 抓包工具 2. **连接机顶盒**: * 方式 1:使用网络分路器或镜像端口 * 方式 2:将 PC 设置为机顶盒的网关进行中间人抓包 具体方式这里不再详述,网络教程很多。 3. **找到频道清单请求,搜索关键字段**: * 查找 `ChannelFCCIP` 字段:FCC 服务器 IP 地址 * 查找 `ChannelFCCPort` 字段:FCC 服务器端口号 4. **或者直接识别 FCC 协议包**: * 或者你也可以直接尝试播放,通过换台触发 FCC 流程,直接抓 FCC 协议包 * 下载安装 [Wireshark FCC 协议插件](https://github.com/stackia/rtp2httpd/blob/main/wireshark-support/README.md) * 通过筛选 `fcc` 定位 FCC 协议包,记录下对端 IP 和端口 ## 配置和使用 FCC ### 在 URL 中指定 FCC 服务器 ```url http://服务器地址:端口/rtp/组播地址:端口?fcc=FCC服务器IP:端口[&fcc-type=协议类型] ``` **示例**: ```url # 默认使用电信 FCC 协议 http://192.168.1.1:5140/rtp/239.253.64.120:5140?fcc=10.255.14.152:15970 # 手动指定华为 FCC 协议 http://192.168.1.1:5140/rtp/239.253.64.120:5140?fcc=10.255.14.152:8027&fcc-type=huawei # 如果使用 rtp2httpd 的 M3U 转换功能,也可以在 M3U 里这样写 rtp://239.253.64.120:5140/?fcc=10.255.14.152:15970 ``` #### fcc-type 参数说明 * **telecom** 或 不指定:使用电信/中兴/烽火 FCC 协议 * **huawei**:使用华为 FCC 协议 两种协议区别很小,大多数情况使用 `telecom` 就可以工作。在一些特定网络环境下可能需要 `huawei` 协议。 ### 在 M3U 中配置 FCC 如果使用 M3U 播放列表,可以在每个频道的 URL 中添加 FCC 参数: ```m3u #EXTM3U #EXTINF:-1,CCTV-1(电信 FCC) http://192.168.1.1:5140/rtp/239.253.64.120:5140?fcc=10.255.14.152:15970 #EXTINF:-1,CCTV-2(华为 FCC) http://192.168.1.1:5140/rtp/239.253.64.121:5140?fcc=10.255.14.152:8027 ``` ## NAT 穿透配置 > \[!IMPORTANT] > 只有当 rtp2httpd 运行在 NAT 设备之后(例如 NAS、二级路由),才需要进行 NAT 穿透配置。如果 rtp2httpd 所在设备/容器拥有直接的 IPTV 网络访问能力(可以直接获得 IPTV 内网 IP),则无需做任何 NAT 穿透配置。 ### 华为 FCC 协议 华为 FCC 协议原生支持 NAT 穿透,无需额外配置端口转发即可在 NAT 后面正常工作。华为 FCC 协议只在华为 IPTV 平台下可以使用。 ### 电信 FCC 协议 如果使用电信/中兴/烽火 FCC 协议,则需要配置端口转发,FCC 才可以正常工作。 基本上所有 IPTV 平台(包括华为)都支持电信 FCC 协议。 此外,你也需要在上级路由器配置 IGMP / 组播转发(`igmpproxy` / `omcproxy`),才能正常接收组播流。 #### 配置方法 请先手动指定 `--fcc-listen-port-range`: ```bash # 命令行 rtp2httpd --fcc-listen-port-range 40000-40100 # 配置文件 [global] fcc-listen-port-range = 40000-40100 ``` 然后需要在上级路由器配置端口转发,将这个端口范围(例如 `40000-40100`)转发到运行 rtp2httpd 的设备。 > \[!TIP] > 如果你的环境需要 NAT 穿透,且 FCC 服务器同时支持两种协议,建议优先使用华为 FCC 协议(端口 8027),可以省去端口转发配置。 ## 测试 FCC 是否工作 1. **使用起播较快播放器**:确保播放器本身起播速度足够快,不能成为瓶颈,例如 [内置 Web 播放器](./web-player.md)。 2. **观察换台速度**: * 正常启用 FCC:换台延迟 < 1s * 未启用 FCC:换台延迟 2-5 秒 3. **查看日志**: * 出现 `FCC: Unicast stream started successfully` 表示 FCC 地址有效,并且成功收到单播流。 * 出现 `FCC: Server response timeout (80 ms), falling back to multicast` 有两种可能 1. FCC 地址无效。 2. 你的网络配置不正确,导致无法连接到 FCC 服务器。一般来说必须通过 DHCP/IPoE/PPPoE 获得 IPTV 内网 IP 后,并启用 rtp2httpd `--upstream-interface-fcc` 或 `--upstream-interface` 选项指定 IPTV 接口后,才能访问 FCC。请结合 ping / traceroute 等工具判断。 ## 相关文档 * [各地 FCC 地址汇总](../reference/cn-fcc-collection.md):中国各省 FCC 服务器地址 * [URL 格式说明](./url-formats.md):FCC URL 格式 * [配置参数详解](../reference/configuration.md):FCC 相关配置参数 --- --- url: /guide/m3u-integration.md --- # M3U 播放列表集成 rtp2httpd 全面支持 M3U/M3U8 播放列表格式,可自动识别节目并提供转换后的播放列表,让你可以一键导入外部 m3u 频道列表,自动替换 URL,直接在 IPTV 播放器中使用。 ## 配置方法 ### 方法一:使用外部 M3U 文件 在配置文件中指定外部 M3U URL: ```ini [global] # 外部 M3U 配置(支持 file://, http://, https://) # 注意:HTTP/HTTPS 需要安装 curl 或 uclient-fetch 或 wget 命令 external-m3u = https://example.com/iptv.m3u # 或使用本地文件 external-m3u = file:///path/to/playlist.m3u # 外部 M3U 更新间隔(秒) # 默认 7200(2 小时),设为 0 禁用自动更新 external-m3u-update-interval = 7200 ``` ### 方法二:在配置文件中直接内联 M3U 在 `[services]` 区段直接编写 M3U 内容: ```ini [services] # 直接编写 M3U 内容,以 #EXTM3U 开头 #EXTM3U x-tvg-url="https://example.com/epg.xml.gz" # 基础频道配置 #EXTINF:-1 tvg-id="CCTV1" tvg-name="CCTV1" tvg-logo="https://example.com/logo/CCTV1.png" group-title="央视",CCTV-1 rtp://239.253.64.120:5140 # 带时移回看的频道配置 #EXTINF:-1 tvg-id="CCTV2" tvg-name="CCTV2" group-title="央视" catchup="default" catchup-source="rtsp://10.0.0.50:554/catchup?playseek={utc:YmdHMS}-{utcend:YmdHMS}",CCTV-2 rtp://239.253.64.121:5140 # 简单配置(只有频道名) #EXTINF:-1,广东卫视 rtp://239.194.10.15:1234 ``` ## 使用播放列表 ### 方式一:使用内置播放器 配置好 M3U 后,通过浏览器访问 `http://服务器地址:端口/player` 即可使用 [内置 Web 播放器](./web-player.md)。 ### 方式二:导出播放列表到其他播放器 转换后的 M3U 播放列表可通过以下 URL 访问: ``` http://服务器地址:端口/playlist.m3u ``` **示例**: ``` http://192.168.1.1:5140/playlist.m3u ``` 将此 URL 添加到支持 M3U 的 IPTV 播放器(如 APTV、TiviMate 等)即可使用。 ## 转换示例 ### 输入 M3U ```m3u #EXTM3U x-tvg-url="https://example.com/epg.xml.gz" #EXTINF:-1 tvg-id="CCTV1" tvg-name="CCTV1" tvg-logo="https://example.com/logo/CCTV1.png" group-title="央视" catchup="default" catchup-source="rtsp://10.0.0.50:554/catchup?auth=loremipsum&playseek={utc:YmdHMS}-{utcend:YmdHMS}",CCTV-1 rtp://239.253.64.120:5140 #EXTINF:-1 tvg-id="CCTV2" tvg-name="CCTV2" group-title="央视",CCTV-2 rtp://239.253.64.121:5140 #EXTINF:-1 tvg-id="HLS1" tvg-name="内网HLS源",内网HLS源 http://10.0.0.60/live/stream.m3u8 ``` ### 输出 M3U(转换后) ```m3u #EXTM3U x-tvg-url="http://192.168.1.1:5140/epg.xml.gz" #EXTINF:-1 tvg-id="CCTV1" tvg-name="CCTV1" tvg-logo="https://example.com/logo/CCTV1.png" group-title="央视" catchup="default" catchup-source="http://192.168.1.1:5140/CCTV-1/catchup?playseek={utc:YmdHMS}-{utcend:YmdHMS}",CCTV-1 http://192.168.1.1:5140/央视/CCTV-1 #EXTINF:-1 tvg-id="CCTV2" tvg-name="CCTV2" group-title="央视",CCTV-2 http://192.168.1.1:5140/央视/CCTV-2 #EXTINF:-1 tvg-id="HLS1" tvg-name="内网HLS源",内网HLS源 http://192.168.1.1:5140/内网HLS源 ``` > \[!NOTE] > > * EPG 的 URL 已转换为 rtp2httpd 代理地址 > * CCTV-1 和 CCTV-2 的 URL 已转换为 rtp2httpd 代理地址 > * CCTV-1 的 catchup-source 也已转换,并保留动态占位符 > * HLS 源的 HTTP URL 也会被转换为 rtp2httpd 代理地址,便于通过 rtp2httpd 为内网 HLS 源提供外网访问 ## 使用建议 1. **HTTP/HTTPS 支持** * 需要系统安装 `curl` 或 `uclient-fetch` 或 `wget` 命令 * rtp2httpd 会自动检测并使用可用的工具 2. **更新策略** * 默认 2 小时自动更新外部 M3U * 可根据源更新频率调整 `external-m3u-update-interval` * 设为 0 禁用自动更新(需手动重启服务更新) 3. **混合使用** * 可同时配置外部 M3U 和内联 M3U * 两者会合并到同一个转换后的播放列表中 * 内置 M3U 转换会转换所有可识别 URL(包括普通 HTTP URL)。这适合把内网 HLS 源转换为 rtp2httpd 代理地址后提供外网访问;如果希望某些 HTTP 源在导出的播放列表中保留原始 URL,请自行维护给播放器使用的 M3U 文件,而不要依赖 rtp2httpd 的转换输出。 4. **使用反向代理时开启 `xff` 选项** * M3U 在转换过程中,需要知道自身的完整访问地址,因此如果使用反向代理,请开启 `xff` 选项,并确保反代程序可以透传 `X-Forwarded-*` 相关头。详见 [公网访问建议](./public-access.md)。 ## URL 识别与转换规则 ### 支持的 URL 格式 rtp2httpd 能够识别并转换以下格式的 URL: 1. **直接协议 URL**: * `rtp://[source@]multicast_addr:port[?query]` * `rtsp://server:port/path[?query]` * `udp://multicast_addr:port[?query]` * `http://server/path[?query]`(作为 HTTP 反向代理服务) 2. **UDPxy 格式的 HTTP URL**: * `http://hostname:port/rtp/multicast_addr:port` * `http://hostname:port/rtsp/server:port/path` * `http://hostname:port/http/server/path` * 会自动把 `hostname:port` 替换为 rtp2httpd 实际的地址和端口 ### 转换示例 | 原始 URL | 转换后 URL | | ------------------------------------------- | --------------------------------------------- | | `rtp://239.253.64.120:5140` | `http://hostname:5140/CCTV-1` | | `rtsp://10.0.0.50:554/live` | `http://hostname:5140/CCTV-2` | | `http://router:5140/rtp/239.1.1.1:1234` | `http://hostname:5140/频道名` | | `http://10.0.0.60/live/stream.m3u8`(HLS 源) | `http://hostname:5140/频道名` | **服务名称提取规则**:使用 `#EXTINF` 行中最后一个逗号后的文本作为服务名称。 ``` #EXTINF:-1 tvg-id="..." tvg-name="..." group-title="...",CCTV-1 ^^^^^^ 服务名称 ``` ## 时移回看(Catchup)支持 当 M3U 中包含 `catchup-source` 属性时,rtp2httpd 会自动创建对应的时移服务。 ### 配置示例 ```m3u #EXTINF:-1 tvg-id="CCTV1" catchup="default" catchup-source="rtsp://10.0.0.50:554/catchup?playseek={utc:YmdHMS}-{utcend:YmdHMS}",CCTV-1 rtp://239.253.64.120:5140 #EXTINF:-1 catchup="append" catchup-source="?starttime=${(b)yyyyMMdd|UTC}T${(b)HHmmss|UTC}&endtime=${(e)yyyyMMdd|UTC}T${(e)HHmmss|UTC}",CCTV-1 http://iptv.example.com/live/channel1.m3u8 ``` ### 转换结果 * **直播服务**:`http://hostname:5140/CCTV-1` * **时移服务**:`http://hostname:5140/CCTV-1/catchup?playseek={utc:YmdHMS}-{utcend:YmdHMS}` ### 占位符处理 * **动态占位符**(包含 `{` 或 `}`):保留在转换后的 URL 中,由播放器填充 * 例如:`{utc:YmdHMS}`、`{utcend:YmdHMS}` * **静态参数**:其他查询参数不会保留在转换的 m3u 中。但依然会保留在对上游的请求中。 ### 不可识别 URL 的处理 无法识别的 URL 会原样保留,不进行转换。例如,`catchup-source` 使用不支持的 HTTPS URL(如 `https://10.0.0.60/catchup`)时会保持原样。 ## 线路标签 一行 `#EXTINF` 后面紧跟多行 URL,每行代表该频道的一条线路。通过在 URL 末尾添加 `$标签` 后缀,可以为每条线路指定显示标签(如清晰度)。`$标签` 必须位于整个 URL 的最末尾。 只有在支持标签和频道聚合的播放器中(例如 [内置 Web 播放器](./web-player.md))才有效果。 ### 示例输入 ```m3u #EXTINF:-1 tvg-id="广东卫视" tvg-name="广东卫视" tvg-logo="https://example.com/logo/广东卫视.png" group-title="卫视",广东卫视 rtp://239.253.64.96:5140/?fcc=10.255.75.73:15970$超高清 rtp://239.253.64.200:5140/?fcc=10.255.75.73:15970$高清 rtp://239.253.64.44:5140/?fcc=10.255.75.73:15970$标清 ``` ### 示例输出 每条线路会生成独立的服务路径,`$label` 转换为 `/label` 子路径,同时 `$label` 保留在转换后 URL 的末尾。转换后的 M3U 保持与输入相同的结构: ```m3u #EXTINF:-1 tvg-id="广东卫视" tvg-name="广东卫视" tvg-logo="https://example.com/logo/广东卫视.png" group-title="卫视",广东卫视 http://192.168.1.1:5140/卫视/广东卫视/超高清$超高清 http://192.168.1.1:5140/卫视/广东卫视/高清$高清 http://192.168.1.1:5140/卫视/广东卫视/标清$标清 ``` ## 相关文档 * [内置 Web 播放器](./web-player.md):播放器功能、频道聚合、时间占位符 * [URL 格式说明](./url-formats.md):了解所有支持的 URL 格式 * [配置参数详解](../reference/configuration.md):查看完整配置选项 --- --- url: /guide/url-formats.md --- # URL 格式说明 rtp2httpd 支持多种流媒体协议,通过不同的 URL 前缀进行区分。 基本格式:`http://服务器地址:端口/路径[?参数1=值1][&参数2=值2][&参数3=值3]` 如果配置了 `app-path-prefix`,所有路径都需要加上此前缀。例如 `app-path-prefix = /app/rtp2httpd` 时,`/rtp/...`、`/status`、`/player`、`/playlist.m3u` 等路径分别变为 `/app/rtp2httpd/rtp/...`、`/app/rtp2httpd/status`、`/app/rtp2httpd/player`、`/app/rtp2httpd/playlist.m3u`。 当配置了 `r2h-token(HTTP 请求认证令牌)` 时,所有 URL 都需要额外带上参数 `r2h-token=` 才能访问。 > \[!TIP] > 除了 URL 参数,也支持通过 Cookie 或者 User Agent 来传递 `r2h-token`。例如 `Cookie: r2h-token=xxx` 或 `User-Agent: R2HTOKEN/xxx`。 ## 组播 RTP 转 HTTP 单播流 ```url http://服务器地址:端口/rtp/组播地址:端口[?fcc=FCC服务器:端口][&fcc-type=协议类型][&fec=FEC端口] ``` **示例**: ```url http://192.168.1.1:5140/rtp/239.253.64.120:5140 http://192.168.1.1:5140/rtp/239.253.64.120:5140?fcc=10.255.14.152:15970 http://192.168.1.1:5140/rtp/239.253.64.120:5140?fcc=10.255.14.152:8027&fcc-type=huawei http://192.168.1.1:5140/rtp/239.81.0.195:4056?fec=4055 http://192.168.1.1:5140/rtp/239.253.64.120:5140?fcc=10.255.14.152:15970&r2h-ifname=eth0&r2h-ifname-fcc=eth1 ``` ### 参数说明 * **组播地址**:IPTV 运营商提供的组播地址 * **端口**:组播端口号 * **fcc**(可选):FCC 快速换台服务器地址,格式为 `IP:端口` * **fcc-type**(可选):FCC 协议类型,可选值: * `telecom`:电信/中兴/烽火 FCC 协议(默认) * `huawei`:华为 FCC 协议 * **fec**(可选):FEC 前向纠错端口号,用于接收 FEC 冗余数据包来恢复丢包 * **r2h-ifname**(可选):指定使用的上游网络接口(覆盖全局配置) * **r2h-ifname-fcc**(可选):指定 FCC 使用的上游网络接口(覆盖全局配置) * **r2h-filename**(可选):下载文件名,详见 [下载文件名](#下载文件名) ### 使用场景 * 将运营商 IPTV 组播流转换为 HTTP 单播流 * 在局域网内多设备共享 IPTV 流 * 配合 FCC 实现毫秒级换台 * 配合 FEC 实现丢包恢复,提高播放稳定性 ## RTSP 转 HTTP ```url http://服务器地址:端口/rtsp/RTSP服务器:端口/路径[?参数] ``` **示例**: ```url # 直播流 http://192.168.1.1:5140/rtsp/iptv.example.com:554/channel1 # 时移回看(使用 playseek 参数) http://192.168.1.1:5140/rtsp/iptv.example.com:554/channel1?playseek=20240101120000-20240101130000 # 时移回看(使用 tvdr 参数) http://192.168.1.1:5140/rtsp/iptv.example.com:554/channel1?tvdr=20240101120000GMT-20240101130000GMT # 自定义时移参数名 + 起止时间独立偏移 http://192.168.1.1:5140/rtsp/iptv.example.com:554/channel1?seek=20240101120000-20240101130000&r2h-seek-name=seek&r2h-seek-offset=12,-12 # 显式开启 RTSP 近实时优化(参见 r2h-seek-mode 文档) http://192.168.1.1:5140/rtsp/iptv.example.com:554/channel1?playseek=20240101120000&r2h-seek-mode=range(UTC%2B8/3600) # 指定上游网络接口 http://192.168.1.1:5140/rtsp/iptv.example.com:554/channel1?r2h-ifname=eth0 ``` ### 使用场景 * 将 IPTV RTSP 单播流转换为 HTTP 流 * 实现 RTSP 时移回看功能 > \[!IMPORTANT] > rtp2httpd 的 RTSP 支持仅适用于承载单路 MPEG-TS 流的场景(即 IPTV 单播/时移回看),不支持监控摄像头等其他 RTSP 用途。 ### 常见问题:时移回看时,实际回看时间比节目单早了/晚了 8 小时 这是由于时区未能匹配。需要做时区转换。你可以尝试以下几种方式。 * 修改播放器 User Agent 设置,加上 `TZ/UTC+8` 或 `TZ/UTC-8`。例如 `AptvPlayer/1.3.3 TZ/UTC+8`。 * 修改播放链接,加上参数 `&r2h-seek-offset=28800` 或 `&r2h-seek-offset=-28800`。如果只需要调整起始/结束边界,可以使用 `&r2h-seek-offset=12,-12` 这样的形式分别偏移起始和结束时间 关于时移回看的参数处理(时区、偏移),详见 [时间处理说明](./time-processing.md)。 ## 上游流 Metadata 响应头 RTSP、普通组播和 FCC 流会在 HTTP Headers 带上以下 `R2H-*` Metadata: | 响应头 | 含义 | | --- | --- | | `R2H-Upstream-Protocol` | 上游类型:`rtsp` 或 `multicast`。FCC 流也属于 `multicast`。 | | `R2H-Upstream-Transport` | RTSP 实际协商的传输方式:`tcp-interleaved` 或 `udp`。 | | `R2H-Upstream-Payload` | 已确认的 MPEG-TS 封装:`mp2t-rtp` 或 `mp2t-direct`。 | | `R2H-Playback-Scale` | RTSP `PLAY` 响应明确确认的播放速率。 | | `R2H-Playback-Range` | RTSP `PLAY` 响应明确确认的播放范围。 | | `R2H-Media-Duration` | SDP 有限 `npt` 范围的时长,单位为秒。 | | `R2H-FCC-Type` | 已配置的 FCC 协议:`telecom` 或 `huawei`。 | | `R2H-FCC-Status` | 从 FCC 单播起播为 `active`;从组播起播为 `fallback`。 | ## 下载文件名 组播 RTP 和 RTSP 的 MPEG-TS 响应支持 `r2h-filename` 查询参数。参数非空时,rtp2httpd 会输出 `Content-Disposition: attachment`,让浏览器按指定文件名保存下载。服务端会去掉路径分隔符和控制字符,并在缺少后缀时补上 `.ts`。 该参数只作用于 rtp2httpd 自身,不会转发给上游。HTTP/HLS 反向代理会在转发前剥离该参数,也不会设置 `Content-Disposition`。 ```url http://192.168.1.1:5140/rtp/239.253.64.120:5140?r2h-filename=CCTV-1.ts http://192.168.1.1:5140/rtsp/iptv.example.com:554/channel1?playseek=20240101120000-20240101130000&r2h-filename=CCTV-1_新闻联播_20240101-120000_20240101-130000.ts ``` 内置 Web 播放器复制媒体直链时会自动带上该参数。 ## HTTP 反向代理 ```url http://服务器地址:端口/http/上游服务器[:端口]/路径[?参数] ``` **示例**: ```url # 代理 HLS 流(指定端口) http://192.168.1.1:5140/http/upstream.example.com:8080/live/stream.m3u8 # 代理 HTTP 请求(省略端口,默认 80) http://192.168.1.1:5140/http/api.example.com/video?auth=xxx&quality=hd ``` ### 参数说明 * **上游服务器**:目标 HTTP 服务器地址 * **端口**(可选):目标服务器端口,默认 80 * **路径**:请求路径,包括查询参数 ### 使用场景 * 代理上游 HLS/DASH 流媒体,统一认证和访问控制 * 为不支持直接访问的 IPTV 内网服务提供 HTTP 反向代理 ### 时移回看支持 HTTP 代理同样支持 `r2h-seek-name`、`r2h-seek-offset` 参数和 User-Agent 时区转换,处理方式与 RTSP 代理一致。 ```url # 自动识别 playseek 参数并进行时区转换 http://192.168.1.1:5140/http/iptv.example.com/channel1?playseek=20240101120000-20240101130000 # 使用自定义参数名 + 时间偏移 http://192.168.1.1:5140/http/iptv.example.com/channel1?catchup=20240101120000&r2h-seek-name=catchup&r2h-seek-offset=3600 # 指定上游网络接口 http://192.168.1.1:5140/http/iptv.example.com/channel1?r2h-ifname=eth0 ``` 详见 [时间处理说明](./time-processing.md)。 ### 上游 30x 重定向 当上游返回 `301` / `302` / `303` / `307` / `308` 时,rtp2httpd 会按协议改写 `Location`,让播放器继续走本实例: | 上游 `Location` | 转发给客户端 | | --- | --- | | `http://iptv.example.com:8080/path` | `/http/iptv.example.com:8080/path` | | `rtsp://iptv.example.com:554/path?auth=...` | `/rtsp/iptv.example.com:554/path?auth=...` | | `rtp://239.0.0.1:1234` | `/rtp/239.0.0.1:1234` | | `udp://239.0.0.1:1234` | `/udp/239.0.0.1:1234` | | `/rtsp/iptv.example.com:554/path`(根路径相对地址) | 原样转发 | | `https://...` 或其他未支持的协议 | 原样转发 | 改写范围与 M3U 可识别的 URL 格式一致:`http://`、`rtsp://`、`rtp://`、`udp://`。这适用于 `catchup-source` 先指向一个 HTTP 鉴权/换链服务,再由该服务 302 到真实播放地址的场景。如果配置了 `app-path-prefix`,改写后的地址会带上此前缀。 ### 注意事项 * 仅支持 HTTP 上游(不支持 HTTPS) * 可通过 `upstream-interface-http` 配置指定上游网络接口,也可以通过 `r2h-ifname` 参数在每次请求中指定 * 如果被代理的目标 URL 是 m3u 类型,其中所有 `http://` URL 会被自动改写为经过 rtp2httpd 代理后的地址(为了保证 HLS 流能被正确代理) ## IPv6 支持 所有 URL 中的主机地址均支持 IPv6。在 URL 中书写 IPv6 字面量时,需要使用方括号 `[]` 包裹: ```url # HTTP 反向代理(IPv6 上游) http://192.168.1.1:5140/http/[2001:db8::1]:8080/live/stream.m3u8 # RTSP 转 HTTP(IPv6 上游) http://192.168.1.1:5140/rtsp/[2001:db8::1]:554/channel1 # RTSP URL 带认证信息 rtsp://user:pass@[2001:db8::1]:554/live # IPv6 组播(需要系统和网络接口支持 IPv6 组播) http://192.168.1.1:5140/rtp/[ff3e::1]:1234 ``` ### 行为说明 * **域名自动双栈解析**:上游地址为域名时,按系统解析顺序依次尝试 IPv6 / IPv4 地址,连接失败时自动回退到下一个地址 * **Host 校验**:配置了 `hostname` 时,请求头中的 `[IPv6]:端口` 格式 Host 也能正确通过校验 * **服务监听**:`[bind]` 配置节和 `--listen` 参数均支持 IPv6 地址(如 `::1 5140` 或 `-l [::1]:5140`) ### 限制 * **`mcast-rejoin-interval` 不支持 IPv6** ## M3U 播放列表访问 ```url http://服务器地址:端口/playlist.m3u ``` **示例**: ```url http://192.168.1.1:5140/playlist.m3u ``` 获取转换后的 M3U 播放列表,包含所有通过配置文件和外部 M3U 定义的频道,并将 URL 转换成 rtp2httpd 监听的地址和端口,并使用频道名替换原始 IP、查询参数、认证信息。 ### 使用场景 * 一键导入别人维护的 m3u 频道源 * 隐藏频道源 IP、认证信息 * 自动更新频道信息 详见 [M3U 播放列表集成](./m3u-integration.md)。 ## 内置 Web 播放器 ```url http://服务器地址:端口/player ``` **示例**: ```url http://192.168.1.1:5140/player ``` 访问[内置 Web 播放器](./web-player.md),可以在网页端播放已配置的 M3U 频道列表。 播放器页面路径可以通过配置项 `player-page-path` 自定义。设置为 `/` 可以实现不带任何路径直接访问。 ## 状态页面 ```url http://服务器地址:端口/status ``` **示例**: ```url http://192.168.1.1:5140/status ``` 访问 Web 状态页面,查看: * 实时客户端连接统计 * 每个连接的 IP、状态、带宽使用、传输数据量 * 系统日志查看 * 远程管理功能(强制断开连接、调整日志级别等) * 服务控制:重载配置、重启工作进程 强制断开某个客户端时,rtp2httpd 会立即关闭该连接,并在随后 5 秒内拒绝该客户端 IP 的所有新连接(返回 `HTTP 429 Too Many Requests`,并带有 `Retry-After`),避免播放器立刻重连。 **服务控制**(等效于向 supervisor 发送 Unix 信号): | 操作 | 等效信号 | API | | --- | --- | --- | | 重载配置 | `SIGHUP` | `POST /status/api/reload-config` | | 重启工作进程 | `SIGUSR1` | `POST /status/api/restart-workers` | 将 `/status` 替换为实际的 `status-page-path` 配置值。详见 [配置参数详解 — 运行时配置管理](../reference/configuration.md#运行时配置管理)。 状态页面路径可以通过配置项 `status-page-path` 自定义。设置为 `/` 可以实现不带任何路径直接访问。 ## udpxy 兼容模式 rtp2httpd 完全兼容 udpxy URL 格式,可以无缝替换 udpxy / msd\_lite 等组播转单播服务。 ### udpxy 格式 ```url http://服务器地址:端口/udp/组播地址:端口 http://服务器地址:端口/rtp/组播地址:端口 ``` **示例**: ```url http://192.168.1.1:5140/udp/239.253.64.120:5140 http://192.168.1.1:5140/rtp/239.253.64.120:5140 ``` udpxy 兼容模式默认启用,可以通过配置参数 `udpxy = no` 禁用。禁用后仅支持通过 m3u 提供服务。 > \[!TIP] > 使用 `/udp/` 和 `/rtp/` 没有任何差别,选择任意一种即可。 ## 视频快照 在任意流媒体 URL 后添加 `snapshot=1` 参数,或在 HTTP 请求头中添加 `Accept: image/jpeg` 或 `X-Request-Snapshot: 1`,即可获取视频流的 JPEG 快照。 **示例**: ```url # 方式 1:URL 参数 http://192.168.1.1:5140/rtp/239.253.64.120:5140?snapshot=1 # 方式 2:HTTP 请求头 curl -H "Accept: image/jpeg" http://192.168.1.1:5140/rtp/239.253.64.120:5140 # 方式 3:自定义请求头 curl -H "X-Request-Snapshot: 1" http://192.168.1.1:5140/rtp/239.253.64.120:5140 ``` 详见 [视频快照配置](./video-snapshot.md)。 ## 相关文档 * [M3U 播放列表集成](./m3u-integration.md):播放列表配置 * [FCC 快速换台配置](./fcc-setup.md):启用毫秒级换台 * [视频快照配置](./video-snapshot.md):频道预览图功能 * [配置参数详解](../reference/configuration.md):查看完整配置选项 --- --- url: /guide/public-access.md --- # 公网访问建议 如果你需要将 rtp2httpd 暴露到公网,请务必做好安全防护。 目前公网上存在大量自动化扫描器,专门探测开放的 udpxy / msd\_lite 等无认证组播转单播服务,一旦被发现就会被持续盗用带宽。rtp2httpd 默认兼容 udpxy URL 格式,如果不加任何防护直接暴露,同样会被这些扫描器利用。 ## 安全配置 开放公网访问时,建议修改 `hostname` / `r2h-token` / `status-page-path` / `player-page-path` 以加强安全性。 ```ini [global] hostname = iptv.example.com r2h-token = my-secret-token-12345 status-page-path = /my-status-page player-page-path = /my-player ``` ## 前置反向代理 如有条件,建议前置 nginx / lucky / caddy 等反向代理负责转发,并开启 rtp2httpd 的 `xff` 选项 ```ini [global] xff = yes ``` 需要确保反向代理可以透传 `X-Forwarded-For` / `X-Forwarded-Host` / `X-Forwarded-Proto` 头。 对于 lucky,开启 `万事大吉` 选项即可。 对于 nginx,以下是一个配置示例: ```nginx server { listen 80; server_name iptv.example.com; location / { proxy_pass http://127.0.0.1:5140; proxy_http_version 1.1; # 透传客户端真实 IP 和协议信息 proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Proto $scheme; # 流媒体相关优化 proxy_buffering off; } } ``` ## 性能调优 建议修改内核参数,[开启 BBR](https://blog.clash-plus.com/post/openwrt-bbr/) 有助于在公网环境提高传输稳定性、降低起播延迟。 ## 跨运营商公网访问 > \[!NOTE] > 本节内容主要针对**中国大陆**的网络环境。其他国家和地区的 ISP 政策可能有所不同。 近年来中国大陆运营商大力整治 PCDN,对家庭宽带的上行带宽实施了越来越严格的限制。许多地区上行带宽虽然标称 30-50Mbps,但如果发生跨网上行(例如从中国移动上传到中国电信),会出现非常严格的上行限速(可能只有几 Mbps,不足以串流 4K 视频)。 此外,如果因为过往行为,被运营商判断为 PCDN 用户后,全部上行流量将会被送入流量清洗池,即使是同运营商,上行带宽也可能会被严格限制。 一条 1080p IPTV 流的码率通常在 6-10 Mbps,4K 流可达 30-40 Mbps。这意味着在 30Mbps 上行带宽下,可能只能同时支持 3-5 个 1080p 客户端,或仅 1 个 4K 客户端。 ### 带宽不足时的表现 当上行带宽不足以承载所有客户端的流量时,rtp2httpd 会出现以下现象: * **日志输出缓冲池扩容消息**:由于数据发送不出去,在内存中持续积累,rtp2httpd 会自动扩容缓冲池以尝试容纳更多待发送数据 * **状态页面显示慢客户端**:在 `/status` 页面可以看到部分客户端被标记为 `慢客户端`,表示其发送队列已积压 * **客户端缓冲池占满后丢包**:当某个客户端的缓冲积压达到上限,新到达的数据包会被丢弃,在观看端表现为频繁花屏、卡顿、重新加载 这些现象的根本原因是上行带宽受限,数据无法及时发送到客户端。 ## 相关文档 * [配置参数详解](../reference/configuration.md):完整配置选项说明 * [URL 格式说明](./url-formats.md):认证令牌传递方式 * [性能测试报告](../reference/benchmark.md):与其他方案的性能对比 --- --- url: /guide/web-player.md --- # 内置 Web 播放器 rtp2httpd 内置了一个基于 Web 的现代化播放器,可以直接在浏览器中观看已配置的 M3U 频道列表,无需安装任何客户端。 ## 功能特性 * **频道列表**:自动加载配置的 M3U 频道列表 * **在线直播**:在浏览器中直接观看直播 * **时移回看**:支持 EPG 电子节目单和时移回看(需要有回看源) * **快速起播**:搭配 FCC 可实现毫秒级换台速度 * **无缝换台**:换台时预加载新流,减少黑屏 * **响应式设计**:桌面和移动端 UI 自适应 * **PWA 支持**:可添加到手机、平板、桌面或 LG webOS 电视主屏幕,像原生应用一样快捷打开 * **零开销**:纯 Web 前端实现,对 rtp2httpd 运行几乎没有资源占用(无解码转码开销) > \[!IMPORTANT] > 播放器依赖浏览器的原生解码能力,部分编码格式(如 E-AC3)可能在某些浏览器中无法播放(表现为无音频、画面黑屏)。推荐使用最新版本的 Chrome、Edge 或 Safari。 ## 访问方式 配置好 M3U 播放列表后,通过浏览器访问: ```url http://服务器地址:端口/player ``` **示例**: ```url http://192.168.1.1:5140/player ``` 播放器页面路径可以通过配置项 `player-page-path` 自定义。设置为 `/` 可以实现不带任何路径直接访问。 ## 链接直达频道 可以在播放器地址后附加 `#频道序号` 或 `#频道名称`,直接打开指定频道,适合收藏或分享给他人: ```url http://服务器地址:端口/player#5 http://服务器地址:端口/player#CCTV-1 ``` 播放器在切换频道时会自动更新地址栏,随时复制即可分享当前正在播放的频道。 ## 复制媒体直链 在频道列表中键点击频道,可复制该频道当前线路的直播地址。在节目单中键点击节目,可复制该节目的回看地址(需要频道配置了 `catchup-source`)。复制成功后页面会弹出提示。 复制得到的是可直接请求的 HTTP 媒体地址,可用于 FFmpeg、N\_m3u8DL-RE、IDM 等工具下载或在第三方播放器中打开。多线路频道会复制最近一次使用的线路;若当前页面带有 `r2h-token`,复制的链接也会带上该参数。 组播和 RTSP 直链还会带上 `r2h-filename` 查询参数,值为频道名、线路标签、节目名和时间范围组成的 `.ts` 文件名。用浏览器打开并触发下载时,会按该文件名保存。详见 [URL 格式说明](./url-formats.md#下载文件名)。 > \[!NOTE] > 正在播出且没有回看源的节目会复制直播地址。尚未开始且没有回看源的节目无法复制。 ## PWA 支持与添加到主屏幕 内置 Web 播放器支持 PWA(Progressive Web App)。你可以将播放器页面添加到设备主屏幕(包括手机、平板、电脑,以及 LG webOS 智能电视),像打开原生应用一样一键进入,获得全屏、沉浸式的观看体验。 添加到主屏幕后,桌面图标名称默认为 **R2H 播放器**,并会使用内置的应用图标。播放器会保留主题等本地设置。 ### iOS / iPadOS(Safari) 1. 在 Safari 中打开播放器页面(例如 `http://192.168.1.1:5140/player`) 2. 点击地址栏左侧扩展按钮中的 **分享** 3. 在分享菜单中下滑,选择 **添加到主屏幕** 4. 确认名称后点击 **添加** ### Android(Chrome、Edge 等) 1. 在浏览器中打开播放器页面 2. 点击浏览器右上角的 **菜单**(⋮) 3. 选择 **添加到主屏幕** 或 **安装应用** 4. 按提示确认安装 部分浏览器还会在地址栏或页面底部显示安装横幅,点击 **安装** 或 **添加** 即可完成。 ### 桌面端(Chrome、Edge) 1. 在浏览器中打开播放器页面 2. 点击地址栏右侧的 **安装** 图标(如有),或从浏览器菜单中选择 **投放、保存和分享** → **创建快捷方式** 3. 按提示确认 安装后,播放器会以独立窗口运行,可从系统应用列表或 Dock / 任务栏快速启动。 ### LG 电视(webOS) LG webOS 智能电视同样支持通过内置浏览器使用播放器,并将页面固定到电视桌面: 1. 在电视上打开 **Web Browser** 应用 2. 在地址栏输入播放器页面地址(例如 `http://192.168.1.1:5140/player`) 3. 打开浏览器菜单,选择 **添加到主屏幕**(Add shortcut to the Home screen) 4. 返回电视主界面,即可从桌面快捷方式启动播放器 > \[!NOTE] > 若通过 `player-page-path` 自定义了播放器路径,请使用实际路径访问后再添加到主屏幕。添加到主屏幕的快捷方式会固定指向添加时的 URL,包括其中的 `r2h-token` 等查询参数(如有)。 > 也可以在 URL 末尾附加 `#频道名称` 或 `#频道序号`,将快捷方式固定到指定频道。 ## 频道聚合 在 M3U 中,一行 `#EXTINF` 后面紧跟多行 URL,即表示该频道拥有多条线路。播放器会将它们聚合为一个频道,在频道列表中只显示一次,用户可以通过线路选择器切换不同线路(如不同清晰度): ![频道源选择器](../images/channel-source-selector.png) ```m3u #EXTINF:-1 group-title="卫视",广东卫视 http://192.168.1.1:5140/rtp/239.253.64.96:5140$超高清 http://192.168.1.1:5140/rtp/239.253.64.200:5140$高清 ``` 如果源 URL 带有 `$标签` 后缀,播放器会将其提取为源的显示标签(如「超高清」「高清」「标清」)。没有 `$标签` 的源则按序号显示(如「线路 1」「线路 2」)。 > \[!NOTE] > 频道聚合是 **内置 Web 播放器** 的前端功能,并非 rtp2httpd 服务端行为。第三方播放器(如 APTV、TiviMate 等)是否支持类似的聚合显示取决于其自身实现。rtp2httpd 服务端仅负责解析 `$标签`、生成独立的服务路径,以及在转换后的 M3U 中保留 `$标签`。 关于线路标签的 M3U 配置方式,详见 [M3U 播放列表集成](./m3u-integration.md#线路标签)。 ## 无缝换台 内置 Web 播放器默认开启 **无缝换台** 。换台或切换线路时,播放器会在后台预先加载新频道的视频流,待新流准备就绪后再切换画面,减少黑屏和等待时间,配合 [FCC 快速换台](./fcc-setup.md) 可获得更流畅的换台体验。 该功能通过双槽位预加载实现。由于在换台过程中短暂存在两路视频同时拉流的情况,如果你的带宽比较小(公网访问时),或是上游只支持单路组播,导致换台出现卡顿,可以手动关闭这个选项——在播放器页面右上角的 **设置**(齿轮图标)中关闭 **无缝换台** 即可。关闭后换台会先断开当前流再加载新流,占用带宽更低,但切换时可能出现短暂黑屏。 ## 时间占位符 内置 Web 播放器支持以下时间占位符格式,可在 M3U `catchup-source` URL 中使用: ### `${}` 格式(使用 long format) | 占位符 | 说明 | 示例输出 | | ----------------------------- | --------------------------------------- | ------------------------ | | `${utc}` | 节目开始时间(UTC,ISO8601 格式) | 2025-01-15T10:30:45.000Z | | `${utc:yyyyMMddHHmmss}` | 节目开始时间(UTC,自定义 long format) | 20250115103045 | | `${utcend}` | 节目结束时间(UTC,ISO8601 格式) | 2025-01-15T12:30:45.000Z | | `${utcend:yyyyMMddHHmmss}` | 节目结束时间(UTC,自定义 long format) | 20250115123045 | | `${start}` | 同 `${utc}` | 2025-01-15T10:30:45.000Z | | `${start:yyyyMMddHHmmss}` | 同 `${utc:yyyyMMddHHmmss}` | 20250115103045 | | `${end}` | 同 `${utcend}` | 2025-01-15T12:30:45.000Z | | `${end:yyyyMMddHHmmss}` | 同 `${utcend:yyyyMMddHHmmss}` | 20250115123045 | | `${lutc}` | 当前时间(UTC,ISO8601 格式) | 2025-01-15T14:00:00.000Z | | `${lutc:yyyyMMddHHmmss}` | 当前时间(UTC,自定义 long format) | 20250115140000 | | `${now}` | 同 `${lutc}` | 2025-01-15T14:00:00.000Z | | `${now:yyyyMMddHHmmss}` | 同 `${lutc:yyyyMMddHHmmss}` | 20250115140000 | | `${timestamp}` | 当前 Unix 时间戳(秒) | 1736949600 | | `${timestamp:yyyyMMddHHmmss}` | 同 `${lutc:yyyyMMddHHmmss}` | 20250115140000 | | `${(b)yyyyMMddHHmmss}` | 节目开始时间(本地时间,long format) | 20250115183045 | | `${(e)yyyyMMddHHmmss}` | 节目结束时间(本地时间,long format) | 20250115203045 | | `${(b)yyyyMMdd\|UTC}` | 节目开始时间(UTC,long format) | 20250115103045 | | `${(e)yyyyMMdd\|UTC}` | 节目结束时间(UTC,long format) | 20250115123045 | | `${(b)timestamp}` | 节目开始时间的 Unix 时间戳(秒) | 1736937045 | | `${(e)timestamp}` | 节目结束时间的 Unix 时间戳(秒) | 1736944245 | | `${yyyy}` | 节目开始时间:4 位年份(本地时间) | 2025 | | `${MM}` | 节目开始时间:月份 01-12(本地时间) | 01 | | `${dd}` | 节目开始时间:日期 01-31(本地时间) | 15 | | `${HH}` | 节目开始时间:小时 00-23(本地时间) | 18 | | `${mm}` | 节目开始时间:分钟 00-59(本地时间) | 30 | | `${ss}` | 节目开始时间:秒数 00-59(本地时间) | 45 | | `${duration}` | 节目时长(秒) | 7200 | | `${offset}` | 当前时间距节目开始的秒数 | 12600 | ### `{}` 格式(使用 short format) | 占位符 | 说明 | 示例输出 | | -------------------- | ---------------------------------------- | ------------------------ | | `{utc}` | 节目开始时间(UTC,ISO8601 格式) | 2025-01-15T10:30:45.000Z | | `{utc:YmdHMS}` | 节目开始时间(UTC,自定义 short format) | 20250115103045 | | `{utcend}` | 节目结束时间(UTC,ISO8601 格式) | 2025-01-15T12:30:45.000Z | | `{utcend:YmdHMS}` | 节目结束时间(UTC,自定义 short format) | 20250115123045 | | `{start}` | 同 `{utc}` | 2025-01-15T10:30:45.000Z | | `{start:YmdHMS}` | 同 `{utc:YmdHMS}` | 20250115103045 | | `{end}` | 同 `{utcend}` | 2025-01-15T12:30:45.000Z | | `{end:YmdHMS}` | 同 `{utcend:YmdHMS}` | 20250115123045 | | `{lutc}` | 当前时间(UTC,ISO8601 格式) | 2025-01-15T14:00:00.000Z | | `{lutc:YmdHMS}` | 当前时间(UTC,自定义 short format) | 20250115140000 | | `{now}` | 同 `{lutc}` | 2025-01-15T14:00:00.000Z | | `{now:YmdHMS}` | 同 `{lutc:YmdHMS}` | 20250115140000 | | `{timestamp}` | 当前 Unix 时间戳(秒) | 1736949600 | | `{timestamp:YmdHMS}` | 同 `{lutc:YmdHMS}` | 20250115140000 | | `{(b)YmdHMS}` | 节目开始时间(本地时间,short format) | 20250115183045 | | `{(e)YmdHMS}` | 节目结束时间(本地时间,short format) | 20250115203045 | | `{(b)YmdHMS\|UTC}` | 节目开始时间(UTC,short format) | 20250115103045 | | `{(e)YmdHMS\|UTC}` | 节目结束时间(UTC,short format) | 20250115123045 | | `{(b)timestamp}` | 节目开始时间的 Unix 时间戳(秒) | 1736937045 | | `{(e)timestamp}` | 节目结束时间的 Unix 时间戳(秒) | 1736944245 | | `{Y}` | 节目开始时间:4 位年份(本地时间) | 2025 | | `{m}` | 节目开始时间:月份 01-12(本地时间) | 01 | | `{d}` | 节目开始时间:日期 01-31(本地时间) | 15 | | `{H}` | 节目开始时间:小时 00-23(本地时间) | 18 | | `{M}` | 节目开始时间:分钟 00-59(本地时间) | 30 | | `{S}` | 节目开始时间:秒数 00-59(本地时间) | 45 | | `{duration}` | 节目时长(秒) | 7200 | | `{offset}` | 当前时间距节目开始的秒数 | 12600 | ### 格式说明 **Long Format(长格式)**:用于 `${}` 括号中的自定义格式 * `yyyy` - 4 位年份 * `MM` - 2 位月份(01-12) * `dd` - 2 位日期(01-31) * `HH` - 2 位小时(00-23) * `mm` - 2 位分钟(00-59) * `ss` - 2 位秒数(00-59) 示例:`${utc:yyyyMMddHHmmss}` → `20250115103045` **Short Format(短格式)**:用于 `{}` 括号中的自定义格式 * `Y` - 4 位年份 * `m` - 2 位月份(01-12) * `d` - 2 位日期(01-31) * `H` - 2 位小时(00-23) * `M` - 2 位分钟(00-59) * `S` - 2 位秒数(00-59) 示例:`{utc:YmdHMS}` → `20250115103045` ## 相关文档 * [M3U 播放列表集成](./m3u-integration.md):M3U 配置和线路标签 * [FCC 快速换台配置](./fcc-setup.md):启用毫秒级换台功能 * [配置参数详解](../reference/configuration.md):播放器相关配置参数 --- --- url: /reference/cn-fcc-collection.md --- # 各地 FCC 地址汇总 以下是从互联网收集的中国各地区 FCC 服务器,不保证可用,如有不可用请到 讨论反馈。 > \[!TIP] > > 1. 如果没有列出本城市 IP,可以尝试临近城市或省会的 IP。 > 2. 有些地区 FCC IP 和 RTSP 单播源的 IP 是一样的,只是端口不一样。如果你能找到当地 RTSP 单播地址,可以把端口换成 8027 或 15970 作为 FCC 地址试试看。 > 3. 可以根据 rtp2httpd 的日志判断 FCC 是否生效。 > * 出现 `FCC: Unicast stream started successfully` 表示 FCC 地址有效,并且成功收到单播流。 > * 出现 `FCC: Server response timeout (80 ms), falling back to multicast` 有两种可能 > 1. FCC 地址无效。 > 2. 你的网络配置不正确,导致无法连接到 FCC 服务器。一般来说必须通过 DHCP/IPoE/PPPoE 获得 IPTV 内网 IP 后,并启用 rtp2httpd `--upstream-interface-fcc` 或 `--upstream-interface` 选项指定 IPTV 接口后,才能访问 FCC。请结合 ping / traceroute 等工具判断。 > 4. 在一些地区,不同的组播地址需要使用不同的 FCC IP,也可能存在一些组播频道未启用 FCC 的情况。 > 5. 有些地区同一运营商内同时存在中兴、华为、烽火等多个 IPTV 平台,可能也会有不同的 FCC 地址,因此可能会出现同地区 A 网友可用,B 网友不可用,因为属于不同的 IPTV 平台。 > * 通常 8027 端口是华为平台,15970 端口是中兴/烽火平台 ## 海南 * 电信:`10.255.75.73:15970` ## 江苏 * 电信: * `180.100.72.185:15970` * `180.100.106.54:554` ## 浙江 * 电信: * `115.233.40.137:8027`(杭州) * `115.233.41.137:8027`(杭州) * `220.186.210.205:8027`(温州) * `220.186.213.242:8027`(温州) * `220.186.213.247:8027`(温州) * `220.186.213.249:8027`(温州) * `220.186.213.250:8027`(温州) * `115.233.43.70:8027`(金华) * `220.191.136.24:8027`(台州) * `115.233.42.69:8027`(绍兴) * `202.101.181.109:8027`(衢州) * `115.208.248.108:8027`(湖州) ## 上海 * 电信: * `124.75.26.151:15970` * `124.75.25.211:7777` * `124.75.25.214:7777` * `124.75.25.212:7777` * `124.75.25.215:7777` * `124.75.25.216:7777` * 联通:`10.223.3.189:8027` ## 天津 * 电信:`10.255.4.140:8027` * 移动:`10.206.255.108:8027` ## 湖南 * 电信: * `10.255.168.4:15970` * `124.232.149.47:15970` * `61.150.161.42:8027` * `222.241.55.41:8027`(常德) * `218.76.213.41:8027`(邵阳) * 移动:`100.127.255.233:15970` ## 湖北 * 电信:`121.60.255.120:15970` ## 河南 * 联通: * `10.254.185.70:15970` * `10.254.192.94:8027` * `10.254.199.130:8027`(郑州) * `10.254.223.130:8027`(驻马店) ## 河北 * 电信: * `192.168.19.28:8027` * `192.168.30.150:8027`(唐山) * `192.168.72.20:8027`(保定) * 联通: * `10.7.50.172:8027`(唐山) * `10.7.35.172:8027`(秦皇岛) * `10.7.10.172:8027`(石家庄) * `10.7.70.172:8027`(廊坊) * `10.7.60.172:8027`(沧州) * 移动:`192.168.247.9:8027`(廊坊) ## 山东 * 电信:`150.138.8.132:8027`(青岛) * 联通: * `124.132.240.66:15970` * `61.156.103.83:8027`(青岛) * `119.184.120.108:8027`(日照) * `60.210.139.78:8027`(潍坊) ## 山西 * 电信:`10.56.17.68:8027` * 联通:`10.112.7.159:8027` ## 陕西 * 电信: * `113.136.29.140:8027`(西安) * `113.136.242.134:8027`(西安) ## 广东 * 电信: * `183.59.156.166:8027`(广州) * `183.59.160.61:8027`(深圳) * `183.59.168.166:8027`(东莞) * `183.59.144.166:8027`(佛山) ## 广西 * 电信: * `180.141.207.228:8027` * `180.141.206.228:8027` * `113.15.79.82:8027` * `171.104.238.90:8027`(柳州) * `10.255.136.86:8027`(柳州) * `10.255.165.82:8027`(防城港) * `124.226.158.81:8027`(贺州、梧州) ## 四川 * 电信: * `182.139.234.40:8027`(成都) * `182.139.229.78:8027`(成都) * `220.167.81.247:8027`(成都) * `118.123.55.74:8027`(成都) * `118.119.188.42:8027`(峨眉山) * `118.119.178.42:8027`(乐山) * `182.128.24.170:8027`(广元) * `182.134.43.42:8027`(宜宾) * `182.138.3.103:15970`(遂宁、南充) * 移动:`183.223.164.65:8027` ## 重庆 * 电信: * `172.23.35.216:15970`(永川) * `172.23.2.138:8027`(大足) * 联通:`123.147.117.148:15970` * 移动:`172.16.4.155:8027` ## 贵州 * 电信: * `10.255.133.132:15970` * `10.255.5.32:8027` * 移动:`117.187.29.36:15970`(黔南) ## 安徽 * 电信:`117.71.18.200:15970` ## 辽宁 * 电信: * `10.255.128.136:8027`(沈阳) * `10.255.132.132:15970`(沈阳) * 联通:`218.24.21.133:15970` ## 吉林 * 移动:`111.26.238.155:8027` ## 甘肃 * 电信:`125.76.62.60:8027` ## 青海 * 电信: * `125.72.115.252:158` * `125.72.108.212:15970`(西宁) --- --- url: /guide/installation.md --- # 安装方式 rtp2httpd 支持多种安装方式,适应不同的使用场景。 ## OpenWrt 路由器部署 OpenWrt 是 rtp2httpd 的最佳运行环境。在中国大陆,通常需要先完成 IPTV 网络融合(可以搜索教程 `OpenWrt IPTV 融合`),通过 DHCP 获取到 IPTV 内网 IP,才能访问运营商的 IPTV 组播网络。 详见 [快速上手](./quick-start.md)。 ## 固件内置 以下固件/平台已经内置 rtp2httpd(或者可以在应用市场、官方源直接下载安装 rtp2httpd)。 > \[!IMPORTANT] > 为了保证稳定性,通常内置/上架的 rtp2httpd 版本落后于官方最新版。如果你希望追新,建议使用其他方式来安装。 * [飞牛 fnOS](https://www.fnnas.com):应用中心已上架 rtp2httpd,与飞牛桌面、统一网关、FN Connect 深度集成 * [iStoreOS](https://site.istoreos.com):iStore 已上架 rtp2httpd * [爱快 iKuai](https://www.ikuai8.com):应用市场已上架 rtp2httpd * [懒猫微服](https://lazycat.cloud):应用商店已上架 rtp2httpd * [cooluc's OpenWrt](https://github.com/sbwml/builder):已内置 rtp2httpd * [ImmortalWrt](https://github.com/immortalwrt/immortalwrt):已加入官方源 * [AutoBuildImmortalWrt](https://github.com/wukongdaily/AutoBuildImmortalWrt):[store](https://github.com/wukongdaily/store) 已内置 rtp2httpd,轻松构建 * [潘多拉 QWRT for K2P](https://www.right.com.cn/forum/forum.php?mod=viewthread\&tid=8346913\&fromuid=402348):已内置 rtp2httpd ## Homebrew 部署 在 macOS 和 Linux 上,可以通过 [Homebrew](https://brew.sh) 安装 rtp2httpd: ```bash brew install rtp2httpd ``` 安装后,编辑 `$(brew --prefix)/etc/rtp2httpd.conf` 配置文件,然后启动服务(并注册开机用户登录后自启): ```bash brew services start rtp2httpd ``` 如果需要在系统开机时自启(无需用户登录),需要使用 sudo: ```bash # 如果之前已启动用户级服务,先停止,避免重复运行 brew services stop rtp2httpd sudo brew services start rtp2httpd ``` ## 静态二进制文件部署 从 [Releases](https://github.com/stackia/rtp2httpd/releases) 页面下载对应架构的静态二进制文件 `rtp2httpd-<版本号>-<架构>`,上传到设备并 `chmod +x` 后即可运行。 默认从 `/etc/rtp2httpd.conf` 读取配置文件。可用 `--config` 或 `--noconfig` 参数覆盖。 **示例**: ```bash # 获取自己的 CPU 架构 uname -m # 下载二进制文件 wget https://github.com/stackia/rtp2httpd/releases/download/vX.Y.Z/rtp2httpd-X.Y.Z-x86_64 chmod +x rtp2httpd-X.Y.Z-x86_64 # 使用配置文件运行 ./rtp2httpd-X.Y.Z-x86_64 --config /path/to/rtp2httpd.conf # 仅使用命令行参数运行 ./rtp2httpd-X.Y.Z-x86_64 --noconfig --verbose 2 --listen 5140 --maxclients 20 ``` > \[!TIP] > 你可以使用这个示例文件 [rtp2httpd.conf](https://github.com/stackia/rtp2httpd/blob/main/rtp2httpd.conf) 作为基础来修改配置。具体说明见 [配置参数详解](../reference/configuration.md)。 对于 Debian/Ubuntu 等使用 systemd 的系统,您可以在 `/etc/systemd/system/rtp2httpd.service` 内添加以下内容以创建 systemd 服务单元。 ```text [Unit] Description=rtp2httpd - Multicast RTP/RTSP to Unicast HTTP stream converter Documentation=https://github.com/stackia/rtp2httpd After=network-online.target Wants=network-online.target StartLimitIntervalSec=60 StartLimitBurst=10 [Service] Type=simple # ExecStart 中的路径需与实际安装位置一致,可用 `command -v rtp2httpd` 或 `which rtp2httpd` 确认。 # ExecStart=/usr/local/bin/rtp2httpd --config /etc/rtp2httpd.conf ExecStart=/opt/rtp2httpd/rtp2httpd --config /opt/rtp2httpd/rtp2httpd.conf ExecReload=/bin/kill -HUP $MAINPID Restart=always RestartSec=3s # 建议以非 root 专用用户运行,可通过 `useradd --system --no-create-home --shell /usr/sbin/nologin rtp2httpd` 创建用户 User=rtp2httpd Group=rtp2httpd AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE NoNewPrivileges=true [Install] WantedBy=multi-user.target ``` 文件创建完成后使用以下指令启动 rtp2httpd 服务。 ```bash sudo systemctl daemon-reload sudo systemctl enable --now rtp2httpd sudo systemctl status rtp2httpd ``` ## Docker 容器部署 适用于支持 Docker 的设备。**需要使用 host 网络模式**以正确接收组播流。 ### 基本启动方式 ```bash docker run --network=host --cap-add=NET_ADMIN --rm \ ghcr.io/stackia/rtp2httpd:latest \ --noconfig --verbose 2 --listen 5140 --maxclients 20 ``` ### 使用 docker-compose ```yaml services: rtp2httpd: image: ghcr.io/stackia/rtp2httpd:latest network_mode: host restart: always cap_add: - NET_ADMIN command: --noconfig --verbose 2 --listen 5140 --maxclients 20 ``` > \[!NOTE] > **关于推荐参数**: > > * `cap_add: NET_ADMIN`:允许通过 `SO_RCVBUFFORCE` 绕过内核参数 `net.core.rmem_max` 限制,设置更大的 UDP 接收缓冲区 ### 挂载配置文件 如果需要使用配置文件(假设配置文件位于 `/path/to/rtp2httpd.conf`): ```bash docker run --network=host --cap-add=NET_ADMIN --rm \ -v /path/to/rtp2httpd.conf:/usr/local/etc/rtp2httpd.conf:ro \ ghcr.io/stackia/rtp2httpd:latest ``` > \[!TIP] > 你可以使用这个示例文件 [rtp2httpd.conf](https://github.com/stackia/rtp2httpd/blob/main/rtp2httpd.conf) 作为基础来修改配置。具体说明见 [配置参数详解](../reference/configuration.md)。 ## OpenWrt 编译安装 如果你希望通过 OpenWrt 源码构建直接把 rtp2httpd 编译到固件里,可以把本仓库直接加入 `feeds.conf.default`: ```text # 使用 main 分支最新代码 src-git rtp2httpd https://github.com/stackia/rtp2httpd.git ``` 或者指定版本号: ```text # 使用 v3.10.1 版本代码 src-git rtp2httpd https://github.com/stackia/rtp2httpd.git;v3.10.1 ``` 运行 `./scripts/feeds update rtp2httpd` 和 `./scripts/feeds install rtp2httpd` 更新 feed。 运行 `make menuconfig`,找到 `LuCI -> Applications -> luci-app-rtp2httpd`,将其勾选为 `*` (编译到固件) 或 `M` (编译成 ipk/apk 包),保存退出。 运行 `make package/feeds/rtp2httpd/luci-app-rtp2httpd/compile -j1 V=sc` 可单独编译 `luci-app-rtp2httpd` 和 `rtp2httpd` 两个包。 ### 固件维护者集成指南 如果你维护第三方 OpenWrt 固件,希望直接将 rtp2httpd 集成到你的 feeds 仓库中(而非通过 `src-git` 引用),可以使用本项目提供的 `Makefile.versioned`: ```bash git clone https://github.com/stackia/rtp2httpd.git cd rtp2httpd # 用预生成的 Makefile 替换原始 Makefile(已包含固定版本号、源码下载地址和 PKG_HASH) mv openwrt-support/rtp2httpd/Makefile.versioned openwrt-support/rtp2httpd/Makefile mv openwrt-support/luci-app-rtp2httpd/Makefile.versioned openwrt-support/luci-app-rtp2httpd/Makefile # 将 openwrt-support 目录内容复制到你的 feeds 仓库 cp -r openwrt-support/* /path/to/your/feeds/ ``` `Makefile.versioned` 与原始 `Makefile` 的区别在于:版本号已固定、`PKG_HASH` 已填充、构建时会从 GitHub Release 下载源码包,无需本地 git 仓库。每次 rtp2httpd 发布新版本时,main 分支 `Makefile.versioned` 都会自动更新。 ## 传统编译安装 适用于需要自定义编译或开发调试的场景。 ### 安装依赖 ```bash # Ubuntu/Debian sudo apt-get install build-essential cmake pkg-config curl # 安装 Node.js LTS(用于构建 Web UI) curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash - sudo apt-get install -y nodejs corepack enable ``` ### 编译步骤 ```bash # 克隆仓库 git clone https://github.com/stackia/rtp2httpd.git cd rtp2httpd # 构建 Web UI 并嵌入静态资源 pnpm install --frozen-lockfile pnpm run web-ui:build # 配置和编译 cmake -B build -DCMAKE_BUILD_TYPE=Release -DENABLE_AGGRESSIVE_OPT=ON cmake --build build -j$(getconf _NPROCESSORS_ONLN) # 安装 sudo cmake --install build ``` ## 下一步 * [快速上手](./quick-start.md):OpenWrt 快速配置指南 * [配置参数详解](../reference/configuration.md):了解所有配置选项 * [URL 格式说明](./url-formats.md):了解所有支持的 URL 格式 * [M3U 播放列表集成](./m3u-integration.md):配置播放列表 * [FCC 快速换台配置](./fcc-setup.md):启用毫秒级换台功能 --- --- url: /guide/quick-start.md --- # 快速上手 ## OpenWrt 一键安装/更新(推荐) 运行以下命令,自动下载并安装最新版本: ```bash uclient-fetch -q -O - https://raw.githubusercontent.com/stackia/rtp2httpd/main/scripts/install-openwrt.sh | sh ``` 脚本会自动: * 检测设备的 CPU 架构 * 从 GitHub Release 获取最新版本 * 下载并安装所有必需的软件包(主程序 + LuCI 界面 + 语言包) * 如果此前已经安装过,运行此脚本,将会卸载旧版,重新安装最新版 > \[!TIP] > 如果无法使用一键脚本,可以手动在 [Releases](https://github.com/stackia/rtp2httpd/releases) 页面下载对应架构的软件包: > > * `rtp2httpd_<版本号>_<架构>.ipk` - 主程序包 > * `luci-app-rtp2httpd_<版本号>_all.ipk` - LuCI Web 界面 > * `luci-i18n-rtp2httpd-zh-cn_<版本号>_all.ipk` - 中文语言包 > > ```bash > # 如果不知道自己的架构,可以用这条命令获取架构 > cat /etc/openwrt_release | grep ARCH > > # 手动将 ipk 上传至设备并安装 > opkg install rtp2httpd_*.ipk luci-app-rtp2httpd_*.ipk luci-i18n-rtp2httpd-*.ipk > ``` ## 基本配置 安装完成后,在 LuCI 管理界面的 "服务" 菜单中找到 "rtp2httpd" 进行配置: ![LuCI 配置界面](../images/luci-config.png) > \[!WARNING] > 每次更新版本后如果 LuCI 出现工作异常,需要 **Ctrl+F5 刷新** 或 **清空浏览器缓存** 或 **使用无痕模式访问** 解决。 > \[!IMPORTANT] > 如果安装后,LuCI 未出现 rtp2httpd 入口,说明你的 LuCI 版本过低,无法支持 JS-based LuCI 插件。请考虑更新固件,或者手动编辑和维护 `/etc/config/rtp2httpd`(需要将 disabled 设为 0),使用 `/etc/init.d/rtp2httpd restart` 重启服务。 > > 有一些热心网友开发了 Lua 版本 luci-app-rtp2httpd,在这种情况下可以尝试使用(非 rtp2httpd 官方维护) > > * > * ### 必需配置项 1. **基本设置 - 启用**:勾选启用 rtp2httpd 2. **基本设置 - 端口**:默认 5140,也可以自定义 3. **网络与性能 - 上游接口**:设置为 IPTV 网络接口 ### 可选配置项 * **播放器与 M3U - 外部 M3U**:如有现成的 M3U 播放列表,填入此设置项后后即可使用 [内置 Web 播放器](./web-player.md)([M3U 播放列表集成](./m3u-integration.md)) * **FCC 服务器**:如需快速换台,需要在节目 URL 带上 FCC 服务器地址([FCC 快速换台配置](./fcc-setup.md)) ## 测试访问 配置完成后,可以通过以下 URL 测试访问: ```bash # 访问 RTP 组播流 http://路由器IP:5140/rtp/239.253.64.120:5140 # 访问状态页面 http://路由器IP:5140/status # 获取 M3U 播放列表(如已配置) http://路由器IP:5140/playlist.m3u ``` ## 使用内置播放器 如果已配置 M3U 播放列表,可直接在浏览器中访问 `http://路由器IP:5140/player` 打开 [内置 Web 播放器](./web-player.md)。 ## 在其他播放器中使用 将 `http://路由器IP:5140/playlist.m3u` 添加到支持 IPTV 的播放器中即可观看。 ## 查看日志 有三种方式可以查看运行日志: 1. 访问状态页面 `/status`,页面底部查看日志 2. 在 OpenWrt 后台,"状态" -> "系统日志" 查看日志 3. SSH 连接路由器后运行 `logread -e rtp2httpd` ## 下一步 * [内置 Web 播放器](./web-player.md):播放器功能、兼容性说明 * [安装方式](./installation.md):了解其他安装方式(Docker、静态二进制、编译安装) * [M3U 播放列表集成](./m3u-integration.md):配置播放列表自动识别和转换 * [URL 格式说明](./url-formats.md):了解所有支持的 URL 格式 * [配置参数详解](../reference/configuration.md):深入了解所有配置选项 * [FCC 快速换台配置](./fcc-setup.md):启用毫秒级换台功能 --- --- url: /reference/benchmark.md --- # 性能测试报告 比较 **rtp2httpd**、**[msd\_lite](https://github.com/rozhuk-im/msd_lite)**、**[udpxy](https://github.com/pcherenkov/udpxy)** 和 **[TVGate](https://github.com/qist/tvgate)** 在多频道、同频道多客户端及高码率负载下的 CPU 和内存占用。 ## 测试环境与版本 * 测试日期:2026-09-06。 * 主机:Apple M3 Max;Parallels Ubuntu 24.04 虚拟机,16 vCPU、16 GiB 内存。 * 系统:Linux 6.8.0-138-generic,aarch64;所有程序均为原生 ARM64 执行。 * 编译器:GCC 13.3.0。rtp2httpd 使用 Release 与 `ENABLE_AGGRESSIVE_OPT=ON`;msd\_lite 使用 `-O3`、LTO 及相同的内联、循环展开、向量化优化选项;udpxy 使用 `-O3 -flto`。TVGate 使用官方发布的二进制文件。 * 组播输入及 HTTP 输出均经过 `lo`,不修改内核网络参数。`net.core.rmem_max` 和 `net.core.wmem_max` 均为 212992,TCP 拥塞控制为 cubic。 | 程序 | 测试版本 | | --- | --- | | rtp2httpd | [v3.17.0-beta.1](https://github.com/stackia/rtp2httpd/releases/tag/v3.17.0-beta.1) | | msd\_lite | [`fa68e131`](https://github.com/rozhuk-im/msd_lite/commit/fa68e131343fb58c67ad77b2d26f2cb7c49a2c95),2026-07-20;liblcb `e2f420a2` | | udpxy | [`31d4bcfa`](https://github.com/pcherenkov/udpxy/commit/31d4bcfabaade59d3efdee015df7979febf76bae),2026-04-13 | | TVGate | [v3.2.0](https://github.com/qist/tvgate/releases/tag/v3.2.0),2026-09-06 | ## 测量方法 rtp2httpd 设置 `-C -w 1`,msd\_lite 配置一个事件循环线程,udpxy 保留每个客户端一个子进程的原生模型;这三个程序的全部进程及线程固定在一个 vCPU。TVGate 不设置 `GOMAXPROCS`,不额外限制 CPU 亲和性,使用虚拟机全部 16 个 vCPU 上的默认多核调度。调度方式不同,结果反映各自配置在指定输入负载下的服务 CPU 成本。 CPU 使用率取完整测量窗口内 `/proc/PID/stat` 的用户态与内核态时间增量,除以实际墙钟时间,再对整个服务进程树求和。**100% 表示占满一个 vCPU**,多核程序可以超过 100%。负载发送器、接收器和测量控制进程固定在其他 vCPU,其 CPU 另行记录,不计入服务 CPU;TVGate 的默认调度可使用这些 vCPU。 PSS 和 USS 从 `smaps_rollup` 每秒采样并对进程树求和。PSS 按比例计入共享页,USS 仅统计私有页,均不包含全部内核 socket 内存或未映射的匿名文件页缓存,因此不能作为服务总内存成本。 每个 RTP 数据报携带 7 个 188 字节 MPEG-TS 空包,共 1316 字节负载。接收端解析 HTTP 分块编码后持续读取流。每轮重启服务与负载进程,所有客户端开始收到数据后再预热,测试逐项串行执行,每轮轮换程序顺序,四轮中每个程序在各个执行位置各出现一次。 msd\_lite 保留上游示例的 48 KiB 接收水位、64 KiB 发送水位、1 MiB 环形缓冲;仅适配监听地址、接口、线程数、日志和拥塞控制。udpxy 保留默认缓冲设置。TVGate 仅配置监听端口及 loopback 组播接口,并发、缓冲、连接上限及日志均使用程序默认值。 ## 测试场景 | 场景 | 客户端数 | 组播源数 | 单源负载码率 | 重复次数 | 每轮预热 / 采样 | | --- | ---: | ---: | ---: | ---: | --- | | 多频道 | 8 | 8 | 40 Mbps | 4 | 5 s / 15 s | | 同频道 8 客户端 | 8 | 1 | 40 Mbps | 4 | 5 s / 15 s | | 同频道 64 客户端 | 64 | 1 | 20 Mbps | 4 | 5 s / 15 s | | 高码率 | 1 | 1 | 400 Mbps | 4 | 5 s / 15 s | ## 测试结果 以下 CPU 和内存统计包含每个场景全部完成采样的轮次,衡量指定负载下的资源占用,不用于认证转发正确性或最大可持续吞吐量。 ### CPU 使用率 数值为逐轮平均 CPU 的均值。 | 场景 | rtp2httpd | msd\_lite | udpxy | TVGate | | --- | ---: | ---: | ---: | ---: | | 8 频道,各 40 Mbps | 🏆 3.69% | 12.28% | 23.02% | 56.65% | | 8 客户端同频道,40 Mbps | 🏆 4.87% | 5.58% | 30.92% | 45.09% | | 64 客户端同频道,20 Mbps | 🏆 4.78% | 5.50% | 59.93% | 115.08% | | 单客户端,400 Mbps | 🏆 12.88% | 15.46% | 26.45% | 57.86% | ### PSS 内存占用(MiB) | 场景 | rtp2httpd | msd\_lite | udpxy | TVGate | | --- | ---: | ---: | ---: | ---: | | 8 频道,各 40 Mbps | 1.86 | 8.95 | 🏆 0.79 | 25.82 | | 8 客户端同频道,40 Mbps | 1.13 | 1.35 | 🏆 0.79 | 22.76 | | 64 客户端同频道,20 Mbps | 🏆 1.30 | 1.37 | 4.55 | 46.26 | | 单客户端,400 Mbps | 1.26 | 1.34 | 🏆 0.32 | 19.16 | ### USS 内存占用(MiB) | 场景 | rtp2httpd | msd\_lite | udpxy | TVGate | | --- | ---: | ---: | ---: | ---: | | 8 频道,各 40 Mbps | 1.24 | 8.94 | 🏆 0.52 | 25.82 | | 8 客户端同频道,40 Mbps | 🏆 0.51 | 1.34 | 0.52 | 22.76 | | 64 客户端同频道,20 Mbps | 🏆 0.68 | 1.35 | 3.96 | 46.26 | | 单客户端,400 Mbps | 0.63 | 1.33 | 🏆 0.12 | 19.16 | ## 附:rtp2httpd 的性能优化策略 ### 按生命周期分配内存 连接只为实际使用的协议分配 RTSP 或 HTTP 代理状态,FEC 分组表在需要保存恢复分组时才分配。HTTP 输入缓冲和已解析请求使用独立的匿名内存映射:输入缓冲在解析和路由完成后释放,普通媒体流的请求数据在响应头生成后释放。HTTP 代理保留其仍在使用的请求头和请求体。临时请求页可直接交还操作系统,避免长期连接将这些已空闲的页留在堆中。 普通共享组播客户端使用源级重排窗口,不再各自分配闲置的重排数组。RTSP、FCC、截图或 FEC 独立处理路径才分配客户端窗口;流中途启用 FEC 时,已有客户端和后续加入的客户端都会取得各自的窗口。 包缓冲池初始分配 128 个缓冲,按 128 个扩展;控制缓冲池初始分配 16 个,按 16 个扩展。worker 定时回收完全空闲的分段,保留必要的基础容量。客户端队列的逻辑预算与初始预分配量分开计算,减少初始内存不改变原有的缓冲余量。 ### 每个 worker 共享组播订阅 每个 worker 维护一张共享源表,按照解析后的组播地址、端口、SSM 源地址、有效上游接口及 FEC 端口匹配。频道名称、`/rtp/` 与 `/udp/` 的路径写法、FCC 服务器参数不参与匹配。相同资源只建立一份主组播 socket,以及按需建立的一份 FEC socket。 订阅源拥有独立的生命周期、超时和重加组定时状态。每个客户端持有订阅引用,最后一个引用释放时关闭 socket 并销毁源状态。最早接入的客户端离开时,事件分发会转交给仍存活的订阅者。各 worker 仍独立管理自己的源表。 这主要减少本机重复 socket 接收、系统调用和应用层处理。多个本机 socket 加入同一个组播组,并不等于上游链路一定传输了相同数量的完整数据流。 ### 共享解析、重排和批次数据 普通组播由共享源统一进行 RTP 解析及重排,然后将有效负载合并到容量为 64 KiB 的批次中。每个 RTP 负载保持完整,在下一个负载会超出容量时先发送当前批次;1316 字节负载对应每批 49 个包、64484 字节。这样既减少每客户端重复解析,也减少逐包分发和发送调用。未满的批次在满 100 ms 后的下一次 worker 定时检查中发送;检查周期为 100 ms,实际延迟还受调度影响。 Buffer 层在原有 1536 字节包缓冲池和控制缓冲池之外,增加按需分配的 64 KiB 批次池。批次池归 worker 所有,已排队的数据可在组播源销毁后继续存活。默认初始分配 4 个批次,按 4 个扩展,最大容量按 `buffer-pool-max-size × 1536` 字节预算换算,并至少容纳 4 个批次。这是批次池自身的上限,与原有包池分别计量。批次池耗尽时,仍可通过小包引用继续分发。 多个客户端共享底层 payload,各自拥有独立的 `buffer_ref_t` 视图。视图通过 `owner` 指向同一份不可修改的数据,并保留自己的链表指针、发送偏移和剩余长度。客户端的部分发送只修改自己的视图;最后一个视图释放后,底层内存才返回池中。每个客户端仍有自己的发送队列和容量限制,慢客户端不会暂停其他订阅者的接收。只有一个订阅者时,直接使用批次自身的描述符,省去额外视图分配。 队列限额改为按底层缓冲容量计费,不能再使用「缓冲数量 × 1536」。一个只剩少量字节未发送的批次,仍占用完整 64 KiB 容量,直到该客户端释放引用。这避免共享大缓冲绕过原有慢客户端内存限制。 ### 减少收发路径的固定开销 支持 `recvmmsg` 的平台一次接收最多 16 个数据报,worker 复用接收描述符和未消耗的包缓冲。处理完且没有其他引用的包缓冲直接用于下一次接收;重排、FEC 或发送队列仍持有引用时,使用另一个缓冲,避免覆盖待处理数据。数据直接进入缓冲池,不增加一次接收后的复制;不支持批量接收时使用逐包接收。对于已完成起始重排、序号连续且窗口为空的 RTP 流,未启用 FEC 时直接交付负载,省去重排槽位的插入和移除。 主组播 socket 首次就绪时立即读取;后续按实际接收缓冲容量和每次收到的数据报数量,合并最多 1–2 ms 内的接收工作,减少持续小包带来的事件唤醒。系统报告的接收缓冲至少为 128 KiB 时才允许等待 1 ms,至少为 256 KiB 且包量较小时才允许 2 ms;实际间隔还受系统调度影响。延后读取期间暂停该 socket 的就绪通知,读空后重新启用。worker 只遍历仍有待处理接收任务的源,最后一个订阅者离开时同时移除其待处理任务。 接收缓冲较小或无法查询容量时使用水平触发通知。单次读取达到按缓冲容量计算的保守包量阈值时,也恢复即时读取,并按至少 100 ms 的窗口重新估计包速率;速率降低且留有两倍调度余量时再尝试合并,避免一次突发永久关闭优化。水平触发下读到不足一批即可返回,剩余数据仍会通知;延后读取路径则必须确认读空,避免中断造成的短读留下未处理数据。每次回调最多接收 256 个主组播数据报,使持续到来的数据不会长期占用事件循环。这些策略自动选择,无需额外配置。 发送任务先进入 worker 内部队列,只有 socket 暂时无法继续写入时才订阅内核可写事件,减少每个批次的事件监听切换。每个连接单次最多发送 256 KiB,每轮最多处理 128 个发送任务,剩余任务继续排队,使接收、定时器和其他客户端都能得到处理。 状态统计的客户端归属校验使用进程内缓存的 PID,并在每次 fork 后刷新,省去队列更新和发送统计中重复的 `getpid()` 调用。 队列限额、计数和高水位仍在每次队列操作时更新,向共享状态区发布则集中到 worker 的 100 ms 定时检查中。这样可减少每批数据入队、发送时重复执行的共享内存写入和同步操作;状态页显示最近一次发布的队列快照。 ### 不可修改的批次快照 支持内存文件封存的平台会通过 `memfd_create` 为共享批次建立匿名内存文件,写入一次后封存,再由多个客户端通过 `sendfile` 发送同一份内核数据页。只在多个客户端共享接近满容量的批次时采用该路径;普通内存发送仍通过 `sendmsg` 完成。 每批创建新的文件,发布后禁止写入、增长和截断,不会在缓冲池复用时覆盖旧文件。即使 `sendfile` 已返回、应用已关闭最后一个文件引用,TCP 仍可能持有旧数据页;文件不可变保证这些待发送内容不会被新一批数据改写。创建、写入或封存失败时保留内存发送;客户端的 `sendfile` 不受支持时,只将该客户端的视图回退到内存发送。 ### FCC、FEC 与客户端隔离 FCC 单播和切换状态按客户端独立维护。衔接时先共享组播 socket;等单播和待处理数据完成、重排序号与共享源对齐,再加入共享批次分发。切换前先发送旧批次,避免新订阅者重放之前的内容。 截图处理仍保留独立状态。配置 FEC 端口的源使用共享 socket、每客户端独立的重排及 FEC 恢复路径;运行中首次发现带内 FEC 时,会先发送现有批次,并把共享重排窗口交接给各客户端,再转入独立处理。因而本报告普通组播的 CPU 结果不能直接代表 FCC 补流阶段、FEC 恢复或截图负载。 ## 适用范围 这是 ARM64 Linux 虚拟机内的固定码率转发资源测量,不是物理网卡吞吐上限、视频解码性能或最大可承载客户端数量测试。loopback 内核工作中记在发送器及读流进程上的部分不属于服务 CPU,主机调度也会引入波动。其他硬件、码率、客户端速度、并发频道数量及网络路径应单独测量。 ## 复现测试 脚本及参数见 [tools/stress-test/README.md](https://github.com/stackia/rtp2httpd/blob/main/tools/stress-test/README.md)。准备对应版本的二进制文件后,运行四种场景: ```bash scripts/benchmark.sh rtp2httpd msd_lite udpxy tvgate \ --cases distinct8 shared8 shared64 high400 \ --repetitions 4 --warmup 5 --duration 15 ``` 通过 `--binary 名称=路径` 与 `--revision 名称=版本` 指定实际使用的二进制及版本,按上表设置各场景的重复次数和采样时长。CPU、PSS、USS 汇总位于输出目录中的 `resources.json`。输出目录默认位于 `build/benchmark/`,测试记录仅在本地保留。 --- --- url: /guide/time-processing.md --- # 时间处理说明 本文档说明 rtp2httpd 如何处理「时移回看」(catchup)请求里的时间和时区。RTSP 和 HTTP 代理都适用,但 **Range Seek 模式** 是 RTSP 专属的。 ## 时移回看的两种模式 IPTV 上游服务器通常支持「时移回看」——回放过去时段的直播内容。客户端通过在 URL 中加上时间范围参数(最常见的是 `playseek`、`tvdr`)告诉服务器要看哪一段: ``` http://192.168.1.1:5140/rtsp/iptv.example.com:554/channel1?playseek=20240101120000-20240101130000 ``` rtp2httpd 在向上游转发时支持两种处理方式: ### 模式 1:Playseek 透传(默认) 把客户端的 seek 参数原样作为 URL 查询转发给上游服务器(必要时按时区做格式调整)。 **适用范围**:HTTP 代理 + RTSP 代理,所有支持时移的运营商都能用。 **局限**:上游会按客户端给的「结束时间」播完后关闭流。如果想把后续的实时直播无缝拼上,客户端必须**再发起一次新请求**——中间会有几百毫秒到几秒的间断,可能造成播放卡顿或音视频不同步。 ### 模式 2:RTSP Range Seek(可选,需显式启用) 利用 RTSP 协议自带的 `Range: clock=...` 头让上游从指定时间开始播放,**并在追到当前时间时自动无缝拼到实时直播流**——全程一次连接、无需重连。 启用方式:在 URL 里加 `r2h-seek-mode=range(...)`: ``` http://192.168.1.1:5140/rtsp/iptv.example.com:554/channel1?playseek=20240101120000&r2h-seek-mode=range(UTC%2B8) ``` **优势**:从时移段过渡到直播实时段是一次连续播放,无间断。 **限制**: 1. **不是所有 RTSP 服务器都支持**——这是默认关闭、需要显式启用的根本原因。一旦命中 Range Seek 路径,rtp2httpd 会无条件向上游发送 `Range: clock=...` 头;上游如果不识别,请求会失败而不是自动回退 2. **rtp2httpd 自身有客户端窗口**(默认 1 小时,可通过 `r2h-seek-mode=range(/<秒>)` 调整):仅当起始时间落在窗口内才走 Range Seek,否则按 Playseek 透传处理。把窗口配置得不超过上游服务器实际支持的范围(通常 1–3 小时,因运营商而异),可避免命中上游不支持的过老回看请求 > \[!TIP] > 在 rtp2httpd 客户端窗口外,行为与从未启用 Range Seek **完全一致**(按 Playseek 透传)。窗口内则会发起带 `Range: clock=` 头的 RTSP 请求——只有在确认上游支持 RTSP `Range` 头时才建议启用,并把窗口设置得不超过上游实际支持的回看长度。 > \[!NOTE] > Range Seek 模式只看 seek 的**起始时间**——结束时间被忽略,由实时拼接接管。 ## Seek 参数 ### r2h-seek-name(可选) 指定时移参数的名称。不指定时按以下顺序自动识别:`playseek` → `tvdr`(不区分大小写)。 如果上游使用别的参数名(如 `seek`、`timeshift`),显式指定: ``` ?custom_seek=20240101120000-20240101130000&r2h-seek-name=custom_seek ``` ### r2h-seek-offset(可选) 对识别出的时移时间额外加 / 减若干秒,可正可负。传单个整数时同时作用于起始和结束时间;传 `a,b` 时分别作用于起始时间和结束时间。常用于补偿上游服务器的时钟偏差,或让起播/结束边界分别提前、延后。 ``` # playseek 范围整体后移 1 小时(3600 秒) ?playseek=20240101120000-20240101130000&r2h-seek-offset=3600 # 起始时间后移 12 秒,结束时间提前 12 秒 ?playseek=20240101120000-20240101130000&r2h-seek-offset=12,-12 # 提前 30 秒 ?playseek=20240101120000&r2h-seek-offset=-30 ``` > \[!IMPORTANT] > `r2h-seek-offset` 是「人为时间平移」,不是时区修正。它**总是**叠加到最终结果上,即使输入时间已经自带时区(如 ISO 8601 `Z` 后缀、`yyyyMMddHHmmssGMT`),仍然生效。 > > 在 Range Seek 模式下,offset 也会进入窗口判定——offset 后的起始时间一旦落出窗口,同样回退为透传。使用 `a,b` 形式时,Range Seek 只使用起始时间,因此只有 `a` 会影响窗口判定和 `Range: clock=` 头。 ### r2h-seek-mode(可选,仅 RTSP) 控制是否启用「Range Seek 模式」(参见上方[两种模式说明](#时移回看的两种模式))。 | 取值 | 行为 | | ---------------------------------------------- | ------------------------------------------------------------- | | 不传 / `passthrough` | 默认。使用 Playseek 透传 | | `range` / `range()` | 启用 Range Seek,时区从 UA `TZ/` 推导(无则 UTC),窗口默认 1 小时 | | `range(UTC+8)` / `range(UTC-5)` / `range(UTC)` | 显式指定时区,窗口默认 1 小时 | | `range(7200)` | 自动推导时区,窗口 7200 秒 | | `range(UTC+8/7200)` | 同时显式指定时区与窗口 | | `range(/7200)` | 自动推导时区 + 显式窗口 | 窗口取值范围 1–86400 秒。无法识别的值会按 `passthrough` 处理(不会让请求失败)。 > \[!IMPORTANT] > `range()` 里指定的时区**只在 Range Seek 模式中生效**——用来判断时间是否在窗口内、以及生成 `Range: clock=` 头里的 UTC 时间。一旦回退到 Playseek 透传,行为与不传 `r2h-seek-mode` 时**字节级完全相同**,`range()` 不会去改写透传字符串。 ### r2h-start(可选,仅 RTSP) 从指定的 NPT 时间点(秒)开始播放,常用于续播: ``` ?r2h-start=123.45 ``` 在 RTSP `PLAY` 请求中以 `Range: npt=<时间>-` 头发送给上游。如果同一请求又带了 `r2h-seek-mode=range(...)` 且命中 Range Seek 模式,`r2h-start` 会被忽略,由 seek 起始时间生成 `Range: clock=` 头。 ## 支持的时间格式 rtp2httpd 能识别下面的时间格式。**输出格式始终与输入保持一致**(保留 `Z`、`±HH:MM`、`GMT` 等后缀)。 | 格式 | 示例 | 是否自带时区 | | ----------------------------------- | ----------------------------- | ---------------- | | Unix 时间戳(≤10 位数字) | `1704096000` | 是(UTC) | | 14 位 `yyyyMMddHHmmss` | `20240101120000` | 否 | | 14 位 + `GMT` 后缀 | `20240101120000GMT` | 是(UTC) | | 紧凑 ISO 8601 | `20240101T120000` | 否 | | 紧凑 ISO 8601 + `Z` | `20240101T120000Z` | 是(UTC) | | 紧凑 ISO 8601 + `±HH:MM` | `20240101T200000+08:00` | 是 | | 完整 ISO 8601 | `2024-01-01T12:00:00` | 否 | | 完整 ISO 8601 + `Z` / `±HH:MM` | `2024-01-01T12:00:00Z` | 是 | | 完整 ISO 8601 + 毫秒 | `2024-01-01T12:00:00.123Z` | 视后缀而定 | 「自带时区」的格式 rtp2httpd 不会再去推导时区——任何外部时区配置(UA `TZ/...`、`r2h-seek-mode=range()`)都被忽略,但 `r2h-seek-offset` 仍然会叠加。「不自带时区」的格式按下文「时区推导」处理。 > \[!NOTE] > `yyyyMMddHHmmssGMT` 的 `GMT` 后缀语义与 ISO 8601 的 `Z` 等价——都视为「自带 UTC 时区」。 ## 时区推导 仅适用于「不自带时区」的格式(14 位 `yyyyMMddHHmmss`、不带 `Z`/`±HH:MM` 的 ISO 8601)。 ### 默认(Playseek 透传) rtp2httpd 从 User-Agent 头里查找 `TZ/` 标记获取客户端时区: ``` TZ/UTC → UTC TZ/UTC+8 → 东八区 TZ/UTC-5 → 西五区 ``` UA 里没有 `TZ/` 标记时,按 UTC 处理(不做时区转换)。 ### Range Seek 模式 启用 `r2h-seek-mode=range(...)` 时,**仅 Range Seek 路径**按下面的优先级取时区: 1. `range(UTC+N)` 显式声明 2. UA `TZ/UTC+N` 3. UTC 回退到 Playseek 透传时,时区推导回到上面「默认」一节的规则——`range()` 里的时区不参与。 ## 相关文档 * [URL 格式说明](./url-formats.md):RTSP / HTTP 代理 URL 格式说明 * [配置参数详解](../reference/configuration.md):服务器配置选项 --- --- url: /reference/related-resources.md --- # 相关教程和软件 本页汇总了社区提供的 IPTV 搭建教程、配套工具和播放器软件,方便用户快速找到所需资源。 > \[!NOTE] > 以下资源均由社区用户贡献和维护,不属于 rtp2httpd 项目本身。如有问题请联系对应项目的维护者。 ## IPTV 搭建教程 如果是首次搭建 IPTV 组播转发服务,对相关网络知识比较陌生(DHCP 鉴权、路由、组播、防火墙),可以参考以下教程: * [浙江杭州电信 IPTV 内网融合教程:在局域网任意设备观看 IPTV](https://baiyun.me/zhejiang-hangzhou-telecom-iptv) * [自动抓取IPTV单播地址,实现时移回看](https://www.bandwh.com/net/2571.html) * [K2P 利用 rtp2httpd 刷 openwrt 单线复用双网融合完美解决看 IPTV 超简单详细](https://www.right.com.cn/forum/forum.php?mod=viewthread\&tid=8457970\&fromuid=402348) * [重庆电信 IPTV 内网融合 抓包 rtp2httpd](https://www.right.com.cn/forum/forum.php?mod=viewthread\&tid=8457356\&fromuid=402348) * [浙江 电信 IPTV 组播 转单播 rtp2httpd 去花屏](https://www.right.com.cn/forum/forum.php?mod=viewthread\&tid=8452510\&fromuid=402348) * [使用 Rtp2httpd 酷 9 浙江 电信 IPTV 单播 回看](https://www.right.com.cn/forum/forum.php?mod=viewthread\&tid=8453715\&fromuid=402348) * [上海电信 猫棒/光猫桥接 OpenWrt下实现 Internet+IPTV盒子+udpxy/rtp2httpd+VoIP](https://www.right.com.cn/forum/forum.php?mod=viewthread\&tid=8268077\&fromuid=402348) * [上海电信 SDN光猫桥接 华硕路由器 单线复用 梅林固件 rtp2httpd 开启FCC 功能](https://www.right.com.cn/forum/forum.php?mod=viewthread\&tid=8467200\&fromuid=402348) * [爱快主路由+rtp2httpd(运行在内网设备)开启FCC](https://www.right.com.cn/forum/forum.php?mod=viewthread\&tid=8469614\&fromuid=402348) * [成都 电信IPTV 组播转换单播 openwrt/immortalwrt rtp2httpd](https://www.right.com.cn/forum/forum.php?mod=viewthread\&tid=8468805\&fromuid=402348) * [RouterOS 容器安装 rtp2httpd 看 IPTV](https://www.right.com.cn/forum/forum.php?mod=viewthread\&tid=8470410\&fromuid=402348) * [湖南电信 OpenWrt 拨号 IPTV 全流程教程 | 内网融合组播转单播 + 单播回看全搞定](https://mp.weixin.qq.com/s/_hEVbrgHll_qIePXGtATTw) * [世界杯最强 IPTV 方案:rtp2httpd + VLAN 单线复用 + 全设备可看](https://mp.weixin.qq.com/s/zwPMAkIaHhQ2R6FsuVl0ZQ) * [折腾 IPTV 时一定会遇到的几个概念:IGMP Snooping、IGMP Proxy、泛洪,到底是啥?](https://mp.weixin.qq.com/s/oKS-tl1-hqgcZ_H01CTtXQ) * [IPTV 里的 FCC 和 FEC 到底是什么?为什么有些源“高级得多”?](https://mp.weixin.qq.com/s/5l2Cg204YdqtWAV-RnqiYw) * [IPTV 折腾到最后一步:播放列表的几种写法,一篇讲清](https://mp.weixin.qq.com/s/wZpO74_NJvlwBbI9uvEhWw) * [手把手教你搞定浙江电信IPTV融合:安安稳稳看电视](https://zeaurx.com/archives/iptv) ### 视频教程 * [旁路由 IPTV 插件使用篇](https://www.bilibili.com/video/BV1ioiKBNE8t/) * [组播转单播系列第二期:借助 rtp2httpd 插件实现全家设备观看 iptv](https://www.bilibili.com/video/BV1Zhr4B3ELy/) ## 相关软件 ### IPTV 播放器 #### 电视直播TV mytv-android * 项目地址: * 配合 rtp2httpd 使用教程: Android 平台 IPTV 播放器,支持 M3U 播放列表、FCC 快速换台、EPG 电子节目单、时移回看、rtp2httpd [视频快照](../guide/video-snapshot.md) 等功能。 #### LiteTV * 项目地址: 面向 Android TV / Google TV 的极简 IPTV 直播播放器,针对遥控器操作深度优化,交互接近机顶盒原版习惯。支持 M3U / TXT 播放列表、EPG 电子节目单、频道分组与收藏,可通过网页远程配置直播源和 EPG。换台复用播放器实例,起播与切换速度接近 rtp2httpd 内置 Web 播放器。 #### APTV * 项目地址: 苹果生态里体验很突出的 IPTV M3U 播放器,覆盖 iPhone、iPad、Mac、Apple Vision、Apple TV、Apple Watch 等设备。支持 M3U 播放列表、EPG 电子节目单、iCloud 配置同步、实时预览、回看、多源配置、4K/HDR/HLG、画中画、AirPlay/DLNA 投屏等功能,并支持组播 FCC 快速换台优化。 #### 源匣 SrcBox * 项目地址: Windows 平台 IPTV 播放器,基于 libmpv 播放内核和 WPF 原生界面。支持 M3U 播放列表、FCC 快速切台、EPG 电子节目单、时移回看、UDP 组播优化、rtp2httpd [视频快照](../guide/video-snapshot.md) 等功能。 #### IPTV 影视 iptvys * 项目地址: 基于蜂蜜影视(TVBox)的定制影视播放器,支持通过 rtp2httpd 代理 RTSP 源。开启 RTSP 代理并配置 rtp2httpd 地址后,可播放 rtp2httpd 代理的 RTSP 点播节目,并支持获取节目时长、进度条拖动、快进快退等功能。 ### IPTV 订阅和频道工具 #### 频道哨兵 Channel Sentinel * 项目地址: 基于 Docker 的 IPTV 单播/组播批量扫描检测工具。主要功能: * 批量导入组播流地址,自动检测在线状态、分辨率、编码、帧率等信息 * 支持按在线/离线筛选,按频道名或地址搜索 * 导出为 TXT 或 M3U 格式(M3U 支持 FCC 参数、catchup 回看地址) * 同名频道按质量优先排序(组播 4K > HD > SD > 单播) * 版本管理,支持保存和加载检测结果 #### IPTV 工具箱 iptv-tool * 项目地址: 基于 Docker 部署的 IPTV 综合管理工具箱,集 EPG 节目单管理、直播源管理、台标管理于一体。主要功能: * 支持 DIYP/百川、超级直播、xmltv 等多种格式 * 直播源聚合(TXT/M3U)、测速校验、直播源代理 * 台标模糊匹配,支持 tvbox 接口 * 频道别名、正则表达式匹配,支持繁体中文 * 定时更新数据、缓存支持(Memcached/Redis) #### IPTV Sniffer Web * 项目地址: 适用于 OpenWrt / iStoreOS / 飞牛 NAS / 其它 Linux Docker 宿主机的 IPTV 组播嗅探、运营商频道发现与 rtp2httpd 播放列表统一工作台。支持从机顶盒开机流量中解析频道表和 FCC 参数,也支持网页选择网卡实时嗅探组播流、识别编码/分辨率/截图/EPG,并导出直连 M3U、rtp2httpd 外部源 M3U、JSON、TXT、CSV 等格式。 #### IPTV-channels(四川电信) * 项目地址: 基于 Docker 的 IPTV 订阅获取工具,针对四川电信,自动从 IPTV 内网获取节目地址和 EPG,并生成包含 FCC、FEC 和单播回看地址的 M3U 播放列表。 #### iptv-cd-telecom(四川电信) * 项目地址: 成都/四川电信 IPTV 直播源项目,提供官方单播源和组播转单播两种接入方式,支持回看时移、FCC 快速换台、EPG 电子节目单,兼容 tvbox、KODI、APTV、mytv-android 等主流播放器。提供在线播放列表生成服务,可自定义 FCC、RTSP 代理、r2h-token 等参数。 #### beijing-unicom-iptv-playlist(北京联通) * 项目地址: 北京联通 IPTV 播放列表,每日自动更新。提供组播、单播、RTSP 等多种格式的 M3U 播放列表,支持时移回看和 EPG。配套在线播放链接生成器和 Python 转换工具(generator.py),可灵活自定义直播源、时移源、代理地址等参数,支持 Flask/FastAPI 动态服务部署。 #### plsy1/iptv(山东联通) * 项目地址: 山东联通 IPTV 播放列表,覆盖济南、青岛、烟台、潍坊等山东各地市的组播源,同时提供单播源(APTV、酷九、rtp2httpd 多种格式)。配套机顶盒登录鉴权模拟、EPG 节目单、RTSP 代理、数据抓取与 M3U 生成等工具。 #### SDU-IPTV-PRO(山东 IPTV) * 项目地址: 山东 IPTV 播放列表项目,汇集山东联通、山东移动、山东电信三大运营商的 IPTV 内网直播源,并按各地市用户收视习惯做本地化频道排序。提供通用版和各地市版 M3U,覆盖山东联通组播/单播、山东移动 HTTP/RTSP 单播、山东电信单播等来源,并配套聚合型 EPG。山东联通组播源可配合 rtp2httpd 转为 HTTP 流,并支持 FCC(快速频道切换)参数,起播与换台体验接近单播。 #### Shanghai-IPTV(上海电信) * 项目地址: 上海电信 IPTV 组播节目单管理工具,基于 PHP + SQLite,支持 TXT 格式导入和 M3U8 格式导出。支持多线路、多清晰度(4K/HD/SD/LD)、多 EPG 源映射、UDPXY/rtp2httpd 转换、FCC 快速换台、台标管理等功能,可通过 PHP 内置服务器提供在线播放列表服务。 --- --- url: /guide/video-snapshot.md --- # 视频快照配置 rtp2httpd 支持使用 FFmpeg 来生成视频流的快照(snapshot)功能。如果播放器集成了此功能,将会获得极快的频道预览图加载速度。 > \[!IMPORTANT] > 此功能需要播放器支持,目前已知支持 rtp2httpd 视频快照的播放器有 [mytv-android](https://github.com/mytv-android/mytv-android) 和 [SrcBox](https://github.com/CGG888/SrcBox)。 ## 功能特点 * **快速生成**:配合 FCC 使用时,通常在 0.3 秒内返回快照 * **自动提取关键帧**:从视频流中截取 I 帧进行转码 * **JPEG 格式**:返回标准 JPEG 图片,兼容性好 * **降低播放端压力**:无需播放器解码视频流即可显示预览图 ## FFmpeg ### 安装 FFmpeg 视频快照功能依赖 FFmpeg 来提供解码能力,请先手动安装 FFmpeg。 > \[!CAUTION] > 不要使用 OpenWrt 官方源的 `ffmpeg` 包,它阉割了 h264/hevc 编解码器,将导致无法解码视频流。 > \[!TIP] > 对于飞牛 fnOS,一般已经内置了带硬件加速 ffmpeg,可以直接使用。 #### 推荐方法:下载静态编译版本 从 [johnvansickle.com](https://johnvansickle.com/ffmpeg/) 下载静态编译的 FFmpeg(注意此版本不支持硬件解码): ```bash # 下载 FFmpeg(以 amd64 为例) cd /tmp wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz tar xf ffmpeg-release-amd64-static.tar.xz # 复制到系统目录 sudo cp ffmpeg-*-static/ffmpeg /usr/local/bin/ sudo chmod +x /usr/local/bin/ffmpeg # 配置 rtp2httpd 使用此 FFmpeg # 在配置文件中设置: # ffmpeg-path = /usr/local/bin/ffmpeg ``` ## 启用视频快照 视频快照功能默认关闭,需要手动启用。 此功能对硬件有一定要求,请只考虑在性能强大的 x86 设备上启用。 ### 命令行方式 ```bash rtp2httpd --video-snapshot --ffmpeg-path /usr/bin/ffmpeg --ffmpeg-args "-hwaccel none" ``` ### 配置文件方式 ```ini [global] # 启用视频快照功能 video-snapshot = yes # FFmpeg 可执行文件路径(可选,默认: ffmpeg) ffmpeg-path = /usr/bin/ffmpeg # FFmpeg 额外参数(可选,默认: -hwaccel none) ffmpeg-args = -hwaccel none ``` ### ffmpeg-path 参数 指定 FFmpeg 可执行文件的路径。 * **默认值**:`ffmpeg`(使用系统 PATH 中的 ffmpeg) * **使用场景**: * FFmpeg 不在系统 PATH 中 * 需要使用特定版本的 FFmpeg * 使用自定义编译的 FFmpeg **示例**: ```ini [global] ffmpeg-path = /usr/local/bin/ffmpeg ``` ### ffmpeg-args 参数 指定传递给 FFmpeg 的额外参数,主要用于硬件加速配置。 * **默认值**:`-hwaccel none`(禁用硬件加速,兼容性最好) * **常用选项**: * `-hwaccel none`:禁用硬件加速 * `-hwaccel auto`:自动检测并使用硬件加速 * `-hwaccel vaapi`:使用 VA-API 硬件加速(Intel GPU) * `-hwaccel v4l2m2m`:使用 V4L2 硬件加速(嵌入式 SoC) * `-hwaccel qsv`:使用 Intel Quick Sync Video 加速 **示例**: ```ini [global] # 使用 VA-API 硬件加速(Intel GPU) ffmpeg-args = -hwaccel vaapi # 或使用自动检测 ffmpeg-args = -hwaccel auto ``` ## 硬件加速配置 ### Intel GPU (VA-API) 如果你的设备有 Intel 集成显卡,可以使用 VA-API 硬件加速: ```ini [global] video-snapshot = yes ffmpeg-args = -hwaccel vaapi ``` 针对 Intel GPU 的预编译 FFmpeg,请参考:[rtp2httpd#37](https://github.com/stackia/rtp2httpd/issues/37) ### 嵌入式设备 (V4L2) 某些嵌入式 SoC 支持 V4L2 硬件加速: ```ini [global] video-snapshot = yes ffmpeg-args = -hwaccel v4l2m2m ``` ### 性能提示 * 在 CPU 性能较低的设备上,如果没有硬件加速支持,生成快照可能产生较大 CPU 占用 * 建议先使用 `-hwaccel none` 测试功能是否正常 * 确认正常后,再尝试启用硬件加速以降低 CPU 占用 ## 响应时间 * **使用 FCC**:通常在 0.3 秒内返回快照(快速获取关键帧) * **不使用 FCC**:最长约 1 秒返回(等待下一个 IDR 帧) 大多数运营商组播流每秒发送一个 IDR 帧,因此不使用 FCC 时最长需要等待 1 秒。 ## 播放器集成建议 如果你是播放器开发者,建议按以下方式集成预览图功能: 1. **请求快照时带上自定义请求头**: ```http GET /rtp/239.253.64.120:5140 HTTP/1.1 X-Request-Snapshot: 1 ``` 2. **根据响应的 Content-Type 决定处理方式**: * 如果响应 `Content-Type: image/jpeg`:直接渲染 JPEG 图片 * 如果响应其他类型:说明服务器不支持快照,尝试解码媒体流 3. **兼容性**:这种方式可以同时兼容 rtp2httpd 和其他不支持快照的流媒体服务器 除了 `X-Request-Snapshot: 1`,也支持另外两种请求方式获取快照: ### URL 查询参数 在任意流媒体 URL 后添加 `snapshot=1` 参数: ```url http://192.168.1.1:5140/rtp/239.253.64.120:5140?snapshot=1 http://192.168.1.1:5140/CCTV-1?snapshot=1 ``` ### Accept 请求头 ```bash curl -H "Accept: image/jpeg" http://192.168.1.1:5140/rtp/239.253.64.120:5140 ``` 成功生成 JPEG 时,响应会同时包含 `Content-Length` 和 `R2H-*` 上游流 Metadata。字段说明见 [URL 格式说明](./url-formats.md#上游流-metadata-响应头)。 ## 故障排查 ### 快照请求返回视频流而不是图片 可能的原因: 1. **未启用 video-snapshot**:检查配置文件或命令行参数 2. **FFmpeg 不可用**:检查 FFmpeg 是否正确安装 3. **FFmpeg 解码失败**:查看 rtp2httpd 日志 ### FFmpeg 解码失败 可能的原因: 1. **编解码器缺失**:OpenWrt 官方源的 FFmpeg 缺少 h264/hevc 编解码器 2. **硬件加速不支持**:尝试改用 `-hwaccel none` 3. **硬件忙**:有些硬件解码器,同时解码的媒体流有上限,并发请求过多时可能出现硬件忙碌错误。 ### CPU 占用过高 * 禁用硬件加速后 CPU 占用高是正常现象 * 解决方案: 1. 使用硬件加速(如果设备支持) 2. 减少同时请求快照的客户端数量 3. 在播放器设置中降低预览图请求并发数 ## 相关文档 * [URL 格式说明](./url-formats.md):快照 URL 格式 * [配置参数详解](../reference/configuration.md):视频快照相关配置 * [FCC 快速换台配置](./fcc-setup.md):配合 FCC 获得更快的快照速度 --- --- url: /guide/access-log.md --- # 访问日志 rtp2httpd 可以为媒体请求写入访问日志,便于审计客户端访问了哪些频道、排查反向代理后的客户端来源,以及对接外部日志系统。 ## 启用访问日志 访问日志默认关闭。只有配置 `access-log` 后才会写入日志。 ### 配置文件 ```ini [global] access-log = /var/log/rtp2httpd/access.log log-format = $client_addr [$time_iso8601] "$service_url" $service_type "$upstream_url" ``` ### 命令行 ```bash rtp2httpd --access-log /var/log/rtp2httpd/access.log \ --log-format '$client_addr [$time_iso8601] "$service_url" $service_type "$upstream_url"' ``` OpenWrt LuCI 页面中也可以配置访问日志路径和格式。 ## 默认格式 `log-format` 未配置或为空时,使用以下默认格式: ```text $client_addr [$time_iso8601] "$service_url" $service_type "$upstream_url" ``` 示例输出: ```text 192.0.2.10:53124 [2026-06-25T20:10:12+08:00] "/CCTV-1" rtp "rtp://239.0.0.1:1234" ``` ## 占位符 `log-format` 使用类似 nginx 的 `$变量` 形式。支持的占位符如下: | 占位符 | 说明 | | --- | --- | | `$time_iso8601` | 本地时间,ISO 8601 格式,例如 `2026-06-25T20:10:12+08:00` | | `$time_local` | 本地时间,nginx 风格格式,例如 `25/Jun/2026:20:10:12 +0800` | | `$msec` | Unix 时间戳,精确到毫秒,例如 `1782389412.123` | | `$client_addr` | 状态页面显示的客户端地址 | | `$remote_addr` | 从 `$client_addr` 拆出的客户端 IP 或地址 | | `$remote_port` | 从 `$client_addr` 拆出的客户端端口;没有端口时输出 `-` | | `$worker_pid` | 处理该请求的 worker 进程 PID | | `$request` | 请求方法和 Service URL,例如 `GET /rtp/239.0.0.1:1234` | | `$request_method` | HTTP 请求方法,例如 `GET` | | `$service_url` | 客户端访问的 Service URL | | `$host` | HTTP `Host` 头 | | `$http_user_agent` | HTTP `User-Agent` 头 | | `$http_x_forwarded_for` | HTTP `X-Forwarded-For` 头 | | `$service_type` | 服务类型:`rtp`、`rtsp` 或 `http` | | `$upstream_url` | 实际上游 URL | | `$$` | 输出字面量 `$` | 未知占位符会按原样输出。空值会输出为 `-`。日志值中的引号、反斜杠、换行和控制字符会被转义,单行日志最长 8192 字节。 ## 客户端地址与 X-Forwarded-For `$client_addr` 与状态页面显示的客户端地址一致。 启用 `xff` 后,如果请求中的 `X-Forwarded-For` 被接受,`$client_addr` 会使用 `X-Forwarded-For` 中的第一个地址。这种情况下通常没有客户端端口,因此 `$remote_port` 会输出 `-`。 ## 令牌隐藏 如果请求 URL 中包含 `r2h-token` 查询参数,访问日志中的 `$service_url` 和 `$upstream_url` 不会包含该参数。`$http_user_agent` 也会隐藏 `R2HTOKEN/...` 片段,避免令牌通过访问日志泄露。 ## 配合 logrotate rtp2httpd worker 会保持访问日志文件打开。轮转日志后,需要向 supervisor 进程发送 `SIGHUP`,让 worker 重新打开日志文件。 先通过配置文件或 CLI 参数启用 PID 文件: ```ini [global] pid-file = /var/run/rtp2httpd.pid ``` logrotate 配置示例: ```text /var/log/rtp2httpd/access.log { daily rotate 7 missingok notifempty compress create 0644 root root sharedscripts postrotate [ ! -s /var/run/rtp2httpd.pid ] || kill -HUP "$(cat /var/run/rtp2httpd.pid)" 2>/dev/null || true endscript } ``` --- --- url: /reference/configuration.md --- # 配置参数详解 rtp2httpd 支持通过命令行参数和配置文件两种方式进行配置。 > \[!TIP] > > 1. 命令行参数具有最高优先级 > 2. 配置文件参数次之 > 3. 内置默认值最低 ## 命令行参数 ```bash rtp2httpd [选项] ``` ### 网络配置 * `-l, --listen [地址:]端口|/path/to/rtp2httpd.sock` - 绑定 TCP 监听地址/端口,或监听 Unix domain socket (默认: \*:5140) * `-m, --maxclients <数量>` - 最大并发客户端数 (默认: 5) * `-w, --workers <数量>` - 工作进程数 (默认: 1) `--listen` 可以重复指定,用于同时监听多个 TCP 地址/端口或 Unix socket: ```bash rtp2httpd --listen 5140 --listen 192.168.1.1:8081 --listen '[::1]:5140' --listen /var/run/rtp2httpd.sock ``` Unix socket 监听路径必须是绝对路径,且路径中不能包含空白字符。启动时如果同路径已存在 socket 文件,rtp2httpd 会先探测该 socket 是否仍在使用:如果已有进程正在监听该路径,则拒绝启动;只有确认是残留 socket 文件时才会自动清理。如果同路径是普通文件、目录或符号链接,则会拒绝启动以避免误删数据。 #### 上游网络接口配置 * `-i, --upstream-interface <接口>` - 默认上游接口(作用于所有流量类型,优先级最低) * `-f, --upstream-interface-fcc <接口>` - FCC 上游接口(覆盖 `-i` 设置) * `-t, --upstream-interface-rtsp <接口>` - RTSP 上游接口(覆盖 `-i` 设置) * `-r, --upstream-interface-multicast <接口>` - 组播上游接口(覆盖 `-i` 设置) * `-y, --upstream-interface-http <接口>` - HTTP 代理上游接口(覆盖 `-i` 设置) **优先级规则**:`upstream-interface-{fcc,rtsp,multicast,http}` > `upstream-interface` > 系统路由表 > \[!TIP] > 除了全局配置外,还可以在每个请求的 URL 中通过 `r2h-ifname` 和 `r2h-ifname-fcc` 参数指定上游接口,详见 [URL 格式说明](../guide/url-formats.md)。 > \[!TIP] > FreeBSD 系统下不支持指定除组播外的接口。 ### 性能优化 * `-b, --buffer-pool-max-size <数量>` - 缓冲池最大缓冲区数量 (默认: 16384) * 每个缓冲区 1536 字节,16384 个约占用 24MB 内存 * 增大此值以提高多客户端并发时的吞吐量 * `-B, --udp-rcvbuf-size <字节>` - UDP socket 接收缓冲区大小 (默认: 524288 = 512KB) * 作用于组播、FCC、RTSP RTP/RTCP 所有 UDP socket * 对于 30 Mbps 的 4K IPTV 流,512KB 可提供约 140ms 的缓冲 * 增大此值以减少高带宽流的丢包 * 实际缓冲区大小可能受内核参数 `net.core.rmem_max` 限制 ### FCC 快速换台 * `-P, --fcc-listen-port-range <起始[-结束]>` - FCC UDP 监听端口范围 (默认: 随机端口) ### 服务控制 * `-c, --config <文件>` - 指定配置文件路径 (默认 `/etc/rtp2httpd.conf`) * `-C, --noconfig` - 不读取任何配置文件(避免读到默认的 `/etc/rtp2httpd.conf`) * `--pid-file <路径>` - 写入并锁定 supervisor PID 文件 (默认: 禁用) ### 日志控制 * `-v, --verbose` - 日志详细程度 (0=FATAL, 1=ERROR, 2=WARN, 3=INFO, 4=DEBUG) * `-q, --quiet` - 仅显示致命错误 * `--access-log <路径>` - 将访问日志写入指定文件 (默认: 禁用) * `--log-format <格式>` - 访问日志格式,使用类似 nginx 的 `$变量` 占位符,详见 [访问日志](../guide/access-log.md) ### 安全控制 * `-H, --hostname <主机名>` - 检查 HTTP Host 头的主机名 * `-X, --xff` - 启用 X-Forwarded-For 解析 * `-T, --r2h-token <令牌>` - HTTP 请求认证令牌 (所有请求必须携带 r2h-token 查询参数) * `-O, --cors-allow-origin <值>` - 设置 CORS Access-Control-Allow-Origin 头 (默认: 禁用) * 设为 `*` 允许所有来源,或指定具体域名(如 `https://example.com`) * `-s, --status-page-path <路径>` - 状态页面与 API 根路径 (默认: /status) * `-p, --player-page-path <路径>` - 内置播放器页面路径 (默认: /player) * `--app-path-prefix <路径>` - 所有 HTTP 资源的公开访问前缀 (默认: 无) * `--use-relative-path-in-m3u` - 生成 playlist.m3u 或 HTTP 代理改写 M3U 时使用站点根相对 URL (默认: 关闭) ### 兼容性 * `-U, --noudpxy` - 禁用 UDPxy 兼容模式 (禁用后只能使用 `[services]` 或 `external-m3u` 中定义的服务) ### HTTP 代理相关 * `-g, --http-proxy-user-agent <值>` - 向 HTTP 上游请求时的 User-Agent 头 (默认: 透传客户端 User-Agent) * 作用于通过 `/http/...` 路径代理到上游 HTTP 服务器的请求 * 配置后会替换原本透传给上游的客户端 User-Agent ### RTSP 相关 * `-u, --rtsp-user-agent <值>` - 向 RTSP 上游请求时的 User-Agent 头 (默认: `rtp2httpd/`) * 作用于 OPTIONS、DESCRIBE、SETUP、PLAY、TEARDOWN、GET\_PARAMETER 等上游 RTSP 请求 * 某些上游 RTSP 服务器会校验或依赖特定 User-Agent,可通过此参数进行兼容 * `-N, --rtsp-stun-server ` - STUN 服务器地址 (默认: 禁用) * 当 RTSP 服务器仅支持 UDP 传输且客户端位于 NAT 后时,可尝试使用 STUN 进行 NAT 穿透(不保证成功) * 格式:`host:port` 或 `host`(默认端口 3478) * 示例:`stun.miwifi.com` 或 `stun.miwifi.com:3478` ### 其他 * `-S, --video-snapshot` - 启用视频快照功能 (默认: 关闭) * `-F, --ffmpeg-path <路径>` - FFmpeg 可执行文件路径 (默认: ffmpeg) * `-A, --ffmpeg-args <参数>` - FFmpeg 额外参数 (默认: -hwaccel none) * `-h, --help` - 显示帮助信息 ## 配置文件格式 配置文件路径:`/etc/rtp2httpd.conf`,每行如果使用 `#` 或 `;` 开头表示注释。 ```ini [global] # 日志详细程度: 0=FATAL 1=ERROR 2=WARN 3=INFO 4=DEBUG verbosity = 3 # 访问日志文件路径(留空或不配置时禁用) access-log = /var/log/rtp2httpd/access.log # 访问日志格式(可选,nginx 风格 $变量) # 默认: $client_addr [$time_iso8601] "$service_url" $service_type "$upstream_url" log-format = $client_addr [$time_iso8601] "$service_url" $service_type "$upstream_url" # supervisor PID 文件路径(留空或不配置时禁用) pid-file = /var/run/rtp2httpd.pid # 最大并发客户端数 maxclients = 20 # UDPxy 兼容性 udpxy = yes # 工作进程数(默认: 1) workers = 1 # 检查 HTTP 请求的 Host 头 (默认:无) hostname = somehost.example.com # 启用后,将使用 HTTP X-Forwarded-For 头作为客户端地址,用于显示在状态面板上 (默认:no) # 并接受 X-Forwarded-Host / X-Forwarded-Proto 头作为 playlist.m3u 中的地址前缀 # 建议仅在使用反向代理时启用 xff = no # HTTP 请求认证令牌(可选,默认: 无) # 设置后,所有 HTTP 请求必须携带 r2h-token 查询参数,且值与此配置匹配 # 例如: # http://server:5140/rtp/239.253.64.120:5140?fcc=10.255.14.152:15970&r2h-token=your-secret-token # http://server:5140/player?r2h-token=your-secret-token r2h-token = your-secret-token-here # 状态页应用内路径(默认: /status;配置 app-path-prefix 时会挂载在该前缀下) status-page-path = /status # 播放器页应用内路径(默认: /player;配置 app-path-prefix 时会挂载在该前缀下) player-page-path = /player # 所有 HTTP 资源的公开访问前缀(默认: 无) # 设置后,状态页、播放器、静态资源、playlist.m3u、epg.xml 和流媒体 URL # 都会在此前缀下提供,例如 /app/rtp2httpd/player。 app-path-prefix = /app/rtp2httpd # M3U 输出使用站点根相对路径(默认: no) # 开启后,playlist.m3u 和 HTTP 代理改写后的 M3U 中不会包含 http://host 前缀, # 只保留 / 或 app-path-prefix 开头的路径,例如 /app/rtp2httpd/rtp/... use-relative-path-in-m3u = no # 上游网络接口配置 (可选) # # 简单配置:只配置一个默认接口,所有流量类型都使用此接口 upstream-interface = eth0 # # 高级配置:为不同流量类型配置专用接口 # 注意:专用接口配置优先级高于默认接口 # upstream-interface-multicast = eth0 # 组播流量 (RTP/UDP) # upstream-interface-fcc = eth1 # FCC # upstream-interface-rtsp = eth2 # RTSP # upstream-interface-http = eth3 # HTTP 代理 # # 混合配置示例:默认使用 eth0,但 FCC 使用更快的 eth1 # upstream-interface = eth0 # upstream-interface-fcc = eth1 # # 优先级:upstream-interface-{multicast,fcc,rtsp,http} > upstream-interface > 系统路由表 # 对于 FreeBSD 系统,仅支持设置组播接口 # 外部 M3U 配置(支持 file://, http://, https://) # 注意:HTTP/HTTPS 需要安装 curl 或 uclient-fetch 或 wget 命令 external-m3u = https://example.com/iptv.m3u # 或使用本地文件 external-m3u = file:///path/to/playlist.m3u # 外部 M3U 更新间隔(秒) # 默认 7200(2 小时),设为 0 禁用自动更新 external-m3u-update-interval = 7200 # 组播周期性重新加入间隔(秒,默认: 0 禁用) # 设置为正值(如 60)以周期性重新加入组播组 # 这是针对以下网络环境的兼容性解决方案: # - 启用 IGMP snooping 的交换机在没有路由器 IGMP Query 时超时 # - 配置不当的网络设备会丢弃组播成员关系 # 推荐值: 30-120 秒(小于典型交换机超时 260 秒) # 注意:默认禁用(0),仅在遇到组播流中断时才需要启用 # 注意:不支持 IPv6 mcast-rejoin-interval = 0 # FCC 监听媒体流端口范围(可选,格式: 起始-结束,默认随机端口) fcc-listen-port-range = 40000-40100 # 缓冲池最大缓冲区数量(默认: 16384) # 每个缓冲区 1536 字节,16384 个约占用 24MB 内存 # 增大此值以提高多客户端并发时的吞吐量,例如设置为 32768 或更高 buffer-pool-max-size = 16384 # UDP socket 接收缓冲区大小(默认: 524288 = 512KB) # 作用于组播、FCC、RTSP RTP/RTCP 所有 UDP socket # 对于 30 Mbps 的 4K IPTV 流,512KB 可提供约 140ms 的缓冲 # 增大此值以减少高带宽流的丢包 # 实际缓冲区大小可能受内核参数 net.core.rmem_max 限制 udp-rcvbuf-size = 524288 # 覆盖上游 HTTP 代理请求的 User-Agent(默认: 不覆盖) # 设置后将替换发送给 /http/ 上游服务器的客户端 User-Agent http-proxy-user-agent = rtp2httpd-http-proxy/1.0 # 上游 RTSP 请求的 User-Agent(默认: rtp2httpd/) # 当上游 RTSP 服务器要求特定 User-Agent 时可配置此项 rtsp-user-agent = rtp2httpd/custom # STUN 服务器用于 RTSP NAT 穿透(默认: 禁用) # 当 RTSP 服务器仅支持 UDP 传输且客户端位于 NAT 后时,可尝试使用 STUN 进行 NAT 穿透(不保证成功) # 格式: host:port 或 host(默认端口 3478) rtsp-stun-server = stun.miwifi.com # CORS 跨域请求配置(默认: 禁用) # 设置后启用 CORS # 设为 * 允许所有域名,或指定具体域名 ;cors-allow-origin = * # 启用视频快照功能(默认: no) # 启用后可通过 `snapshot=1` 查询参数获取视频流的实时快照 video-snapshot = no # FFmpeg 可执行文件路径(默认: ffmpeg,使用系统 PATH) # 如果 ffmpeg 不在 PATH 中或想使用特定版本,请指定完整路径 ffmpeg-path = /usr/bin/ffmpeg # FFmpeg 额外参数(默认: -hwaccel none) # 这些参数在生成快照时传递给 ffmpeg # 常用选项: -hwaccel none, -hwaccel auto, -hwaccel vaapi, -hwaccel qsv ffmpeg-args = -hwaccel none [bind] # 监听所有地址的 5140 端口 * 5140 # 监听特定 IP 的 8081 端口 192.168.1.1 8081 # 监听 IPv6 地址(可省略方括号) 2001:db8::1 5140 # 监听 Unix domain socket(路径必须是绝对路径) /var/run/rtp2httpd.sock # 支持多个监听地址 # [services] 内可以直接编写以 #EXTM3U 开头的 m3u 节目清单 # 和 external-m3u 功能类似,只是直接把 m3u 写在了配置文件内 [services] #EXTM3U x-tvg-url="https://example.com/epg.xml.gz" #EXTINF:-1 tvg-id="CCTV1" tvg-name="CCTV1" tvg-logo="https://example.com/logo/CCTV1.png" group-title="央视" catchup="default" catchup-source="rtsp://10.0.0.50:554/catchup?playseek={utc:YmdHMS}-{utcend:YmdHMS}",CCTV-1 rtp://239.253.64.120:5140 #EXTINF:-1 tvg-id="CCTV2" tvg-name="CCTV2" group-title="央视",CCTV-2 rtp://239.253.64.121:5140 ``` 访问日志的启用方式、格式占位符和 logrotate 配置见 [访问日志](../guide/access-log.md)。 ## 运行时配置管理 rtp2httpd 支持配置热重载:修改配置文件后,通过发送信号或状态页面触发重载,即可应用变更,无需重启整个进程。rtp2httpd 采用 supervisor + worker 多进程架构,信号应发送给 **supervisor 进程**(即主 `rtp2httpd` 进程,而非 worker 子进程)。 ### 信号说明 | 信号 | 作用 | | --- | --- | | `SIGHUP` | 热重载配置:从配置文件重新读取并应用 | | `SIGUSR1` | 重启所有工作进程 | **示例**(将 `12345` 替换为 supervisor 进程的 PID): ```bash # 热重载配置 kill -HUP 12345 # 重启所有工作进程 kill -USR1 12345 ``` ### SIGHUP 热重载行为 * 从配置文件(默认 `/etc/rtp2httpd.conf`,或通过 `--config` 指定的路径)重新读取配置 * 若 `[bind]` 监听地址发生变化,supervisor 会向所有工作进程发送 `SIGTERM` 并重新拉起,以应用新的监听地址 * 若 `workers` 数量发生变化,supervisor 会自动增减工作进程 * 若配置文件中的 `pid-file` 发生变化,supervisor 会先建立并锁定新文件,再删除旧文件;新路径失败时保留旧配置和旧 PID 文件 * 其他配置变更会转发 `SIGHUP` 给各工作进程,由工作进程在运行时应用 * 工作进程会在重载时重新打开 [访问日志](../guide/access-log.md) 文件,便于配合 logrotate * 若配置文件解析失败,保留旧配置,不会中断现有连接 > \[!NOTE] > 使用 `--noconfig` 启动时,没有配置文件可供重载;此时 `SIGHUP` 仅触发 M3U/EPG 的重新加载。 ### SIGUSR1 重启工作进程 向 supervisor 发送 `SIGUSR1` 后,所有工作进程会被终止并由 supervisor 自动重新拉起。适用于需要刷新工作进程状态、但不修改配置文件的场景。进行中的客户端连接会被中断。 ### 通过状态页面操作 [状态页面](../guide/url-formats.md#状态页面) 提供了等效的管理功能,无需手动查找 PID: * **重载配置**:对应 `SIGHUP`(API:`POST /api/reload-config`) * **重启工作进程**:对应 `SIGUSR1`(API:`POST /api/restart-workers`)