环境
- python 3.11.8
- opencv-python == 4.9.0.80
- numpy == 1.26.4
通过rtsp协议拉流
有一个问题就是如果要同时拉流保存与同时保存最近1分钟视频的需求,会触发一个问题。当写入视频的时候同时读取回抛错。目前是采取每10秒钟保存视频的方式保存。
而且有个采用opencv拼接视频效率并不高
如果是采用opencv读取视频后转存为另一部视频时在cv2.waitkey(1000 // 帧率),不然会出现另存的视频播放速度快的问题
import datetime
import math
import os
import cv2
import time
username = 'username'
password = 'password'
ip = '192.168.1.101'
# 显示的视频分辨率
show_width = 1600
show_height = 800
# 保存的视频分辨率
save_width = 1920
save_height = 1080
# 每个厂商的视频流地址不一定相同,示例使用的海康威视的摄像头
url = f'rtsp://{username}:{password}@{ip}/Stream2'
# url = f'rtsp://{username}:{password}@{ip}/Streaming/channels/1'
# 通过rtsp协议获取码流数据
cap = cv2.VideoCapture(url)
# 获取视频分辨率与帧率
old_width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
old_height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
old_fps = cap.get(cv2.CAP_PROP_FPS)
print(f'{old_width}@{old_height} {old_fps}')
# 设置视频保存的编码格式
fourcc = cv2.VideoWriter.fourcc(*'mp4v')
# 保存视频播放倍率
play_speed = 1.0
play_interval = int(round(1000 / old_fps * play_speed))
# 判断展示分辨率与保存分辨率
if show_width > old_width and show_height > old_height:
show_width, show_height = old_width, old_height
if save_width > old_width and save_height > old_height:
save_width, save_height = old_width, old_height
curr_time = datetime.datetime.now()
curr_time_minutes_fmt = curr_time.strftime('%Y%m%d%H%M')
curr_time_second = curr_time.second // 10
curr_time_second_fmt = curr_time.strftime(f'%Y%m%d%H%M{curr_time_second}')
last_time = curr_time - datetime.timedelta(minutes=1)
last_time_second_fmt = last_time.second // 10
last_time_fmt = last_time.strftime(f'%Y%m%d%H%M{last_time_second_fmt}')
video_field_path = os.path.join('./Video', ip, curr_time_minutes_fmt)
if not os.path.exists(video_field_path):
os.mkdir(video_field_path)
video_file_path = os.path.join(video_field_path, f'{curr_time_second_fmt}@{int(old_fps)}.mp4')
out_frame = cv2.VideoWriter(video_file_path, fourcc, math.floor(old_fps), (int(save_width), int(save_height)))
while True:
curr_time = datetime.datetime.now()
pre_time = curr_time - datetime.timedelta(minutes=1)
pre_time_second_fmt = pre_time.second // 10
pre_time_fmt = pre_time.strftime(f'%Y%m%d%H%M{pre_time_second_fmt}')
# 按每分钟去保存数据
if last_time_fmt != pre_time_fmt:
curr_time_second_fmt = curr_time.second // 10
curr_time_minutes_fmt = curr_time.strftime(f'%Y%m%d%H%M')
curr_time_fmt = curr_time.strftime(f'%Y%m%d%H%M{curr_time_second_fmt}')
print(curr_time_fmt, pre_time_fmt, last_time_fmt)
out_frame.release()
last_time_fmt = pre_time_fmt
video_field_path = os.path.join('./Video', ip, curr_time_minutes_fmt)
if not os.path.exists(video_field_path):
os.mkdir(video_field_path)
video_file_path = os.path.join(video_field_path, f'{curr_time_fmt}@{int(old_fps)}.mp4')
out_frame = cv2.VideoWriter(video_file_path, fourcc, math.floor(old_fps),
(int(save_width), int(save_height)))
list_dir = os.listdir(os.path.join('./Video', ip))
if len(list_dir) > 10:
datetime_video = list(filter(lambda x: str(x).isdigit(), list_dir))
first_video_dir = list(sorted(datetime_video, key=lambda x: int(str(x))))[0]
remove_video_dir = os.path.join('./Video', ip, first_video_dir)
print(remove_video_dir)
for video_file in os.listdir(remove_video_dir):
video_file_path = os.path.join(remove_video_dir, video_file)
os.remove(video_file_path)
os.rmdir(remove_video_dir)
ret, frame = cap.read()
if not ret:
break
save_img = cv2.resize(frame, (int(save_width), int(save_height)))
show_img = cv2.resize(frame, (int(show_width), int(show_height)))
out_frame.write(save_img)
cv2.imshow('hk_video', show_img)
current_time = time.time()
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
cap.release()
out_frame.release()