Анимированный GIF со звуком

    «Что позволило остаться GIF, это — циклическое проигрывание анимации, которое добавил Netscape. Если бы Netscape не добавил поддержку GIF в свой браузер, GIF умер бы в 1998»

    — Александр Тревор (Alexander Trevor),
    руководитель команды по созданию GIF в CompuServe

    Формат GIF в июне этого года отпраздновал свое 25-летие, и является сегодня самым старым графическим форматом, который распространен в интернете. Посвящая выходные просмотру смешных анимированных гифок понимаешь, что некоторые из них были бы в разы лучше со звуком. Все текущие решения для циклической анимации со звуком (например: coub.com, gifsound.com) предлагают отказаться от GIF, но это — не выход. И я решил пожертвовать просмотром гифок на выходных для решения этой крайне важной проблемы.

    Первая в интернете гифка со звуком по ссылке. Надо нажать на синюю кнопку, а потом на гифке. Плеер должен работать во всех современных браузерах (тестировался в последнем Firefox и Chrome).

    Гифок под катом не будет, а будет процесс создания расширения для стандарта, написания конвертера и плеера.

    С 1987 формат GIF пережил всего два существенных изменения:
    1. В 89 году вышла вторая версия формата (названная GIF 89a). Стало возможным указывать задержку между картинками (нескольких картинок в одном файле было в первом формате GIF 87a). Сторонние разработчики теперь смогли добавлять свои собственные блоки в файл (Application Extension Block).
    2. В 90 году компания Netscape добавила свой блок, который позволял указывать сколько раз будет повторяться анимация.

    Разработка расширения формата


    Как было сказано выше, стандарт GIF 89a позволяет приложениям размещать в GIF файле свои данные. Формат блока расширения для приложений:
    Размер, байт Содержание
    2 Заголовок блока расширения приложения (всегда 0x21, 0xFF)
    1 Размер блока (всегда 11)
    8 Идентификатор приложения
    3 Код аутентификации приложения (может использоваться для проверки, что блок создан конкретным приложением)
    * Вложенные блоки данных
    1 Указатель конца блока (0x00)

    Попробуем уместить сюда заголовка WAVE файла:
    Размер, байт Содержание
    4 Заголовок файла (всегда «RIFF»)
    4 Размер данных
    4 Формат данных (для WAVE фалов — «WAVE»)

    Так как размер блока контролируется форматом GIF, выкинем из заголовка поле с размером данных, а в идентификатор приложения запишем «RIFFWAVE». Остаток WAVE файла запишем как вложенные GIF блоки.

    Блок со звуком будем вставлять прямо перед первым блоком с изображением (на самом деле можно его вставить в любом месте).

    Разработка конвертера


    Конвертер на входе принимает GIF и WAVE файлы, а на выходе выдает GIF с RIFFWAVE блоком. Исходный код можно посмотреть посмотреть на google code.

    Код довольно простой, читаем WAVE файл, создаем из него GIF блок. Потом читаем гиф файл и записываем все блоки, как только находим первый блок с картинкой, перед ним вставляем блок со звуком. Самый важный участок кода — конвертация WAVE файла в GIF блок:

    def get_wav_block(file): 
         # читаем данные из фала
         (signature, 
          size, 
          format) = unpack('4sI4s', file) 
         if signature != 'RIFF': 
            raise Exception('Not a RIFF file') 
         if format != 'WAVE': 
            raise Exception('Not a WAVE file') 
         data = file.read(size - 4) 
    
         # Готовим заголовок блока
         wave_block_header = struct.pack('BBB8sBBB', 0x21, 0xff, 11, 'RIFFWAVE', 0, 0, 0) 
         data_subblocks = [wave_block_header]; 
    
         # разбиваем данные на блоки из 255 байт
         for i in range(0, len(data) // 255): 
              data_subblocks.append(chr(0xff)) 
              data_subblocks.append(data[i*255:(i + 1)*255]) 
         if (len(data) % 255) > 0: 
              rest = len(data) % 255 
              data_subblocks.append(chr(rest)) 
              data_subblocks.append(data[-rest:])          
    
         # добавляем сивол окончания блока
         data_subblocks.append(chr(0)) 
    
         return ''.join(data_subblocks) 
    

    Делаем гифку со звуком


    Делаем анимированный гиф:
    # ffmpeg получаем отдельные кадры 
    ffmpeg -ss 0:00:9.73 -t 2.86 -i warlus.webm -s 500x280 -r 10 frames/image%03d.png 
    # делаем анимированный  GIF
    convert -delay 10 -loop 0 frames/*.png source.gif
    

    Получаем звук и проверяем, что все выглядит (и звучит), как мы запланировали:
    mplayer -ss 0:00:9.73 -endpos 2.86 warlus.webm -ao pcm:file="source.wav" -vo null 
    mplayer -loop 0 -audiofile source.wav source.gif 
    

    Конвертируем в GIF со звуком
    python wave2gif.py example/source.gif example/source.wav result.gif
    

    Делаем плеер


    За основу плеера возьмем jsgif — плеер для анимированных GIF на JavaScript. jsgif разбирает gif и проигрывает рисуя каждый кадр на Canvas. Добавим в него функцию, которая при обнаружении «RIFFWAVE» блока:
    • преобразовываем данные из блока обратно в формат WAVE файла;
    • конвертируем полученный файл в data: URL и передаем в элемент Audio.

    var doSound = function(sound) { 
              // Header 
              var size = sound.data.length + 4 
              var size_text = String.fromCharCode(size  & 255, (size  >> 8) & 255, (size  >> 16) & 255, (size  >> 24) & 255); 
              var header = [ 
                  "RIFF", 
                  size_text, // length 
                  "WAVE" 
              ].join(''); 
              
              var out = [header, sound.data].join(''); 
              var dataURI = "data:audio/wav;base64," + escape(window.btoa(out)); 
              
              sound_element = new Audio(); 
              sound_element.src = dataURI; 
        };
    

    jsgif работает не быстро, а с добавлением звука стал еще медленнее. Так же, чтобы получить данные файла, плеер вызывает XMLHttpRequest, поэтому плеер работает только с картинками с одного домена. Но разве это помехи для искусства.

    Что дальше?



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

    Источники


    GIF89a Specification
    WAVE PCM soundfile format
    jsgif: A GIF player in JavaScript
    Метки:
    Поделиться публикацией
    Похожие публикации
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 39
    • +70
      • +4
        У кого тогда колонки стояли, да ещё в офисе?
      • +9
        Это со спикера ))))
        • +3
          Из ума выпрыгнуть!
          • +17
            wave в gif совать — как-то совсем бесчеловечно )))
            • –7
              главное что не flac
              • +16
                Почему же? Всяко меньше весить будет :)
              • +4
                Аудио поток можно было вставить любой.

                Но, скрещивание старичка GIF с форматами которые в 2,5 раза младше (например Ogg Vorbis) это — нарушение гармонии.
              • +1
                не переживайте! для начала можно добавить ограниченную реализацию: двухбитный звук с дикретизацией, скажем, 5,5кГц :-))
                • +1
                  Сайт с гифкой к сожалению лег.
                  • +1
                    У меня работает. Зашел вот сейчас вот.
                  • –5
                    Зачем?
                    • НЛО прилетело и опубликовало эту надпись здесь
                      • +1
                        Аналогичный вопрос. Ведь анимация со звуком — это видео. Берём OGM или WebM. Тег video сейчас поддерживается большинством браузеров. Но тут скорее был мотив — «а получится ли?».
                        • +4
                          Just 4 fun?
                          • +1
                            Ну, в общем-то «а получится ли?» и «just for fun» неразрывны.
                        • +6
                          Это мой асимметричный ответ Google. Он со своим WebM хочет занять нишу картинок (WebP), а тут его поджидают анимированные гифки со звуком)
                          • –3
                            а зачем минусовать? вполне логичный вопрос кажется задал
                        • +3
                          Если вы взяли браузеры, которые понимают CANVAS и AUDIO, то это браузеры, которые понимают и VIDEO. Не проще ли взять этот тег? Но извращение годное :)
                          • 0
                            Если представить, что мы говорим о анимированных гифках со звуком всерьез, то у них лучше обратная совместимость.

                            Если использовать данный формат, то пользователи Internet Explorer 3 и Netscape Navigator 2 увидят просто о анимированные картинки, и не увидят ничего, если использовать тег video.
                            • +1
                              Делов-то :) Вкладываем внутрь тега VIDEO, тег EMBED.

                              А проблему синхронизации звука и видео вы как-то решали?
                              • 0
                                С EMBED они тоже ничего не увидят, пока не загрузят гипотетический плагин.

                                Синхронизацию делаю в лоб, если выводим первый кадр, то перезапускаем звук:
                                if (curFrame == 1) {
                                  if (sound_element != null) {
                                    sound_element.currentTime = 0;
                                    sound_element.play();
                                  };
                                };
                                
                                • 0
                                  В Виндах давно уже работает безо всякого плагина — через плеер, на Маке — через КвикТайм. Как на Линуксах не знаю.
                                  • 0
                                    Для отладки.
                                    Если на предпоследней секунде мышь резко вывести за границу кадра, звук продолжает звучать и похоже время звучания звука длиннее секвенции картинки.
                                    У меня в моем flash-плеер такая же беда, не знаю как лечить.

                                    А вообще идея хорошая.
                          • +3
                            Пожалуйста-пожалуйста скажите что Вы шутите — не хочу рекламные баннеры со звуком. Ох что-то будет…
                            • +1
                              Чего будет-то? Тег видео и флеш ещё пока почти везде работает.
                              • +1
                                Вот-вот, достаточно и там звука.
                              • 0
                                Будет GifBlock. Или FlashBlock расширят.
                                • 0
                                  Их и так чуть более, чем достаточно, чёрт подери!
                                • 0
                                  Да у вас пытливый ум, однако!
                                  • 0
                                    Плагины required!
                                    Идея — супер!
                                    Реализация тоже =)
                                    • 0
                                      <O_o>Я вздрагиваю когда представляю рекламные баннеры со звуком</O_o>
                                      • 0
                                        Вам повезло, вы их не видели.
                                      • НЛО прилетело и опубликовало эту надпись здесь
                                        • 0
                                          Странно, что раньше вы этого не делали
                                          • НЛО прилетело и опубликовало эту надпись здесь
                                      • 0
                                        Кстати, я знаю один хороший хостинг анимированных «GIF» со звуком, созданный компанией Google
                                        Youtube называется

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