Вопрос или проблема
Я пытаюсь сохранить некоторые видео с веб-камеры, но сталкиваюсь с проблемами. Моя веб-камера поддерживает сжатые (MJPG) и необработанные (YUYv 4:2:2) форматы, и я пытаюсь получить MJPG из-за более высокой частоты кадров. Я упростил свой код (ниже) и воспроизвел проблему.
import cv2
from datetime import datetime, timedelta
fourcc = cv2.VideoWriter_fourcc(*'avc1')
fn = "out.mp4"
cap = cv2.VideoCapture(0, cv2.CAP_V4L2)
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*"MJPG"))
fps = int(cap.get(cv2.CAP_PROP_FPS))
out = cv2.VideoWriter(fn, fourcc, fps, (int(cap.get(3)), int(cap.get(4))))
frames_written = 0
print(f"FPS {fps}")
show = False
end = datetime.utcnow() + timedelta(seconds=20)
while end >= datetime.utcnow():
ret, frame = cap.read()
if not ret:
raise Exception("NO FRAME")
out.write(frame)
frames_written+=1
if show:
cv2.imshow("f", frame)
cv2.waitKey(33)
cap.release()
out.release()
cv2.destroyAllWindows()
Когда я пытаюсь использовать видео-устройство веб-камеры напрямую в OpenCV, записанное видео, хотя и плавное, идет с ускорением.
Я также пробовал создать фиктивное видео-устройство и отправлять на него вывод ffmpeg с помощью следующей команды:
ffmpeg -f v4l2 -input_format mjpeg -framerate 30 -video_size 1920x1080 -i /dev/video0 -pix_fmt yuyv422 -f v4l2 /dev/video4
Когда я пытаюсь использовать фиктивное видео-устройство в качестве источника, в первые пару секунд кажется, что скорость нормальная, но видео дергается, потом ускоряется, а затем становится менее дерганым. Любая помощь была бы оценена. Я бьюсь головой об стену последние несколько дней.
Мой вывод для v4l2-ctl –list-formats-exts:
ioctl: VIDIOC_ENUM_FMT
Тип: Видеозахват
[0]: 'MJPG' (Motion-JPEG, сжатый)
Размер: Дискретный 2592x1944
Интервал: Дискретный 0.033с (30.000 fps)
Размер: Дискретный 2560x1440
Интервал: Дискретный 0.033с (30.000 fps)
Размер: Дискретный 1920x1080
Интервал: Дискретный 0.033с (30.000 fps)
Размер: Дискретный 1280x1024
Интервал: Дискретный 0.033с (30.000 fps)
Размер: Дискретный 1280x720
Интервал: Дискретный 0.033с (30.000 fps)
Размер: Дискретный 960x540
Интервал: Дискретный 0.033с (30.000 fps)
Размер: Дискретный 848x480
Интервал: Дискретный 0.033с (30.000 fps)
Размер: Дискретный 800x600
Интервал: Дискретный 0.033с (30.000 fps)
Размер: Дискретный 640x480
Интервал: Дискретный 0.033с (30.000 fps)
Размер: Дискретный 320x240
Интервал: Дискретный 0.033с (30.000 fps)
Размер: Дискретный 160x120
Интервал: Дискретный 0.033с (30.000 fps)
[1]: 'YUYV' (YUYV 4:2:2)
Размер: Дискретный 2592x1944
Интервал: Дискретный 0.500с (2.000 fps)
Размер: Дискретный 2560x1440
Интервал: Дискретный 0.500с (2.000 fps)
Размер: Дискретный 1920x1080
Интервал: Дискретный 0.500с (2.000 fps)
Размер: Дискретный 1280x1024
Интервал: Дискретный 0.200с (5.000 fps)
Размер: Дискретный 1280x720
Интервал: Дискретный 0.200с (5.000 fps)
Размер: Дискретный 960x540
Интервал: Дискретный 0.067с (15.000 fps)
Размер: Дискретный 848x480
Интервал: Дискретный 0.050с (20.000 fps)
Размер: Дискретный 800x600
Интервал: Дискретный 0.050с (20.000 fps)
Размер: Дискретный 640x480
Интервал: Дискретный 0.033с (30.000 fps)
Размер: Дискретный 320x240
Интервал: Дискретный 0.033с (30.000 fps)
Размер: Дискретный 160x120
Интервал: Дискретный 0.033с (30.000 fps)
Ответ или решение
Проблема, с которой вы столкнулись при записи видео с веб-камеры с использованием OpenCV, связана с различиями в частоте кадров (FPS) и общими настройками записи. Ниже приведены рекомендации по решению проблемы с «ускоренной» записью видео.
1. Настройка кодека
Вы используете кодек avc1
для записи, который не обязательно подходит для кодирования MJPEG видеопотока. Попробуйте использовать кодек, который лучше подходит для MJPEG. Например, XVID
может быть более подходящим:
fourcc = cv2.VideoWriter_fourcc(*'XVID')
2. Проверка частоты кадров
Вы получаете FPS с помощью cap.get(cv2.CAP_PROP_FPS)
, но иногда эта информация может быть некорректной. Попробуйте установить частоту кадров вручную, основываясь на спецификации вашей камеры. Например, если у вас 30 FPS:
fps = 30 # Задайте значение FPS вручную
3. Убедитесь, что используете правильный формат
Вы указали, что ваша камера поддерживает MJPEG. Убедитесь, что вы точно установили нужный формат перед использованием VideoCapture
. Например:
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*"MJPG"))
cap.set(cv2.CAP_PROP_FPS, fps) # Установите FPS
4. Управление чтением кадров
Чтобы избежать проблем с ускорением, вам нужно контролировать, как быстро вы читаете и записываете кадры. Если обработка происходит быстрее, чем камера их отправляет, это может привести к ускорению воспроизведения. Попробуйте добавить небольшую задержку между циклами чтения и записи:
import time
while end >= datetime.utcnow():
ret, frame = cap.read()
if not ret:
raise Exception("NO FRAME")
out.write(frame)
frames_written+=1
time.sleep(1 / fps) # Задержка для соответствия FPS
5. Использование FFmpeg
Если вы хотите использовать FFmpeg с виртуальным устройством, убедитесь, что условия для потока правильные. Например, используйте:
ffmpeg -f v4l2 -input_format mjpeg -framerate 30 -video_size 1920x1080 -i /dev/video0 -pix_fmt mjpeg -f v4l2 /dev/video4
Здесь вы можете также задать правильный -pix_fmt
для меньшей задержки и лучшей производительности.
Заключение
Попробуйте внести предложенные изменения и посмотрите, поможет ли это предотвратить ускорение записи. Если проблема сохраняется, возможно, вам стоит провести дополнительные тесты с разными настройками камеры и кодеками. Не забывайте контролировать результаты, чтобы удостовериться, что видео записывается в нужном формате и с корректной частотой кадров.