Catframes.py ============ Скрипт, который соединяет (англ. `concatenate`) кадры (англ. `frames`). Сокращение `cat` в этом контексте `знакомо `_ любому пользователю Unix-подобных систем. .. meta:: :description: Скрипт, который соединяет папки с изображениями в видеоролики с помощью FFmpeg. :keywords: таймлапс, таймлапсы, видеонаблюдение, сжатие, сжать, FFmpeg, webm, mp4 Примеры использования --------------------- .. highlight:: bash В первом примере вы можете убедиться в нескольких вещах: стандартные настройки качества подойдут практически для всего, кадры с отличающимся соотношением сторон выравниваются по центру и цвет полей у этих кадров совпадает с цветом фона. Анимация была отрендерена Блендером в серию PNG-изображений с прозрачным фоном, после чего первые несколько кадров обрезаны сверху и снизу, чтобы продемонстрировать поля. :: catframes.py --margin-color='#a143ac' monkey/ monkey.webm catframes.py --margin-color='#a143ac' monkey/ monkey.mp4 catframes.py --margin-color='#a143ac' -q high monkey/ monkey_hq.webm catframes.py --margin-color='#a143ac' -q high monkey/ monkey_hq.mp4 catframes.py --margin-color='#a143ac' -q poor monkey/ monkey_pq.webm catframes.py --margin-color='#a143ac' -q poor monkey/ monkey_pq.mp4 .. image:: http://itustinov.ru/cona/monkey_preview.jpg :class: no-scaled-link :width: 96% `monkey_hq.webm `_ (76M), `monkey.webm `_ (21M), `monkey_pq.webm `_ (9.2M) `monkey_hq.mp4 `_ (61M), `monkey.mp4 `_ (22M), `monkey_pq.mp4 `_ (12M) Стоп-кадры для сравнения качества: `monkey_hq.webm.png `_, `monkey.webm.png `_, `monkey_pq.webm.png `_ `monkey_hq.mp4.png `_, `monkey.mp4.png `_, `monkey_pq.mp4.png `_ `monkey_orig.png `_ Во втором примере склеивается последовательность каталогов в заданном порядке, причем у содержимого этих каталогов отличаются разрешения, что отражено в названиях. Вы можете наблюдать, что положение надписей не зависит ни от разрешений, ни от соотношений сторон; надписи легко читаются как на светлом, так и на тёмном фоне; скрипт сам выбирает разрешение (в данном случае 1280x960). :: catframes.py -r 60 \ --bottom='{catframes}\n' \ 06_1280_720 \ 07_1280_640 \ 08_800_600 \ 09_1024_768 \ 10_640_480 \ 11_720_1280 \ 12_1440_1080 \ 13_1440_1080 \ 14_1280_960 \ 15_1280_960 \ 16_1280_960 \ 17_800_600 \ 18_800_600 \ 19_800_600 \ mixed_resolutions.webm .. image:: http://itustinov.ru/cona/mixed_resolutions_preview.png :class: no-scaled-link `mixed_resolutions.webm `_ (113M), `mixed_resolutions.mp4 `_ (383M) Перейдём ближе к реальной практике. Для примера я выставил из окна веб-камеру и направил её в небо, чтобы не вторгаться ни в чью частную жизнь. На компьютер круглосуточно сохранялись снимки. В реальной системе папки с ними пережимались бы по расписанию примерно следующей командой. :: catframes.py \ --left-top='{dir}/{fn} (кадр {frame:video})\n\nПоследнее изменение: {mtime:%d.%m.%Y %H:%M:%S}\nРазмер файла, байты: {size}' \ --top='' --right-top='WARN' \ --right='{symlink:L}' \ --bottom-left='Архивировано {vtime:%d.%m.%Y} в {vtime:%H:%M} с помощью {catframes}.' \ /путь/к/кадрам/2022-08-27T00/ \ /путь/к/кадрам/2022-08-27T01/ \ /путь/к/кадрам/2022-08-27T02/ \ /путь/к/кадрам/2022-08-27T03/ \ /путь/к/кадрам/2022-08-27T04/ \ /путь/к/кадрам/2022-08-27T05/ \ /путь/к/кадрам/2022-08-27T06/ \ /путь/к/кадрам/2022-08-27T07/ \ /путь/к/кадрам/2022-08-27T08/ \ /путь/к/кадрам/2022-08-27T09/ \ /путь/к/кадрам/2022-08-27T10/ \ /путь/к/кадрам/2022-08-27T11/ \ /путь/к/кадрам/2022-08-27T12/ \ /путь/к/кадрам/2022-08-27T13/ \ /путь/к/кадрам/2022-08-27T14/ \ /путь/к/кадрам/2022-08-27T15/ \ /путь/к/кадрам/2022-08-27T16/ \ /путь/к/кадрам/2022-08-27T17/ \ /путь/к/кадрам/2022-08-27T18/ \ /путь/к/кадрам/2022-08-27T19/ \ /путь/к/кадрам/2022-08-27T20/ \ /путь/к/кадрам/2022-08-27T21/ \ /путь/к/кадрам/2022-08-27T22/ \ /путь/к/кадрам/2022-08-27T23/ \ /путь/к/архивам/2022-08-27.webm .. warning:: Скрипт завершается с ненулевым статусом, если какие-то папки с кадрами не существуют. Я не настраивал у себя архивацию по расписанию, а выбрал интересный фрагмент и сжал его отдельно. :: catframes.py \ --left-top='{dir}/{fn} (кадр {frame:video})\n\nПоследнее изменение: {mtime:%d.%m.%Y %H:%M:%S}\nРазмер файла, байты: {size}' \ --top='' --right-top='WARN' \ --right='{symlink:L}' \ --bottom-left='Архивировано {vtime:%d.%m.%Y} в {vtime:%H:%M} с помощью {catframes}.' \ 2022-08-26T23/ \ 2022-08-27T00/ \ 2022-08-27T01/ \ 2022-08-27T02/ \ 2022-08-27.webm .. image:: http://itustinov.ru/cona/2022-08-27.webm_preview.png :class: no-scaled-link `2022-08-27.webm `_ (13M) Любые данные, оказывающиеся на периферии нашего внимания, чтобы быть по́нятыми, требуют встраивания в некоторый контекст, от которого зависит, как мы видим и формулируем факты. Видео — не исключение. Если описать это видео вне контекста, получится что-то вроде «на записи перемещается едва заметная точка». Обратимся к напечатанной на кадрах метаинформации. В ней не сказано, где находится камера, но я сам *недавно* её ставил и помню, что она находилась в Казани и была направлена на юг и вверх примерно под 45 градусов. На кадрах зафиксировано время съёмки (имена файлов). Через эти отметки времени и горизонтальный угол обзора (около 45 градусов, я измерял) можно оценить угловую скорость, а с помощью перемотки и линейки, приложенной к экрану, — траекторию. Нетрудно убедиться, что точка движется почти по идеальной прямой, и время прохода перед камерой равнялось примерно трём часам. Это исключает практически любые атмосферные объекты, включая распространённые виды летательных аппаратов, и всё, что находится на низких орбитах. Объект двигался с востока на запад, и с учётом скорости прохождения поля зрения, вероятно, он находился в дальнем космосе, а его движение на видео — иллюзия, вызванная вращением Земли. Воспользуемся виртуальным планетарием, например https://stellarium-web.org/, укажем в нём время и место и убедимся, что как раз тогда на юге проходил Юпитер, один из самых ярких астрономических объектов. .. tip:: Самая важная метаинформация у видео — время и место съёмки. Пример также демонстрирует фиксацию подозрительных действий на сервере. Я нарочно #. отредактировал три кадра, начиная с ``2022-08-27-00-00-01.jpg`` (см. время модификации), #. следующий отредактировал прямо во время архивирования (об этом сигнализирует предупреждение), #. один кадр заменил симлинком (буква L справа), #. один кадр во время архивирования удалил (красный экран), #. один кадр во время архивирования запретил на чтение (красный экран), #. один кадр запретил на чтение еще до запуска скрипта (красный экран). Обратите внимание, сколько пришлось привнести сторонней информации для построения непротиворечивой интерпретационной модели, даже несмотря на эти индикаторы. Я апеллировал в основном к личному опыту, что не гарантирует достоверность и не всегда возможно. Вопрос критериев отбора такой информации остаётся открытым. .. highlight:: default Пользовательский интерфейс -------------------------- .. autoclass:: catframes.OverLang :members: .. autoclass:: catframes.ConsoleInterface :members: Сетевые возможности ------------------- Catframes использует протокол HTTP, чтобы передавать кадры в FFmpeg. .. autodata:: catframes.WebApp .. autodata:: catframes.WebJob .. autoclass:: catframes.JobServer :members: Файловая система ---------------- Архивирование видео может запускаться автоматически и выполняться без присмотра. При этом нежелательно, чтобы сжатие данных за целый день аварийно остановилось, если что-то не получится сделать с одним кадром. Поэтому здесь реализованы обёртки над системными функциями для максимальной предсказуемости. .. autoclass:: catframes.FileUtils :members: Основные сущности ----------------- .. autoclass:: catframes.Resolution :members: :special-members: __str__, __eq__ .. autoclass:: catframes.Frame :members: .. autoclass:: catframes.OverlayModel :members: .. autodata:: catframes.OverlayTemplate .. autoclass:: catframes.Layout :members: Работа с размерами ------------------ .. autoclass:: catframes.ResolutionUtils :members: .. autoclass:: catframes.ResolutionStatistics :members: Рендеринг --------- .. autoclass:: catframes.FrameResponse .. autoclass:: catframes.FrameView :members: .. autoclass:: catframes.PillowFrameView :show-inheritance: :members: :private-members: .. autoclass:: catframes.DefaultFrameView :show-inheritance: :members: Сохранение видео ---------------- .. autoclass:: catframes.Quality :members: .. autoclass:: catframes.OutputOptions :members: