cv2 创建一个不可读的 .mp4v(和 .avi)文件

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

我正在尝试使用 Python 创建一个简单的屏幕录像机。这是代码

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

它在运行过程中没有报错,并且正确地创建了一个.mp4v 文件,但是当我尝试观看应该录制的视频时,它无法打开。我尝试使用 VLC 和其他应用程序,但它在任何地方都不被支持。

谁能告诉我为什么?

有几个实施问题:

  • 到目前为止 "output.mp4v" 在当前上下文中不是有效的 mp4 文件扩展名。
    将文件名更改为 "output.mp4"
  • "MP4V" 区分大小写,应该是 "mp4v".
  • 正如 gerda 所说,帧大小可能不是 1920x1080。
  • 循环结束的else:break可能会在一帧后中断循环
  • cv2.waitKey 在不使用 cv2.imshow 的情况下无法工作(没有打开 windows)。
    按下 q 时循环不会终止。
    代码可能永远不会到达 out.release().

基于following post,我尝试在Linux.
中创建一个等待Esc键的可移植代码,没有root权限 我找到的解决方案(等待Esc)似乎有点复杂......你可以尝试其他解决方案。


代码示例:

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