|
2026 用程序保存监控摄像头rtsp的图片和视频

2026 用程序保存监控摄像头rtsp的图片和视频

当我们安装监控摄像头时,我们可以选择使用厂家提供的录像机作为监控的工具,但如果动一点编程,我们也可以通过rtsp通过我们的计算机直接连接摄像头,把影像或者图片保存到我们的计算机上。如果你还会一点人工智能的编程技能,那通过摄像头的影响来监控你感兴趣的目标对象,那会更加好玩,但我们这篇文章先不讨论人工智能,我们先确保影响能被计算机保存下来。

RTSP简介

Real Time Streaming Protocol,RTSP,中文叫实时流协议,是一种网络应用协议,专为娱乐和通信系统的使用,以控制流媒体服务器。该协议用于创建和控制终端之间的媒体会话。媒体服务器的客户端发布VCR命令,例如播放,录制和暂停,以便于实时控制从服务器到客户端(视频点播)或从客户端到服务器(语音录音)的媒体流。

监控摄像头的RTSP

现在大部分的网络监控摄像头都支持RTSP的推流,你可以通过查看说明书,或者登录到摄像头的后台管理界面,找到摄像头的推流RTSP URL,用户密码并启用它。当然,如果你启用了摄像头推流,记得修改一个密码,以免黑客通过扫描默认端口,获得了你的摄像头的控制权。

常见大厂的摄像头RTSP地址

海康威视

说明RTSP URL类型备注
第1个通道的主码流rtsp://{user}:{pwd}@{host}:{port}/Streaming/Channels/101摄像头新款
第1个通道的子码流rtsp://{user}:{pwd}@{host}:{port}/Streaming/Channels/102摄像头新款
多播取流rtsp://{user}:{pwd}@{host}:{port}/Streaming/Channels/101?transportmode=multicast摄像头/录像机
第1个通道的主码流rtsp://{user}:{pwd@{host}:{port}/{videotype}/ch1/main/av_stream摄像头旧型号摄像头(2012年之前的设备)
第1个通道的子码流rtsp://{user}:{pwd@{host}:{port}/videotype}/ch1/sub/av_stream摄像头旧型号摄像头(2012年之前的设备)

说明 user: 用户名。例如: admin。 pwd: 密码。例如: 888888(默认)。 ip: 为设备IP。例如 10.7.8.122。 port: 端口号默认为554,若为默认可不填写。 channel: 通道号,新款格式是N01,N02,N代表通道,例如901;旧款的chN,N代表通道,例如:ch2 subtype: 码流类型,主码流为101(新款)或 main,子码流为102,或者sub

大华

说明RTSP URL类型
第1个通道的主码流rtsp://{user}:{pwd}@{ip}:{port}/cam/realmonitor?channel=1&subtype=0摄像头
第1个通道的辅码流rtsp://{user}:{pwd}@{ip}:{port}/cam/realmonitor?channel=1&subtype=1摄像头

说明 user: 用户名。例如: admin。 pwd: 密码。例如: 888888(默认)。 ip: 为设备IP。例如 10.7.8.122。 port: 端口号默认为554,若为默认可不填写。 channel: 通道号,起始为1。例如通道2,则为channel=2。 subtype: 码流类型,主码流为0(即subtype=0),辅码流为1(即subtype=1)。

使用Python程序来保存图片或视频片段

准备

先安装ffmpeg工具

sudo apt install ffmpeg

保存图片

下面程序可以保存一张图片,文件名为img001.jpg,如果需要保存多张图片,可以把cap_count改成大于1。

import os

user = '>>'
pwd = '>'
host = '>>'
port = 554
img_files = 'img%03d.jpg'
cap_count = 1

url = "rtsp://{user}:{pwd}@{host}:{port}/Streaming/Channels/101".format(user=user, pwd=pwd, host=host, port=port)

