Video Streaming

Natchniony artykułem "Własne Google Video, czyli video streaming w PHP" w magazynie PHP Solutions 5/2006 (16) postanowiłem stworzyć prosty system na wzór google video. Użytkownik wrzuca plik (film bądź plik audio) w praktycznie dowolnym formacie a system konwertuje go do animacji Flash, generuje miniaturkę z klatki filmu i umieszcza odnośnik na stronie po kliknięciu na który uruchomiony zostaje odtwarzacz z wybranym filmem bądź muzyką pobierający kolejne części strumieniowo. Wydaje się być to proste i ku mojemu wielkiemu zdumieniu właśnie takie jest.

Aby dobrze zrozumieć zagadnienie zacznijmy od teorii czyli co będzie nam potrzebne. W skrócie będziemy potrzebowali formularza wysyłającego plik na serwer, enkodera, który wykona konwersję pliku oraz odtwarzacza multimedialnego stworzonego we Flashu.

Formularz

Jak wiadomo aby wysłać plik na serwer należy posłużyć się formularzem i polem typu file oraz opcjonalnym polecem ukrytym z nazwą MAX_FILE_SIZE umieszczonym przed polem typu file oznaczającym maksymalną wielkość pliku (w bajtach) jaka może być przesłana. Mimo, iż pole to jest opcjonalne warto je dodać do formularza, ponieważ unikneimy w ten sposób próby wysłania zbyt dużego pliku, który i tak zostanie odrzucony po stronie serwera, jeśli jego rozmiar będzie większy niż pozwala na to opcja upload_max_filesize i/lub post_max_size. Należy także pamiętać, że formularz musi być wysłany metodą POST a do jego definicji należy dodać atrybut enctype z wartością multipart/form-data informującego formularz, iż przesyłana będą zawartość wieloczęściowa. Formularz w najprostszej wersji może wyglądać tak:

HTML:
  1. <form name="upload" action="index.php" method="post" enctype="multipart/form-data">
  2.   <input type="hidden" name="MAX_FILE_SIZE" value="1000000" />
  3.   <input type="file" name="my_file" />
  4.   <input type="submit" value="wyślij" />
  5. </form>

Po poprawnym wysłaniu formularza plik trafia do katalogu tymczasowego i stamtąd powinien być przeniesiony do dowolnego naszego katalogu (posiadającego odpowiednie prawa do zapisu) np. upload co można wykonać prostym skryptem:

PHP:
  1. if(isset($_FILES['my_file'])) {
  2.     if(is_uploaded_file($_FILES['my_file']['tmp_name'])) {
  3.         move_uploaded_file($_FILES['my_file']['tmp_name'], 'upload/'.$_FILES['my_file']['name']));
  4.     }
  5. }

Glonalna tablica $_FILES zawieraja informacje o przesłanych plikach i posiada takie elementy jak:

  • $_FILES['my_file']['name'] - nazwa przesyłanego pliku
  • $_FILES['my_file']['type'] - typ mime przesyłanego pliku
  • $_FILES['my_file']['size'] - rozmiar przesyłanego pliku
  • $_FILES['my_file']['tmp_name'] - nazwa pliku w katalogu tymczasowym
  • $_FILES['my_file']['error'] - kod ewentualnego błędu

Dokładny opis obsługi uploadu w PHP znajduje się w manualu.

Jeśli powyższe operację się powiadą w naszym katalogu upload pojawi się przesłany plik. Dodatkowo, można zadbać o to, czy przesyłany format pliku jest właściwy co można wykonać poprzez sprawdzenie rozszerzenia (bywa zawodne) lub sprawdzenie typu mime (pewniejszy sposób).

Konwersja

Jak już wcześniej wspomniałem do wyświetlania uploadowanego pliku wykorzystamy odtwarzacz multimedialny wykonany we Flashu. Odtwarzacz ten standardowo obsługuje format pliku FLV (Flash Video) a więc aby poprawnie odtworzyć plik musimy dokonać konwersji przesłanego pliku. Do tego zadania wykorzystamy zewnętrzeny program ffmpeg dostępny zarówno dla systemów Uniksowych jak i Windowsowych. Program ten obsługuje pokaźną ilość formatów (audio, video oraz obrazki) i znakomicie nada się do naszych potrzeb. Posiada on sporą liczbę opcji i umożliwia dokonywanie wielu operacji na przetwarzanych plikach. Pełna lista opcji dostępna jest w dokumentacji. Aby bardziej zintegrować program ffmpeg z technologią PHP i ułatwić korzystanie z niego stworzono moduł do tego języka. Ze względu na problemy wynikające z różnych wersji PHP oraz małą dostępność na serwerach hostingowych nie będziemy używać modułu lecz zewnętrzenej aplikacji. Składnia polecenia dokonującego konwersji jest następująca:

CODE:
  1. ffmpeg [[opcje pliku wejściowego][-i plik wejściowy]]... {[opcje pliku wyjściowego] plik wyjściowy}...

W naszym przypadku musimy dokonać konwersji pliku do formatu FLV użyjemy więc poelcenia:

CODE:
  1. ffmpeg -i plik_wejsciowy -s 352x288 -r 25 -ar 22050 -ab 24 -f flv plik_wyjsciowy.flv

Powyższe polecenie dokona konwersji pliku wejściowego do formatu FLV. Dodane opcje oznaczają:

  • -s ustalenie rozmiaru (szerokość x wysokość) pliku wyjściowego (352x288)
  • -r ustawienie framerate'u pliku wyjściowego (25 klatek/sek)
  • -ar ustawienie częstotliwości próbkowania dźwięku w Hz (22050)
  • -ab ustawienie bitrate'u dźwięku pliku wyjściowego (24)
  • -f wymuszenie formatu pliku wyjściowego (FLV)

Po wykonaniu powyższego polecenia na ekranie zostaną pokazane informacje o typach plików, informacjach o nich oraz o wyniku operacji. Jeśli konwersja się powiedzie otrzymamy plik wynikowy w formacie Flash Video.

Teraz pozostaje wykonać to polecenie w skrypcie PHP podając jako plik wejściowy uploadowany poprzez formularz plik. Aby wykonać polecenie z poziomu skryptu PHP można skorzystać z kilku podobnych funkcji czyli exec, system, shell_exec oraz passthru. Różnią się one od siebie sposobem i typem zwracanego wyniku. My skorzystamy z funkcji exec.

PHP:
  1. exec('ffmpeg -i upload/'.$_FILES['my_file']['name'].' -s 352x288 -r 25 -ar 22050 -ab 24 -f flv upload/'.$_FILES['my_file']['name'].'.flv', $result);

Po wykonaniu powyższego skryptu przesłany na serwer plik zostanie skonwertowany do formatu FLV, do jego nazwy zostanie dodane nowe rozszerzenie a nowy plik zostanie utworzony w tym samym katalogu co plim przesłany czyli upload. Wynik operacji zostanie wstawiony do tablicy $result.

Program ffmpeg posiada także możliwość tworzenia zrzutów ekranu z wybranych klatek filmu co umożliwia nam np. wygenerowanie miniaturki zrzutu z klatek zaraz po konwersji pliku. Skrypt wykonujący taki zrzut może wyglądać następująco:

PHP:
  1. exec('ffmpeg -i upload/'.$_FILES['my_file']['name'].' -s 80x60 -vframes 1 -f mjpeg upload/'.$_FILES['my_file']['name'].'.jpg', $result)

Dokładny opis wszystkich opcji programu ffmpeg można znaleźć w dokumentacji.

Aby uniknąć trudnych do zlokalizowania błędów polecam najpierw przeprowadzić konwersję bezpośrednio z wiersza poleceń i śledzić komunikaty pojawiające się na ekranie i jeśli konwersja się powiedzie wtedy uruchomić polecenie ze skryptu PHP.

Po wykonaniu powyższych operacji powstanie nowy skonwertowany plik w formacie akceptowalnym przez odtwarzacz we Flashu.

Odtwarzanie

Na koniec przejdźmy do najbardziej efektownej operacji czyli odtworzenia przekonwertowanego filmu bądź dźwięku. Będziemy potrzebowali do tego odtwarzacz multimedialny, który dostępny jest jako komponent w programie Macromedia Flash. Ze względu na fakt, iż program ten jest komercyjny możemy skorzystać z innych rozwiązań. Jeśli mamy czas i jesteśmy zapalonymi programistami możemy stworzyć własny odtwarzacz bez posiadania programu firmy Macromedia i skorzystać z modułu PHP o nazwie MING. Moduł ten pozwala na generowanie animacji Flash bez żadnych zewnętrznych aplikacji. Instalacja tego rozszerzenia opisana jest w dokumentacji.

Możemy jednak pominąć ten krok i skorzystać z gotowych odtwarzaczy plików FLV. Godnym uwagi jest darmowy do zastosowań niekomercyjnych Flash Video Player umożliwiający odtwarzanie strumieniowe plików FLV. Na stronie autora dostępna jest zarówno wersja skompilowana (SWF) jak i źródła (FLA) dzięki czemu możemy sami dokonać stosowanych modyfikacji w odtwarzaczu dostosowując go do naszych potrzeb. Odtwarzacz ten jest bardzo prosty i przez to idealnie nadaje się do naszych celów.

Aby skorzystać z odtwarzacza należy osadzić go w kodzie strony a następnie dodać zmienną file, której wartość stanowi nazwa pliku FLV, który ma być odtworzony. Najprościej można zrobić to w następujący sposób:

HTML:
  1. <object type="application/x-shockwave-flash" width="352" height="288" wmode="transparent" data="flvplayer.swf?file=upload/plik.flv">
  2.     <param name="movie" value="flvplayer.swf?file=upload/plik.flv" />
  3.     <param name="wmode" value="transparent" />
  4. </object>

Odtwarzacz znajduje się w pliku flvplayer.swf, jego rozmiar to 400x200 a odtwarzany plik znajduje się w katalogu upload/plik.flv. Pozostałe zmienne, których użyć można aby zmodyfikować nieco sam odtwarzacz opisane są w pliku readme.html.

Podsumowanie

Na koniec chciałbym złożyć wszystko w jedną całość czyli 1 skrypt PHP, który umożliwi upload pliku, wyświetlenie listy plików wraz ze zrzutami ekranu a następnie ich odtworzenie. Do poprawnego działania będzie potrzebny opisany wcześniej program ffmpeg, możliwość użycia jednej z wcześniej opisanych funkcji uruchamiających polecenia systemowe oraz katalog do uploadu (z prawami do zapisu).

Źródło skryptu napisane w PHP5 znajduje się w pliku stream.php. Umieściłem w nim formularz do upload'u plików, kod odtwarzacza oraz centralną klasę stream, która zawiera metody umożliwiające obsługę uploadu, konwersje pliku i wygenerowanie zrzutu. Dodatkowo użyłem w nim stałych, które definiują ścieżki do plików oraz programu ffmpeg. Kod został napisany w PHP5 jednak ze względu na nadal dużą popularność PHP4 na serwerach hostingowych napisałem także wersję pod PHP4 - stream4.php.

Mam nadzieje, że opis wykonania streamingu video wydał się zrozumiały. Jeśli pojawią się jakieś problemy bądź uwagi proszę o komentarze bądź maile.

Leave a Reply

You must be logged in to post a comment.