Kiedyś zastanawiałem się na jakiej zasadzie działają serwisy a’la YouTube. Wrzucam film, a on po chwili wyświetlany jest we Flashowym odtwarzaczu. W tym artykule postaram się wytłumaczyć na czym to polega i przedstawić praktyczne tworzenie takiego serwisu. Teoretycznie wygląda to tak, że wrzucam plik przez formularz na stronie, skrypt na serwerze go odbiera i zapisuje. Następnie sprawdzamy rozszerzenie i typ MIME pliku, czy rzeczywiście jest to materiał wideo. Na koniec musimy przekonwertować na serwerze owy film do formatu FLV (Flash Video). Tylko taki format obsługuje Flash. Do tego będzie potrzebny specjalny enkoder – ffmpeg. Wywołujemy go z poziomu PHP jako zewnętrzny program, ale o tym za chwilę. Ffmpeg musi być preinstalowany na serwerze, a z tego co się orientuję, żadna polska firma hostingowa nie udostępnia takiej funkcjonalności. Zdarzyło mi się sprawdzić w praktyce dwie zagraniczne firmy:
- www.cirtexhosting.com – serwery w USA, dość wolny transfer, wieczne problemy z CRONem (tydzień działa, tydzień nie działa), nie ma możliwości wprowadzenia własnych ustawień dla PHP5 (zarówno w .htaccess jak i przez własny php.ini) w przeciwieństwie do PHP4;
- www.apthost.com – serwery w Kanadzie, tu również dwie wersje PHP, ale problemów z własnymi ustawieniami nie miałem. Natomiast największą wadą jaką zauważyłem jest brak niektórych kodeków, np. do obsługi (konwersji) plików 3GP;
Niemniej jednak od czasu moich “testów” mogło coś się zmienić.
Jak zdobyć ffmpeg?
Oczywiście aby pisać tego typu serwis, trzeba go testować na bieżąco i sprawdzać czy wszystko działa tak jak należy. Nie może się to obyć bez ffmpeg-a na naszym lokalnym komputerze. Ze strony projektu można pobrać źródła, natomiast skompilowane binarki dla Windows można ściągnąć chociażby z tej strony. Pobrane archiwum rozpakowujemy do C:\Windows\ (lub do innego folderu ze zmiennej środowiskowej PATH). Dzięki temu zabiegowi będzie można wywoływać program z samej nazwy, bez podawania ścieżki.
Na początek formularz
Zbudujmy prosty formularz, za pomocą którego możliwe będzie wgranie pliku na serwer. Należy pamiętać o kilku obowiązkowych rzeczach:
- znacznik FORM musi mieć atrybut enctype=”miltipart/form-data” mówiący o tym, że będziemy przesyłać pliki;
- formularz musimy wysłać metodą POST;
-
<form action="plik.php" enctype="multipart/form-data" method="post">
-
<input name="MAX_FILE_SIZE" type="hidden" value="1048576" />
-
<input name="plik" type="file" />
-
<input type="submit" value="Prześlij plik" />
-
</form>
Ukryte pole MAX_FILE_SIZE mówi o maksymalnym rozmiarze przesyłanego pliku. Nie jest to pole obowiązkowe, ale bardzo przydatne. Jako wartość przyjmuje rozmiar wyrażony w bajtach. Pamiętaj o ustawieniach dotyczących rozmiaru przesyłanego pliku w php.ini (post_max_size i upload_max_filesize). Jeśli wprowadzisz dużą wartość w pole MAX_FILE_SIZE, a ustawienia PHP będą bardziej ograniczały plik, zostanie on odrzucony po stronie serwera.
Odbiór pliku
Przesłany plik zapisany jest w katalogu tymczasowym. Aby go zachować musimy go przenieść do dowolnego wybranego katalogu na serwerze, który musi mieć prawa do zapisu.
-
if(isset($_FILES['plik'])) {
-
if(is_uploaded_file($_FILES['plik']['tmp_name'])) { //czy plik rzeczywiście uploadowany
-
move_uploaded_file($_FILES['plik']['tmp_name'], 'pliki/'.$_FILES['plik']['name'])); //zapisz plik
-
}
-
}
W międzyczasie powinniśmy sprawdzić rozszerzenie i typ MIME pliku oraz dla pewności rozmiar.
-
if(isset($_FILES['plik'])) {
-
if(is_uploaded_file($_FILES['plik']['tmp_name'])) {
-
if($_FILES['plik']['size']<=1048576) { //sprawdzenie rozmiaru
-
$rozszerzenia=array('mpg','mpeg','avi','rmvb');
-
$mime=array('video/avi','video/mpeg','video/x-ms-wmv','');
-
$roz=strtolower(substr(strrchr($_FILES['plik']['name'],'.'),1)); //rozszerzenie wgranego pliku
-
if(in_array($roz, $rozszerzenia)&&in_array($_FILES['plik']['type'], $mime))
-
move_uploaded_file($_FILES['plik']['tmp_name'], 'pliki/'.$_FILES['plik']['name']));
-
}
-
}
-
}
Dla zachowania czytelności przedstawiłem w przykładzie tylko kilka rozszerzeń i typów MIME. W ostatecznym kodzie nie powinno zabraknąć następujących rozszerzeń: avi, mpg, mpeg, mpe, asf, asx, movie, wmv, 3gp, mp4, mov i rmvb oraz następujących typów MIME:
- video/avi
- video/mpeg
- video/mpeg4
- video/quicktime
- video/mp4
- video/x-msvideo
- video/x-ms-asf
- video/x-sgi-movie
- video/x-ms-wmv
- video/3gpp
- video/3gp
- application/force-download
- application/octet-stream
- application/mpeg4-iod
- application/mpeg4-muxcodetable
- video/vnd.rn-realvideo
Zauważ, że w przykładzie w tablicy $mime znalazła się jedna pusta wartość. Jest ona tam celowo. Zdarza się niekiedy, że tablica superglobalna $_FILES['video']['type'] przechowuje pustą wartość, mimo poprawności pliku.
Konwersja
Przyszedł czas na konwersję pliku. Aby tego dokonać, musimy wywołać program ffmpeg z poziomu PHP. Samo wywołanie ffmpeg z wiersza poleceń może wyglądać tak:
-
ffmpeg -i plik_wejsciowy -r 25 -ar 22050 -ab 24k -f flv plik_wyjsciowy
Natomiast aby wywołać program z poziomu PHP możemy posłużyć się funkcją exec(), system() lub shell_exec(). My skorzystamy z exec():
-
exec('ffmpeg -i pliki/'.$_FILES['plik']['name'].'-r 25 -ar 22050 -ab 24k -f flv pliki/'.$_FILES['plik']['name'].'.flv');
Poszczególne przełączniki w wywołaniu oznaczają:
- -i lokalizacja pliku wejściowego;
- -r framerate pliku wyjściowego;
- -ar częstotliwość próbkowania dźwięku;
- -ab bitrate dźwięku;
- -f informacja o formacie pliku wyjściowego (flv) i lokalizacji tego pliku;
Oczywiście ffmpeg ma wiele więcej innych przełączników. Pełną ich listę znajdziemy na stronie dokumentacji.
Należy pamiętać, że katalog pliku wyjściowego musi mieć prawa zapisu. W powyższym przykładzie zostało to pominięte, ale trzeba także sprawdzić nazwę pliku pod kątem niebezpiecznych znaków, które mogą stanowić komendę służącą do wykonania innego polecenia powłoki.
Dodatkowo ffmpeg umożliwia wyciągnięcie jednego kadru z filmu i zapisanie go jako obrazu. W ten sposób uzyskamy miniaturkę (podgląd) filmu:
-
exec('ffmpeg -i pliki/'.$_FILES['plik']['name'].'-s 160×120 -vframes 1 -f mjpeg pliki/'.$_FILES['plik']['name'].'.jpg');
Poszczególne przełączniki w wywołaniu oznaczają:
- -i lokalizacja pliku wejściowegoz filmem;
- -s rozdzielczość miniaturki;
- -vframes numer klatki do wyciągnięcia;
- -f informacja o formacie pliku wyjściowego (mjpeg) i lokalizacji tego pliku;
Oczywiście po konwersji możemy usunąć stary plik wideo, by nie zajmował cennego miejsca na serwerze:
-
unlink('pliki/'.$_FILES['plik']['name']);
Należy pamiętać, że PHP czeka na zakończenie działania wywołanego programu. W przypadku dużych plików konwersja może potrwać dość długo i potrzebować sporo pamięci. Niskie wartości max_execution_time i memory_limit w php.ini mogą zabić skrypt przed zakończeniem jego działania. Dlatego jeśli na naszym serwerze wartości te są niskie oraz nasza firma hostingowa nie pozwala ich zmienić, trzeba wprowadzić proporcjonalny ogranicznik rozmiaru pliku.
Odtwarzanie
Przyszedł czas na ostatnią operację, czyli wyświetlenie filmu na stronie www. Flashowy odtwarzacz możemy oczywiście zrobić samemu za pomocą programu Adobe Flash (lub zamienników). Możemy też skorzystać z gotowca. Udało mi się przetestować dwa tego typu odtwarzacze (darmowe do zastosowań niekomercyjnych): flowplayer i JW FLV Media Player. Na ich oficjalnych stronach możemy pobrać zarówno źródła, jak również skompilowane pliki SWF.
Na przykładzie flowplayer’a przedstawię jak umieścić film na stronie. W pobranej paczce znajduje się odtwarzacz w kilku skórkach, wybieramy jedną, na przykład FlowPlayerClassic.swf. Przykładowy kod wyświetlający film może wyglądać tak:
-
<object type="application/x-shockwave-flash" width="352" height="288" data="FlowPlayerClassic.swf" id="FlowPlayer">
-
<param name="allowScriptAccess" value="sameDomain" />
-
<param name="movie" value="FlowPlayerClassic.swf" />
-
<param name="quality" value="high" />
-
<param name="scale" value="noScale" />
-
<param name="wmode" value="transparent" />
-
<param name="flashvars" value="config={videoFile:\'pliki/'.$_FILES['plik']['name'].’.flv\',loop:false,showFullScreenButton:false}" />
-
</object>
Uwaga! Kod ten obowiązuje do wersji odtwarzacza z czasów pisania tej notki. Informacje o implementacji najnowszej wersji znajdują się na stronie autora FlowPlayera.
Obydwa odtwarzacze mają wiele przełączników pozwalających dostosować odtwarzacz do naszych upodobań:
-
<param name="flashvars" value="config={videoFile:\'pliki/'.$_FILES['plik']['name'].’.flv\',loop:false,showFullScreenButton:false}" />
Pierwszy z nich, videoFile, (tu: flowplayer) jest obowiązkowy i informuje jaki plik ma zostać odtworzony. Kolejne są opcjonalne, w powyższym skrypcie wyłączyłem powtarzanie odtwarzania filmu i dostępność przycisku umożliwiającego użycie “pełnego ekranu”.
Pełna lista przełączników dla flowplayer’a dostępna jest tutaj, a dla JW FLV Media Player’a tutaj.