cmd = "ffmpeg -rtsp_transport tcp -y -i \"{url}\" -vframes {cap_count} {img_files}".format(url=url, cap_count=cap_count, img_files=img_files)
os.system(cmd)

保存视频

下面程序可以保存一段10秒视频,文件名为video.mp4,如果需要修改视频时长,可以把duration改成其他数字。

import os

user = '>>'
pwd = '>>'
host = '>>'
port = 554
duration = 10
video_files = 'video.mp4'

url = "rtsp://{user}:{pwd}@{host}:{port}/Streaming/Channels/101".format(user=user, pwd=pwd, host=host, port=port)

cmd = "ffmpeg -rtsp_transport tcp -y -t {duration} -i \"{url}\" -acodec copy -vcodec copy -hide_banner -loglevel error -an {video_files}".format(url=url, duration=duration, video_files=video_files)
os.system(cmd)

FFmpeg RTSP完整命令参考

下面整理了使用FFmpeg处理RTSP流时最常用的参数和命令格式。

核心参数说明

参数说明示例
-rtsp_transport指定传输协议tcp(推荐)或udp
-i输入源RTSP URL
-t录制时长(秒)-t 30表示30秒
-vframes保存的帧数(图片数量)-vframes 1保存一张图
-vcodec视频编码器copy(直接复制)或libx264
-acodec音频编码器copyaac
-an去掉音频录像时不需要音频可加此参数
-y覆盖已有文件不询问直接覆盖
-r帧率-r 1表示每秒1帧
-s分辨率-s 1280x720

FFmpeg RTSP常用命令模板

# 基础命令:从RTSP流截取一张图片
ffmpeg -rtsp_transport tcp -y -i "rtsp://user:pwd@ip:554/stream" -vframes 1 snapshot.jpg

# 录制10秒视频
ffmpeg -rtsp_transport tcp -y -t 10 -i "rtsp://user:pwd@ip:554/stream" -c copy output.mp4

# 以H.264重新编码并压缩(文件更小)
ffmpeg -rtsp_transport tcp -y -t 30 -i "rtsp://user:pwd@ip:554/stream" -vcodec libx264 -crf 23 compressed.mp4

# 截图并调整分辨率
ffmpeg -rtsp_transport tcp -y -i "rtsp://user:pwd@ip:554/stream" -vframes 1 -s 640x480 small.jpg

定时截图:使用Cron实现每隔N秒拍照

在实际监控应用中,我们经常需要每隔一段时间拍一张照片保存下来。

方法一:使用Linux Cron定时任务

创建一个截图脚本snapshot.sh

#!/bin/bash
# snapshot.sh - 从RTSP流截取一张图片

USER='admin'
PWD='password'
HOST='192.168.1.100'
PORT=554
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
OUTPUT_DIR="/home/user/snapshots"

mkdir -p "$OUTPUT_DIR"

URL="rtsp://${USER}:${PWD}@${HOST}:${PORT}/Streaming/Channels/101"

ffmpeg -rtsp_transport tcp -y -i "$URL" -vframes 1 "${OUTPUT_DIR}/snapshot_${TIMESTAMP}.jpg" 2>/dev/null

给脚本添加执行权限:

chmod +x snapshot.sh

编辑crontab,设置每分钟执行一次:

crontab -e

添加以下行:

# 每分钟从摄像头截取一张图片
* * * * * /home/user/snapshot.sh

如果只想在工作时间(9:00-18:00)截图:

# 周一到周五,9:00到18:00,每分钟截图
* 9-18 * * 1-5 /home/user/snapshot.sh

方法二:Python循环截图(更灵活)

import os
import time
from datetime import datetime

user = 'admin'
pwd = 'password'
host = '192.168.1.100'
port = 554
interval = 60  # 每60秒截图一次
output_dir = '/home/user/snapshots'

os.makedirs(output_dir, exist_ok=True)

url = f"rtsp://{user}:{pwd}@{host}:{port}/Streaming/Channels/101"

while True:
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    output_file = f"{output_dir}/snapshot_{timestamp}.jpg"

    cmd = f'ffmpeg -rtsp_transport tcp -y -i "{url}" -vframes 1 "{output_file}" 2>/dev/null'
    os.system(cmd)

    print(f"截图已保存: {output_file}")
    time.sleep(interval)

录制指定时长的视频到MP4

上面的保存视频示例已经给出了基本用法,这里补充一些实用选项:

import os

user = 'admin'
pwd = 'password'
host = '192.168.1.100'
port = 554

url = f"rtsp://{user}:{pwd}@{host}:{port}/Streaming/Channels/101"

# 录制60秒视频,直接复制编码流(最快,文件较大)
cmd = f'ffmpeg -rtsp_transport tcp -y -t 60 -i "{url}" -c copy output_copy.mp4'
os.system(cmd)

# 录制60秒视频,使用H.264重新编码(压缩率高,文件较小)
cmd = f'ffmpeg -rtsp_transport tcp -y -t 60 -i "{url}" -vcodec libx264 -crf 23 output_compressed.mp4'
os.system(cmd)

# 录制并包含音频
cmd = f'ffmpeg -rtsp_transport tcp -y -t 60 -i "{url}" -c copy output_with_audio.mp4'
os.system(cmd)

# 分段录制(每小时一个文件,自动命名)
cmd = f'ffmpeg -rtsp_transport tcp -y -i "{url}" -c copy -f segment -segment_time 3600 -strftime 1 "recording_%Y%m%d_%H%M%S.mp4"'
os.system(cmd)

处理连接断开:自动重连

RTSP连接可能因为网络不稳定而中断,以下方法可以实现自动重连:

方法一:使用FFmpeg的-reconnect参数

ffmpeg -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5 \
  -rtsp_transport tcp -i "rtsp://user:pwd@ip:554/stream" \
  -c copy -f segment -segment_time 3600 output_%03d.mp4

方法二:Python自动重连脚本

import os
import time
import subprocess

user = 'admin'
pwd = 'password'
host = '192.168.1.100'
port = 554
url = f"rtsp://{user}:{pwd}@{host}:{port}/Streaming/Channels/101"

def record_with_reconnect(url, duration=3600, max_retries=5):
    """录制视频,断开后自动重连"""
    retry_count = 0

    while retry_count < max_retries:
        output_file = f"recording_{int(time.time())}.mp4"
        cmd = [
            'ffmpeg', '-rtsp_transport', 'tcp',
            '-y', '-t', str(duration),
            '-i', url,
            '-c', 'copy', '-an',
            '-loglevel', 'error',
            output_file
        ]

        print(f"开始录制: {output_file} (尝试 {retry_count + 1}/{max_retries})")
        result = subprocess.run(cmd)

        if result.returncode == 0:
            print("录制完成")
            retry_count = 0  # 成功录制,重置重试计数
        else:
            retry_count += 1
            wait_time = min(30, 5 * retry_count)  # 递增等待时间
            print(f"录制失败,{wait_time}秒后重试...")
            time.sleep(wait_time)

    print("已达最大重试次数,停止录制")

# 每小时录制一段,断开自动重连
while True:
    record_with_reconnect(url, duration=3600)

批量处理多个摄像头

如果你有多个摄像头需要同时录制或截图,可以编写批量处理脚本:

import os
import subprocess
from datetime import datetime

# 摄像头配置列表
cameras = [
    {
        'name': 'front_door',
        'url': 'rtsp://admin:pwd@192.168.1.100:554/Streaming/Channels/101'
    },
    {
        'name': 'backyard',
        'url': 'rtsp://admin:pwd@192.168.1.101:554/Streaming/Channels/101'
    },
    {
        'name': 'garage',
        'url': 'rtsp://admin:pwd@192.168.1.102:554/Streaming/Channels/101'
    }
]

output_dir = '/home/user/multi_camera'

