Обладание большой видеотекой сегодня не редкость, и обычно в нее стараются собрать все в самом лучшем качестве. Однако другая сторона медали — несовместимость со старыми бытовыми проигрывателями, древними ноутбуками и прочими портативными гаджетами.
Я столкнулся с этим по банальной причине бытового комфорта. Имея неплохую медиастанцию под Windows, с подключенной 60" плазмой и шестиканальным звуком, настроенную с душой, с написанными скриптами для AutoHotkey и переписанным под собственный USB ИК приемник WinLIRC, я понял что не могу смотреть скачанные киношки каждый вечер, так как делать это хочется не вылезая из под одеяла в спальне. Где висит простенький 40" комбайн, купленный на распродаже, по случаю, в магазине одной из крупных торговых сетей. Возможностей бытового плеера, втроенного в LCD-телевизор, как оказалось, хватило на чтение флешек и SD карт любого размера, но вот в форматах он оказался ограничен AVI и кодеками MPEG-4-ASP и более слабыми.
Решение было простым — перегнать пару сотен несмотренных фильмов в AVI, а в дальнейшем автоматически создавать Lite-версию при окончании загрузки торрента rtorrent-ом на домашнем сервере. Таким образом решение должно было работать как под Windows так и под Linux, так как сервер работает под управлением Gentoo.
Однако технически осуществить все это с наскоку оказалось не так просто. Виндовые конвертеры с блекджеком и прочей мишурой отметались сразу, без попытки установки, а из остального остался только Avidemuх, имеющий как кросс-платформенную реализацию так и нормальный CLI интерфейс. Оставалось только автоматизировать процесс и дать технике заниматься тем, чем ей положено — работать.
На поверку CLI интерфейс Avidemux-а оказался довольно ущербным, но его спасает возможность записи конфигурации проекта в скрипт и последующее его выполнение опцией run:
Подглядеть формат скрипта довольно просто, для этого достаточно запустить GUI-версию Avidemux, сделать все необходимые настройки, а потом сохранить проект в файл. В этом файле хранятся все настройки кодеков и фильтров преобразования.
Собственно смену контейнера с помощью Avidemux можно делать без перекодирования видео, но в моем случае возникла необходимость изменять разрешение выходного файла и ограничивать его ширину 720 пикселями. При этом я не нашел иного способа установить выходное разрешение, кроме явного указания ширины и высоты в пикселях, поэтому идея использовать один скрипт для всех файлов отпала. Пришлось использовать MediaInfo, который также доступен для Linux, и получать из него размеры, а самое главное аспект, выводимого на экран изображения, и исходя из установленной ширины вычислять высоту. Дополнительно появилась идея слегка растягивать «широкоэкранные» фильмы по высоте, чтобы компенсировать визуальное сжатие висящего под небольшим углом телевизора.
Таким образом появился awk-скрипт (выбор awk обусловлен компактностью его реализации для windows, по сравнению, например с перлом). Скрипт ищет по маске *.mkv все файлы (строчку поиска легко изменить для любой платформы), затем для каждого найденного файла вызывает MediaInfo и создает скрипт для AviDemux, а также добавляет команду для вызова конвертера в пакетный файл. В дальнейшем этот скрипт легко переделывается для преобразования отдельного выбранного файла и подключению его менеджеру закачек.
В приведенном исходнике удалены настройки выбранного видео-кодека, так как они занимают места больше чем весь скрипт и могут быть легко получены из проекта AviDemux. При этом следует экранировать все двойные кавычки символом обратной косой черты (в этом awk схож с си).
Я столкнулся с этим по банальной причине бытового комфорта. Имея неплохую медиастанцию под Windows, с подключенной 60" плазмой и шестиканальным звуком, настроенную с душой, с написанными скриптами для AutoHotkey и переписанным под собственный USB ИК приемник WinLIRC, я понял что не могу смотреть скачанные киношки каждый вечер, так как делать это хочется не вылезая из под одеяла в спальне. Где висит простенький 40" комбайн, купленный на распродаже, по случаю, в магазине одной из крупных торговых сетей. Возможностей бытового плеера, втроенного в LCD-телевизор, как оказалось, хватило на чтение флешек и SD карт любого размера, но вот в форматах он оказался ограничен AVI и кодеками MPEG-4-ASP и более слабыми.
Решение было простым — перегнать пару сотен несмотренных фильмов в AVI, а в дальнейшем автоматически создавать Lite-версию при окончании загрузки торрента rtorrent-ом на домашнем сервере. Таким образом решение должно было работать как под Windows так и под Linux, так как сервер работает под управлением Gentoo.
Однако технически осуществить все это с наскоку оказалось не так просто. Виндовые конвертеры с блекджеком и прочей мишурой отметались сразу, без попытки установки, а из остального остался только Avidemuх, имеющий как кросс-платформенную реализацию так и нормальный CLI интерфейс. Оставалось только автоматизировать процесс и дать технике заниматься тем, чем ей положено — работать.
Автоматизация создания скриптов Avidemux
На поверку CLI интерфейс Avidemux-а оказался довольно ущербным, но его спасает возможность записи конфигурации проекта в скрипт и последующее его выполнение опцией run:
avidemux2_cli --run script
Подглядеть формат скрипта довольно просто, для этого достаточно запустить GUI-версию Avidemux, сделать все необходимые настройки, а потом сохранить проект в файл. В этом файле хранятся все настройки кодеков и фильтров преобразования.
Собственно смену контейнера с помощью Avidemux можно делать без перекодирования видео, но в моем случае возникла необходимость изменять разрешение выходного файла и ограничивать его ширину 720 пикселями. При этом я не нашел иного способа установить выходное разрешение, кроме явного указания ширины и высоты в пикселях, поэтому идея использовать один скрипт для всех файлов отпала. Пришлось использовать MediaInfo, который также доступен для Linux, и получать из него размеры, а самое главное аспект, выводимого на экран изображения, и исходя из установленной ширины вычислять высоту. Дополнительно появилась идея слегка растягивать «широкоэкранные» фильмы по высоте, чтобы компенсировать визуальное сжатие висящего под небольшим углом телевизора.
Таким образом появился awk-скрипт (выбор awk обусловлен компактностью его реализации для windows, по сравнению, например с перлом). Скрипт ищет по маске *.mkv все файлы (строчку поиска легко изменить для любой платформы), затем для каждого найденного файла вызывает MediaInfo и создает скрипт для AviDemux, а также добавляет команду для вызова конвертера в пакетный файл. В дальнейшем этот скрипт легко переделывается для преобразования отдельного выбранного файла и подключению его менеджеру закачек.
Исходник скрипта
В приведенном исходнике удалены настройки выбранного видео-кодека, так как они занимают места больше чем весь скрипт и могут быть легко получены из проекта AviDemux. При этом следует экранировать все двойные кавычки символом обратной косой черты (в этом awk схож с си).
BEGIN { # настройки # ширина и высота дисплея, на котором будут проигрываться полученные файлы WIDTH = 720 HEIGHT = 404 # следует ли образать края чтобы подогнать видео под размер экрана CROP = 1 # макс. коэффициент растяжения для устранения/уменьшения ченых полос STRETCH = 0.15 # имя командного файла, в который будут записаны команды для каждого видео BATCH = "run.cmd" # имена исполняемых файлов AVIDEMUX = "P:\\myProgs\\AVIDemux.2.5.6\\avidemux2_cli.exe" MEDIAINFO = "P:\\myProgs\\MediaInfo_CLI_0.7.59\\MediaInfo.exe" # команда, формирующая список нужных файлов (dir, ls, find) LIST = "dir /b *.mkv" # конец настроек ASPECT = WIDTH / HEIGHT STRETCH += 1 while((LIST | getline fn) > 0) { printf("FILE: %s\r\n", fn); InfoCommand = MEDIAINFO " --Output=Video;%Width%/%Height%/%AspectRatio%/%DisplayAspectRatio% \""fn"\"" if((InfoCommand | getline tmp) > 0) { if (match(tmp, /([0-9]+)\/([0-9]+)\/([0-9.]+)\/([0-9.]+)/, m)) { w = int(m[1]) h = int(m[2]) a = 0.0 + m[3] d = 0.0 + m[4] if (a != d) { printf("\tAspect/Display are not equal %d %d\r\n", a, d); } # correct dimentions to square pixels cw = w ch = w / d # stretch to fit display if (cw / ch > ASPECT) { sh = cw / d * STRETCH printf("\timage is wider than display, do vertical stretch\r\n") if (sh > cw / ASPECT) { sh = cw / ASPECT } sw = cw # crop to fit display if (CROP && (sw / sh > ASPECT)) { printf("\timage is still wider than display, do horisontal crop\r\n") sw = sh * ASPECT } fw = (sw < WIDTH) ? rint(sw, 8) : rint(WIDTH, 8) fh = rint(sh / sw * fw, 4) } else if (cw / ch < ASPECT) { sw = ch * d * STRETCH printf("\timage is higher than display, do horisontal stretch\r\n") if (sw > ch * ASPECT) { sw = ch * ASPECT } sh = ch # crop if (CROP && (sw / sh > ASPECT)) { printf("\timage is still higher than display, do horisontal crop\r\n") sh = sw / ASPECT } fh = (sh < HEIGHT) ? rint(sh, 4) : rint(HEIGHT, 4) fw = rint(sw / sh * fh, 8) } rw = cw - sw rh = ch - sh printf("\t%dx%d -stretch-crop-> %d(%+d)x%d(%+d) -display-fit-> %dx%d\r\n", w, h, sw, -rw, sh, -rh, fw, fh); # calc 4 crop values if (rw < 0) rw = 0 if (rh < 0) rh = 0 rwl = int(rw / 2) rwr = int(rw - rwl) rht = int(rh / 2) rhb = int(rh - rht) # make new filenames rsfn = fn avifn = fn sub(/\.[A-Za-z0-9_]+$/, ".rs", rsfn) if (rsfn == fn) rsfn = rsfn ".rs" sub(/\.[A-Za-z0-9_]+$/, ".avi", avifn) if (avifn == fn) avifn = avifn ".avi" # avidemux sript does not like "\" in path gsub(/\\/, "/", fn) gsub(/\\/, "/", avifn) # save run script printf("//AD <- Needed to identify//\r\n")>rsfn printf("var app = new Avidemux();\r\napp.load(\"%s\");\r\napp.video.setPostProc(3,3,0);\r\napp.video.addFilter(\"crop\",\"left=%d\",\"right=%d\",\"top=%d\",\"bottom=%d\");\r\napp.video.addFilter(\"resize\",\"w=%d\",\"h=%d\",\"algo=0\");\r\n", fn, rwl, rwr, rht, rhb, fw, fh)>rsfn printf("app.video.codecPlugin(\"ЗДЕСЬ*ДОЛЖНЫ*БЫТЬ*НАСТРОЙКИ*КОДЕКА\");\r\n")>rsfn printf("app.audio.reset();\r\napp.audio.codec(\"Lame\",128,20,\"80 00 00 00 00 00 00 00 02 00 00 00 05 00 00 00 00 00 00 00 \");\r\napp.audio.normalizeMode=1;\r\napp.audio.normalizeValue=0;\r\napp.audio.delay=0;\r\napp.audio.mixer=\"STEREO\";\r\napp.audio.drc=true;\r\napp.setContainer(\"AVI\");\r\n")>rsfn printf("app.save(\"%s\");\r\napp.Exit();\r\n", avifn)>rsfn # add to batch printf("%s --nogui --run \"%s\"\r\n", AVIDEMUX, rsfn)>BATCH } } close(InfoCommand) } close(LIST) } function rint(v, b) { # floor value to specified base return int(int(v + 0.5) / b) * b }
