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

如何让Python脚本通过命令行接收多个RTSP地址并同时显示视频?

解决Python多RTSP流同时播放的问题

你遇到的问题主要出在命令行参数解析和多进程管理这两个核心部分,下面我帮你梳理问题根源并给出修复后的完整方案:

问题根源分析

  1. 参数解析不支持多URI:原代码的--uri参数只能接收单个地址,无法处理命令行传入的多个RTSP链接
  2. 多进程串行执行:原代码在循环里启动进程后立刻调用process.join(),这会导致当前主进程等待子进程完全结束后才启动下一个,最终只能逐个播放视频流

修复后的完整代码

import sys
import argparse
import cv2
from multiprocessing import Process

WINDOW_NAME_PREFIX = 'Network Camera Demo - '

def parse_args():
    # Parse input arguments
    desc = 'Capture and display live video feed from multiple RTSP streams'
    parser = argparse.ArgumentParser(description=desc)
    parser.add_argument('--rtsp', dest='use_rtsp', help='use IP CAM (remember to also set --uri)', action='store_true')
    # 修改参数配置,支持一次性接收多个RTSP URI
    parser.add_argument('--uri', dest='rtsp_uri', help='RTSP URI(s), e.g. rtsp://192.168.1.64:554', default=[], type=str, nargs='+')
    parser.add_argument('--latency', dest='rtsp_latency', help='latency in ms for RTSP [200]', default=25, type=int)
    parser.add_argument('--width', dest='image_width', help='image width [1920]', default=1920, type=int)
    parser.add_argument('--height', dest='image_height', help='image height [1080]', default=1080, type=int)
    args = parser.parse_args()
    return args

def open_cam_rtsp(uri, width, height, latency):
    gst_str = ('rtspsrc location={} latency={} ! '
               'rtph264depay ! h264parse ! omxh264dec ! '
               'nvvidconv ! '
               'video/x-raw, width=(int){}, height=(int){}, '
               'format=(string)BGRx ! '
               'videoconvert ! appsink').format(uri, latency, width, height)
    return cv2.VideoCapture(gst_str, cv2.CAP_GSTREAMER)

def open_window(window_name, width, height, window_idx):
    # 每个流使用独立窗口名称,避免冲突
    cv2.namedWindow(window_name, cv2.WINDOW_NORMAL)
    cv2.resizeWindow(window_name, width, height)
    # 窗口错开排列,方便同时查看多个流
    cv2.moveWindow(window_name, window_idx * width//2, 0)
    cv2.setWindowTitle(window_name, f'Network Cam Demo - Stream {window_idx+1}')

def read_cam(cap, window_name):
    show_help = True
    full_scrn = False
    help_text = '"Esc" to Quit, "H" for Help, "F" to Toggle Fullscreen'
    font = cv2.FONT_HERSHEY_PLAIN
    while True:
        if cv2.getWindowProperty(window_name, 0) < 0:
            # 检查当前窗口是否被用户关闭
            break
        _, img = cap.read() # 获取下一帧图像
        if img is None:
            print(f"Failed to read frame from stream: {window_name}")
            break
        if show_help:
            cv2.putText(img, help_text, (11, 20), font, 1.0, (32, 32, 32), 4, cv2.LINE_AA)
            cv2.putText(img, help_text, (10, 20), font, 1.0, (240, 240, 240), 1, cv2.LINE_AA)
        cv2.imshow(window_name, img)
        key = cv2.waitKey(10)
        if key == 27: # ESC键退出当前流
            break
        elif key == ord('h') or key == ord('H'): # H键切换帮助文本显示
            show_help = not show_help
        elif key == ord('f') or key == ord('F'): # F键切换全屏模式
            full_scrn = not full_scrn
            cv2.setWindowProperty(window_name, cv2.WND_PROP_FULLSCREEN, 
                                  cv2.WINDOW_FULLSCREEN if full_scrn else cv2.WINDOW_NORMAL)

def main(rtsp_uri, args, window_idx):
    window_name = f"{WINDOW_NAME_PREFIX}{window_idx+1}"
    print(f'Starting stream {window_idx+1}: {rtsp_uri}')
    print('OpenCV version: {}'.format(cv2.__version__))
    cap = open_cam_rtsp(rtsp_uri, args.image_width, args.image_height, args.rtsp_latency)
    if not cap.isOpened():
        print(f'Failed to open camera stream {window_idx+1}: {rtsp_uri}')
        return
    open_window(window_name, args.image_width, args.image_height, window_idx)
    read_cam(cap, window_name)
    cap.release()
    cv2.destroyWindow(window_name)

if __name__ == '__main__':
    args = parse_args()
    
    if not args.use_rtsp or not args.rtsp_uri:
        print("Please use --rtsp flag and provide at least one --uri RTSP address")
        sys.exit(1)
    
    processes = []
    # 批量启动所有流的进程
    for idx, rtsp_uri in enumerate(args.rtsp_uri):
        # 注意args需要传元组,末尾逗号不能省略
        process = Process(target=main, args=(rtsp_uri, args, idx))
        processes.append(process)
        process.start()
    
    # 等待所有进程执行完成
    for process in processes:
        process.join()
    
    # 最后清理所有残留窗口
    cv2.destroyAllWindows()

关键改动说明

  1. 参数解析优化:

    • 给--uri参数添加nargs='+'配置,支持一次性传入多个RTSP地址,命令行使用格式:
      python rtsp.py --rtsp --uri rtsp://admin:password@192.168.1.63:554 rtsp://admin:password@192.168.1.61:554 rtsp://admin:password@192.168.1.62:554
      
    • 如果需要支持多次使用--uri(比如--uri xxx --uri yyy),可以再加上action='append'配置。
  2. 多进程并行修复:

    • 先将所有进程加入列表统一启动,最后再批量调用join(),确保所有流进程同时并行运行,不再串行等待。
    • 给每个进程传递独立的窗口索引,生成唯一窗口名称,避免窗口冲突,同时自动错开窗口位置方便查看。
  3. 流与窗口稳定性优化:

    • 每个流的窗口独立控制,关闭单个窗口只会终止对应流,不影响其他流播放。
    • 增加帧读取失败的判断逻辑,避免因单个流异常导致整个程序崩溃。
    • 保留了帮助文本、全屏切换等交互功能,每个窗口可独立操作。

现在运行修改后的脚本,就能同时播放多个RTSP视频流了!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:44:18