flysoft
Компания
30,28
рейтинг
29 августа 2013 в 16:01

Разработка → To GIF or not to GIF?

Всем привет! Меня зовут Антон, я занимаюсь разработкой серверной части iFunny — мобильного юмористического сервиса. В этой статье я расскажу о том, как эволюционировал наш подход в работе с анимацией в проекте и какие профиты были получены в конечном итоге.




Известно, что юмор замедляет процессы старения, а смех продлевает жизнь, именно поэтому нам столь приятно делать iFunny, который ежедневно дарит улыбки и хорошее настроение более, чем 4 миллионам пользователей (в данный момент, к сожалению или счастью, по большей части из США). Мы стремимся стать самым удобным fun-браузером в мире, а также местом, где рождается лучший юмор. В сутки наши пользователи загружают более 250 000 работ.

До недавнего времени мы раздавали около 150TB статики в сутки, но с добавлением анимации в проект получили прирост количества загружаемого контента на 17% и увеличение ежесуточного трафика до 750TB.

Оптимизация GIF


Так сложилось, что в настоящее время в GIF кодируют самые интересные нарезки из юмористических (и не очень) видеороликов, что печально отражается на объеме результирующих файлов. По нашим ощущениям, средний размер GIF-анимации в современном интернете составляет порядка 5Mb. Логичный вопрос, которым мы задались при разработке — сможем ли мы как-то оптимизировать анимацию на серверной стороне, чтобы уменьшить её объём?

Проведя ряд экспериментов с различными анимированными файлами и алгоритмами оптимизации (Basic Frame Optimization, Transparency Optimization), мы пришли к выводу, что выигрыш от оптимизации для большей части изображений оказался совсем небольшим, порядка 10-20%. Более того, если GIF-анимация была уже неплохо оптимизирована её автором, то при автоматическом подходе мы могли получить противоположный эффект.

Свет надежды на то, что удастся как-то облегчить объём файлов анимации, потух, и мы стали использовать GIF в том виде, в котором его нам загружают пользователи.

Релиз версии с GIF


Если с реализацией поддержки GIF на стороне сервера и в iOS-клиенте было всё довольно просто, то на Android-клиенте нам пришлось прибегнуть к инструментам бородатых джедаев — libgif + JNI, что только раззадорило нас.

Как только все было закончено, мы прошли проверку цензоров в App Store, залили приложение в Google Play и запустились… И сразу по итогам первого дня увидели резкий скачок просмотров контента и, соответственно, трафика. В первые 24 часа трафик вырос в 6 раз!



Суммарно за полмесяца объем раздаваемого трафика возрос на 200% и в июне, благодаря запуску анимации в iFunny, мы раздали 4.75 Петабайта! Увеличение активности аудитории, безусловно, не может не радовать, но так ли все оказалось хорошо в итоге?

Мы были готовы к определенному количеству GIF-анимации в iFunny, но та статистика, которую мы получили в первые несколько суток, дала нам понять, что мы недобитые оптимисты: реальное количество загружаемой GIF-анимации в сутки превышало ожидаемое в 5 раз. Вкупе с массивными 3-4-мегабайтными GIF, идущими через каждые 3-5 статичных изображений, мы получили сервис, которым можно было пользоваться только через WiFi. Даже пользователям с безлимитным 3G приходилось туго: анимация грузилась долго, а из-за активной работы 3G-модуля девайс сильно разогревался и убивалась батарейка.

Нужно что-то делать...


На фоне отрезвляющей статистики мы задались вопросом: насколько GIF (набор изображений, по сути) подходит для подобного использования? Нам видится, что если мы имеем дело с простой анимацией, содержащей небольшое количество фреймов, то использование GIF более чем оправдано. Однако, как я говорил выше, современный юмористический GIF — это нарезка интересных моментов из видеороликов…

Исходя из вышесказанного, мы решили попробовать отказаться от GIF в пользу какого-нибудь подходящего для воспроизведения коротких анимированных роликов видеоформата. В таком случае, необходимо было найти подходящий формат кодирования. Были рассмотрены стандарты кодирования h.263, h.264, а также видеокодек vp8 в контейнере WebM.

Провели тесты рекодирования GIF в видео, и замаячил свет в конце тоннеля: размер результирующих видеороликов получался в 2-10 раз меньше, чем GIF-исходник!

Осталось определиться с кодеком. Использование кодека-пенсионера — h.263 давало ужасную результирующую картинку и противоречило нашим моральным нормам, поэтому его мы отмели первым.
h.264 — хороший кодек, однако связываться с охраняемыми патентами технологиями нам не хотелось, да и результирующий размер файла оказывался довольно большим: на 20-40% больше, чем при кодировании того же фрагмента в vp8. Поэтому мы решили остановиться на vp8.

Дополнительным аргументом при выборе vp8 также послужило то, что Google активно внедряет и использует его на YouTube, и в настоящий момент разрабатывается улучшенный формат VP9, что позволяет судить об успешности и перспективности всего проекта в целом.

Для конвертации из GIF в WebM используем сборку ffmpeg с поддержкой GIF-декодера и vp8-энкодера. Сам процесс конвертации проходит без особых замечаний и довольно быстро, но сразу же сталкиваемся с проблемой в результирующем видеоролике. Возьмем такую GIF-анимацию, например:



Обратите внимание, у последнего кадра есть задержка в 2 секунды, после чего анимация проигрывается заново. В полученном WebM-файле эта задержка куда-то волшебным образом исчезает, и последний кадр “проскакивает”. Анализ прочего контента показал, что задержка после последнего кадра у анимации убирается всегда, что для нас является довольно большой проблемой, ведь мы хотим, чтобы пользователи в приложении вообще не видели разницу между GIF и видеороликом. Проблему решили, но таким костылём, что до сих пор краснеем от стыда: к конвертируемой GIF добавляем дубликат последнего фрейма.

В рядах мобильных разработчиков в это время царил хардкор: собрали libvpx под нужные платформы, написали обёртку-плеер на Си и вуаля.

Релиз версии с WebM


После релиза версии, где пользователям вместо GIF-анимации мы стали проигрывать короткие видеоролики, стало ясно, что проделанная работа принесла свои плоды: расход трафика за одну сессию снизился с неадекватных 50-100Mb до вполне комфортных 7-20Mb, девайсы стали меньше греться и убивать батарейку, а самое главное, пользователи стали видеть контент чаще, чем его прелоадер.

Если говорить о нашем раздаваемом трафике, то картина получилась следующая:



Переход с GIF на WebM позволил сократить объемы раздаваемого трафика на 30% и снизить CDN-расходы примерно на $50 000 в месяц.

Выводы


Формат GIF87, созданный более 20 лет назад, по задумке автора должен был использоваться для передачи растровых изображений по сети, а модификация GIF89 позволяла использовать изображения с прозрачностью и хранить набор простых слайдов с определенной задержкой — анимацию.

На своем жизненном пути формат успел сделать несколько значительных революций, то умирая, то рождаясь заново.

Например, все мы помним анимированные рекламные баннеры, которые, к сожалению, до сих пор используются в некоторых рекламных сетях. Да, сейчас воспоминания о мигающих и дёрганых баннерах больше ассоциируются с галлюцинациями от ЛСД, но 10-20 лет назад это была революция — интернет перестал быть статичным.

Сейчас GIF также делает революцию, способствуя лавинообразному распространению нового формата юмористического контента — коротких видеофрагментов. Однако, с высоты нашего опыта, можем сказать, что использование GIF для такого контента не является правильным по ряду перечисленных выше причин, и лишь один весомый аргумент заставляет пользователей распространять нарезки из видеороликов в GIF — это повсеместная его поддержка во всех браузерах. У нас не связаны руки возможностью веб-навигаторов, поэтому нам удалось «оживить» iFunny без минусов, присущих GIF.
Автор: @hackPNZ
flysoft
рейтинг 30,28
Компания прекратила активность на сайте

