Pull to refresh

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

Reading time8 min
Views5.9K
Эта статья — перепечатка статьи от 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

Этот раздел не отличается полнотой, на самом деле, конечно же, пришлось несколько больше излазать:)
Tags:
Hubs:
Total votes 19: ↑19 and ↓0+19
Comments20

Articles