80

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). 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()
Gadzooks34
  • 1,718
  • 2
  • 20
  • 29

13 Answers13

100

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))
10SecTom
  • 2,484
  • 4
  • 22
  • 26
  • 2
    It's been two years! You hadn't expected this upvote, huh? :P I was using H264 to write to an mp4 file. It created laggy videos upon seeking, this suggestion helped me. MP4V codec solved the issue! :) – varun Mar 31 '17 at 14:08
  • 2
    @varun ha no didnt see it coming :) .. glad it helped you bud. – 10SecTom Apr 03 '17 at 10:51
  • @10SecTom does this require ffmpeg to be present ? – Akash Goyal Jun 05 '17 at 13:10
  • 1
    @AkashGoyal its been a while since I played with this stuff. I believe it worked with h264. I had to install openh264. http://www.openh264.org/faq.html – 10SecTom Jun 07 '17 at 08:39
  • 32
    It is not working, and says the below 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/' ???'` – Bahramdun Adil Jan 03 '18 at 02:09
  • @Bahramdun Adil its been so long since I played with this stuff and was not an expert, to begin with. I did a quick google of your error (which does look familiar) and found a good few posts citing the same issue. Hope you find a solution. – 10SecTom Jan 11 '18 at 09:12
  • Sorry if it is not related, but can we apply it to opencv c++ as well? – gameon67 Feb 12 '19 at 04:43
  • not sure of the C++ API but I imagine the translation should be similar – 10SecTom Feb 12 '19 at 07:43
  • 2
    @BahramdunAdil the name of the output file must end with `.mp4`, that's why you are having that error – Gonzalo Garcia Apr 08 '19 at 15:22
  • 13
    I had error codec id 12 instead of @BahramdunAdil 's 13 and changing the CODEC to `*'mp4v'` from to `*'MP4V'` fixed it for me. – ijuneja May 02 '21 at 17:33
24

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
ling
  • 9,545
  • 4
  • 52
  • 49
18

There are some things to change in your code:

  1. Change the name of your output to 'output.mp4' (change to .mp4)
  2. 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))
Ruzihm
  • 19,749
  • 5
  • 36
  • 48
Alan Soder
  • 179
  • 1
  • 5
13

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
6

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/' ???'"

Ali_Sh
  • 2,667
  • 3
  • 43
  • 66
4

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()
2

For someone whoe still struggle with the problem. According this article 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.

Ivan Talalaev
  • 6,014
  • 9
  • 40
  • 49
  • Instructions on how to compile opencv here https://www.swiftlane.com/eng/generating-mp4s-using-opencv-python-with-the-avc1-codec – Narek Jul 20 '20 at 14:46
2

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() 
abhiTronix
  • 1,248
  • 13
  • 17
  • As to the case of OpenCV as a backend: since OpenCV's video writer is itself [a wrapper](https://docs.opencv.org/4.5.4/dd/d9e/classcv_1_1VideoWriter.html#ad59c61d8881ba2b2da22cff5487465b5) around ffmpeg and other libraries as per the OS platform, I wonder whether there are really particular advantages to using this library with OpenCV as its backend compared to using OpenCV itself. Happy to learn. – matanster Dec 09 '21 at 23:07
  • 1
    Yes, it not only provides direct access to OpenCV writer in case of OpenCV backend but also automatically handles output file paths, [simplifies assigning FOURCC Codecs](https://abhitronix.github.io/vidgear/latest/gears/writegear/non_compression/params/#supported-fourcc-codecs) names and handles any error while encoding files. – abhiTronix Dec 10 '21 at 13:38
1

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.

TanLingxiao
  • 402
  • 5
  • 7
  • No, that problem is because the video codec doesn't match with the output's filename. If u are using `MP4V`, the output file must end with `.mp4`. Same way with `XVID` output filename should end with `.avi` – Gonzalo Garcia Apr 08 '19 at 15:36
  • I went down this deep dive and recorded my solution in this blog post if that helps https://www.swiftlane.com/eng/generating-mp4s-using-opencv-python-with-the-avc1-codec – Narek Jul 20 '20 at 14:45
1

The OpenCV documentation is not very rich with regard to the VideoWriter, however I managed to get it working in the following way (by looking at the stacktrace):

import cv2

HEIGHT = 480
WIDTH = 640
FPS = 30.0

cap = cv2.VideoCapture(0, cv2.CAP_ANY)

cap.set(cv2.CAP_PROP_FPS, FPS)
cap.set(cv2.CAP_PROP_CONVERT_RGB , 1)
cap.set(cv2.CAP_PROP_BUFFERSIZE, 100)


cap.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT)

fourcc = cv2.VideoWriter_fourcc(*'mp4v')

# output parameters such as fps and size can be changed
output = cv2.VideoWriter("output.mp4", fourcc, FPS, (WIDTH, HEIGHT))

while True:
    if cap.isOpened():
        (ret, frame) = cap.read()
        if ret:
            output.write(frame)
        cv2.imshow("frame", frame)

    if cv2.waitKey(10) == ord('q'):
        break

output.release()
cap.release()
cv2.destroyAllWindows()

The stacktrace error was:

OpenCV: FFMPEG: tag 0x5634504d/'MP4V' is not supported with codec id 12 and 
format 'mp4 / MP4 (MPEG-4 Part 14)'
OpenCV: FFMPEG: fallback to use tag 0x7634706d/'mp4v'

Unfortunately, it is difficult to find a list of the official codecs used by OpenCV, or at least I could not find them. In any case, it appears that you have to enter the codec 'mp4v' written in lower case.

https://docs.opencv.org/3.4/dd/d01/group__videoio__c.html#gac005718f121379beffdbdbfb44f2646a

One important thing I noticed is that the aspect ratio of the frame and the output video must be the same, which is why I use two variables for height and width. If these two are different, the file is created, but the frames are not saved (you always end up with a 1KB mp4 file). To avoid any problems you could do the same for FPS.

0

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)))
Chris
  • 18,724
  • 6
  • 46
  • 80
0

On Ubuntu 22.04 (2023) cv2.VideoWriter_fourcc(*'mp4v') worked for me.

nayakasu
  • 889
  • 1
  • 11
  • 32
-2

just change the codec to "DIVX". This codec works with all formats.

fourcc = cv2.VideoWriter_fourcc(*'DIVX')

i hope this works for you!

BeeFriedman
  • 1,800
  • 1
  • 11
  • 29