def snapshot_all_cameras():
    """对所有摄像头同时截图"""
    os.makedirs(output_dir, exist_ok=True)
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")

    processes = []
    for cam in cameras:
        output_file = f"{output_dir}/{cam['name']}_{timestamp}.jpg"
        cmd = [
            'ffmpeg', '-rtsp_transport', 'tcp',
            '-y', '-i', cam['url'],
            '-vframes', '1',
            '-loglevel', 'error',
            output_file
        ]
        # 使用subprocess.Popen实现并行截图
        p = subprocess.Popen(cmd)
        processes.append((cam['name'], p))

    # 等待所有截图完成
    for name, p in processes:
        p.wait()
        print(f"{name} 截图完成")

def record_all_cameras(duration=60):
    """对所有摄像头同时录制"""
    os.makedirs(output_dir, exist_ok=True)
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")

    processes = []
    for cam in cameras:
        output_file = f"{output_dir}/{cam['name']}_{timestamp}.mp4"
        cmd = [
            'ffmpeg', '-rtsp_transport', 'tcp',
            '-y', '-t', str(duration),
            '-i', cam['url'],
            '-c', 'copy', '-an',
            '-loglevel', 'error',
            output_file
        ]
        p = subprocess.Popen(cmd)
        processes.append((cam['name'], p))
        print(f"开始录制 {name}")

    for name, p in processes:
        p.wait()
        print(f"{name} 录制完成")

# 执行批量截图
snapshot_all_cameras()

常见错误及解决方案

错误1:Connection timed out(连接超时)

原因:网络不通或摄像头未启用RTSP,或者使用了UDP传输模式被防火墙拦截。

解决方案

# 使用TCP传输代替UDP
ffmpeg -rtsp_transport tcp -i "rtsp://..."

# 增加超时时间
ffmpeg -rtsp_transport tcp -stimeout 10000000 -i "rtsp://..."

错误2:Protocol not found(协议未找到)

原因:FFmpeg编译时未包含RTSP支持。

解决方案

# 检查FFmpeg是否支持RTSP
ffmpeg -protocols | grep rtsp

# 如果不支持,需要重新编译FFmpeg或安装完整版本
sudo apt install ffmpeg  # 使用包管理器安装通常包含RTSP支持

错误3:Invalid data found when processing input(输入数据无效)

原因:摄像头编码格式与FFmpeg不兼容,或者码流类型不对(主码流vs子码流)。

解决方案

# 先查看摄像头的视频流信息
ffprobe -rtsp_transport tcp -i "rtsp://user:pwd@ip:554/stream"

# 尝试使用子码流(通常兼容性更好)
# 海康:将101改102,大华:将subtype=0改subtype=1

错误4:Output file does not contain any stream(输出文件无内容)

原因:摄像头推流了但FFmpeg未能正确解码。

解决方案

# 添加-an去掉音频(某些摄像头音频编码不支持)
ffmpeg -rtsp_transport tcp -y -t 10 -i "rtsp://..." -c copy -an output.mp4

# 强制指定输入格式
ffmpeg -rtsp_transport tcp -f rtsp -i "rtsp://..." -c copy output.mp4

错误5:录制文件无法播放

原因:录制过程中程序被强制杀死,MP4文件没有写入moov atom(文件索引信息)。

解决方案

# 方法一:使用-movflags +faststart或-movflags +frag_keyframe+empty_moov
ffmpeg -rtsp_transport tcp -y -i "rtsp://..." -c copy -movflags +faststart output.mp4

# 方法二:录制为MKV格式(MKV对中断更友好)
ffmpeg -rtsp_transport tcp -y -i "rtsp://..." -c copy output.mkv

# 方法三:使用ts格式(适合流式录制)
ffmpeg -rtsp_transport tcp -y -i "rtsp://..." -c copy output.ts

希望这些补充内容能帮助你更灵活地使用FFmpeg处理RTSP监控摄像头的视频流!