Writing an mp4 video using python opencv
PythonOpencvVideoPython Problem Overview
I want to capture video from a webcam and save it to an mp4 file using opencv. I found example code on stackoverflow (below) that works great. The only hitch is that I'm trying to save it as mp4, not avi. Part of what I don't get is that the 'XVID' argument passed to the FOURCC writer is supposed to be, I think, an mp4 codec (from [this link][1]). If I change the filename to 'output.mp4' it tells me that the tag is invalid, so I have to believe that the XVID codec is actually making an avi file. Is this a stupid question? How do I write to an mp4?
I have found links showing how to convert an avi to an mp4 after the fact but that seems inefficient. Seems like I should be able to do it during the initial write.
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
# Define the codec and create VideoWriter object
fourcc = cv2.cv.CV_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)
# 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()
[1]: http://www.fourcc.org/codecs.php "this link"
Python Solutions
Solution 1 - Python
This worked for me.
self._name = name + '.mp4'
self._cap = VideoCapture(0)
self._fourcc = VideoWriter_fourcc(*'MP4V')
self._out = VideoWriter(self._name, self._fourcc, 20.0, (640,480))
Solution 2 - Python
What worked for me was to make sure the input 'frame' size is equal to output video's size (in this case, (680, 480) ).
http://answers.opencv.org/question/27902/how-to-record-video-using-opencv-and-python/
Here is my working code (Mac OSX Sierra 10.12.6):
cap = cv2.VideoCapture(0)
cap.set(3,640)
cap.set(4,480)
fourcc = cv2.VideoWriter_fourcc(*'MP4V')
out = cv2.VideoWriter('output.mp4', fourcc, 20.0, (640,480))
while(True):
ret, frame = cap.read()
out.write(frame)
cv2.imshow('frame', frame)
c = cv2.waitKey(1)
if c & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
Note: I installed openh264 as suggested by @10SecTom but I'm not sure if that was relevant to the problem.
Just in case:
brew install openh264
Solution 3 - Python
There are some things to change in your code:
- Change the name of your output to 'output.mp4' (change to .mp4)
- I had the the same issues that people have in the comments, so I changed the fourcc to
0x7634706d
:out = cv2.VideoWriter('output.mp4',0x7634706d , 20.0, (640,480))
Solution 4 - Python
This is the default code given to save a video captured by camera
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
# Define the codec and create VideoWriter object
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)
# 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()
For about two minutes of a clip captured that FULL HD
Using
cap = cv2.VideoCapture(0,cv2.CAP_DSHOW)
cap.set(3,1920)
cap.set(4,1080)
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (1920,1080))
The file saved was more than 150MB
Then had to use ffmpeg
to reduce the size of the file saved, between 30MB
to 60MB
based on the quality of the video that is required changed using crf
lower the crf better the quality of the video and larger the file size generated. You can also change the format avi
,mp4
,mkv
,etc
Then i found ffmpeg-python
Here a code to save numpy array
of each frame as video using ffmpeg-python
import numpy as np
import cv2
import ffmpeg
def save_video(cap,saving_file_name,fps=33.0):
while cap.isOpened():
ret, frame = cap.read()
if ret:
i_width,i_height = frame.shape[1],frame.shape[0]
break
process = (
ffmpeg
.input('pipe:',format='rawvideo', pix_fmt='rgb24',s='{}x{}'.format(i_width,i_height))
.output(saved_video_file_name,pix_fmt='yuv420p',vcodec='libx264',r=fps,crf=37)
.overwrite_output()
.run_async(pipe_stdin=True)
)
return process
if __name__=='__main__':
cap = cv2.VideoCapture(0,cv2.CAP_DSHOW)
cap.set(3,1920)
cap.set(4,1080)
saved_video_file_name = 'output.avi'
process = save_video(cap,saved_video_file_name)
while(cap.isOpened()):
ret, frame = cap.read()
if ret==True:
frame = cv2.flip(frame,0)
process.stdin.write(
cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
.astype(np.uint8)
.tobytes()
)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
process.stdin.close()
process.wait()
cap.release()
cv2.destroyAllWindows()
break
else:
process.stdin.close()
process.wait()
cap.release()
cv2.destroyAllWindows()
break
Solution 5 - Python
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
'mp4v' returns no errors unlike 'MP4V' which is defined inside fourcc
for the error:
> "OpenCV: FFMPEG: tag 0x5634504d/'MP4V' is not supported with codec id > 13 and format 'mp4 / MP4 (MPEG-4 Part 14)' OpenCV: FFMPEG: fallback to > use tag 0x00000020/' ???'"
Solution 6 - Python
This worked for me, I added images.sort() to keep the sequence order:
import cv2
import numpy as np
import os
image_folder = 'data-set-race-01'
video_file = 'race-01.mp4'
image_size = (160, 120)
fps = 24
images = [img for img in os.listdir(image_folder) if img.endswith(".jpg")]
images.sort()
out = cv2.VideoWriter(video_file, cv2.VideoWriter_fourcc(*'MP4V'), fps, image_size)
img_array = []
for filename in images:
img = cv2.imread(os.path.join(image_folder, filename))
img_array.append(img)
out.write(img)
out.release()
Solution 7 - Python
For someone whoe still struggle with the problem. According [this article][1] I used this sample and it works for me:
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc(*'X264')
out = cv2.VideoWriter('output.mp4',fourcc, 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()
So I had to use cv2.VideoWriter_fourcc(*'X264')
codec. Tested with OpenCV 3.4.3 compiled from sources.
[1]: https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_gui/py_video_display/py_video_display.html#saving-a-video
Solution 8 - Python
Anyone who's looking for most convenient and robust way of writing MP4 files with OpenCV or FFmpeg, can see my state-of-the-art VidGear Video-Processing Python library's WriteGear API that works with both OpenCV backend and FFmpeg backend and even supports GPU encoders. Here's an example to encode with H264 encoder in WriteGear with FFmpeg backend:
# import required libraries
from vidgear.gears import WriteGear
import cv2
# define suitable (Codec,CRF,preset) FFmpeg parameters for writer
output_params = {"-vcodec":"libx264", "-crf": 0, "-preset": "fast"}
# Open suitable video stream, such as webcam on first index(i.e. 0)
stream = cv2.VideoCapture(0)
# Define writer with defined parameters and suitable output filename for e.g. `Output.mp4`
writer = WriteGear(output_filename = 'Output.mp4', logging = True, **output_params)
# loop over
while True:
# read frames from stream
(grabbed, frame) = stream.read()
# check for frame if not grabbed
if not grabbed:
break
# {do something with the frame here}
# lets convert frame to gray for this example
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# write gray frame to writer
writer.write(gray)
# Show output window
cv2.imshow("Output Gray Frame", gray)
# check for 'q' key if pressed
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
# close output window
cv2.destroyAllWindows()
# safely close video stream
stream.release()
# safely close writer
writer.close()
- Source: https://github.com/abhiTronix/vidgear
- Docs: https://abhitronix.github.io/vidgear/
- More FFmpeg backend examples:https://abhitronix.github.io/vidgear/latest/gears/writegear/compression/usage/
- OpenCV backend examples: https://abhitronix.github.io/vidgear/gears/writegear/non_compression/usage/
Solution 9 - Python
The problem such as OpenCV: FFMPEG: tag 0x5634504d/'MP4V' is not supported with codec id 13 and format 'mp4 / MP4 (MPEG-4 Part 14)' OpenCV: FFMPEG: fallback to use tag 0x00000020/' ???'
maybe that your output video size is not the same as original video. You can look over the frame size of video first.
Solution 10 - Python
You need to set the codec to 'mp4v'
(lowercase). If set in uppercase, an error would be thrown saying that is not supported, suggesting to use lowercase instead: OpenCV:
FFMPEG
:fallback to use tag 0x7634706d/'mp4v'
. You may also want to have a look at the documentation of VideoWriter, as well as the examples given here. Also, please make sure your output video's size is equal to your input frame
size (the below takes care of this, using the dimensions of the VideoCapture
object).
cap = cv2.VideoCapture(0)
w = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
h = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
fps = cap.get(cv2.CAP_PROP_FPS)
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter('output.mp4', fourcc, fps, (int(w),int(h)))
You can get the entire list of codecs available for mp4
, etc., by setting fourcc=-1
. For instance:
out = cv2.VideoWriter('output.mp4', -1, fps, (int(w),int(h)))
Solution 11 - Python
just change the codec to "DIVX"
. This codec works with all formats.
fourcc = cv2.VideoWriter_fourcc(*'DIVX')
i hope this works for you!