flash-видео на веб-страницах и PHP

    Эта статья — перепечатка статьи от 16 ноября 2007 г. с моего блога, ссылку на который можно найти в моем же профайле — но, поскольку так уж вышло, что тема эта, кажется, до сих пор многим интересна, к тому же не так давно я читал на эту тему доклад на конференции PHPConf… в общем — судите сами.

    Вступление


    В последнее время все большее распространение получает технология трансляции видео через веб – без необходимости скачивать медиа-контент на машину пользователя, с просмотром прямо из браузера. Таким образом можно просматривать довольно большое количество различных форматов видео, однако, это требует наличия определенных плагинов на стороне пользователя. Очевидно, самым распространенным подобным плагином является flash-player (ну хорошо, хорошо: если быть точным, то он, конечно же, не может сам по себе проигрывать видео – но позволяет легко создать приложение, способное воспроизводить видео-контент). Яркий пример такого подхода – youtube.com. Попытаюсь рассказать о том, как самостоятельно организовать трансляции флэш-видео на своей веб-странице и какие существуют подходы к этой проблеме.


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

    1. О формате FLV


    Итак, flash-player воспроизводит видео в формате FLV, других форматов не понимает.
    Подробнее о самом формате можно почитать, например, здесь: en.wikipedia.org/wiki/FLV, а также, само собой, на сайте компании Adobe – производителя flash-player. В рамках данного доклада нам не понадобятся детальные знания о формате, а те, что понадобятся, приведены ниже.
    FLV-файл состоит из заголовка и собственно самого фильма.
    Заголовок содержит определенную мета-информацию о фильме: продолжительность, размер, и т. д. и т. п. На самом деле, нас с вами в этой мета-информации заинтересует только одно обстоятельство – а именно то, что там содержатся данные о ключевых фреймах фильма (их позиции по временной и байтовой шкале). Сама мета-информация представляет собой произвольной вложенности ассоциативный массив, сериализованный в формат AMF, который является одним из принятых стандартов при разработке приложений на flash.
    Примечание: для PHP существует несколько библиотек, позволяющих выполнять (де)сериализацию в/из AMF.

    2. Как организовать трансляцию FLV-файлов на веб-страницах


    Чтобы считать трансляцию успешной, нужно соблюсти два условия: сервер успешно показал контент, а клиент его не менее успешно посмотрел. Соответственно, необходимы две части приложения – сервер и клиент. В качестве клиента выступает flash-приложение, способное воспроизвести видео-поток с указанного URL. Подобных программ существует множество, и мы здесь не будем подробно на них останавливаться. Поговорим о серверной части. Итак, какие же есть возможные пути реализации?

    2.1. Download — скачивание


    Это самый простой путь. Он требует простейшего клиента, который просто запрашивает видео-поток по заданному URL и воспроизводит его.Серверу только и надо, что обработать HTTP-запрос и выдать соответствующий контент. Не нужно никакого специфического софта.
    «Тогда к чему какие-то еще другие пути?» — такой вопрос сложно не задать. Однако, не все так гладко с этим способом… Дело в том, что если он отлично подходит для показа небольших видео-фрагментов, длиной до 2-3 минут, то фильмы подлиннее так показывать не годится: для того чтобы пользователь мог посмотреть какой-либо кусок фильма, необходимо, чтобы этот кусок уже закачался на его компьютер. Другими словами, находясь в начале фильма, мы не можем передвинуть «ползунок» таймера в конец и посмотреть финальные титры. Такой способ не дает также никаких возможностей для защиты видео-контента от скачивания.

    2.2. Streaming – потоковое видео


    Этот способ – пожалуй, наиболее продвинутый. Здесь есть возможность перемотки к произвольному месту в потоке, определенные механизмы защиты контента (если говорить откровенно, то эти механизмы всего лишь затрудняют получение контента, являясь, по сути, защитой только от неумелого взломщика). Также полезная возможность – организация «живых» видео-трансляций. Если вам необходимы живые трансляции – нужно стримить, другого выхода у вас нет.
    Что ж, возникает тот же вопрос, что и с предыдущим способом: «если стриминг так хорошо, то к чему какие-то еще другие пути?». Стриминг хорош, но не каждому по карману. За медиа-сервер (например, «Flash Media Server») придется выложить кругленькую сумму. Впрочем, имеются и опенсорс решения, например, ffserver (который, однако, не вполне подпадает под тему доклада, поскольку не умеет стримить файлы), а также Red5, который написан на Java и поэтому также подойдет не для всех.

    2.3. HTTP-streaming (эмуляция потокового видео через HTTP)


    Из названия можно сделать догадку о том, что третий способ является комбинацией первых двух. В каком-то приближении можно считать, что это так и есть. Как мы уже отмечали, большим недостатком 1-го способа (download) является невозможность перемотки в произвольное место фильма. В HTTP-streaming эта проблема решается так: при перемотке в то место, которое еще не успело скачаться на машину пользователя, текущее скачаивание прекращается и на сервер отправляется новый запрос, содержащий указатель на то, с какого места в фильме нужно начать скачивание. Здесь есть определенные тонкости, которые мы подробнее обсудим в следующей главе. Что же касается преимуществ и недостатков такого подхода… На мой взгляд, для трансляции файлов – это лучший вариант. Он достаточно прост для того, чтобы реализовать его на любом языке (скриптовом, как PHP или Ruby – или же компилируемом, как C), так что вы можете решать, что использовать, исходя из требований к скорости разработки, скорости работы результирующего приложения, имеющегося ПО и прочая, прочая. Также для таких распространенных быстрых веб-серверов как Nginx и Lighttpd имеются готовые модули для трансляции FLV-файлов, написанные на C и работающие весьма шустро.
    На этом способе я и остановлюсь немного подробнее…

    3.Http-streaming


    Итак, рассмотрим подробнее вариант трансляции флэш-видео с помощью Http-streaming. Как иы уже говорили, для того чтобы проиграть фильм с произвольного места, клиент отправляет на сервер HTTP-запрос, содержащий «координату» места, с которого следует выдавать видео-поток. ну, например: localhost/flv/film.php?start=XXXXX. Что представляет собой эта координата? Это всего лишь номер байта, с которого начинается нужный фрейм. К слову сказать, начинать проигрывание FLV-файла нужно всегда с ключевого фрейма.
    «Однако, позвольте! Откуда же клиенту известен этот номер байта, с которого начинается фрейм? да еще обязательно ключевой?»
    Отвечаю. Помните, в начале, когда я в двух словах рассказал о том, из чего состоит файл FLV, я упомянул о мета-информации, которая содержится в заголовке? В этой мета-информации содержатся данные о ключевых фреймах фильма (их позиции по временной и байтовой шкале). Таким образом, клиент всегда может найти ближайший ключевой фрейм к той позиции в потоке, которую запросил пользователь – и перевести ее в байты, каковые и передать на сервер.
    А что же сервер? Ну, собственно, его задача теперь минимальна: обработать запрос, считать значение параметра (в нашем случае это переменная $_GET['start']), и выдать требуемый видео-файл, начиная с запрошенного байта. Все обстоит почти так. Почти, но не совсем. FLV-файл обязательно должен содержать заголовок. Если запрошенный пользователем байт не нулевой, то перед тем как выдать содержимое файла, начиная с этого байта, нужно вставить минимально возможный заголовок (честно говоря, я не разбирался подробно, что он из себя представляет, но догадываюсь, что это пустой массив или объект, сериализованный в AMF и предваренный символами «FLV»).

    3.1. Готовые решения: lighttpd, nginx+http_flv_module, flv4php.


    Поддержка Http-streaming осуществлена в популярных веб-серверах lighttpd и nginx. В случае использования этих решений, вам всего лишь нужно положить FLV-файлы в место, доступное веб-серверу, все остальное – дело сервера и клиента, никакого программного кода для серверной части писать не придется. Клиент же должен будет запрашивать FLV-файлы, добавляя к URL'у GET-параметр «start», например, local-nginx/sample.flv?start=12345.
    Существует также бесплатное решение (возможно, их и больше) на основе PHP — flv4php. Его большой плюс – в том, что в этом проекте имеется готовый плеер – клиент для HTTP-streaming. Минус – в том, что это решение довольно тяжеловесное, и, по данным моих тестов на своей рабочей машине, сильно нагружает процессор (странное явление, адекватного объяснения которому мы не нашли, однако, от греха подальше, поспешили отказаться от использования серверной части flv4php и ограничились тем, что позаимствовали у них плеер, который после модификации под наши нужды стал служить нам верой и правдой). Еще один недостаток – в качестве «тумбы» (картинка, которую пользователь видит при открытии страницы на экране плеера) используется первый фрейм фильма, и это поведение не кастомизируется. Допускаю мысль о том, что flv4php можно настроить и лучшим образом, и заставить его таки делать то, что нужно, и без диких нагрузок на процессор. И тем не менее, небольшой фрагмент PHP-кода, приведенный ниже, делает практически то же самое, что flv4php – и гарантированно с хорошей производительностью :)

    3.2. Сделай сам или все только кажется сложным.


    <?php

    $start = (int) filter_input(INPUT_GET, 'position', FILTER_VALIDATE_INT);
    if ($start < 0) die("Incorrect request");
    // open file for reading
    $fp = fopen('sample.flv', 'r');
    $fsize = filesize($file);
    if ($start > 0)
    {
    // seek to requested position
    fseek($fp, $start);
    // FLV header for the movie part. Magic. Trust me ;)
    // Header code is completely taken from flv4php project
    $header = "FLV" . pack('C', 1 ) . pack('C', 5 ) . pack('N', 9 ) . pack('N', 9 );
    header("Content-Length: " . (strlen($header) + $fsize - $start));
    echo $header;
    } else {
    header("Content-Length: " . $fsize);
    }
    while(!feof($fp)) {
    print(fread($fp, 1024));
    }
    fclose($fp);

    ?>


    Как видите, все предельно просто, думаю, пояснения излишни.

    4.Преобразование в FLV из других форматов. Основы ffmpeg & mencoder. Мета-информация и как ее впихнуть в FLV-файл.



    Уфф, практически, мы закончили. В этой главе я немного расскажу о том, как перевести видео-контент в формат FLV и как запихнуть в готовые фильмы мета-информацию, которая необходима для осуществления HTTP-streaming. Я не буду останавливаться на ПО, доступном под MS Windows, вместо этого сосредоточусь на *nix-решениях (не секрет, что большинство веб-проектов работают на серверах под управлением *nix/Linux/FreeBSD, и эта информация может оказаться полезной).
    Самые известные и мощные проекты – ffmpeg и mencoder. И та, и другая программы работают с большинством известных на сегодняшний день видео-форматов, имеют обширную базу кодеков и/или возможность подключения пользовательских кодеков. Обе работают с хорошей скоростью (впрочем, вы понимаете, что обработка видео – дело неблагодарное и отнимает много ресурсов и времени).
    Чтобы перевести имеющийся фильм в формат FLV, нужно выполнить примерно следующие команды:
    ffmpeg:
    $ ffmpeg -i sample.avi sample.flv
    (см. документацию к ffmpegffmpeg.mplayerhq.hu/ffmpeg-doc.html, чтобы узнать о дополнительных опциях)
    mencoder:
    $ mencoder sample.avi -of lavf -lavfopts i_certify_that_my_video_stream_does_not_use_b_frames -ovc lavc -lavcopts vcodec=flv:vbitrate=500:mbd=2:mv0:trell:v4mv:cbp:last_pred=3 -oac mp3lame -lameopts abr:br=56 -srate 44100 -o sample.flv
    (см. документацию к mencoderwww.mplayerhq.hu/DOCS/HTML/en/index.html, чтобы узнать о дополнительных опциях).
    И снова о мета-информации.
    Ни ffmpeg, ни mencoder не вставляют в заголовок результирующего FLV-файла мета-информацию о ключевых фреймах. Между тем, информация эта совершенно необходима для того, чтобы организовать HTTP-streaming. Как быть? На помощь разработчикам снова приходят они – опенсорс-продукты :). Например, маленькая программа под названием Yamdi (Yet Another Meta-Data Injector): sourceforge.net/projects/yamdi. С ее помощью даже FLV-файлы большого размера (ну, скажем, в гигабайт) за очень небольшое время можно снабдить необходимыми мета-данными.

    Литература и ссылки:


    flv streaming with lighttpd: blog.lighttpd.net/articles/2006/03/09/flv-streaming-with-lighttpd
    Стриминг Flash Video при помощи Nginx:
    blog.kovyrin.net/2006/10/14/flash-video-flv-streaming-nginx

    Этот раздел не отличается полнотой, на самом деле, конечно же, пришлось несколько больше излазать:)
    Поделиться публикацией

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

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

      +1
      довольно позновательно.
      хотелось бы ещё увидеть простые реализации самих плееров на flash (play, stop, pause, volume, ну и переключение на stream)
      максимум если кто то ссылку подкинет буду благодарин :)
        0
        Подборка видео-проигрывателей на флэше^
        http://habrahabr.ru/blog/webdev/45520.html
          0
          В принципе, опытный флэшер, снабженный докой на объект NetStream, и в частности, на его метод onMetaData (см. на http://adobe.com), может написать подобный плеер весьма быстро. Впрочем, мне в этом плане повезло - я работаю с одним из признанных гуру в этой области.

          Кстати: если есть еще связанные с этой темой аспекты, которые хотелось бы обсудить - милости прошу. Если только смогу - отвечу.
            0
            а если мне хочется самому написа. как быть?
            Опыр в работе с flash есть (когда то чтото юдрил на 5 версии, ну и с ActionScript немного знаком), кто может подсказать статейку, или может книжку где именно это хорошо и понятно описано (с примерами). уж не хочется сидеть и переберать всё что не надо.
              0
              ну, я уже приводил ссылку на http://adobe.com... Кроме того, если вы создаете flash-приложения среде Adobe Flash - там есть кнопка F1. Ммм, думаю, что и в Adobe Flex Builder есть такая кнопка ;), как и возможность создать видео-плеер - хотя наверное утверждать не могу.
                0
                gotoandlearn.com/
                здесь смотри видеоуроки на тему «Flash Video Basics»
            0
            Любопытно, но больше всего позабавила фраза: "Чтобы считать трансляцию спешной, нужно соблюсти два условия:..."
              0
              спасибо, исправил.
              0
              Спасибо, интересная статейка. :)
                0
                Думаю логичней добавит видео в статью :-)


                В разделе PHP опубликовано видео с конференции
                http://habrahabr.ru/blog/php/48580.html
                  0
                  Спасибо, Саш :)
                  0
                  Очень интересно. Мне понравилось, тем более, что тема лично для меня актуальна. Добавил в избранное.
                  Спасибо большое :)
                    0
                    Нравиться - голосуем :-)
                    Пора Хабра людям получать больше полезной инфы.. :-)
                      –3
                      Red5 хорошая штуковина, все онлайн-видео используют её. У фейсбука видео тоже на Red5 кстати.
                        0
                        Кто спорит? Отличная штуковина! Практически (если верить моим данным - на истину в последней инстанции не претендую) единственная подобная штуковина с открытым кодом, которая действительно хорошо работает.
                        0
                        А у меня несколько вопросов по внедрению всего этого дела. А именно — опыт:

                        У меня есть предложение создать портальчик и там нужно поднять видео сервис.

                        1. Видео ролики исполнителей (стрим, что бы не копировали)
                        2. Какой-то легенький ТВканал т.е. взять например 10 видео роликов, объеденить их в один и поставить на повтор.
                        3. Это для музыкального лейбла, соответсвенно я не думаю, что будут большие нагрузки.

                        Интересует способы реализации, стоимости примерные и т.п. А то пока не сталкивался с этим. :)

                        Может стоить тупо купить этот FLASH MEDIA SERVER 3 и установить (опять же вопрос для знающих — лучше на отдельный сервер или же на сервер с работающим порталом? Нагрузки я думаю будут небольшие).

                        Спасибо за рекомендации :)
                          0
                          1. Стрим — весьма условная защита от копирования.
                          2. Такими вопросами я не занимался, но есть предположение (пока что я не смотрел в доке), что Red5 может это уметь.

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

                          Если все же необходим стрим — посмотри сначала в сторону Red5. Если не устроит — смотри флэш-медиа-сервер. Кстати, с помощью HTTP-download можно организовать простую защиту контента (только от дурака, в общем-то, но стрим, по большому счету, тоже не предоставляет бОльшей защиты). При этом медиа-сервер вообще необязательно ставить. Задача с псевдо-ТВ-каналом тоже решаема при помощи любого языка программирования (при небольших нагрузках тот же PHP или любой другой скриптовый язык справится).
                            0
                            Спасибо. :) Ред5 посмотрю. А вот нашел еще www.wowzamedia.com/products.html. Что скажите?

                            — Задача с псевдо-ТВ-каналом тоже решаема при помощи любого языка программирования (при небольших нагрузках тот же PHP или любой другой скриптовый язык справится).

                            а как именно? в двух словах, что бы я понял о чем речь. :)
                          0
                          «А вот нашел еще www.wowzamedia.com/products.html. Что скажите?»

                          Ничего не скажу. Не пользуюсь платным софтом :)

                          Берем фильм. Берем его мета-данные (позиции ключевых фреймов). Выбираем время начала трансляции. Пришел запрос: смотрим разницу по времени — время запроса минус время начала трансляции. Вычитаем кол-во целых фильмов, которые бы поместились на этом отрезке. Допустим, весь фильм = час. Запрос пришел через полтора часа после выбранного времени начала трансляции. Отбросили час (продолжительность фильма), осталось полчаса. «Проматываем» на полчаса вперед и показываем.

                          Можно нечто подобное с несколькими фильмами сделать, в случайном порядке их показывать. Клиент может в промежутках между фильмами показывать пользователю заставки, рекламу и т. д.
                            0
                            Как раз только что опубликовал статью Демон конвертации видео в FLV
                            Хорошее дополнение к этому топику)))

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

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