Skip to content
Advertisement

cv2 creates a unreadable .mp4v (and .avi) file

I’m trying to create a simple screen recorder with Python. This is the code

import cv2
import numpy as np
import pyautogui
import time

SCREEN_SIZE = (1920, 1080)

fourcc = cv2.VideoWriter_fourcc(*"MP4V")
out = cv2.VideoWriter("output.mp4v", fourcc, 20.0, (SCREEN_SIZE))

fps = 120
prev = 0

print('================= ScreenRecording Started =================')

while True:
    time_elapsed = time.time() - prev
    
    img = pyautogui.screenshot()

    if time_elapsed > 1.0/fps:
        prev = time.time()
        frame = np.array(img)
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        out.write(frame)
    
        if cv2.waitKey(100) & 0xFF == ord('q'):
            break
    else:
        break

cv2.destroyAllWindows()
out.release()

It doesn’t give any error while it’s going, and it creates a .mp4v file correctly, however when I try to watch the video that was supposed to be recorded, it can’t be opened. I tried with VLC and other apps but it’s unsupported everywhere.

Can someone tell me why?

Advertisement

Answer

There are several implementation issues:

  • As far "output.mp4v" is not a valid mp4 file extension in the current context.
    Change the file name to "output.mp4"
  • "MP4V" is case sensitive and suppposed to be "mp4v".
  • As gerda commented, the frame size may not be 1920×1080.
  • The else:, break at the end of the loop may break the loop after one frame.
  • cv2.waitKey is not working without using cv2.imshow (without an open windows).
    The loop is not terminated when q is pressed.
    The code may never reach to out.release().

Based on the following post, I tried to create a portable code that waits for Esc key, without root privilege in Linux.
The solution I found (waiting for Esc) seem a bit complicated… You may try other solutions.


Code sample:

import cv2
import numpy as np
import pyautogui
import time
from threading import Thread
from pynput.keyboard import Key, Listener

esc_key_pressed = False  # Global variable.

# Wait for Esc key to be pressed (and released).
def wait_for_esc_key():
    global esc_key_pressed
    # Collect events until released https://stackoverflow.com/questions/24072790/how-to-detect-key-presses
    with Listener(on_press=None, on_release=lambda key: (False if key == Key.esc else True)) as listener:
        listener.join()
        esc_key_pressed = True


SCREEN_SIZE = (1920, 1080)

fourcc = cv2.VideoWriter_fourcc(*"mp4v")
out = cv2.VideoWriter("output.mp4", fourcc, 20.0, (SCREEN_SIZE))

fps = 120
prev = 0

print('================= ScreenRecording Started =================')
print('Press Esc to end recording')

# Wait for Esc key in a thread (non-blocking wait).
wait_for_esc_key_thread = Thread(target=wait_for_esc_key)
wait_for_esc_key_thread.start()

#while True:
while (not esc_key_pressed):
    time_elapsed = time.time() - prev
    
    img = pyautogui.screenshot()

    if time_elapsed > 1.0/fps:
        prev = time.time()
        frame = np.array(img)

        if (frame.shape[0] != SCREEN_SIZE[1]) or (frame.shape[1] != SCREEN_SIZE[0]):
            frame = cv2.resize(frame, SCREEN_SIZE)  # Resize frame if size is not SCREEN_SIZE

        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        out.write(frame)
    
        #if cv2.waitKey(100) & 0xFF == ord('q'):
        #    break
    time.sleep(0.001)


#cv2.destroyAllWindows()
out.release()
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement