Склеить несколько видеофайлов, что может быть проще…

от автора

Если их пара. А если их пара десятков? А если несколько сотен? А если они еще и в разных форматах? Идея загонять все в видеоредактор отпала почти сразу. Но в начале — небольшая предыстория.

За каждым великим мужчиной стоит женщина, стоит и ворчит. (народная мудрость, отцензурировано)

Как и в прошлый раз, проблема возникла не на пустом месте. С эрой доступной цифровой фотографии началась эра доступного цифрового видео (ну ладно, не сразу, на пару лет позже). И, помимо фотографий, на домашнем сервере начали накапливаться видеофайлы. В данный момент их 299 362 штуки, накопленных примерно за 20 лет, в среднем 40 в день. Но не надо думать, что все это длинные клипы. В 90% случаев это очень короткие ролики вроде: «ребенок сидит», «ребенок идет» и моя «любимая» категория видео — «фотография из семейного альбома с голосовой заметкой» (ну т. е. мы смотрим семейный альбом и жена просто снимает на видео, то, что мы смотрим озвучивая при этом свои мысли; нет чтобы просто записать текстом, займет 300 байт на диске, но нет — появляется видео на 300 мегабайт).

Единственный формат просмотра всей этой коллекции который оказался возможным, — ретроспектива: а как мы провели этот день год/два/десять назад? Но отдельные мелкие ролики все испытанные мной проигрыватели (а уж тем более приставки и телевизоры) воспроизводят с паузой между ними. К тому же стабилизация видео в телефоны пришла далеко не сразу, так что большинство роликов еще и довольно дерганые, плюс многие были сняты еще на древние камеры с чересстрочной разверткой (интересно, остались ли такие на рынке?), так что привет «расческа». В общем, родилась идея, что перед просмотром такие ролики лучше склеивать в один, да еще и желательно с прогонкой деинтерлейсером и стабилизатором.

Первые попытки были через видео редактор, но, по вполне очевидным причинам, такой процесс требует много ручного труда, так что это, как говориться, не наш метод!

Наш метод это: консоль, ffmpeg (и питон)!

Если погуглить «как объединить видеофайлы в командной строке», то можно будет увидеть что‑то вроде:

Создайте файл video.txt с содержимым:

file video1.mp4 file video2.mp4

Затем запустите:

ffmpeg -f concat -safe 0 -i video.txt -c copy output.mp4

Не совсем в одну строку, «такое мы не любим».

Добавляем в запрос «в одну строку» и видим уже ужас типа такого:

ffmpeg -i video1 -i video2-filter_complex "[0:0][0:1][1:0][1:1]concat=n=2:v=1:a=1[outv][outa]" -map "[outv]" -map "[outa]" output.mp4

Не могу сказать, что я разобрался во всех деталях, но монструозность конструкции совсем не порадовала, да и работает через раз. Но главная проблема в том, что оба способа работают только на однотипных файлах. В моем случае видео не только не однотипные, но и включают в себя (о бич современного мира мобильных телефонов!) вертикальные видео, так как в один день съемка могла быть с нескольких разных устройств.

После недолгих раздумий я начал поиск библиотек на python которые могли бы удовлетворить мои нужды. Самый популярный вариант — MoviePy. Написал скрипт, который загружал описание всех видео, подбирал выходное разрешение, поворачивал вертикальное видео с добавлением полей и в конченом итоге выдавал один файл после запуска одной команды.

И все было хорошо, пока скрипт не дошел до 12 декабря 2010 года… Не знаю, чем вы занимались в этот день, но моей видеотеке за этот день оказался 321 видео файл и как говорится «бобик сдох».

Ну, справедливости ради, я почти сразу заметил непомерные аппетиты. Правда, казалось, что 640 Кбайт памяти хватит всем 32GB установленных на моем медиа сервере должно хватить, но не хватило. Сервер ушел в глубокий swap, а я — в глубокие раздумья, так как после более детального анализа выяснилось, что это в этот день количество видео файлов было совсем не рекордным — 30 дней содержали более 500 видео файлов.

Стало ясно, что без промежуточного сохранения файлов не обойтись, и по началу я натыкал костылей в виде вызовов ffmpeg вместе с MoviePy, но вскоре отказался и переписал все на использование только чистого ffmpeg напрямую.

И так, какие же шаги проходят видео файлы, прежде чем стать одним роликом?

