You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用rtsp-simple-server:Python推流网页,Chrome正常Firefox异常

问题:Python生成的视频流无法在Firefox网页中播放(Chrome正常)

更新: 流可以正常运行,但仅在Chrome中可用,Firefox无法播放。

我希望在网页上实时展示程序生成的流,为此部署了支持RTSP和HLS的rtsp-simple-server。已成功通过以下命令从文件推送流,并能在http://localhost:8888/mystream查看:

ffmpeg -re -stream_loop -1 -i file.mp4 -vcodec libx264 -f rtsp -rtsp_transport tcp rtsp://localhost:8554/mystream

但当尝试通过Python向ffmpeg标准输入推送流时,视频无限加载无法播放,Firefox控制台提示:Uncaught (in promise) DOMException: The fetching process for the media resource was aborted by the user agent at the user's request。我的Python代码如下:

import random
import shlex
import subprocess
import time

import numpy as np


def main():
    width = 1024
    height = 720
    framerate = 1
    frame_duration = 1 / framerate
    cmd = shlex.split(
        f'ffmpeg'
        f' -y'
        f' -f rawvideo'
        f' -vcodec rawvideo'
        f' -s {width}x{height}'
        f' -pix_fmt bgr24'
        f' -r {framerate}'
        f' -i -'
        f' -r {framerate}'
        f' -force_key_frames expr:eq(mod(n,3),0)'
        f' -vcodec libx264'
        f' -crf 18'
        f' -preset ultrafast'
        f' -tune zerolatency'
        f' -f rtsp'
        f' -rtsp_transport tcp'
        f' rtsp://localhost:8554/mystream'
    )
    ffmpeg_process = subprocess.Popen(cmd, stdin=subprocess.PIPE)
    try:
        while True:
            image = np.full(
                (height, width, 3),
                (
                    random.randint(0, 255),
                    random.randint(0, 255),
                    random.randint(0, 255),
                ),
                dtype=np.uint8,
            )
            ffmpeg_process.stdin.write(image.tobytes())
            time.sleep(frame_duration)
    finally:
        ffmpeg_process.stdin.close()
        ffmpeg_process.wait()


if __name__ == '__main__':
    main()

服务器日志中仅出现一条404(应该是网站图标favicon的请求错误,不影响),其余日志如下:

2023/03/25 13:50:32 DEB [HLS] [conn 172.18.0.1] GET /mystream/
2023/03/25 13:50:32 DEB [HLS] [conn 172.18.0.1] [c->s] GET /mystream/ HTTP/1.1
Host: localhost:8888
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: ru,en-US;q=0.7,en;q=0.3
Connection: keep-alive
Cookie: csrftoken=iRZDO5rsJzhh5peyyKhViN9yRslNQbuZ; Webstorm-713207de=ca4f5f1e-40e8-4bfd-97da-1be2f15f6e9e
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: cross-site
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0


2023/03/25 13:50:32 INF [HLS] [muxer mystream] created (requested by 172.18.0.1)
2023/03/25 13:50:32 INF [HLS] [muxer mystream] is converting into HLS, 1 track (H264)
2023/03/25 13:50:32 DEB [HLS] [conn 172.18.0.1] [s->c] HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Content-Type: text/html
Server: rtsp-simple-server

