获取视频地址:
f"rtsp://{u}:{p}@{ip}:554/Streaming/Channels/101",
f"rtsp://{u}:{p}@{ip}:554/h264/ch1/main/av_stream",
f"rtsp://{ip}:554/user={u}&password={p}&channel=1&stream=0.sdp"
]
sub = [
f"rtsp://{u}:{p}@{ip}:554/Streaming/Channels/102",
f"rtsp://{u}:{p}@{ip}:554/h264/ch1/sub/av_stream",
f"rtsp://{ip}:554/user={u}&password={p}&channel=1&stream=1.sdp"

import tkinter as tk
from tkinter import ttk, messagebox
import cv2
from PIL import Image, ImageTk
import socket
class CameraApp:
def __init__(self, root):
self.root = root
self.root.title("网络摄像头专用播放器")
self.root.geometry("640x480")
self.root.resizable(False, False)
self.cap = None
self.after_id = None
self.btn_lock = False
self.create_ui()
def create_ui(self):
top_frame = ttk.Frame(self.root)
top_frame.place(x=5, y=5, width=630, height=45)
ttk.Label(top_frame, text="IP:").grid(row=0, column=0, padx=3)
self.ent_ip = ttk.Entry(top_frame, width=18)
self.ent_ip.grid(row=0, column=1, padx=3)
self.ent_ip.insert(0, "192.168.111.234")
ttk.Label(top_frame, text="账号:").grid(row=0, column=2, padx=3)
self.ent_user = ttk.Entry(top_frame, width=12)
self.ent_user.grid(row=0, column=3, padx=3)
self.ent_user.insert(0, "admin")
ttk.Label(top_frame, text="密码:").grid(row=0, column=4, padx=3)
self.ent_pwd = ttk.Entry(top_frame, width=12, show="*")
self.ent_pwd.grid(row=0, column=5, padx=3)
self.ent_pwd.insert(0, "1q2w3e4r")
self.video_w = int(640 * 0.95)
self.video_h = int(345 * 0.95)
self.video_lab = ttk.Label(self.root, text="等待播放...")
self.video_lab.place(x=16, y=58, width=self.video_w, height=self.video_h)
btn_frame = ttk.Frame(self.root)
btn_frame.place(x=0, y=400, width=640, height=80)
self.btn_main = ttk.Button(btn_frame, text="主码流", command=self.play_main)
self.btn_sub = ttk.Button(btn_frame, text="子码流", command=self.play_sub)
self.btn_stop = ttk.Button(btn_frame, text="停止播放", command=self.stop_all)
self.btn_exit = ttk.Button(btn_frame, text="退出程序", command=self.exit_app)
self.btn_main.pack(side=tk.LEFT, padx=10)
self.btn_sub.pack(side=tk.LEFT, padx=10)
self.btn_stop.pack(side=tk.LEFT, padx=10)
self.btn_exit.pack(side=tk.LEFT, padx=10)
def lock_btn(self):
self.btn_lock = True
for btn in [self.btn_main, self.btn_sub, self.btn_stop]:
btn.config(state="disabled")
def unlock_btn(self):
self.btn_lock = False
for btn in [self.btn_main, self.btn_sub, self.btn_stop]:
btn.config(state="normal")
def check_camera(self):
ip = self.ent_ip.get().strip()
if not ip:
messagebox.showwarning("提示", "请输入IP")
return False
try:
for p in [554, 80]:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(1)
if s.connect_ex((ip, p)) == 0:
s.close()
return True
s.close()
except:
pass
messagebox.showerror("错误", "摄像头不在线或未开启RTSP/ONVIF")
return False
def stop_all(self):
self.lock_btn()
if self.after_id:
self.root.after_cancel(self.after_id)
self.after_id = None
if self.cap:
try:
self.cap.release()
except:
pass
self.cap = None
self.video_lab.config(image="", text="已停止")
self.unlock_btn()
def get_rtsp_urls(self, is_main):
ip = self.ent_ip.get().strip()
u = self.ent_user.get().strip()
p = self.ent_pwd.get().strip()
main = [
f"rtsp://{u}:{p}@{ip}:554/Streaming/Channels/101",
f"rtsp://{u}:{p}@{ip}:554/h264/ch1/main/av_stream",
f"rtsp://{ip}:554/user={u}&password={p}&channel=1&stream=0.sdp"
]
sub = [
f"rtsp://{u}:{p}@{ip}:554/Streaming/Channels/102",
f"rtsp://{u}:{p}@{ip}:554/h264/ch1/sub/av_stream",
f"rtsp://{ip}:554/user={u}&password={p}&channel=1&stream=1.sdp"
]
return main if is_main else sub
def try_play(self, is_main):
urls = self.get_rtsp_urls(is_main)
for url in urls:
try:
cap = cv2.VideoCapture(url, cv2.CAP_FFMPEG)
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
if cap.isOpened():
self.cap = cap
return True
cap.release()
except:
continue
return False
def play_main(self):
if self.btn_lock: return
self.lock_btn()
if not self.check_camera():
self.unlock_btn()
return
self.stop_all()
if self.try_play(is_main=True):
self.update_frame()
else:
messagebox.showerror("失败", "无法打开视频,请核对账号密码与码流设置")
self.unlock_btn()
def play_sub(self):
if self.btn_lock: return
self.lock_btn()
if not self.check_camera():
self.unlock_btn()
return
self.stop_all()
if self.try_play(is_main=False):
self.update_frame()
else:
messagebox.showerror("失败", "无法打开视频,请核对账号密码与码流设置")
self.unlock_btn()
def update_frame(self):
if not self.cap or not self.cap.isOpened():
self.unlock_btn()
return
ret, frame = self.cap.read()
if ret:
frame = cv2.resize(frame, (self.video_w, self.video_h))
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
imgtk = ImageTk.PhotoImage(Image.fromarray(frame))
self.video_lab.imgtk = imgtk
self.video_lab.config(image=imgtk, text="")
self.unlock_btn()
self.after_id = self.root.after(30, self.update_frame)
def exit_app(self):
self.stop_all()
self.root.destroy()
if __name__ == "__main__":
win = tk.Tk()
app = CameraApp(win)
win.mainloop()