Интересный момент произошел в развитии направления обработки и преобразования видео. Возникла задача по наложению не статической картинки водяных знаков, а полноценного видеоролика (например, титров или рекламы или динамического лого).

На входе у нас есть:

  • начальный видеоролик
  • последовательность кадров титров для наложения в виде серии PNG-кадров (можно использовать и видео, но возникают вопросы с альфа-каналом)

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

В общем и целом задача решается двумя очевидными методами:
1. плохим – разобрать исходное видео на кучу кадров, последовательно скрестить их с маской
2. хорошим – расковырять vhooks и сделать по подобию watermark соответствующий плагин, который смог добавлять маску в момент перекодирования.

Почему плох первый метод? Ответ на это вполне очевиден, стоит лишь провести серию экспериментов по решению данным путем. Представьте себе, что у вас видео 640 на 480 длится в течение часа (для простоты условимся на 24 кадрах в секунду, т.е. 86 400 кадров). Ffmpeg умеет раскладывать видео в последовательность JPG и PNG файлов. При отображении в PNG потребуется, при «весе» средней картинки в районе 0.5 МБайт, что-то 43.2 Гбайта места на жестком диске (не говоря о том факте, что файловой системе изрядно поплохеет ворочать объем в десятки тысяч файлов, но это мелочи). Т.е. расточительно. Если же проецировать в JPG, то дискового пространства потребуется меньше (от количества файлов мы не уходим, но все полегче), но при этом качество картинки ухудшится из-за сжатия с потерями. Это неприятно. Кроме этого, надо учитывать, что в обоих процессах, как разборки, так и сборки, операции ввода-вывода съедят сколь угодно мощную машину.

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

Сначала сделаем серию кадров из видео простой командой:

1
ffmpeg -i terminator_vp6.flv -f image2 src/i%09d.jpg

Далее, на полученную последовательность наложим маску. Приведенный ниже пример на PHP использует ImageMagic для совмещения кадров:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/usr/bin/php5
<?
    $s = array();
    $m = array();

    $d = dir('src');
    while (false !== ($e = $d->read())) {
    if($e != '.' && $e != '..') array_push($s, $e);
    }
    $d->close();
       
    $d = dir('mask');
    while (false !== ($e = $d->read())) {
    if($e != '.' && $e != '..') array_push($m, $e);
    }
    $d->close();

    sort($s);
    sort($m);
   
    $sz = getimagesize('src/'.$s[0]);
   
    if($sz[0] > 0 && $sz[1] > 0)
        // маску необходимо привести к размеру ролика
    foreach($m as $mi) {
        system("convert mask/$mi -resize $sz[0]x$sz[1] cmask/$mi");
    };
   
    $i = 0;
    while($i < count($s) && count($s) > 0 && count($m) > 0) {
    for($j = 0; $j < count($m); $j++) {    
            // собственно наложение
        system("composite -compose over cmask/".$m[$j]." src/".$s[$i]." result/".$s[$i]);
       
        $i++;
        if($i >= count($s)) break;
    }
    }
?>

И, наконец, соберем полученные кадры в единый ролик. Надо отметить, что мои попытки собрать видео из PNG потерпели неудачу, что, скорее всего, моя вина, глубоко этот вопрос не изучал.

1
ffmpeg -f image2 -i result/i%09d.jpg -f flv -b 128K -vcodec libx264 result.flv

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

На основании вышеизложенных «страшностей» можно обратиться ко второму методу, а именно – к созданию плагина для ffmpeg, позволяющего вставлять маску на лету. Но тут оказалась другая неприятность – ffmpeg как постоянно развивающийся и совершенствующийся проект (для которого нормой использовать не готовы бинарные сборки, а собирать экспортированные из системы контроля версий исходники) потерял vhooks как класс вследствие того, что разработчики сочли это неудачным решением (а так оно и было). Беда в том, что после удаления vhooks в коде проекта не осталось ни одной альтернативы или схожего механизма, а наследник avfilters – находится достаточно в сыром состоянии и еще не включен в основное дерево. Получается, что единственно возможный метод решения на данный момент – написание полноценного приложения, что достаточно трудоемко, учитывая размер кода ffmpeg. К счастью, в рассылке пользователей обнаружилось письмо, приводящее решение вопросов с водяными знаками (которые попали под раздачу вместе с vhooks), на основании которого можно предположить, что имеющаяся функциональность avfilters низведет нашу задачу до статуса тривиальной и решаемой штатными средствами. Осталось немного подождать, пока avfilters не включат в основную ветку.


Прокомментировать

Мой Круг — Максим Крентовский

Рекомендую

Автомобильные видеорегистраторы с GPS на gadgetz.ru