cv2.VideoWriter issues - python

I'm looking to record a Twitch Livestream by feeding it the direct livestream url using streamlink.streams(url) (which returns a .m3u8 url). With this, I have no problem reading the stream and even writing a few images from it, but when it comes to writing it as a video, I get errors.
P.S.: Yes, I know there's other options like Streamlink and yt-dwl, but I want to operate solely in python, not using CLI... which I believe those two are only dealing with (for recording).
Here's what I currently have:
if streamlink.streams(url):
stream = streamlink.streams(url)['best']
stream = str(stream).split(', ')
stream = stream[1].strip("'")
cap = cv2.VideoCapture(stream)
gst_out = "appsrc ! video/x-raw, format=BGR ! queue ! nvvidconv ! omxh264enc ! h264parse ! qtmux ! filesink location=stream "
out = cv2.VideoWriter(gst_out, cv2.VideoWriter_fourcc(*'mp4v'), 30, (1920, 1080))
while True:
_, frame = cap.read()
out.write(frame)
For this code, I get this error msg:
[tls # 0x1278a74f0] Error in the pull function.
And if I remove gst_out and feed stream instead as well as moving cap and out into the while loop like so:
if streamlink.streams(url):
stream = streamlink.streams(url)['best']
stream = str(stream).split(', ')
stream = stream[1].strip("'")
while True:
cap = cv2.VideoCapture(stream)
_, frame = cap.read()
out = cv2.VideoWriter(stream, cv2.VideoWriter_fourcc(*'mp4v'), 30, (1920, 1080))
out.write(frame)
I get:
OpenCV: FFMPEG: tag 0x7634706d/'mp4v' is not supported with codec id 12 and format 'hls / Apple HTTP Live Streaming'
What am I missing here?

The fist part uses GStreamer syntax, and OpenCV for Python is most likely not built with GStreamer.
The answer is going to be focused on the second part (also because I don't know GStreamer so well).
There are several issues:
cap = cv2.VideoCapture(stream) should be before the while True loop.
out = cv2.VideoWriter(stream, cv2.VideoWriter_fourcc(*'mp4v'), 30, (1920, 1080)) should be before the while True loop.
The first argument of cv2.VideoWriter should be MP4 file name, and not stream.
For getting a valid output file, we have to execute out.release() after the loop, but the loop may never end.
It is recommended to get frame size and rate of the input video, and set VideoWriter accordingly:
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = int(cap.get(cv2.CAP_PROP_FPS))
video_file_name = 'output.mp4'
out = cv2.VideoWriter(video_file_name, cv2.VideoWriter_fourcc(*'mp4v'), fps, (width, height)) # Open video file for writing
It is recommended to break the loop if ret is False:
ret, frame = cap.read()
if not ret:
break
One option to end the recording is when user press Esc key.
Break the loop if cv2.waitKey(1) == 27.
cv2.waitKey(1) is going to work only after executing cv2.imshow.
A simple solution is executing cv2.imshow every 30 frames (for example).
if (frame_counter % 30 == 0):
cv2.imshow('frame', frame) # Show frame every 30 frames (for testing)
if cv2.waitKey(1) == 27: # Press Esc for stop recording (cv2.waitKey is going to work only when cv2.imshow is used).
break
Complete code sample:
from streamlink import Streamlink
import cv2
def stream_to_url(url, quality='best'):
session = Streamlink()
streams = session.streams(url)
if streams:
return streams[quality].to_url()
else:
raise ValueError('Could not locate your stream.')
url = 'https://www.twitch.tv/noraexplorer' # Need to login to twitch.tv first (using the browser)...
quality='best'
stream_url = stream_to_url(url, quality) # Get the video URL
cap = cv2.VideoCapture(stream_url, cv2.CAP_FFMPEG) # Open video stream for capturing
# Get frame size and rate of the input video
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = int(cap.get(cv2.CAP_PROP_FPS))
video_file_name = 'output.mp4'
out = cv2.VideoWriter(video_file_name, cv2.VideoWriter_fourcc(*'mp4v'), fps, (width, height)) # Open video file for writing
frame_counter = 0
while True:
ret, frame = cap.read()
if not ret:
break
if (frame_counter % 30 == 0):
cv2.imshow('frame', frame) # Show frame every 30 frames (for testing)
out.write(frame) # Write frame to output.mp4
if cv2.waitKey(1) == 27: # Press Esc for stop recording (cv2.waitKey is going to work only when cv2.imshow is used).
break
frame_counter += 1
cap.release()
out.release()
cv2.destroyAllWindows()
Testing the setup using FFplay and subprocess module:
from streamlink import Streamlink
import subprocess
def stream_to_url(url, quality='best'):
session = Streamlink()
streams = session.streams(url)
if streams:
return streams[quality].to_url()
else:
raise ValueError('Could not locate your stream.')
#url = 'https://www.twitch.tv/noraexplorer' # Need to login to twitch.tv first (using the browser)...
url = 'https://www.twitch.tv/valorant'
quality='best'
stream_url = stream_to_url(url, quality) # Get the video URL
subprocess.run(['ffplay', stream_url])
Update:
Using ffmpeg-python for reading the video, and OpenCV for recording the video:
In cases where cv2.VideoCapture is not working, we may use FFmpeg CLI as sub-process.
ffmpeg-python module is Python binding for FFmpeg CLI.
Using ffmpeg-python is almost like using subprocess module, it used here mainly for simplifying the usage of FFprobe.
Using FFprobe for getting video frames resolution and framerate (without using OpenCV):
p = ffmpeg.probe(stream_url, select_streams='v');
width = p['streams'][0]['width']
height = p['streams'][0]['height']
r_frame_rate = p['streams'][0]['r_frame_rate'] # May return 60000/1001
if '/' in r_frame_rate:
fps = float(r_frame_rate.split("/")[0]) / float(r_frame_rate.split("/")[1]) # Convert from 60000/1001 to 59.94
elif r_frame_rate != '0':
fps = float(r_frame_rate)
else:
fps = 30 # Used as default
Getting the framerate may be a bit of a challenge...
Note: ffprobe CLI should be in the execution path.
Start FFmpeg sub-process with stdout as pipe:
ffmpeg_process = (
ffmpeg
.input(stream_url)
.video
.output('pipe:', format='rawvideo', pix_fmt='bgr24')
.run_async(pipe_stdout=True)
)
Note: ffmpeg CLI should be in the execution path.
Reading a frame from the pipe, and convert it from bytes to NumPy array:
in_bytes = ffmpeg_process.stdout.read(width*height*3)
frame = np.frombuffer(in_bytes, np.uint8).reshape([height, width, 3])
Closing FFmpeg sub-process:
Closing stdout pipe ends FFmpeg (with "broken pipe" error).
ffmpeg_process.stdout.close()
ffmpeg_process.wait() # Wait for the sub-process to finish
Complete code sample:
from streamlink import Streamlink
import cv2
import numpy as np
import ffmpeg
def stream_to_url(url, quality='best'):
session = Streamlink()
streams = session.streams(url)
if streams:
return streams[quality].to_url()
else:
raise ValueError('Could not locate your stream.')
#url = 'https://www.twitch.tv/noraexplorer' # Need to login to twitch.tv first (using the browser)...
url = 'https://www.twitch.tv/valorant'
quality='best'
stream_url = stream_to_url(url, quality) # Get the video URL
#subprocess.run(['ffplay', stream_url]) # Use FFplay for testing
# Use FFprobe to get video frames resolution and framerate.
################################################################################
p = ffmpeg.probe(stream_url, select_streams='v');
width = p['streams'][0]['width']
height = p['streams'][0]['height']
r_frame_rate = p['streams'][0]['r_frame_rate'] # May return 60000/1001
if '/' in r_frame_rate:
fps = float(r_frame_rate.split("/")[0]) / float(r_frame_rate.split("/")[1]) # Convert from 60000/1001 to 59.94
elif r_frame_rate != '0':
fps = float(r_frame_rate)
else:
fps = 30 # Used as default
#cap = cv2.VideoCapture(stream_url, cv2.CAP_FFMPEG) # Open video stream for capturing
#width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
#height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
#fps = int(cap.get(cv2.CAP_PROP_FPS))
################################################################################
# Use FFmpeg sub-process instead of using cv2.VideoCapture
################################################################################
ffmpeg_process = (
ffmpeg
.input(stream_url, an=None) # an=None applies -an argument (used for ignoring the input audio - it is not required, just more elegant).
.video
.output('pipe:', format='rawvideo', pix_fmt='bgr24')
.run_async(pipe_stdout=True)
)
################################################################################
video_file_name = 'output.mp4'
out = cv2.VideoWriter(video_file_name, cv2.VideoWriter_fourcc(*'mp4v'), fps, (width, height)) # Open video file for writing
frame_counter = 0
while True:
#ret, frame = cap.read()
in_bytes = ffmpeg_process.stdout.read(width*height*3) # Read raw video frame from stdout as bytes array.
if len(in_bytes) < width*height*3: #if not ret:
break
frame = np.frombuffer(in_bytes, np.uint8).reshape([height, width, 3]) # Convert bytes array to NumPy array.
if (frame_counter % 30 == 0):
cv2.imshow('frame', frame) # Show frame every 30 frames (for testing)
out.write(frame) # Write frame to output.mp4
if cv2.waitKey(1) == 27: # Press Esc for stop recording (cv2.waitKey is going to work only when cv2.imshow is used).
break
frame_counter += 1
#cap.release()
ffmpeg_process.stdout.close() # Close stdout pipe (it also closes FFmpeg).
out.release()
cv2.destroyAllWindows()
ffmpeg_process.wait() # Wait for the sub-process to finish
Note:
In case you care about the quality of the recorded video, using cv2.VideoWriter is not the best choice...

Related

Extract video frames in python using OpenCV

I want to break my video into frames.
I am using the following code:
import cv2
import numpy as np
import os
# Playing video from file:
cap = cv2.VideoCapture('myvideo.mp4')
cap.set(cv2.CAP_PROP_FPS, 5)
try:
if not os.path.exists('data'):
os.makedirs('data')
except OSError:
print ('Error: Creating directory of data')
currentFrame = 0
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
# Saves image of the current frame in jpg file
name = './data/frame' + str(currentFrame) + '.jpg'
print ('Creating...' + name)
cv2.imwrite(name, frame)
# To stop duplicate images
currentFrame += 1
if not ret: break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
I have set the FPS = 5 and 'myvideo.mp4' is 0:55 sec long. So, I'd expect to have 55*5 = 275 frames, but the code above gives me a lot more frames and it doesn't stop generating frames. Is something wrong in the code?
if you want a proper framerate you can do
framerate = vid.get(5)
instead of
cap.set(cv2.CAP_PROP_FPS, 5)
this will give you the exact framerate

Pipe opencv images to ffmpeg using python

How can I pipe openCV images to ffmpeg (running ffmpeg as a subprocess)?
(I am using spyder/anaconda)
I am reading frames from a video file and do some processing on each frame.
import cv2
cap = cv2.VideoCapture(self.avi_path)
img = cap.read()
gray = cv2.cvtColor(img[1], cv2.COLOR_BGR2GRAY)
bgDiv=gray/vidMed #background division
then, to pipe the processed frame to ffmpeg, I found this command in a related question:
sys.stdout.write( bgDiv.tostring() )
next, I am trying to run ffmpeg as a subprocess:
cmd='ffmpeg.exe -f rawvideo -pix_fmt gray -s 2048x2048 -r 30 -i - -an -f avi -r 30 foo.avi'
sp.call(cmd,shell=True)
(this also from the mentioned post)
However, this fills my IPython console with cryptic hieroglyphs and then crashes it. any advice?
ultimately, I would like to pipe out 4 streams and have ffmpeg encode those 4 streams in parallel.
I had similar problem once. I opened an issue on Github, turns out it may be a platform issue.
Related to your question, you can as well pipe OpenCV images to FFMPEG. Here's a sample code:
# This script copies the video frame by frame
import cv2
import subprocess as sp
input_file = 'input_file_name.mp4'
output_file = 'output_file_name.mp4'
cap = cv2.VideoCapture(input_file)
ret, frame = cap.read()
height, width, ch = frame.shape
ffmpeg = 'FFMPEG'
dimension = '{}x{}'.format(width, height)
f_format = 'bgr24' # remember OpenCV uses bgr format
fps = str(cap.get(cv2.CAP_PROP_FPS))
command = [ffmpeg,
'-y',
'-f', 'rawvideo',
'-vcodec','rawvideo',
'-s', dimension,
'-pix_fmt', 'bgr24',
'-r', fps,
'-i', '-',
'-an',
'-vcodec', 'mpeg4',
'-b:v', '5000k',
output_file ]
proc = sp.Popen(command, stdin=sp.PIPE, stderr=sp.PIPE)
while True:
ret, frame = cap.read()
if not ret:
break
proc.stdin.write(frame.tostring())
cap.release()
proc.stdin.close()
proc.stderr.close()
proc.wait()
I'm Kind of late, But my powerful VidGear Python Library automates the process of pipelining OpenCV frames into FFmpeg on any platform with its WriteGear API's Compression Mode. OP, You can implement your answer as follows:
# import libraries
from vidgear.gears import WriteGear
import cv2
output_params = {"-s":"2048x2048", "-r":30} #define FFmpeg tweak parameters for writer
stream = cv2.VideoCapture(0) #Open live webcam video stream on first index(i.e. 0) device
writer = WriteGear(output_filename = 'Output.mp4', compression_mode = True, logging = True, **output_params) #Define writer with output filename 'Output.mp4'
# infinite loop
while True:
(grabbed, frame) = stream.read()
# read frames
# check if frame empty
if not is grabbed:
#if True break the infinite loop
break
# {do something with frame here}
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# write a modified frame to writer
writer.write(gray)
# Show output window
cv2.imshow("Output Frame", frame)
key = cv2.waitKey(1) & 0xFF
# check for 'q' key-press
if key == ord("q"):
#if 'q' key-pressed break out
break
cv2.destroyAllWindows()
# close output window
stream.release()
# safely close video stream
writer.close()
# safely close writer
Source: https://abhitronix.github.io/vidgear/latest/gears/writegear/compression/usage/#using-compression-mode-with-opencv
You can check out VidGear Docs for more advanced applications and features.
Hope that helps!
You can use this pkg. ffmpegcv has Reader and Writer in ffmpeg backbone, similar to cv2.
#!pip install ffmpegcv
import ffmpegcv
vfile_in = 'A.mp4'
vfile_out = 'A_h264.mp4'
vidin = ffmpegcv.VideoCapture(vfile_in)
w, h = vidin.width, vidin.height
vidout = ffmpegcv.VideoWriter(vfile_out, 'h264_nvenc', vidin.fps, (w, h))
for frame in vidin:
vidout.write(frame)
vidin.release()
vidout.release()

Why is cv2.VideoCapture() returning sequences of duplicate frames on RPi Camera module (Using uv4l)

I'm using a Raspberry PI & RPi Camera Module to capture video for a line following robot. I'm using Opencv functions & the uv4l driver. My problem is I'm getting frames returned from cv2.VideoCapture in sequences of 4 identical frames resulting in a low frame rate of about 5 fps. Has anyone else come across this issue?
Here is code used for capturing video:
def open_camera(cam_id = 0):
cap = cv2.VideoCapture(cam_id)
cap.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, 240);
cap.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, 320);
cap.set(cv2.cv.CV_CAP_PROP_FPS, 30);
return cap
def get_frame(device):
ret, img = device.read()
if (ret == False): #failed to capture
print >> sys.stderr, "Error capturing from vid dev"
return None
return img
def run(wh,sh,wh2,sh2):
find_colour(wh,sh,wh2,sh2)
dev = open_camera(0)
while True:
img = get_frame(dev) # get frame from cam
if img is not None:# if possible to get imag
#program code
else: #if failed to cap
#print 'failed to cap'
controller.forward(128)#stop
break
return()