Комментарии (41)

  • +2
    Антон, а как вообще распределяется нагрузка на пользователя? Вы никогда не задумывались, чтобы ввести, эммм, как бы это сказать… Изменение качества анимаций? Грубо говоря, как на ютубе?
    Просто пишу это потому, что с моим 64 кб/с особо не посмотришь 8ми мегабайтных гифок. Вам не кажется, что данный метод был бы весьма удобен?
    • +2
      Мы все же не стримим большие видео-ролики на данный момент. Поэтому, пока что нет особого смысла внедрять «адаптивное качество анимации». Если тяжелая гифка весила 3-4Mb, то ее webm-версия обычно ужимается в 700-900Kb. Такие объемы не напрягают пользователей. По крайней мере, наш саппорт не жалуется)
  • +1
    > Проблему решили, но таким костылём, что до сих пор краснеем от стыда: к конвертируемой GIF добавляем дубликат последнего фрейма.

    А почему бы не добавлять прозрачный фрейм?
    • +5
      Да дело не в том, какой фрейм добавлять — его всё равно не увидит никто, а исходную GIF никто не трогает, это только для конвертации в видео.
      Стыдно потому, что могли бы правильно решить проблему, не прибегая к костылям — пропатчить libvpx, либо ffmpeg, смотря у кого проблема, но сил и времени пока не хватает на это, к сожалению.
      • 0
        Не думали вместе с роликом передвавать длительность задержки после последнего кадра. А при просмотре внутри приложения ставить паузу указаной длительности? Или это нетривиальная задача, учитывая нестандартность плеера?
        • +17
          Это еще более жёсткий костыль, чем описанный в статье.
  • –2
    А тем кто не умеет webM, например всяким ios, которые гененируют львиную долю мобильного трафика так и остался gif?

    • +6
      В посте же: «собрали libvpx под нужные платформы». Таким образом, ios научился webm.
    • 0
      В рядах мобильных разработчиков в это время царил хардкор: собрали libvpx под нужные платформы, написали обёртку-плеер на Си и вуаля.
  • 0
    Переход с GIF на WebM позволил сократить объемы раздаваемого трафика на 30% и снизить CDN-расходы примерно на $50 000 в месяц.
    Сижу с калькулятором и ради забавы рассчитываю варианты сэкономить на CDN. А то в месяц вы тратите около $100 000, что как-то много. Не хватает параметра — сколько занимает места ваш контент и по сколько МБ/ГБ в день его прибавляется?
    • +1
      Траффик намного дороже обходится нежели место.
      • 0
        А я хотел бы посчитать вариант без использования CDN (под CDN, я полагаю, в статье понимается некий сторонний облачный сервис), на обычных железках. И поэтому в этом случае важно знать объемы контента.
        • +1
          Были мы некоторое время на обычных железках для задач по раздаче статики…
          Если интересно, то в этом (scribd) выступлении более подробно, с какими проблемами столкнулись и к чему в итоге пришли. Правда, годичной давности, но в плане CDN сейчас ничего не поменялось у нас.

          Вкратце — поддерживать столько обычных железок, разбросанных по всему миру, нам на данный момент не под силу своей командой, поэтому пользуемся услугами партнёра
  • 0
    Забавно. Очень здорово у вас вышло.
  • +1
    А почему не сделать просто у GIF-ок кнопку play? Ну т.е. в ленте вместо полных GIF-ок идут только картинки с их первыми кадрами, если на какую-то из них нажать — подгрузится вся GIFка и пойдет анимация. Так сделано много где — тот-же 9gag например. По-моему гораздо проще чем кодировать в video.
    Или есть статистика что все пользователи всегда все гифки пытаются посмотреть? :-)
    • +1
      Думали и на этот счет, но… Почему гифки стали так популярны сейчас? Видео дольше загружается, часто показывает рекламу, нужно каждый раз нажимать «play» и тд. Для целых больших фильмов это ок, но когда хочется посмотреть десяток-другой коротких роликов за раз — напрягает.
      • +1
        Понял. У нас просто в проекте был такой вариант, как я описал + когда загрузилась картинка первого кадра — идет ожидание и если пользователь не нажал next в течении некоторого короткого промежутка времени (секунды например) — значит ему интересно и тогда оригинальная GIF-ка автоматически начинала подгружаться.
        Хотя… это тоже костыль, просто не программерский ) этакий лайфхак )
        • 0
          Похожее поведение на сайт версии, заставлять щелкать лишний раз пользователя на «play» очень не хочется, а ждать когда загрузится gif анимация на 3G достаточно долго. Для слабых устройств отказ от gif в пользу первого кадра это небольшой глоток производительности.
          • 0
            habrahabr.ru/post/87083/ lazy-load?
            На мобильных девайсах например показало 50 анимаций, пользователь видит 5. Именно эти 5 анимаций будут загружены. Уменьшение трафика в 10 раз в случае, если пользователь не прокручивает дальше. Также можно сделать так, чтобы перввый кадр был статичен, а дальше при прокрутке загружались анимации.
            • 0
              Там, где нет поддержки webm и приходится отдавать тяжелые гифки (например, в некоторых мобильных браузерах), вариант со статичным первым кадром + дальнейшей подгрузкой GIF неплох. В мобильном приложении проще сделать фоновую подгрузку изображений/webm. Пользователь смотрит конкретный контент и в это время в фоне загружаются несколько «соседних» элементов. Да, он никогда может на них не перейти и мы прогоним этот трафик вхолостую. Но проведя тестирование, мы увидели, что избыточность при таком подходе совсем невысокая. Зато, мы получаем плавность перехода между элементами в «ленте», приложением становится намного приятнее пользоваться.
              • 0
                Если будет приложение, ну очень соверую поставить ручную настройку кэша в настройках. А то часто есть переключатель вкл-выкл, хотя кэш там либо маловат, либо большой слишком. Например у меня есть нексус 4, там 16 гигов памяти, могу для частоиспользуемого приложения кэш хоть гигабайт сделать (хотя тут хватит 100 мегов я так думаю), а есть еще LG Optimus One и там кэш может 1-10 мбайт, не более.
                Кстати как вариант при подгрузке, думаю возможно как нибудь загружать одновременно 3 анимации, и например если они длятся 4 секунды, то они успеют в процессе загрузиться. Т.е. загружаем сразу пакетом несколько штук и если они на экране сразу проигрываем недозагруженные, или библиотеки не позволят?
    • +1
      Я очень жду, когда всплывающую полупрозрачную кнопку stop/play для animated gif введут у себя обычные браузеры.
      • 0
        Думаю, этому не быть :)
  • 0
    GIF87a тоже анимацию умеет.
      • 0
        Спасибо, конечно, за ссылки, но насколько я помню стандарт, ничего не мешает там делать анимированные гифы. В 87-м стандарте только не было величин задержек и расширения для количества повторений (насколько я помню, это вообще не часть стандарта, а расширение браузера Netscape).
        • +3
          Ну из табуретки тоже ничего не мешает сделать колесницу, если прикрутить колёса и лошадь :)
          • +1
            Да-да, ок. Но только GIF87a тоже умеет анимацию.
  • +1
    $100k в месяц раздачи трафика с лихвой окупается рекламой? 4 млн пользователей, даже при CPM 10 (что довольно много) получается всего 4000*10=$40k.
    • –1
      Какой-то не скромный вопрос, вы не находите?
      • +2
        Конечно нескромный, но всем же интересно. Откуда там в картинках может быть большой eCPM, это и есть самое интересное.
        • 0
          Мы упорные. А если серьезно, это тема для отдельной статьи.
  • +1
    Откуда кадр? Шварцнегер играл Гамлета?
    • –9
      Терминатор, тащем-то.
      Стыдно классику не знать…
      • +11
        Последний киногерой… очень стыдно не знать классику…
      • +4
        Не «Терминатор», а «Последний герой боевика» (Last Action Hero)
    • 0
  • 0
    Проблему решили, но таким костылём, что до сих пор краснеем от стыда: к конвертируемой GIF добавляем дубликат последнего фрейма.

    Забавное совпадение, но проблема с задержкой на последнем кадре в GIF была, кажется и в ACDSee. Т.е., когда я просматривал в этом вьювере свои гифки (по малолетке увлекался анимацией в аватарках), то задержка в последнем кадре не воспринималась, и кадр проскакивал мгновенно. Давно это было, надеюсь, не ошибся, и это была ACDSee, а не браузер. Может, у вашего конвертера из того же места уши растут.
  • +1
    Отличная идея у вашей программы, пошёл ставить.

    Думаю, после этого поста количество русскоязычных пользователей добавится.
  • 0
    Воспользовавшись моментом, задам вопрос, — кто-то может подсказать решение для генерации GIF на сервере из кадров? Желательно JS/Ruby/PHP. Пардон за оффтоп.

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

Самое читаемое Разработка