我有一个通过以太网使用rtsp协议的网络摄像机,解码格式是h.264。当我录制rtsp视频时,延迟约为1~2秒。
规格:raspberrypi 4b/RAM 8GB/SDcard 32GB A1 蟒蛇3.11.2/opencv 4.9.0 GPU内存=256
已尝试过:CAP_GStreamer延迟2.5秒
预期:录制rtsp,延迟300~500ms
当前方法:
import cv2
import sys
import os
#need this line to be work
os.environ["OPENCV_FFMPEG_CAPTURE_OPTIONS"] = "rtsp_transport;udp"
# rtsp url
rtsp_url = "rtsp://192.168.144.25:8554/main.264"
# create viedoCapture
cap = cv2.VideoCapture(rtsp_url)
# check video is open or not
if not cap.isOpened():
print("Error: Could not open RTSP stream.")
sys.exit()
# get video info
fps = int(cap.get(cv2.CAP_PROP_FPS))
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# use h.264 to encode video
fourcc = cv2.VideoWriter_fourcc(*'H264')
out = None
recording = False
# show and save video
while True:
ret, frame = cap.read()
if not ret:
print("Error: Could not read frame.")
break
cv2.imshow('RTSP Stream', frame)
# record mode
if recording:
if out is None:
out = cv2.VideoWriter('output.mp4', fourcc, fps, (width, height))
out.write(frame)
key = cv2.waitKey(1) & 0xFF
# press q to quit
if key == ord('q'):
break
# press r to switch record mode
elif key == ord('r'):
recording = not recording
if recording:
print("Recording started.")
else:
print("Recording stopped.")
if out is not None:
out.release()
out = None
# press p to photo
elif key == ord('p'):
cv2.imwrite('photo.jpg', frame)
print("Photo taken.")
# release source
cap.release()
if out is not None:
out.release()
cv2.destroyAllWindows()
问题已解决:以下代码可以解决录制时延迟查看的问题。
新问题:在ffplay或vlc上播放录制的视频已经从20秒减少到5秒,每次动作看起来都很快。我猜可能是写入数据时丢帧了。
猜测方法:我建议在开始录制时,队列需要采集一帧,并按队列写入数据。当录制停止时,队列停止收集帧。但我不知道该怎么做。
from threading import Thread
import imutils
import cv2, time
import sys
camlink1 = "rtsp://192.168.144.25:8554/main.264"
class VideoStreamWidget(object):
def __init__(self, link, camname, src=0):
self.capture = cv2.VideoCapture(link)
# Start the thread to read frames from the video stream
self.thread = Thread(target=self.update, args=())
self.thread.daemon = True
self.thread.start()
self.threadRecord=Thread(target=self.record,args=())
self.threadRecord.daemon=True
self.camname = camname
self.link = link
self.recording=False
self.out=None
print(camname)
print(link)
def update(self):
# Read the next frame from the stream in a different thread
while True:
if self.capture.isOpened():
(self.status, self.frame) = self.capture.read()
time.sleep(.01)
def show_frame(self):
# Display frames in main program
#frame = imutils.resize(self.frame, width=400)
cv2.imshow('Frame ' + self.camname, self.frame)
def closewindow(self):
self.capture.release()
cv2.destroyAllWindows()
sys.exit(0)
def record(self):
while True:
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
fps = int(self.capture.get(cv2.CAP_PROP_FPS))
width = int(self.capture.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(self.capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
#self.recording=not self.recording
if not self.recording:
if self.out is not None:
self.out.release()
self.out = None
return
if self.recording:
if self.out is None:
self.out = cv2.VideoWriter('output_test.mp4', fourcc, fps, (width, height))
self.out.write(self.frame)
time.sleep(1/fps)
if __name__ == '__main__':
video_stream_widget = VideoStreamWidget(camlink1,"Cam1")
while True:
try:
video_stream_widget.show_frame()
key=cv2.waitKey(1)
if key==ord('q'):
video_stream_widget.closewindow()
elif key==ord('r'):
video_stream_widget.recording=not video_stream_widget.recording
if not video_stream_widget.threadRecord.is_alive():
video_stream_widget.threadRecord.start()
except AttributeError:
pass