Lipiec 7th, 2008 at 19:07
Mam pytanie jak wyciągnąc plik video ze strony na dysk jeżeli jest odtwarzany przez JW Player ?
Lipiec 7th, 2008 at 21:44
W przypadku JW FLV Player’a zainteresuje nas linia:
<param name=”movie” value=”flvplayer.swf?file=pliki/mojpliczek.flv” />
Jak widać zmienna “file” zawiera lokalizację pliku z filmem.
Listopad 26th, 2008 at 18:44
A gdzie w tym kodzie wstawić adres pliku z filmem?
Chodzi o flowplayer. Próbuję od 2 dni i mi nie wychodzi.
Listopad 26th, 2008 at 21:33
Wszystko działa, tylko film się nie wyświetla. W którym miejscu kodu należy wpisać adres do pliku z filmem we flowplayerze?
Z góry dziękuję za pomoc.
Listopad 27th, 2008 at 12:17
Informację o filmie należy przesłać w formie zmiennej Flasha:
<param name=”flashvars” value=”config={videoFile:\’pliki/’.$_FILES['plik']['name'].’.flv\’” />
gdzie:
pliki/’.$_FILES['plik']['name'].’.flv
to nasz film.
Listopad 27th, 2008 at 16:45
Czy mozna gotowy plik *.flv wysłac na serwer i odtwarzać go za pomocą tego kodu? Jak wpisać w nim taki plik:
http://www.sp1.raciborz.com.pl/v/11listopada.flv
Dzięki za odpowiedź.
Listopad 27th, 2008 at 16:53
Czy mógłbyś wpisać tą linię jeszcze raz z dowolną lokalizacją jakiegoś pliku, np.: “domek.flv”?
Dzięki za odpowiedź
Listopad 27th, 2008 at 21:48
Jeśli plik z filmem jest umieszczony w tym samym katalogu co strona, która będzie go wyświetlać, wystarczy taka składnia:
<param name=”flashvars” value=”config={videoFile:’11listopada.flv’” />
Tak, można
Listopad 28th, 2008 at 16:20
Dziękuję za odpowiedź, jednak jeszcze coś robię źle. Umieściłem na serwerze plik “FlowPlayerClassic.swf” i w powyższym kodzie 2 razy wpisałem do niego adres, tj data=… i value=… Czy tak ma być, bo film nadal mi się nie wyświetla?
Listopad 28th, 2008 at 19:47
Wróżką nie jestem. Bez kodu nie powiem dlaczego nie działa.
Listopad 28th, 2008 at 22:08
Nie moge wstawić tego kodu (nie wyświetla się) jak to zrobić?
Listopad 28th, 2008 at 22:18
http://www.unit1.pl/pb
Listopad 28th, 2008 at 22:55
http://www.unit1.pl/pb-930
Listopad 28th, 2008 at 23:46
Okazuje się, że autor FlowPlayera wydał nową wersję swojego odtwarzacza, która nie jest kompatybilna z wcześniejszymi ustawieniami. Informacje o implementacji najnowszej wersji playera znajdują się tutaj: http://flowplayer.org/documentation/installation.html
Listopad 29th, 2008 at 00:37
Niestety dla mnie to czarna magia i to jeszcze po angielsku. Czy mógłbyś mi podać kod, do tej nowej wersji. Jeżeli nie to i tak dziękuję za chęć pomocy i nie chcę już zawracać głowy, zawsze mogę pozostać przy łatwiejszych plikach *.wmv.
Jeszcze raz dziękuję i pozdrawiam. krzych.
Listopad 29th, 2008 at 10:41
Dzięki Kutar za pomoc. Już sobie poradziłem z JWPlayer’em.
Po 3 dniach analizy różnych kodów dałem taki:http://www.unit1.pl/pb-932, i działa.
Dzięki i pozdrawiam
Listopad 29th, 2008 at 11:39
Co do FlowPlayera kod będzie taki:
<script src=”flowplayer-3.0.0.min.js”></script>
<a href=”tutaj_plik_flv” style=”display:block;width:400px;height:300px” id=”player”>
</a>
<script language=”JavaScript”>
flowplayer(“player”, “flowplayer-3.0.0.swf”);
</script>
Nie należy zapomnieć o wgraniu pliku flowplayer-3.0.0.min.js z pobranego archiwum (poza samym plikiem odtwarzacza).
Listopad 29th, 2008 at 14:37
Czy tam gdzie jest nazwa pliku “flowplayer-3.0.0.min.js” i “flowplayer-3.0.0.swf” należy podać cały adres do tych plików? Bo tak zrobiłem i film nie wyświetla się.
Listopad 29th, 2008 at 16:08
Musi to być pełna, właściwa ścieżka.
Listopad 29th, 2008 at 18:20
Wielkie dzięki za pomoc.Już mi działa mediaplayer. Teraz eksperymentuję również z flowplayerem. Na razie wszystko działa oprócz wyświetlania filmu ale myślę, że też do dego dojdę. Pozdrawiam.