openCV video saving in python

I am trying to save the video but it's not working.
I followed the instructions from the openCV documentation.
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640,480))
while(cap.isOpened()):
ret, frame = cap.read()
if ret==True:
frame = cv2.flip(frame,0)
out.write(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
cap.release()
out.release()
cv2.destroyAllWindows()
What is wrong?
Try this. It's working for me (Windows 10).
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
# Define the codec and create VideoWriter object
#fourcc = cv2.cv.CV_FOURCC(*'DIVX')
#out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))
out = cv2.VideoWriter('output.avi', -1, 20.0, (640,480))
while(cap.isOpened()):
ret, frame = cap.read()
if ret==True:
frame = cv2.flip(frame,0)
# write the flipped frame
out.write(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
# Release everything if job is finished
cap.release()
out.release()
cv2.destroyAllWindows()
jveitchmichaelis at https://github.com/ContinuumIO/anaconda-issues/issues/223 provided a thorough answer. Here I copied his answer:
The documentation in OpenCV says (hidden away) that you can only write
to avi using OpenCV3. Whether that's true or not I've not been able to
determine, but I've been unable to write to anything else.
However, OpenCV is mainly a computer vision library, not a video stream, codec and write one. Therefore, the developers tried to keep
this part as simple as possible. Due to this OpenCV for video
containers supports only the avi extension, its first version.
From: http://docs.opencv.org/3.1.0/d7/d9e/tutorial_video_write.html
My setup: I built OpenCV 3 from source using MSVC 2015, including
ffmpeg. I've also downloaded and installed XVID and openh264 from
Cisco, which I added to my PATH. I'm running Anaconda Python 3. I also
downloaded a recent build of ffmpeg and added the bin folder to my
path, though that shouldn't make a difference as its baked into
OpenCV.
I'm running in Win 10 64-bit.
This code seems to work fine on my computer. It will generate a video
containing random static:
writer = cv2.VideoWriter("output.avi",
cv2.VideoWriter_fourcc(*"MJPG"), 30,(640,480))
for frame in range(1000):
writer.write(np.random.randint(0, 255, (480,640,3)).astype('uint8'))
writer.release()
Some things I've learned through trial and error:
Only use '.avi', it's just a container, the codec is the important thing.
Be careful with specifying frame sizes. In the constructor you need to pass the frame size as (column, row) e.g. 640x480. However the
array you pass in, is indexed as (row, column). See in the above
example how it's switched?
If your input image has a different size to the VideoWriter, it will fail (often silently)
Only pass in 8 bit images, manually cast your arrays if you have to (.astype('uint8'))
In fact, never mind, just always cast. Even if you load in images using cv2.imread, you need to cast to uint8...
MJPG will fail if you don't pass in a 3 channel, 8-bit image. I get an assertion failure for this at least.
XVID also requires a 3 channel image but fails silently if you don't do this.
H264 seems to be fine with a single channel image
If you need raw output, say from a machine vision camera, you can use 'DIB '. 'RAW ' or an empty codec sometimes works. Oddly if I use
DIB, I get an ffmpeg error, but the video is saved fine. If I use RAW,
there isn't an error, but Windows Video player won't open it. All are
fine in VLC.
In the end I think the key point is that OpenCV is not designed to be
a video capture library - it doesn't even support sound. VideoWriter
is useful, but 99% of the time you're better off saving all your
images into a folder and using ffmpeg to turn them into a useful
video.
In my case, I found that size of Writer have to matched with the frame size both from camera or files. So that I read the frame size first and apply to writer setting as below.
(grabbed, frame) = camera.read()
fshape = frame.shape
fheight = fshape[0]
fwidth = fshape[1]
print fwidth , fheight
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (fwidth,fheight))
You need to get the exact size of the capture like this:
import cv2
cap = cv2.VideoCapture(0)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH) + 0.5)
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT) + 0.5)
size = (width, height)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('your_video.avi', fourcc, 20.0, size)
while(True):
_, frame = cap.read()
cv2.imshow('Recording...', frame)
out.write(frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
I also faced same problem but it worked when I used 'MJPG' instead of 'XVID'
I used
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
instead of
fourcc = cv2.VideoWriter_fourcc(*'XVID')
Please make sure to set correct width and height. You can set it like bellow
cv2.VideoWriter('output.avi', fourcc, 20.0, (int(cap.get(3)), int(cap.get(4))))
This answer covers what's what in terms of variables and importantly, output size shall be same for input frame and video size.
import cv2
save_name = "output.mp4"
fps = 10
width = 600
height = 480
output_size = (width, height)
out = cv2.VideoWriter(save_name,cv2.VideoWriter_fourcc('M','J','P','G'), fps , output_size )
cap = cv2.VideoCapture(0) # 0 for webcam or you can put in videopath
while(True):
_, frame = cap.read()
cv2.imshow('Video Frame', frame)
out.write(cv2.resize(frame, output_size ))
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
This is an answer was only tested in MacOS but it will probably also work in Linux and Windows.
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
# Get the Default resolutions
frame_width = int(cap.get(3))
frame_height = int(cap.get(4))
# Define the codec and filename.
out = cv2.VideoWriter('output.avi',cv2.VideoWriter_fourcc('M','J','P','G'), 10, (frame_width,frame_height))
while(cap.isOpened()):
ret, frame = cap.read()
if ret==True:
# write the frame
out.write(frame)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
# Release everything if job is finished
cap.release()
out.release()
cv2.destroyAllWindows()
I had the same problem and then I tried this:
frame = cv2.flip(frame,180)
instead of
frame= cv2.flip(frame,0)
and it's working.
I wasn't having codec issues or dimension issues as the answers above. Instead, my issue was because my output frames were in greyscale.
I had to create a VideoWriter with the parameter isColor=False
out = cv2.VideoWriter(output_path,
cv2.VideoWriter_fourcc(*'mp4v'),
30,
(INPUT_VIDEO_WIDTH,INPUT_VIDEO_HEIGHT),
isColor=False
)
In the API Docs, it wrongly says that the flag is currently supported on Windows only. I have tested on Ubuntu 20.04, with opencv-python==4.2.0.34, and it finally writes out to file correctly.
The other answers work for saving a single video feed. But if you have more then one video source, say numerous IP camera feeds, RTSP streams, or webcams, you may want to record them all at once. Here's a method for saving multiple video feeds simultaneously using multithreading. The idea is to have two threads for each video source: 1) dedicated to only reading frames from the stream and 2) dedicated for processing frames (showing and saving).
Since cv2.VideoCapture.read() is a blocking operation, we must separate reading frames from saving frames. We can read frames in its own independent thread to improve performance by reducing latency due to I/O operations. By dedicating frame capture to its own thread, there will always be a frame ready to be processed instead of having to wait for the I/O operation to complete and return a fresh frame. The second thread is dedicated to processing and saving frames to the output file. We can encapsulate all of this into a single object, where it can be scaled regardless of the number of simultaneous video streams. Be sure to change the video src parameter to your own video source. Here's an example of simultaneously recording three video streams.
from threading import Thread
import cv2
import time
class VideoWriterWidget(object):
def __init__(self, video_file_name, src=0):
# Create a VideoCapture object
self.frame_name = str(src)
self.video_file = video_file_name
self.video_file_name = video_file_name + '.avi'
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(self.video_file_name, 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()
# Start another thread to show/save frames
self.start_recording()
print('initialized {}'.format(self.video_file))
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(self.frame_name, 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)
def start_recording(self):
# Create another thread to show/save frames
def start_recording_thread():
while True:
try:
self.show_frame()
self.save_frame()
except AttributeError:
pass
self.recording_thread = Thread(target=start_recording_thread, args=())
self.recording_thread.daemon = True
self.recording_thread.start()
if __name__ == '__main__':
src1 = 'Your link1'
video_writer_widget1 = VideoWriterWidget('Camera 1', src1)
src2 = 'Your link2'
video_writer_widget2 = VideoWriterWidget('Camera 2', src2)
src3 = 'Your link3'
video_writer_widget3 = VideoWriterWidget('Camera 3', src3)
# Since each video player is in its own thread, we need to keep the main thread alive.
# Keep spinning using time.sleep() so the background threads keep running
# Threads are set to daemon=True so they will automatically die
# when the main thread dies
while True:
time.sleep(5)
Related camera/IP/RTSP/streaming, FPS, video, threading, and multiprocessing posts
Python OpenCV streaming from camera - multithreading, timestamps
Video Streaming from IP Camera in Python Using OpenCV cv2.VideoCapture
How to capture multiple camera streams with OpenCV?
OpenCV real time streaming video capture is slow. How to drop frames or get synced with real time?
Storing RTSP stream as video file with OpenCV VideoWriter
OpenCV video saving
Python OpenCV multiprocessing cv2.VideoCapture mp4
Nuru answer actually works, only thing is remove this line frame = cv2.flip(frame,0) under if ret==True: loop which will output the video file without flipping
As an example :
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
out_corner = cv2.VideoWriter('img_corner_1.avi',fourcc, 20.0, (640, 480))
At that place, have to define X,Y as width and height
But, when you create an image (a blank image for instance) you have to define Y,X as height and width :
img_corner = np.zeros((480, 640, 3), np.uint8)
I'm Kind of late, But VidGear Python Library's WriteGear API automates the process of pipelining OpenCV frames into FFmpeg on any platform in real-time with Hardware Encoders support and at the same time provides same opencv-python syntax. Here's a basic python example:
# import libraries
from vidgear.gears import WriteGear
import cv2
output_params = {"-vcodec":"libx264", "-crf": 0, "-preset": "fast"} #define (Codec,CRF,preset) FFmpeg tweak parameters for writer
stream = cv2.VideoCapture(0) #Open live webcam video stream on first index(i.e. 0) device
writer = WriteGear(output_filename = 'Output.mp4', compression_mode = True, logging = True, **output_params) #Define writer with output filename 'Output.mp4'
# infinite loop
while True:
(grabbed, frame) = stream.read()
# read frames
# check if frame empty
if not is grabbed:
#if True break the infinite loop
break
# {do something with frame here}
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# write a modified frame to writer
writer.write(gray)
# Show output window
cv2.imshow("Output Frame", frame)
key = cv2.waitKey(1) & 0xFF
# check for 'q' key-press
if key == ord("q"):
#if 'q' key-pressed break out
break
cv2.destroyAllWindows()
# close output window
stream.release()
# safely close video stream
writer.close()
# safely close writer
Source:https://abhitronix.github.io/vidgear/latest/gears/writegear/compression/usage/#using-compression-mode-with-opencv
You can check out VidGear Docs for more advanced applications and features.
As #ปรีดา ตั้งนภากร said: the sizes of Writer have to match with the frame from the camera or files.
You can use such code to check if your camera is (640, 480) or not:
print(int(cap.get(3)), int(cap.get(4)))
For myself, I found my camera is (1280, 720) and replaced (640, 480) with (1280, 720). Then it can save videos.
import cv2
cap = cv2.VideoCapture(0)
fourcc = cv2.VideoWriter_fourcc('X','V','I','D')
frame_width = int(cap.get(3))
frame_height = int(cap.get(4))
out = cv2.VideoWriter('output.mp4', fourcc, 20,(frame_width,frame_height),True )
print(int(cap.get(3)))
print(int(cap.get(4)))
while(cap.isOpened()):
ret,frame = cap.read()
if ret == True:
print(frame.shape)
out.write(frame)
cv2.imshow('Frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
cap.release()
out.release()`enter code here`
cv2.destroyAllWindows()
This works fine but the problem of having video size relatively very small means nothing is captured. So make sure the height and width of a video and the image that you are going to recorded is same. If you are using some manipulation after capturing a video than you must confirm the size (before and after).
Hope it will save some1's hour
I wanted to write a grayscale image and nothing worked for me, I had to add a 0 to VideoWriter
out = cv2.VideoWriter(outfilename, fourcc, fps, (width, height), 0)
You have to specify the width and the height of the video according to the size of the image feed. Otherwise, it will create a file size of around 5.5KB.
result = cv2.VideoWriter(name,cv2.VideoWriter_fourcc(*'MJPG'), 10, (**960, 540**))

OpenCV write frame to file python

Hey so im starting to play around with OpenCV and I cant get my webcam output saved to a file. Here is what I have. This runs fine, launches the webcam and creates "output.avi" The issue is output.avi is tiny(414 bytes) and the same exact bytes each time I run the program.
Im guessing the issue is with the fourcc encoding but I havent been able to find what works in my case. I am running on Mac OS X. Let me know if you need anymore information.
import numpy as np
import cv2
path = ('/full/path/Directory/output.avi')
cap = cv2.VideoCapture(0)
cap.set(1, 20.0) #Match fps
cap.set(3,640) #Match width
cap.set(4,480) #Match height
fourcc = cv2.cv.CV_FOURCC(*'XVID')
video_writer = cv2.VideoWriter(path,fourcc, 20.0, (640,480))
while(cap.isOpened()):
#read the frame
ret, frame = cap.read()
if ret==True:
#show the frame
cv2.imshow('frame',frame)
#Write the frame
video_writer.write(frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
break
# Release everything if job is finished
cap.release()
video_writer.release()
cv2.destroyAllWindows()
Just need to change
fourcc = cv2.cv.CV_FOURCC(*'XVID')
to
fourcc = cv2.cv.CV_FOURCC('m', 'p', '4', 'v')
Found answer here:
opencv VideoWriter under OSX producing no output
Organize your code into class and separate clear functions, find several functions for saving your results in API OpenCV, try other formats and run your code on several OS.
You can also turn to C++ or a Java/C# with OpenCV
I guess there is a chapter on your problem in a Computer Vison book http://www.amazon.com/s/ref=nb_sb_noss_1?url=search-alias%3Dstripbooks&field-keywords=Cassandra%20NoSQL#/ref=nb_sb_noss_2?url=search-alias%3Dstripbooks&field-keywords=python+computer+vision+open+cv&rh=n%3A283155%2Ck%3Apython+computer+vision+open+cv
That is all I could for helping you
The main problem is that you are not coding safely:
path = ('/full/path/Directory/output.avi')
cap = cv2.VideoCapture(0)
if not cap:
print "!!! Failed VideoCapture: invalid parameter!"
sys.exit(1)
cap.set(1, 20.0) #Match fps
cap.set(3,640) #Match width
cap.set(4,480) #Match height
# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc(*'XVID')
video_writer = cv2.VideoWriter(path, fourcc, 20.0, (640,480))
if not video_writer :
print "!!! Failed VideoWriter: invalid parameters"
sys.exit(1)
# ...
So when VideoCapture() or VideoWriter() fails, the program knows immediately that it can't go on.
Also, notice how the legacy cv2.cv.CV_FOURCC() call is replaced by the cv2.VideoWriter_fourcc(). I did this because this page shows up-to-date samples on how to do this stuff with Python. You could also try all the FourCC codes until you find one that works in your system.
Another important thing to realize is that setting the frame size of the capture interface may not work simply because the camera might not support that resolution. The same can be said for the FPS. Why is this a problem? Since we need to define these settings in the VideoWriter constructor, all frames sent to this object must have that exact dimension, else the writer won't be able to write the frames to the file.
This is how you should go about this:
path = ('/full/path/Directory/output.avi')
cap = cv2.VideoCapture(0)
if not cap:
print "!!! Failed VideoCapture: invalid parameter!"
sys.exit(1)
# The following might fail if the device doesn't support these values
cap.set(1, 20.0) #Match fps
cap.set(3,640) #Match width
cap.set(4,480) #Match height
# So it's always safer to retrieve it afterwards
fps = cap.get(CV_CAP_PROP_FPS)
w = cap.get(CV_CAP_PROP_FRAME_WIDTH);
h = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc(*'XVID')
video_writer = cv2.VideoWriter(path, fourcc, fps, (w, h))
if not video_writer :
print "!!! Failed VideoWriter: invalid parameters"
sys.exit(1)
while (cap.isOpened()):
ret, frame = cap.read()
if ret == False:
break
cv2.imshow('frame',frame)
video_writer.write(frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
video_writer.release()

Categories

Resources