воскресенье, 31 июля 2011 г.

Грабим и конвертим

Задача довольно типичная: сграбить видео с камеры Mini-DV и получить что-нибудь удобоваримое (будем считать эталонным выходом DVD, хотя, конечно же, каждому своё).
Традиционное решение --- то, что я видел, что делают другие --- это:
  1. использовать kino для того, чтобы списать содержимое ленты на жёсткий диск (как говорят, "сграбить" в файлы *.dv)
  2. использовать ещё одну GUI-программу, чтобы сконвертить эти файлы в то, что нужно
Такое решение неуклюже: использование графических оболочек, кучи места для промежуточных файлов. Поэтому поставлю задачу: в командной строке сделать всё за один проход без промежуточных файлов. Амбициозно? надеюсь, что да. Реально? совершенно точно: ДА. И это --- хорошая демонстрация unix-way.
С чего начну? с инструментария, очевидно. Попробуем так:
  • dvgrab --- "грабит" из командной строки
  • ffmpeg --- прекрасно и гибко конвертит

Небольшое отступление: в процессе "хакинга" проблемы захотелось проделать банальную операцию: выделить звуковую дорожку из видео-файла. Возможно, многие вспомнят, что это можно сделать из avidemux. Прочь окна и менюшки! В командной строке:
$ ffmpeg -i mov016.dv -vn -acodec copy /tmp/1.wav
Получается WAV с одной дорожкой аудио, что и требовалось.
Итак, несколько кирпичиков, из которых я построил решение:
  • Простая конвертация файла видео в формат DVD (vob):
    $ ffmpeg -i mov016.dv -target dvd mov016.vob
  • unix-way ffmpeg: использование pipe-ов:
    $ ffmpeg -i mov016.dv -vn -acodec copy -f wav pipe: > /tmp/1.wav
  • заменить звуковую дорожку при конвертации:
    $ ffmpeg -i mov016.dv -i /tmp/1.wav -map 0:0 -map 1:0 mov016.avi
А теперь полностью задача и моё решение:
Задача: сконвертить готовый MiniDV-граб, записанный на DVD. При этом, почему-то, конверторы считают, что звук имеет частоту сэмплирования 48кГц (должно быть, это граббер напортачил). Надо вернуть звук в правильные 32кГц. (Это удалось выяснить, выделив 20 сек. звуковой дорожки, и проанализировав звук в audacity)
Решение:
$ mkfifo /tmp/v/a ; for f in `ls /media/cdrom/`; do screen -d -m bash -c "ffmpeg -i /media/cdrom/$f -vn -acodec copy -f s16le pipe: > /tmp/v/a" ; idlewrap ffmpeg -i /media/cdrom/$f -f s16le -ar 32000 -i pipe: -map 0:0 -map 1:0 -deinterlace -target dvd $f.vob < /tmp/v/a ; done ; while true; do aplay ~/Documents/sound/Масяня/Па-ба-бам-па-бам\ \(типа\,\ труба\).wav ; sleep 30 ; done
Не хочу объяснять, как это работает. Кто не сможет разобраться, тем лучше пока не пытаться писать длинные выражения в шелле. Впрочем, уважая читателя, я приведу ту же команду в отформатированном виде:
mkfifo /tmp/v/a ;
for f in `ls /media/cdrom/`; do
  screen -d -m bash -c "ffmpeg -i /media/cdrom/$f -vn -acodec copy -f s16le pipe: > /tmp/v/a" ;
  idlewrap ffmpeg -i /media/cdrom/$f -f s16le -ar 32000 -i pipe: -map 0:0 -map 1:0 -deinterlace -target dvd $f.vob < /tmp/v/a ;
done ;
while true; do
  aplay ~/Documents/sound/Масяня/Па-ба-бам-па-бам\ \(типа\,\ труба\).wav ;   sleep 30 ;
done

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