I’m developing a Python module, with OpenCV, that connects to an RTSP stream to perform some preprocessing on the video (mostly, reducing fps and resolution), and then store it in the file system.
But, even after trying several codecs, looking for similar developments… I always end up with an empty video. I’ve seen this other thread (cv::VideoWriter yields unreadable video), which may be similar, but was developed on C++.
Has anyone worked on this? I normally use a sample RTSP stream as reference, such as rtsp://freja.hiof.no:1935/rtplive/definst/hessdalen03.stream, and can receive and even watch the stream from VLC correctly.
I’ve seen quite a lot of threads discussing how to capture video from an RTSP stream, or how to work with VideoWriters and VideoReaders classes and video files, but almost nothing combining the two.
Any help would be highly appreciated 🙂 Thanks!!
Edit 1: Sample code used to store the frames.
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import cv2 import numpy # Test frame. width, height = 400, 300 width_2, height_2 = int(width / 2), int(height / 2) frame = numpy.zeros((height, width, 3), numpy.uint8) cv2.rectangle(frame, (0, 0), (width_2, height_2), (255, 0, 0), cv2.FILLED) cv2.rectangle(frame, (width_2, height_2), (width, height), (0, 255, 0), cv2.FILLED) frames = [frame for _ in range(100)] fps = 25 # Define the codec. #fourcc = cv2.VideoWriter_fourcc(*'X264') #fourcc = cv2.VideoWriter_fourcc(*'XVID') fourcc = cv2.VideoWriter_fourcc(*'MJPG') # Create VideoWriter object out = cv2.VideoWriter(filename='video.avi', fourcc=fourcc, apiPreference=cv2.CAP_FFMPEG, fps=float(fps), frameSize=(width, height), isColor=True) result = 0 for frame in frames: result += 0 if out.write(frame) is None else 1 print(result) out.release()
Edit 2: Solution
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import cv2 import numpy # Test frame. width, height = 400, 300 width_2, height_2 = int(width / 2), int(height / 2) frame1 = numpy.zeros((height, width, 3), numpy.uint8) cv2.rectangle(frame1, (0, 0), (width_2, height_2), (255, 0, 0), cv2.FILLED) cv2.rectangle(frame1, (width_2, height_2), (width, height), (0, 255, 0), cv2.FILLED) cv2.imwrite('frame1.jpg', frame1) frame2 = numpy.zeros((height, width, 3), numpy.uint8) cv2.rectangle(frame2, (width_2, 0), (width, height_2), (255, 0, 0), cv2.FILLED) cv2.rectangle(frame2, (0, height_2), (width_2, height), (0, 255, 0), cv2.FILLED) cv2.imwrite('frame2.jpg', frame2) range1 = [frame1 for _ in range(10)] range2 = [frame2 for _ in range(10)] frames = range1 + range2 + range1 + range2 + range1 fps = 2 # Define the codec. fourcc = cv2.VideoWriter_fourcc(*'MJPG') # Create VideoWriter object out = cv2.VideoWriter('video.avi', fourcc, float(fps), (width, height)) for frame in frames: out.write(frame) out.release()
Here’s a RTSP stream to video widget. I would recommend creating another thread for obtaining the frames as
cv2.VideoCapture.read() is blocking. This can be expensive and cause latency as the main thread has to wait until it has obtained a frame. By putting this operation into a separate thread that just focuses on grabbing frames and processing/saving the frames in the main thread, it dramatically improves performance. You also can experiment with other codecs but using
MJPG should be safe since its built into OpenCV. I used my IP camera stream and saved the frames to
output.avi. Be sure to change
rtsp_stream_link to your own RTSP stream link. 🙂
from threading import Thread import cv2 class RTSPVideoWriterObject(object): def __init__(self, src=0): # Create a VideoCapture object self.capture = cv2.VideoCapture(src) # Default resolutions of the frame are obtained (system dependent) self.frame_width = int(self.capture.get(3)) self.frame_height = int(self.capture.get(4)) # Set up codec and output video settings self.codec = cv2.VideoWriter_fourcc('M','J','P','G') self.output_video = cv2.VideoWriter('output.avi', self.codec, 30, (self.frame_width, self.frame_height)) # Start the thread to read frames from the video stream self.thread = Thread(target=self.update, args=()) self.thread.daemon = True self.thread.start() 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() def show_frame(self): # Display frames in main program if self.status: cv2.imshow('frame', self.frame) # Press Q on keyboard to stop recording key = cv2.waitKey(1) if key == ord('q'): self.capture.release() self.output_video.release() cv2.destroyAllWindows() exit(1) def save_frame(self): # Save obtained frame into video output file self.output_video.write(self.frame) if __name__ == '__main__': rtsp_stream_link = 'your stream link!' video_stream_widget = RTSPVideoWriterObject(rtsp_stream_link) while True: try: video_stream_widget.show_frame() video_stream_widget.save_frame() except AttributeError: pass
Related camera/IP/RTSP/streaming, FPS, video, threading, and multiprocessing posts
Answered By – nathancy
Answer Checked By – Willingham (AngularFixing Volunteer)