(body of 1240 bytes)
2023/03/25 13:50:32 DEB [HLS] [conn 172.18.0.1] GET /favicon.ico
2023/03/25 13:50:32 DEB [HLS] [conn 172.18.0.1] [c->s] GET /favicon.ico HTTP/1.1
Host: localhost:8888
Accept: image/avif,image/webp,*/*
Accept-Encoding: gzip, deflate, br
Accept-Language: ru,en-US;q=0.7,en;q=0.3
Connection: keep-alive
Cookie: csrftoken=iRZDO5rsJzhh5peyyKhViN9yRslNQbuZ; Webstorm-713207de=ca4f5f1e-40e8-4bfd-97da-1be2f15f6e9e
Referer: http://localhost:8888/mystream/
Sec-Fetch-Dest: image
Sec-Fetch-Mode: no-cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0


2023/03/25 13:50:32 DEB [HLS] [conn 172.18.0.1] [s->c] HTTP/1.1 404 Not Found
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Server: rtsp-simple-server


2023/03/25 13:50:32 DEB [HLS] [conn 172.18.0.1] GET /mystream/index.m3u8
2023/03/25 13:50:32 DEB [HLS] [conn 172.18.0.1] [c->s] GET /mystream/index.m3u8 HTTP/1.1
Host: localhost:8888
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: ru,en-US;q=0.7,en;q=0.3
Connection: keep-alive
Cookie: csrftoken=iRZDO5rsJzhh5peyyKhViN9yRslNQbuZ; Webstorm-713207de=ca4f5f1e-40e8-4bfd-97da-1be2f15f6e9e
Referer: http://localhost:8888/mystream/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0


2023/03/25 13:50:32 DEB [HLS] [conn 172.18.0.1] [s->c] HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Content-Type: application/x-mpegURL
Server: rtsp-simple-server

(body of 122 bytes)
2023/03/25 13:50:34 DEB [HLS] [conn 172.18.0.1] GET /mystream/index.m3u8
2023/03/25 13:50:34 DEB [HLS] [conn 172.18.0.1] [c->s] GET /mystream/index.m3u8 HTTP/1.1
Host: localhost:8888
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: ru,en-US;q=0.7,en;q=0.3
Connection: keep-alive
Cookie: csrftoken=iRZDO5rsJzhh5peyyKhViN9yRslNQbuZ; Webstorm-713207de=ca4f5f1e-40e8-4bfd-97da-1be2f15f6e9e
Referer: http://localhost:8888/mystream/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0


2023/03/25 13:50:34 DEB [HLS] [conn 172.18.0.1] [s->c] HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Content-Type: application/x-mpegURL
Server: rtsp-simple-server

(body of 122 bytes)
2023/03/25 13:50:36 DEB [HLS] [conn 172.18.0.1] GET /mystream/index.m3u8
2023/03/25 13:50:36 DEB [HLS] [conn 172.18.0.1] [c->s] GET /mystream/index.m3u8 HTTP/1.1
Host: localhost:8888
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: ru,en-US;q=0.7,en;q=0.3
Connection: keep-alive
Cookie: csrftoken=iRZDO5rsJzhh5peyyKhViN9yRslNQbuZ; Webstorm-713207de=ca4f5f1e-40e8-4bfd-97da-1be2f15f6e9e
Referer: http://localhost:8888/mystream/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/111.0


2023/03/25 13:50:36 DEB [HLS] [conn 172.18.0.1] [s->c] HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Content-Type: application/x-mpegURL
Server: rtsp-simple-server

(body of 122 bytes)

如何让Python生成的流在Firefox网页上正常显示?


解决方案

1. 调整FFmpeg参数,优化HLS兼容性

Firefox对HLS的兼容性要求更严格,尤其是关键帧、封装格式的处理。修改FFmpeg命令参数:

  • 添加-movflags frag_keyframe+empty_moov:确保输出流碎片化,适配实时HLS播放
  • 调整关键帧间隔:将-force_key_frames expr:eq(mod(n,3),0)改为-g 2(每2帧一个关键帧,匹配低帧率场景)

修改后的Python中FFmpeg命令部分:

cmd = shlex.split(
    f'ffmpeg'
    f' -y'
    f' -f rawvideo'
    f' -vcodec rawvideo'
    f' -s {width}x{height}'
    f' -pix_fmt bgr24'
    f' -r {framerate}'
    f' -i -'
    f' -r {framerate}'
    f' -g 2'
    f' -vcodec libx264'
    f' -crf 18'
    f' -preset ultrafast'
    f' -tune zerolatency'
    f' -movflags frag_keyframe+empty_moov'
    f' -f rtsp'
    f' -rtsp_transport tcp'
    f' rtsp://localhost:8554/mystream'
)

2. 强制刷新FFmpeg输入缓冲区

Python写入数据后,缓冲区可能未及时刷新,导致FFmpeg无法处理帧。在write后添加flush操作:

ffmpeg_process.stdin.write(image.tobytes())
ffmpeg_process.stdin.flush()  # 强制刷新缓冲区
time.sleep(frame_duration)

3. 优化rtsp-simple-server的HLS配置

在服务器配置文件中调整以下参数:

  • hlsSegmentCount: 5:保留更多历史片段,避免Firefox请求不到有效内容
  • hlsSegmentDuration: 2:片段长度与关键帧间隔匹配

4. 测试中间封装成MP4(可选)

如果原始帧推送仍有问题,可先将帧封装为MP4再转RTSP,补充元数据:

cmd = shlex.split(
    f'ffmpeg'
    f' -y'
    f' -f rawvideo'
    f' -vcodec rawvideo'
    f' -s {width}x{height}'
    f' -pix_fmt bgr24'
    f' -r {framerate}'
    f' -i -'
    f' -r {framerate}'
    f' -g 2'
    f' -vcodec libx264'
    f' -crf 18'
    f' -preset ultrafast'
    f' -tune zerolatency'
    f' -movflags frag_keyframe+empty_moov+faststart'
    f' -f mp4 - | ffmpeg -y -i - -f rtsp -rtsp_transport tcp rtsp://localhost:8554/mystream'
)

注意:此方式需启用shell=True(需注意安全风险),或调整subprocess的管道处理逻辑。


内容的提问来源于stack exchange,提问作者Powercoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 18:02:04