摄像头的RTSP地址能在播放器里打开,浏览器却不能直接播放,是接入视频页面时常见的断点。把同一个 rtsp:// 地址填进网页的 <video>,并不会自动得到画面。要补的是一条浏览器能接收的播放链路。
我把MediaMTX官方资料整理成一个具体场景:用Docker拉取已有RTSP视频源,再通过HLS播放。本篇固定1.21.2,给出两份完整配置、播放地址和排查顺序;不涉及录像、识别模型或直播平台搭建。
1. 先把输入和输出分清
本例的链路是:RTSP视频源 → MediaMTX → HLS → 浏览器。源可以是摄像头,也可以是已经提供RTSP的媒体服务;需要事先知道实际地址、账号、密码和码流路径。
如果把容器放在ECS,先确认它能访问视频源。办公室的私网摄像头不会因为部署了ECS就自动可达,需要已有的VPN、专线路由或其他可信网络连接。播放端的SSH转发只连接浏览器与ECS,不能替ECS打通摄像头网络。
MediaMTX在这里做协议转换和转封装,不会自动把H.265改成H.264,也不会自动降低码率。首次接入可优先选择H.264视频与AAC音频;摄像头没有合适音轨时,先用无音频码流确认画面。编码支持还要结合目标浏览器验证。
2. 保存两份配置,只发布HLS端口
前提是已有Docker Engine与Compose V2。在独立目录先创建 mediamtx.yml,将占位值替换为自己的视频源:
logLevel: info
api: false
rtsp: false
rtmp: false
webrtc: false
srt: false
moq: false
hls: true
hlsAddress: :8888
hlsVariant: mpegts
paths:
cam:
source: "rtsp://CAMERA_USER:CAMERA_PASSWORD@CAMERA_HOST:554/STREAM_PATH"
rtspTransport: tcp
sourceOnDemand: true
cam 是本服务的播放路径名,和摄像头原来的 STREAM_PATH 不必相同。密码含 @、:、? 等特殊字符时,要对用户名、密码分别做URL编码;真实凭据只留在受控配置中,不贴进文章、截图或公开仓库。
rtspTransport: tcp 是拉取源的传输选项,不是RTSP服务端的 rtspTransports。本例关闭RTSP监听,仍由RTSP客户端向远端视频源发起连接;无需对外开放服务器的8554端口。
sourceOnDemand: true 表示有读者时才拉取源。hlsVariant: mpegts 使用常规HLS分片,本篇先处理播放与兼容,不追求最低延迟。
在同一目录保存 compose.yaml:
services:
mediamtx:
image: docker.1ms.run/bluenviron/mediamtx:1.21.2
restart: unless-stopped
command: ["/mediamtx.yml"]
ports:
- "127.0.0.1:8888:8888"
volumes:
- type: bind
source: ./mediamtx.yml
target: /mediamtx.yml
read_only: true
bind:
create_host_path: false
配置文件以只读方式挂到容器的 /mediamtx.yml,启动参数明确指向它;缺文件时不自动创建同名目录。镜像固定具体版本,后续更新要连同配置字段一起复核。这里通过毫秒镜像获取官方项目镜像,它只作用于镜像获取环节;视频源认证、网络和编码仍要分别检查。
3. 启动后,用正确的播放地址
在保存配置的目录执行:
docker compose config --quiet
docker compose pull
docker compose up -d
docker compose logs --tail=50 mediamtx
第一条只检查Compose结构,不替代MediaMTX对自身配置的解析。后续看真实启动日志,检查配置是否加载、拉源是否认证失败、是否能连到源地址;不要把容器Running当作已经有视频。
同机浏览器打开 http://127.0.0.1:8888/cam,这是内置播放页。远程ECS部署则在自己的电脑建立转发,替换示例账号和服务器:
ssh -N -L 8888:127.0.0.1:8888 YOUR_USER@YOUR_ECS
保持连接,再在本地浏览器打开同一地址。默认不把8888映射到公网;本例也没有启用管理API,因此不要把播放页当管理控制台。
HLS清单是 http://127.0.0.1:8888/cam/index.m3u8。它给支持HLS的播放器使用,不能把“浏览器下载了m3u8”当作网页播放成功。首次打开可能要等待源接入及分片生成,随后检查画面是否持续更新,而非只显示播放器边框。
按需拉取时,尚未有人播放,日志暂时没有源连接不一定是故障。先发起播放请求,再观察源认证和分片请求;所有读者退出后,源连接可以按配置关闭。这也意味着首次观看和持续观看的等待情况可能不同,不要把启动后的静默当成没有加载配置。

4. 页面能打开但没画面,按三段排查
| 检查位置 | 先确认什么 | 不应混为一谈 |
|---|---|---|
| RTSP输入 | 容器到源的网络、源账号、准确码流路径 | 本机播放器能看不代表ECS能连到源 |
| HLS输出 | 使用cam路径,清单及分片请求是否成功 | 页面200不等于源已提供可播放媒体 |
| 浏览器 | 视频与音频编码、播放错误、页面协议 | HLS转封装不等于已完成转码 |
如果源是H.265或音频为G.711,即使RTSP能读取,也要检查目标HLS格式和浏览器是否支持。先切换摄像头的兼容码流;确需改变编码时,另接FFmpeg或GStreamer。本例的标准MediaMTX镜像不包含FFmpeg,不要直接在里面套用转码命令。
将画面嵌入业务网站前,先独立打开播放页确认链路。HTTPS网站应配套使用HTTPS播放入口,避免混合内容被浏览器拦截;还需按网站方式处理访问认证和跨域。本篇的本地HTTP示例用于初次接入,不能直接当成公开媒体服务的配置。
WebRTC通常延迟更低,但需要处理额外的媒体连通性、地址与编码条件。本篇关闭它,不要把HLS的8888访问方法套到WebRTC,也不通过增加一堆端口解决HLS黑屏。
5. 留下能复用的接入记录
记录固定版本、源的码流设置、播放路径、目标浏览器和实际播放结果。至少确认画面能持续更新、源断开时表现明确、重新连接后的播放能恢复;同时核对宿主端口仍只绑定本地地址。敏感源地址与密码不进入公开记录。
这条链路接通后,再决定是否接入网站或改用其他输出协议。把输入可达、HLS输出和浏览器解码分开看,才能知道下一步该调整网络、路径还是编码。