2010-03-30 FFmpeg и именованные каналы
Прикольная фишка консольного ffmpeg’а — его можно использовать вместе с именованными каналами (named pipes) для нарезки и слияния видео.
Шаг первый: создаём именованные каналы. А допустим, у нас ещё и аудиодорожек несколько.
Сначала я хотел написать, как завещал великий FAQ — по одному файлу на каждую дорожку, то есть целую кучу: file1.v file1.a1 file1.a2 file2.v file2.a1 file2.a2 file.v file.a1 file.a2. Однако обнаружил, что AVI-контейнер прекрасно переживает конкатенацию и что в этом случае результат получается даже лучше — на мгновении, когда Балу дёргает Багиру за хвост в процессе пения Bare Necessities, не возникает никакого затупа. А в случае с кучей raw-файлов — возникало. Так что попробуем AVI.
mkfifo file1.avi mkfifo file2.avi mkfifo file.avi
Шаг второй: запускаем декодирующие в сырые форматы ffmpeg’и и конкатенирующий потоки cat в фоновом режиме — пускай ждут, пока им разрешат писать в каналы. Пусть входные файлы у нас — это грёбаные DVD’шные VOB’ы с тремя аудиодорожками, дискретизированными на 48 KHz, первые две — 5.1, последняя — моно.
Кстати 1: -ss нужно указывать время либо в секундах, либо в формате HH:MM:SS[.mmm]. Именно в таком, то есть просто MM:SS не прокатит.
Командная строка FFmpeg’а некоммутативна :) от перемены аргументов местами меняется смысл. Например, если указать -ss после -i файл, вы задолбаетесь ждать, пока оно перейдёт к нужному месту в файле, потому что будет seek’ать на уровне кодека. А если указать -ss до -i файл, seek’ать оно будет на уровне контейнера и сделает это быстро.
Кстати 2: для сырых аудиоформатов обязательно указывать параметры -ac -ar и -f (например s16le) либо -acodec (например pcm_s16le), как при кодировании, так и при декодировании, иначе как же оно узнает, какой raw формат мы хотим? При чтении raw формата эти параметры нужно указывать до -i входного_файла.
А -newaudio, например, нужно указывать после имени выходного файла. А опции для добавляемой -newaudio аудиодорожки — непосредственно перед -newaudio.
Кстати 3: -y поможет нам избежать предупреждений.
Кстати 4: запуск ffmpeg’ов с «выпуском» в именованный канал нормально не удавался под непривилигерованным юзером — ffmpeg получал SIGSTOP. В чём дело, я разбираться особенно не стал, а просто пускал его под рутом.
ffmpeg -y -ss 00:24:18 -i VTS_01_1.VOB -map 0.0 -map 0.1 -map 0.2 -map 0.3 \ -vcodec rawvideo -acodec pcm_s16le -ac 6 -ar 48000 file1.avi \ -acodec pcm_s16le -ac 6 -ar 48000 -newaudio -acodec pcm_s16le \ -ac 1 -ar 48000 -newaudio &>log1 & ffmpeg -y -t 91 -i VTS_01_2.VOB -map 0.0 -map 0.1 -map 0.2 -map 0.3 \ -vcodec rawvideo -acodec pcm_s16le -ac 6 -ar 48000 file2.avi \ -acodec pcm_s16le -ac 6 -ar 48000 -newaudio -acodec pcm_s16le \ -ac 1 -ar 48000 -newaudio &>log2 & cat file1.avi file2.avi > file.avi &
ffmpeg -y -ss 00:24:18 -i file1.avi -an -f yuv4mpegpipe file1.v &>log1.v & ffmpeg -y -ss 00:24:18 -i file1.avi -vn -map 0.1 -ac 6 -ar 48000 -f s16le file1.a1 &>log1.a1 & ffmpeg -y -ss 00:24:18 -i file1.avi -vn -map 0.2 -ac 2 -ar 48000 -f s16le file1.a2 &>log1.a2 & { ffmpeg -y -i file2.avi -t 91 -an -f yuv4mpegpipe - 2>log2.v | tail -n +2 >file2.v ; } & ffmpeg -y -i file2.avi -t 91 -vn -map 0.1 -ac 6 -ar 48000 -f s16le file2.a1 &>log2.a1 & ffmpeg -y -i file2.avi -t 91 -vn -map 0.2 -ac 2 -ar 48000 -f s16le file2.a2 &>log2.a2 & for i in v a1 a2; do cat file1.$i file2.$i > file.$i & done
Кстати 1: запустить один ffmpeg, который будет писать сразу несколько выходных файлов, не получится, т.к. кодирующий ffmpeg их будет анализировать по очереди, а декодирующий захочет писать все вместе. А писать в канал, из которого никто не читает, нельзя. Поэтому "сборка" просто повиснет.
Кстати 2: сырой видеоформат называется -f yuv4mpegpipe. Он допускает конкатенацию, но в этом случае нужно отрезать первую строку у всех файлов, кроме первого, чтобы их потоки начинались со слова "FRAME". Сырой видеокодек - -vcodec rawvideo.
Шаг третий: запускаем кодирующий ffmpeg.
Кстати: для libx264, начиная с какой-то (Х-З какой) версии ffmpeg’а, нужно указывать опцию -vpre. А ещё лично я люблю забивать максимальный фактор квантования и не париться о качестве.
ffmpeg -y -i file.avi -vcodec libx264 -vpre hq -qmax 28 \ -acodec libfaac -ab 448k -ac 6 BareNecessities6ch.avi \ -acodec libfaac -ab 384k -ac 6 -newaudio \ -acodec libfaac -ab 96k -ac 1 -newaudio
И всё, с данного момента вся спящая в фоновом режиме машинерия активизируется и начнёт кодировать-декодировать.
Изначально вкурено с http://ffmpeg.org/faq.html#TOC29, но сильно исправлено и дополнено :)
[ Хронологический вид ]Комментарии
Войдите, чтобы комментировать.