Конвертируем видео… в SVG

    Так уж сложилось, что испокон веков единственный кроссбраузерный способ показать анимацию в браузере без JS — анимированный gif. Был бы у него JPEG-based аналог — и интернет мог бы быть совсем другим… Современные альтернативы, например APNG — работает не везде и со столь же небольшим сжатием, а долгожданный тэг <video> страдает от патентов.

    Хочу поделится результатами моего небольшого академического эксперимента по конвертированию видео в формат SVG (которое затем при везении можно просто показать через <img src="">).

    Академического — потому что проблемы кросс-браузерной совместимости далеки от решения, и потому в нынешнем виде это едва-ли где-то применимо.
    SVG — это не только векторная графика, но и 3 а то и 4 метра качественного видео...

    Сначала результат

    Счастливые обладатели Firefox сразу могли бы видеть видео не отходя от кассы, но Chrome — при встраивании получившейся у нас svg-картинки через <img src=""> падает, потому её пришлось убрать из статьи.

    Но вы можете открыть SVG в отдельном окне. IE требует и открытия в новом окне, и применения встроенного в SVG JS (такой вариант в отдельном окне работает во всех 3-х браузерах, но во встроенном через <img src=""> виде не работает нигде...).

    Размер: это видео в формате SVG занимает 2.3Мб, после GZIP сжатия веб-сервером — 1.56Мб (base64 жмется до размера файла до кодирования). В формате GIF-же видео занимает 24.1Мб. Таким образом, выигрыш в размере в 15 раз при намного лучшем качестве.

    Подходы к реализации

    foreignObject
    SVG позволяет вставлять внутрь себя произвольный HTML (и не только) код через foreignObject. С его помощью можно вставить внутрь SVG и тэг video/flash-плеер, но работает это все совершенно по разному в разных браузерах. В FF например video работает, а flash ничего не показывает, но играет звук. В Chrome — наоборот, flash работает а video-нет.

    Похоже так ничего не выйдет…

    Встроенный через base64 jpeg
    Уже достаточно давно используют включение base64-encoded картинок внутрь css и svg файлов:
    <image id="frame0" width="480" height="201" xlink:href="data:image/jpeg;base64,/9j//gAPTGF2YzU0Lj[...]"></image>

    Попробуем это использовать. Осталось лишь найти способ показывать картинки по очереди…

    SVG SMIL
    SMIL (Synchronized Multimedia Integration Language) позволяет нам реализовать нужную анимацию множества встроенных в SVG кадров:
    <svg version="1.1" baseProfile="tiny" id="svg-root"
      width="100%" height="100%" viewBox="0 0 480 360"
      xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
     
       <image id='frame0' width="320" height="240" xlink:href="data:image/jpeg;base64,/9j//gAPTGF2YzU0Lj[...]" display='inline'>
    <set id="show1" attributeName="display" to="inline" begin="0s;show4.end" dur="1s" fill="freeze"/>
    <set id="hide1" attributeName="display" to="none"  begin="show1.end" dur="0.01s" fill="freeze"/>      
       </image>
       <image id='frame1' width="320" height="240" xlink:href="data:image/jpeg;base64,/9j//gAPTGF2YzU0Lj[...]" display='none'>
    <set id="show2" attributeName="display" to="inline" begin="show1.end" dur="1s" fill="freeze"/>
    <set id="hide2" attributeName="display" to="none"  begin="show2.end" dur="0.01s" fill="freeze"/>      
       </image>
       <image id='frame2' width="320" height="240" xlink:href="data:image/jpeg;base64,/9j//gAPTGF2YzU0Lj[...]" display='none'>
    <set id="show3" attributeName="display" to="inline" begin="show2.end" dur="1s" fill="freeze"/>
    <set id="hide3" attributeName="display" to="none"  begin="show3.end" dur="0.01s" fill="freeze"/>      
       </image>
       <image id='frame3' width="320" height="240" xlink:href="data:image/jpeg;base64,/9j//gAPTGF2YzU0Lj[...]" display='none'>
    <set id="show4" attributeName="display" to="inline" begin="show3.end" dur="1s" fill="freeze"/>
    <set id="hide4" attributeName="display" to="none"  begin="show4.end" dur="0.01s" fill="freeze"/>      
       </image>
    </svg>
    

    Очевидно, это не работает в IE (ни 9 ни 10) — т.к. он не поддерживает SMIL. В Firefox/Chrome это уже работает в отдельном окне, а в FireFox — и в случае встраивания через тэг img.

    Встроенный в SVG JavaScript для IE
    Сама возможность встраивать JavaScript внутрь картинки меня несколько покоробила.
    Тем не менее, такая возможность есть:
    <svg>
    [....]
    <script type="text/ecmascript"><![CDATA[
      var svgDoc;
      var desiredFramesPerSecond=12;
      var msPerFrame = 1000/desiredFramesPerSecond;
      var numFrames = 4;
      
      var frameCt=0;  
    
      svgDoc = document.getElementsByTagName("svg")[0];
      setTimeout("AnimateEm()",msPerFrame);
    
      function AnimateEm(){
        if (frameCt==0) startTime = new Date();
        setTimeout("AnimateEm()",msPerFrame);
    
        svgDoc.getElementById('frame'+frameCt.toString()).style.display='none';
        frameCt=(frameCt+1)%numFrames;
        svgDoc.getElementById('frame'+frameCt.toString()).style.display='inline';
      }
    
    ]]></script>
    </svg>

    При открытии svg в отдельном окне это работает во всех 3-х браузерах, но при встраивании — ни в одном. Возможно специалисты JS смогут это исправить…

    Генерируем наше SVG видео
    1. Раздираем avi-файл на изображения:
    ffmpeg -i "atari.avi" -r 12 -y -qscale 5 -vf scale=480:-1 -f image2 atari%%03d.jpg
    

    2. Генерируем svg
    php -q convert.php >convert.svg
    

    <svg version="1.1" baseProfile="tiny" id="svg-root"
      width="100%" height="100%" viewBox="0 0 480 201"
      xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
     <?
    
    $numFrames = 217;
    $FPS = 12;
    
    for($i=0;$i<=$numFrames-1;$i++)
    {
    ?>
    <image id="frame<?=$i?>" width="480" height="201" xlink:href="data:image/jpeg;base64,<?=base64_encode(file_get_contents("atari".str_pad(($i+1),3,"0",STR_PAD_LEFT).".jpg"))?>" display="<?=($i==0)?"inline":"none"?>">
    <set id="show<?=$i?>" attributeName="display" to="inline" begin="<?=($i==0?"0s;":"")?>show<?=($i+$numFrames-1)%$numFrames?>.end" dur="<?=1/$FPS?>s" fill="freeze"/>
    <set id="hide<?=$i?>" attributeName="display" to="none"  begin="show<?=$i?>.end" dur="0.01s" fill="freeze"/>      
    </image>
    <?
    }
    ?>
    </svg>
    

    Скачать тестовые картинки и скрипт генерации можно тут.

    Надеюсь, более светлые умы хабра смогут улучшить кросс-браузерную совместимость svg-видео, и мы сможем забыть мегабайтные анимированные gif-ы как страшный сон 90-х…
    Поделиться публикацией

    Похожие публикации

    Комментарии 60

      0
      А где можно сразу посмотреть видео?
          0
          Второй показал нормально.
            +7
            у меня хром упал на просмотре
            • НЛО прилетело и опубликовало эту надпись здесь
                0
                Chrome 23.0.1271.64 показывает нормально.
              +9
              Opera: оба играются нормально
                +2
                Chrome 22.0.1229.96, WinXP SP3:
                Первый SVG — показывается первый кадр, а затем падает вкладка.
                Второй SVG — работает нормально.
                  0
                  Что-то ни Хром (23.0.1271.64 m) ни Лиса (17) видео не показывают, показывают только один кадр. Вин7 — 64
                  Оно просто грузится долго, потом всё же показывает, видать хабраэффект…

                  Ещё оба варианта заработали в Rekonq под Kubuntu 12.10 в виртуалбоксе на вин-7
                  И второй заработал под IE-10 в win-8RC в виртуалбоксе на вин-7
                    0
                    Сафари 6.0.2 под OSX 10.8.2, обе ссылки летают.
                    А Хром 23.0.1271.64, как у всех, уронил вкладку после пары кадров по первой ссылке, но отыграл вторую.
                      0
                      Оба показывает без всяких проблем. Хром 23.0.1271.64 m
                      • НЛО прилетело и опубликовало эту надпись здесь
                          0
                          Звука и не должно быть, автор предлагает это как замену gif.
                          0
                          Обе ссылки 404
                      0
                      Подумал, показал два кадра, вкладка упала. Chrome 23.0.1271.64, MacOS
                        0
                        [deleted]
                          0
                          Первый, второй не заметил сразу в тексте(точнее думал что он только для IE). Второй хорошо показывает.
                          0
                          Также падает в Chrome 23.0.1271.64 m Win7
                          +13
                          может мало кого заинтересует, но в Opera хорошо работают оба варианта
                            0
                            А через img src?
                              0
                              Да, тоже.
                                0
                                Хотя не всегда. Если открывать html как file:// — то работает, если руками вставить в какую-нибудь страницу — тоже, а вот если отдано, например, с локального веб-сервера — то нет. Примерно так.
                                  0
                                  Впрочем, Firefox похоже ведет себя также.
                            0
                            Оба вариант норм отыграли на Chrome 23.0.1271.64, Ubuntu 12.04
                              0
                              Chrome 23.0.1271.64 Linux Mint 13, работает только второй
                                +1
                                поправочка: первый вариант тоже не работает, просто сначала я его открыл в отдельном окне, закрыл, а потом чтобы проверить в соседней вкладке, и в этом случае, видать сработал кеш; теперь после сброса кеша первый вариант падает, второй отрабатывает норм
                                  0
                                  Чем принципиально отличаются открытие в отдельном окне и в отдельной вкладке? Хром в обоих случаях создает новый процесс.
                                    0
                                    да, вы правы, но падает все равно через раз как-то, в самый первый раз не упал
                                      +2
                                      Аналогично, у меня тоже в первый раз не упал. Похоже, что процесс падения недетерминирован.
                                0
                                Оба варианта работают, Opera 12.10, OS X 10.8.2

                                UPD: работают, но не на максимальной скорости. Открыл в сафари — там FPS выше примерно в 2 раза.
                                  +3
                                  Прочитав тему, посчитал почему-то, что речь об векторной аппроксимации каждого кадра :) Оказалось не так интересно, но все равно хорошо.
                                    +1
                                    Связь SVG — вектор сильна. Я тоже так подумал
                                    +2
                                    Chrome 23.0.1271.64, MacOS — полет нормальный.

                                    Но интересно, что нормально показывается (даже без тормозов) в Safari на iOS.
                                      0
                                      Chrome 23.0.1271.64 m win 7 x64 не упал в обоих.
                                        0
                                        А в IE не удаётся скрестить SVG с HTML+TIME?
                                          0
                                          В IE10 ничего из таких старых вещей уже не осталось: выпилили всё вплоть до условных комментариев.
                                            0
                                            Да и как подсказывает caniuse.com/#feat=xhtmlsmil в IE9 тоже.
                                            0
                                            Safari, iPad retina — все Ок
                                              +8
                                              понт засчитан
                                              +2
                                              Кстати, вспомнил свой вопрос: в IE отказались от SMIL в пользу CSS Animations (точно так же как в SVG2 от фильтров в пользу общей CSS спецификации по фильтрам). Не пробовали скрестить SVG и анимации CSS?
                                                0
                                                Удивительно, но Chrome for android отработал отлично. Запускал galaxy tab2.

                                                А вот на ноуте вкладка отвалилась спустя пару секунд
                                                  0
                                                  > При открытии svg в отдельном окне это работает во всех 3-х браузерах, но при встраивании — ни в одном. Возможно специалисты JS смогут это исправить…

                                                  Для встраивания через img, это явно запрещено стандартом. При встраивании через object/embed/iframe ограничения мягче.
                                                  Никому ведь не нужно, чтобы простая картинка могла воровать куки или редиректить куда подальше.
                                                    +1
                                                    www.w3.org/TR/SVG/concepts.html

                                                    Ничего не запрещено. Правильно бы было выполнять скрипты в IMG и в CSS background с теми же привелегиями, что и скрипты в IFRAME. А сейчас каждый браузер делает что хочет и получается полнейший бардак.
                                                      0
                                                      Начните с www.w3.org/Graphics/SVG/WG/wiki/Features/SVG-as-image и по ссылкам:

                                                      dev.w3.org/SVG/modules/integration/SVGIntegration.html#referencing_modes
                                                      «2.3 Animated Mode
                                                      This is the referencing mode that must be supported for the SVG ‘image’ element and is recommended to apply to the HTML ‘img’ element and for use as a Widget icon.

                                                      script execution no
                                                      interactivity no»

                                                      > Правильно бы было выполнять скрипты в IMG и в CSS background с теми же привелегиями, что и скрипты в IFRAME
                                                      Неправильно. Это позволило бы картинке «редиректить куда подальше», как это можно сделать в ифрейме с top.location.href="http://ya.ru".
                                                        0
                                                        Ну и к чему эти ссылки? Они WIP и ни к чему не привязаны на данный момент. В спеках — ни слова. RTFM.
                                                          0
                                                          Рекомендую последовать собственному совету и поискать в стандарте 2001 года, что-нибудь про модель безопасности. После чего станет ясно почему все браузеры следуют более свежим документам (и здравому смыслу). Что будет в противном случае мы видели совсем недавно.
                                                    +3
                                                    Конечно, это ужасный костыль, но ведь работает!

                                                    Печально что с тегом video все так сильно затормозилось, будь они прокляты, эти копирасты.
                                                      0
                                                      В итоге удалось выиграть в весе у GIF, насколько стало видео легче?
                                                        +3
                                                        Это видео в формате GIF — 24 Мб, в формате SVG — 2.3Мб, после GZIP сжатия (сервер-то отдает в сжатом виде, а base64 жмется до размера файла до кодирования) — 1.56Мб

                                                        Выигрыш по размеру в 15 раз при намного более высоком качестве.
                                                          0
                                                          А оригинал-то сколько весит?
                                                            0
                                                            480x201x3x217 = 62,8Мб, это если считать несжатое видео.
                                                              0
                                                              Нет, интересует именно оригинальная сжатая avi-шка.
                                                                0
                                                                Тогда надо не avi смотреть, а формат ютуба, к примеру.
                                                        +2
                                                        А выложите на Github тогда, раз вы раздаете исходники. Так хотя бы будет возможность улучшить или поддерживать.
                                                          +1
                                                          Можно, кстати, анимировать вертикальный, не прогрессивный спрайт. Кадры будут подгружаться по очереди. Вопрос только один: что делать, если с соединением проблемы.
                                                            0
                                                            Еще бы звук, и можно фильмы смотреть :)
                                                              0
                                                              На Galaxy Nexus (Android 4.1.1):
                                                              • Стандартный браузер — работают оба
                                                              • Firefox — оба
                                                              • Chrome — оба
                                                              • Opera — оба выдают 1 кадр в секунду
                                                                0
                                                                OS X 10.8.2, Safari 6.0.1 — все работает прекрасно
                                                                  0
                                                                  Chrome Версия 24.0.1312.5 dev-m:
                                                                  без js — вкладка падает через несколько секунд воспроизведения видео;
                                                                  с js — всё нормально, играет полностью.

                                                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                  Самое читаемое