Финальная последовательность действий такая:

  1. Анализ с помощью утилиты ffprobe из пакета ffmpeg. Получаем данные о размере файлов, ориентации, частоте кадров и наличии интерлейса.

ffprobe -v error -show_format -show_streams -print_format json входной_файл
  1. Если есть интерлейс, то делаем… барабанная дробь… деинтрелейс!

ffmpeg -i входной_файл -vf yadif -qp 0 -preset ultrafast -c:a flac -c:v libx264 выходной_файл  Где:  -vf yadif: собственно деинтерлейс   -qp 0: сохранение без потери качества  -preset ultrafast: поскольку это временный файл, то выбираем скорость в ущерб размеру  -c:a flac: переводим аудио в flac чтобы не терять качество в промежуточных файлах   -c:v libx264: видео кодек
  1. Стабилизация видео

Оказалось, очень важно делать её именно на этом шаге, так как если сделать её до деинтерлейса, то интерлейс уже не сможет нормально отработать, и «расческа» останется. А если сделать её после изменения размеров и поворота вертикальных видео, то при стабилизации поля начинают «плавать» вместе со стабилизируемым объектом.

Стабилизация делается в два этапа:

На первом этапе создается файл с описанием трансформации:

ffmpeg -i входной_файл -vf vidstabdetect=stepsize=32:shakiness=10:accuracy=10:result=transforms.txt -f null -

На втором этапе‑ непосредственно стабилизация:

ffmpeg -i входной_файл -vf vidstabtransform=input=transforms.txt:zoom=0:smoothing=10,unsharp=5:5:0.8:3:3:0.4 -qp 0 -preset ultrafast -c:a flac -strict experimental -c:v libx264 -f выходной_файл  Параметры сохранения видео такие же как и на предыдущем шаге.
  1. Поворот, изменение размера с добавлением черных полей, если пропорции видео отличаются от заданного размера + унификация частоты кадров:

ffmpeg -i входной_файл -f “scale=w='if(gt(a,{w}/{h}),{w},trunc(oh*a/2)*2)':h='if(gt(a,{w}/{h}),trunc(ow/a/2)*2,{h})',pad={w}:{h}:(ow-iw)/2:(oh-ih)/2:black” -qp 0 -preset ultrafast -c:a flac -strict experimental -c:v libx264 -r {fr} выходной_файл  Где:   {w} - ширина итогового видео,   {h} - высота итогового видео,   {fr} - частота кадров. Плюс те же параметры для сохранения временного файла, что и на предыдущих шагах
  1. К этому моменту у нас имеется N однотипных видео файлов, которые мы можем склеить той самой командой из начала статьи, но с небольшими доработками в виде задания необходимых параметров для оптимального кодирования:

ffmpeg -f concat -safe 0 -i video.txt -c copy -c:v libx264 -crf 23 -c:a aac -q:a 1 output.mp4  Где:   -c:v libx264: видео кодек   -crf 23: стандартное качество, можно заменить на 18, тогда это будет визуально без потерь, но итоговой размер в несколько раз больше   -c:a aac: аудиокодек   -q:a 1: максимальное качество звука, тут особо экономить не на чем, все равно аудио занимает места на пару порядков меньше чем видео.

Ну и для тех, у кого есть похожая задача и не хочется набивать себе мои шишки, — вот готовая библиотека, которую можно использовать и как часть проекта, и как самостоятельную утилиту.

Установка через pip:

pip install mixvideoconcat

Она реализует все шаги, описанные в статье, проста в использовании и, главное, делает то, что мне нужно, в одну строку (ну ок, две с импортом):

from mixvideoconcat import concat concat(['video1.mp4', 'video2.mov', 'video3.avi'], 'output.mp4')

Либо в консоли (тут честная одна строка):

mixvideoconcat video1.mp4 video2.mov video3.avi output.mp4

Все исходники можно найти тут: https://github.com/sashacmc/mixvideoconcat

PS: Изначально я сделал ее как часть более общего проекта по управлению всем моим «видеохозяйством». Но потом решил выделить ее отдельно и как библиотеку, и как статью, так что продолжение следует… Ставьте лайки, подписывайтесь на канал, включайте колокольчик, ой это не сюда, про борьбу с субтитрами ютуба будет потом, в следующей статье 😂


ссылка на оригинал статьи https://habr.com/ru/articles/856648/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *