Запись кадров с камеры с помощью skvideo.io.FFmpegWriter - PullRequest
0 голосов
/ 28 июня 2018

Я пытаюсь точно контролировать кодирование видео кадров изображения камеры, снятых на лету, используя skvideo.io.FFmpegWriter и cv2.VideoCapture, например.

from skvideo import io
import cv2

fps = 60
stream = cv2.VideoCapture(0)                    # 0 is for /dev/video0
print("fps: {}".format(stream.set(cv2.CAP_PROP_FPS, fps)))

stream.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
stream.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
print("bit_depth: {}".format(stream.set(cv2.CAP_PROP_FORMAT, cv2.CV_8U)))

video = io.FFmpegWriter('/tmp/test_ffmpeg.avi', 
            inputdict={'-r': fps, '-width': 1920, '-height': 1080},
            outputdict={'-r': fps, '-vcodec': 'libx264', '-pix_fmt': 'h264'}
)

try:
    for i in range(fps*10):  # 10s of video
        ret, frame = stream.read()
        video.writeFrame(frame)
finally:
    stream.release()

try:
    video.close()
except:
    pass

Однако я получаю следующее исключение (в блокноте Jupyter):

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

<ipython-input-33-007a547c4229> in <module>()
     18     while range(fps*10):
     19         ret, frame = stream.read()
---> 20         video.writeFrame(frame)
     21 except BaseException as err:
     22     raise err

/usr/local/lib/python3.6/site-packages/skvideo/io/ffmpeg.py in writeFrame(self, im)
    446         T, M, N, C = vid.shape
    447         if not self.warmStarted:
--> 448             self._warmStart(M, N, C)
    449 
    450         # Ensure that ndarray image is in uint8

/usr/local/lib/python3.6/site-packages/skvideo/io/ffmpeg.py in _warmStart(self, M, N, C)
    412         cmd = [_FFMPEG_PATH + "/" + _FFMPEG_APPLICATION, "-y"] + iargs + ["-i", "-"] + oargs + [self._filename]
    413 
--> 414         self._cmd = " ".join(cmd)
    415 
    416         # Launch process

TypeError: sequence item 3: expected str instance, int found

Изменение этого значения на video.writeFrame(frame.tostring()) приводит к ValueError: Improper data input, оставляя меня в тупике.

Как мне написать каждый кадр (возвращаемый OpenCV) в мой экземпляр FFmpegWriter?

EDIT

Код работает нормально, если я удаляю inputdict и outputdict из вызова io.FFmpegWriter, однако для меня это не подходит, так как мне нужен точный контроль над кодированием видео (я экспериментирую с без потерь / почти без потерь) сжатие необработанного видео, снятого с камеры, и попытка найти лучший компромисс с точки зрения сжатия и точности для моих нужд).

1 Ответ

0 голосов
/ 28 июня 2018

Здесь стоит отметить несколько моментов:

  • skvideo.io.FFmpegWriter использует инструмент командной строки ffmpeg для кодирования видео, а не C API. Поэтому сначала проверьте команду ffmpeg в терминале, чтобы убедиться, что у вас работает конвейер.
  • inputdict={},outputdict={} принимает строковые значения, а не целые числа. Если у вас целочисленная переменная, используйте str(var_name) для преобразования ее в строку.
  • Вы должны убедиться, что используемый вами pix_fmt поддерживается кодеком. Чтобы получить список всех pix_fmt, используйте ffmpeg -pix_fmts. Помните, что x264 не принимает все pix_fmt, которые ffmpeg поддерживает внутри.

Таким образом, для кодирования почти без потерь (см. это и это ) мы можем использовать следующую команду:

ffmpeg -s 1920x1080 -r 60 -i /dev/video0 -s 1920x1080 -r 60 -c:v libx264 -crf 17 -preset ultrafast -pix_fmt yuv444p test_ffmpeg.avi

Та же команда, переведенная на skvideo.io.FFmpegWriter, будет:

fps = 60
width = 1920
height = 1080
crf = 17
video = io.FFmpegWriter('/tmp/test_ffmpeg.avi', 
            inputdict={'-r': str(fps), '-s':'{}x{}'.format(width,height)},
            outputdict={'-r': str(fps), '-c:v': 'libx264', '-crf': str(crf), '-preset': 'ultrafast', '-pix_fmt': 'yuv444p'}
)
...