cv2.VideoWriter will not write file using fourcc h.264 (with logitech c920, python 2.7, windows 8)

16,730

Solution 1

  • Keep in mind that OpenCV automatically decompresses the incoming H264 stream from the webcam. You cannot pass on the compressed stream. You must recompress.
  • Since the codec ID of -1 displays a prompt asking you for chosing a codec, I assume you are on Windows. On Windows, OpenCV uses ffmpeg or "Video for Windows" backends. Unfortunately, it seems you cannot tell when OpenCV uses which backend. The dialog asking to select an encoder looks like the VfW dialog. There are no sane h264 VfW encoders, you probably did not install a hackish one like x264vfw, so you cannot choose h264 here.
  • The AVI container does not support b-Frames. H264 uses b-frames by default. You cannot change these encoder settings from within OpenCV. As a result, you should not choose AVI for H264 encoded video.
  • In order to save to another container, ffmpeg should be used. I can only guess OpenCV cooses backends wisely and based on container. You should be able to encode h264 into MKV or MP4. Bear in mind that there is some kind of "FOURCC to ffmpeg-Encoder-ID" translation takes place.

Solution 2

So the workaround I found so far is not that efficient but it works for me on Ubuntu 16.04. After writing the video regularly, I convert it again using H264 coder and the final video size is much smaller than the one I got from opencv alone.

Here is the workaround:

import os # We will use it to access the terminal

# Write the video normally using mp4v and make the extension to be '.mp4'
# Note: the output using "mp4v" coder may be efficient for you, if so, you do not need to add the command below
cv2.VideoWriter('Video.mp4',cv2.VideoWriter_fourcc(*"mp4v"), NewFPS, (width,height))

# When your video is ready, just run the following command
# You can actually just write the command below in your terminal
os.system("ffmpeg -i Video.mp4 -vcodec libx264 Video2.mp4")

Solution 3

If you installed this package via pip install opencv-python then there's no encoding support for x264 because it's under GPL license. Upgrading FFmpeg won't help because opencv-python ships with its own FFmpeg.

You'll have to compile OpenCV manually to get support for H264 encoding.

Related issue on Github: https://github.com/skvark/opencv-python/issues/100#issuecomment-394159998

Share:
16,730
pbordeaux
Author by

pbordeaux

Updated on June 19, 2022

Comments

  • pbordeaux
    pbordeaux almost 2 years

    I am new to python (2.7) and opencv (3.0) (and video streaming/writing in general) so forgive this.

    I am using the logitech c920 as my webcam and it can stream video compressed in h264 format so I am trying to write a simple app that sets 4 properties of the VideoCapture instance (fourcc to h264; width to 1920; height to 1080; and fps to 30), and then records a video to the directory one level up named test.mp4 and shows the recording on my screen. Here is code:

    import sys
    import cv2 as cv
    
    cap = cv.VideoCapture(0)
    fourcc = cv.VideoWriter_fourcc('H','2','6','4')                     
    
    cap.set(6, fourcc)
    cap.set(3,1920)
    cap.set(4,1080)
    cap.set(5, 30)                                  
    
    vid = cv.VideoWriter('../test.mp4', fourcc, 20.0, (640,480))     
    print vid.isOpened() #returns false :(                                                       
    while (cap.isOpened()):                                     
    
      ret, frame = cap.read()                                  
    
      if (ret == True):                                        
    
       #gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)          
    
    
       vid.write(frame)
    
       cv.imshow('window', frame)                           
    
       if (cv.waitKey(1) & 0xFF == ord('q')):                  
        break
    
    cap.release()
    vid.release()                                              
    cv.destroyWindow('window')     
    

    cv.imshow('window',frame) works just fine, and the properties are all set; however, vid.isOpened() return false so clearly I have done something wrong in the above. If I pass -1 for the fourcc, I am allowed to pick from a list of codecs and i420 is available and says (for logitech cameras) and vid.isOpened() returns true if I change the file extension from mp4 to avi (I guess that means i420 cannot be stored as .avi ?), however, test.avi is always huge and seemingly raw, 100MB for a few second test video and will not open.

    Any help with this would be great, thanks a lot