播放网络 RTSP 视频流并支持实时画面查看、截图保存、录制片段。优先使用 python3 + opencv-python(通过 exec(action="acquire", package="opencv-python") 按需安装),备选 ffmpeg。
rtsp://192.168.1.100:554/stream1)。media-processing 技能。media-processing 技能(ffmpeg)。desktop + 摄像头驱动。image-processing 技能。| 步骤 | 工具 |
|---|---|
| ------ | ------ |
| Python OpenCV 播放/截图 | exec(command="python3 -c '...'")(先 acquire opencv-python) |
| 定时连续截图(自定义秒/分钟间隔) | exec(command="python3 -c '...'")(先 acquire opencv-python) |
| 多张截图合成 GIF 动图 | exec(command="python3 -c '...'")(先 acquire opencv-python + Pillow) |
| ffmpeg 播放/录制 | exec(command="ffmpeg -i rtsp://... output.mp4")(ffmpeg 需已安装) |
| 流可用性检测 | exec(command="timeout 5 ffprobe rtsp://...") |
| 分析 RTSP URL 和截图间隔参数 | think(text="...") |
rtsp://[username:password@]host[:port]/path
rtsp://192.168.1.100:554/stream1rtsp://admin:password@192.168.1.100:554/h264/ch1/main/av_stream/live、/stream1、/h264/ch1/main/av_stream最佳路径(优先尝试)→ python3 + opencv-python:
exec(action="acquire", package="opencv-python") 安装cv2.VideoCapture(rtsp_url) 打开流备选路径 → ffmpeg:
ffmpeg -rtsp_transport tcp -i rtsp://...(TCP 传输更稳定)ffmpeg -i rtsp://... -vframes 1 output.jpg(截图一帧)| 传输方式 | 特点 | 适用场景 |
|---|---|---|
| ---------- | ------ | ---------- |
| UDP(默认) | 延迟低,易丢包 | 局域网,网络质量好 |
| TCP | 可靠传输,延迟稍高 | 跨网络,网络不稳定 |
| HTTP 隧道 | 穿透防火墙 | 受限网络环境 |
建议:跨网络环境始终使用 TCP 传输(-rtsp_transport tcp 参数)。
cap = cv2.VideoCapture("rtsp://admin:pass@192.168.1.100:554/stream1")
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) # 减小缓冲,降低延迟
cap.set(cv2.CAP_PROP_FPS, 30) # 设置帧率
ret, frame = cap.read() # 读取一帧
if ret:
cv2.imwrite("snapshot.jpg", frame) # 保存截图
用户可通过自然语言指定截图间隔,支持的单位:
| 用户说法 | 转换 | 代码实现 |
|---|---|---|
| ---------- | ------ | ---------- |
| "每5秒"、"每隔5秒" | interval=5 秒 | time.sleep(5) |
| "每30秒"、"半分钟一次" | interval=30 秒 | time.sleep(30) |
| "每1分钟"、"每分钟" | interval=60 秒 | time.sleep(60) |
| "每5分钟"、"5分钟一次" | interval=300 秒 | time.sleep(300) |
核心代码模式:
import cv2, time, os
interval = 5 # 用户指定的间隔(秒)
total = 10 # 总截图次数(可选,不设则持续直到超时)
count = 0
cap = cv2.VideoCapture(url)
while True:
ret, frame = cap.read()
if ret:
path = f"snapshot_{int(time.time())}.jpg"
cv2.imwrite(path, frame)
count += 1
print(f"第{count}张: {path}")
if total and count >= total:
break
time.sleep(interval)
cap.release()
Pillow(已预装)可将多张截图合成为 GIF 动图。支持参数:
| 参数 | 说明 | 默认值 |
|---|---|---|
| ------ | ------ | -------- |
duration | 每帧停留时间(毫秒) | 500(即 0.5 秒/帧) |
loop | 循环次数,0=无限循环 | 0 |
fps | 用户说"每秒几帧"时的换算:duration = 1000/fps | - |
核心代码模式:
from PIL import Image
import glob
frames = []
# 按文件名排序,确保 GIF 帧顺序正确
images = sorted(glob.glob("snapshot_*.jpg"))
for f in images:
im = Image.open(f)
frames.append(im.copy())
im.close()
# 合成 GIF,duration 单位毫秒
frames[0].save(
"rtsp_animation.gif",
save_all=True,
append_images=frames[1:],
duration=500, # 每帧 0.5 秒
loop=0 # 无限循环
)
> 注意:GIF 文件全部由 Pillow 处理,与 ffmpeg 无关。Pillow 已预装,但若遇到 unknown file extension: .gif 错误,需重新安装带 GIF 编码支持的 Pillow:exec(action="acquire", package="Pillow")。若截图数量过多(>100张),建议提高 duration 或只取部分帧合成,避免 GIF 文件过大。
用户要求:「帮我查看摄像头 rtsp://192.168.1.100:554/stream1 的画面。」
# 安装 opencv-python
exec(action="acquire", package="opencv-python")
# 用 OpenCV 打开 RTSP 流并截图
exec(command="python3 -c \"
import cv2
cap = cv2.VideoCapture('rtsp://192.168.1.100:554/stream1')
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
ret, frame = cap.read()
if ret:
cv2.imwrite('rtsp_snapshot.jpg', frame)
print('截图保存成功: rtsp_snapshot.jpg')
else:
print('无法读取 RTSP 流')
cap.release()
\"")
用户要求:「录制摄像头 rtsp://admin:pass@camera.example.com:554/live 的 10 秒片段。」
exec(command="ffmpeg -rtsp_transport tcp -i 'rtsp://admin:pass@camera.example.com:554/live' -t 10 -c copy rtsp_clip.mp4")
输出:录制完成,文件为 rtsp_clip.mp4。
用户要求:「检查 rtsp://192.168.1.100:554/stream1 这个摄像头是否在线。」
exec(command="timeout 10 ffprobe -v quiet -print_format json -show_streams 'rtsp://192.168.1.100:554/stream1' 2>&1 || echo 'UNAVAILABLE'")
如果输出包含 codec_type 等流信息,说明摄像头在线;否则显示 UNAVAILABLE。
用户要求:「播放这个 RTSP 流 rtsp://192.168.1.100:554/stream1。」
exec(action="acquire", package="opencv-python")
若 acquire 失败(如沙箱无网络),回复用户:
> 当前环境不支持实时播放 RTSP 视频流。建议:
> 1. 使用 VLC 播放器(vlc rtsp://...)在本地播放
> 2. 让管理员在数字员工平台上安装 ffmpeg 后重试
用户要求:「每3秒截一张摄像头画面,截5张,然后做成 GIF 动图。」
# 安装 opencv-python(如未安装)
exec(action="acquire", package="opencv-python")
# 定时截图:每3秒截一张,共5张
exec(command="python3 -c \"
import cv2, time, os
url = 'rtsp://admin:pass@192.168.1.100:554/stream1'
os.environ['OPENCV_FFMPEG_CAPTURE_OPTIONS'] = 'rtsp_transport;tcp'
cap = cv2.VideoCapture(url, cv2.CAP_FFMPEG)
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
interval = 3
total = 5
count = 0
for i in range(total):
ret, frame = cap.read()
if ret:
ts = int(time.time())
path = f'snapshot_{ts}.jpg'
cv2.imwrite(path, frame)
count += 1
print(f'第{count}张: {path}')
else:
print(f'第{i+1}次: 读取失败')
time.sleep(interval)
cap.release()
print(f'截图完成: 共{count}张')
\"")
# 将截图合成 GIF 动图
exec(command="python3 -c \"
from PIL import Image
import glob
images = sorted(glob.glob('snapshot_*.jpg'))
if not images:
print('没有找到截图文件')
else:
frames = []
for f in images:
im = Image.open(f)
frames.append(im.copy())
im.close()
gif_path = 'rtsp_animation.gif'
frames[0].save(
gif_path,
save_all=True,
append_images=frames[1:],
duration=500, # 每帧0.5秒
loop=0
)
print(f'GIF 生成成功: {gif_path}')
print(f'帧数: {len(frames)}, 文件大小: {__import__(\"os\").path.getsize(gif_path)//1024}KB')
\"")
用户要求参考:「截10张,每5秒一张,做成每帧0.2秒的 GIF」→ interval=5, total=10, duration=200
用户要求:「每隔5秒截一张摄像头画面,截10张。」
# 安装 opencv-python(如未安装)
exec(action="acquire", package="opencv-python")
# 定时截图:每5秒截一张,共10张
exec(command="python3 -c \"
import cv2, time, os
url = 'rtsp://admin:pass@192.168.1.100:554/stream1'
os.environ['OPENCV_FFMPEG_CAPTURE_OPTIONS'] = 'rtsp_transport;tcp'
cap = cv2.VideoCapture(url, cv2.CAP_FFMPEG)
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
interval = 5 # 间隔秒数
total = 10 # 截图张数
count = 0
for i in range(total):
ret, frame = cap.read()
if ret:
ts = int(time.time())
path = f'snapshot_{ts}.jpg'
cv2.imwrite(path, frame)
count += 1
print(f'第{count}张: {path} ({frame.shape[1]}x{frame.shape[0]})')
else:
print(f'第{i+1}次: 读取失败')
time.sleep(interval)
cap.release()
print(f'完成: 共截图{count}张,间隔{interval}秒')
\"")
用户要求参考:「帮我每30秒截一次摄像头画面」→ 将 interval 改为 30
用户要求参考:「每5分钟截一张,截1小时」→ interval=300, total=12
browser 或 read 工具访问 RTSP URL(它们是应用层协议,不支持 RTSP)。-rtsp_transport tcp)提高稳定性。-t 30 限制30秒),避免无限阻塞。| 现象 | 可能原因 | 处理方式 |
|---|---|---|
| ------ | ---------- | ---------- |
cv2.error: OpenCV(4.x) ... Failed to parse rtsp:// | URL 格式错误 | 检查 URL 是否有拼写错误或缺失端口/路径 |
Connection refused | 摄像头未开机或地址错误 | 确认设备在线,检查 IP 和端口 |
Unauthorized | 鉴权凭据错误 | 检查用户名密码 |
Timeout | 网络不通或设备离线 | 检查网络连通性,使用 TCP 传输重试 |
ModuleNotFoundError: cv2 | opencv-python 未安装 | 执行 exec(action="acquire", package="opencv-python") |
[rtsp @ ...] method DESCRIBE failed: 401 Unauthorized | ffmpeg 鉴权失败 | 确认 URL 中用户名密码是否正确 |
Stream ended unexpectedly | 摄像头主动断流 | 重建连接,可设置自动重试机制 |
| 画面卡顿/花屏 | 网络带宽不足 | 建议降低分辨率或切换到 TCP 模式 |
| 定时截图中途某帧读取失败 | 瞬断/网络抖动 | 跳过该帧,继续下一个间隔,不中断整个任务 |
| 用户指定的间隔小于1秒 | 参数不合理 | 下限为1秒,小于1秒按1秒处理 |
| 用户说"持续截图直到停止"(未指定张数) | 无限循环风险 | 设定默认总时长上限(如30分钟),或让用户明确指定张数/时长 |
| GIF 合成时没有找到截图文件 | 截图步骤失败或文件被删除 | 先检查 .jpg 截图文件是否存在,仅用已有帧合成 |
| GIF 文件过大(>50MB) | 截图数量多或分辨率高 | 建议降低帧数(每隔一张取一张)、提高 duration、或降低分辨率 |
| Pillow import 失败 | Pillow 未安装 | 执行 exec(action="acquire", package="Pillow") 安装 |
| 条件 | 降级方案 |
|---|---|
| ------ | ---------- |
| opencv-python 无法安装(沙箱无网络) | 尝试使用 ffmpeg 方案;若 ffmpeg 也不可用,告知用户使用本地 VLC 播放 |
opencv-python 安装成功但 cv2.VideoCapture 无法打开流 | 尝试使用 rtsp_transport 参数切换传输协议(UDP ↔ TCP) |
| ffmpeg 未安装 | 引导到 exec(action="acquire", package="ffmpeg") 或提示管理员安装 |
| 实时播放不可行(无显示器/GUI环境) | 降级为截图保存一帧为图片,或定时连续截图保存为图片序列 |
| 定时截图任务用户未指定张数(可能无限循环) | 设默认上限:total=60 张,或 max_duration=1800 秒(30分钟),并向用户说明 |
| 定时截图中某帧失败 | 跳过该帧继续,不中断整个任务;统计成功/失败比告知用户 |
| 网络不稳定导致频繁断流 | 设置自动重连循环(最多 3 次),每次等待 2 秒 |
| RTSP 流长时间无响应(超时) | 设定 timeout=15 秒的执行超时,超时后告知用户设备可能离线 |
| 所有播放方案均失败 | 输出详细的错误分析报告,告知用户可能的故障原因和排查方向 |
| Pillow 未安装导致无法合成 GIF | 执行 exec(action="acquire", package="Pillow")" 安装 |
| GIF 合成时截图文件不足(<2张) | 告知用户至少需要2张截图才能合成 GIF,建议先执行定时截图 |
| 操作 | 验证方式 |
|---|---|
| ------ | ---------- |
| 单次截图保存 | 检查截图文件是否生成(ls -la snapshot.jpg)且大小 > 0 |
| 定时连续截图 | 检查生成的截图数量是否匹配用户要求的张数,文件名含时间戳 |
| 截图合成 GIF | 检查 rtsp_animation.gif 文件存在且大小 > 0;通过 Pillow 确认帧数 |
| 录制视频 | 检查输出文件是否存在,通过 ffprobe 确认文件有效 |
| 流可用性检测 | ffprobe 返回码为 0 且输出了流信息 |
| opencv-python 安装 | exec(command="python3 -c 'import cv2; print(cv2.__version__)'") 输出版本号 |
共 1 个版本