- PHP


MyTube, czyli serwis wideo w Flex i PHP


Ostatnio udostępnianie plików wideo w sieci stało sie bardzo popularne. Ułatwiają to takie technologie, jak Adobe® Flash® Player. Witryny takie jak Google Video i YouTube osiągnęły ogromny sukces, ale istnieje też wiele mniejszych stron tego typu. Czy myślałeś kiedyś by mieć własny serwis w stylu YouTube? Jeśli tak to przeczytaj ten artykuł. Pokażę ci w nim, jak można użyć technologii takich jak PHP, Flash oraz Adobe Flex do stworzenia projektu MyTube, czyli naszej strony do udostępniania wideo.

Co będzie nam potrzebne? Po stronie serwera, musisz mieć dostęp do PHP i MySQL. MySQL użyjemy do przechowywania danych o filmach (na przykład nazwę pliku, miniaturę pliku, wysokość i szerokość, tytuł i opis). Przy pomocy PHP będziemy wykonywali wszystkie operacje zarządzania plikami.

Użyjemy również narzędzia "open source" o nazwie FFmpeg. Służy ono do konwersji wideo do Flash Video (FLV). FFmpeg może również generować miniatury filmów do wykorzystania podczas prezentacji listy dostępnych filmów.

A co z interfejsem użytkownika? Jest wiele rozwiązań. Pierwsze wykorzystuje hybrydowy HTML / Flash, podejście podobne do YouTube. Drugie podejście wykorzystuje tylko Flash. W obu tych podejść, należy użyć Flex'a.

A więc zaczynajmy!

Budowanie zaplecza PHP

Najpierw utworzymy potrzebną nam bazę danych przy pomocy następującego polecenia:

mysqladmin create movies;

Teraz stwórz tabelę:

movies.sql
DROP TABLE IF EXISTS movies;
 
CREATE TABLE movies (
    movieId INTEGER NOT NULL AUTO_INCREMENT,
    title VARCHAR( 255 ),
    source VARCHAR( 255 ),
    thumb VARCHAR( 255 ),
    width INTEGER,
    height INTEGER,
    PRIMARY KEY( movieId )    
);


Załadujmy teraz wszystko do bazy w taki sposób:

mysql filmy

Aby zapisać dane do bazy danych, należy najpierw przesłać filmy, przekonwertować go do Flash wideo i stworzyć miniaturę.

Budowa strony do uploadowania filmów

Strona HTML do przesyłania plików wideo jest bardzo prosta.

addmovie.html
<html>
<body>
<form enctype="multipart/form-data" method="post" action="upload.php">
<input type="hidden" name="MAX_FILE_SIZE" value="300000" />
<table>
<tr><td>Tytuł</td><td><input type="text" name="title"></td></tr>
<tr><td>Plik filmu</td><td><input type="file" name="movie"></td></tr>
</table>
<input type="submit" value="Upload" />
</form>
</body>
</html>


Formularz ten wysyła plik do skryptu upload.php, która przetwarza film, tworzy miniaturę, i dodaje dane do bazy. Skrypt przedstawiam poniżej:

upload.php
<html><body>
<?php
require "DB.php";
 
function converttoflv( $in, $out )
{
  unlink( $out );
  $cmd = "ffmpeg -v 0 -i $in -ar 11025 $out 2>&1";
  $fh = popen( $cmd, "r" );
  while( fgets( $fh ) ) { }
  pclose( $fh );
}
 
function getthumbnail( $in, $out )
{
  unlink( $out );
  $cmd = "ffmpeg -i $in -pix_fmt rgb24 -vframes 1 -s 300x200 $out 2>&1";
  $fh = popen( $cmd, "r" );
  while( fgets( $fh ) ) { }
  pclose( $fh );
}
 
function flv_import( $upfile, $fname, $title )
{
  $fname = preg_replace( '/..*$/', '', basename( $fname ) );
  $flvpath = "$fname.flv";
  $thumbpath = "$fname.gif";
 
  converttoflv( $upfile, "movies\$flvpath" );
  getthumbnail( $upfile, "movies\$thumbpath" );
 
  $dsn = 'mysql://root@localhost/movies';
  $db =& DB::connect( $dsn );
  if ( PEAR::isError( $db ) ) { die($db->getMessage()); }
 
  $sth = $db->prepare( 'INSERT INTO movies VALUES ( 0, ?, ?, ?, ?, ? )' );
  $db->execute( $sth, array( $title, $flvpath, $thumbpath, 300, 200 ) );
}
 
flv_import( $_FILES['movie']['tmp_name'], $_FILES['movie']['name'], $_POST['title'] );
?>
Plik został poprawnie dostarczony
</body></html>


Podstawą tego skryptu jest funkcja flv_import (). Dwie kolejne to converttoflv () i getthumbnail () które odpowiednio, dokonuje konwersji filmu do pliku wideo w formacie Flash oraz tworzy miniaturki. Następnie dodaje rekord do bazy danych, który zawiera informacje o filmie. Zarówno FLV i funkcja do tworzenia miniatur używają polecenia FFmpeg z różnymi opcjami wiersza polecenia do pracy z materiałem wideo.

Nasz skrypt ma wiele niedociągnięć. Powinniśmy dodać do niego system kontroli błędów. Największym problemem tego skryptu jest jego powolność przy pracy z dużymi plikami. Duża filmy mogą się długo konwertować, a użytkownik musi czekać.

W celu lepszej obsługi dużych filmów (więcej niż 10 sekund), polecam po prostu kopiowanie filmu do odpowiedniego katalogu, a następnie informowania użytkownika, że film pojawi się później. Następnie, inny skrypt przetwarzy filmy w tym katalogu.

Warto tu wyjaśnić, dlaczego dokonujemy konwersji do Flash wideo. Można co prawda wyświetlać filmy w oryginalnych formatach ale stworzy to wiele problemów na różnych systemeach np. kodeki odtwarzacze, itp. Zaletą korzystania z programu Flash Player napisany w Flex-jest to, że działa on niemal wszędzie.

Następnym krokiem jest stworzenie prostego interfeju HTML / Flash, w formie podobnej do YouTube.

Budowanie interfejsu HTML / Flash

Przejdźmy teraz do stworzenia interfejsu Flash, czyli naszego odtwarzacza klipów.

Tworzymy nowy projekt w programie Adobe Flex Buildert82; 2. Następnie, należy utworzyć plik o nazwie simplemovie.mxml.

simplemovie.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:VBox backgroundColor="white" width="400" height="335">
  <mx:VideoDisplay width="400" height="300" id="videoPlayer"
    source="{Application.application.parameters.movie}" />
  <mx:HBox width="100%" horizontalAlign="center">
    <mx:Button label="Play" click="videoPlayer.play()" />
  </mx:HBox>
</mx:VBox>
</mx:Application>


Ten prosty skrypt Flex składa się z dwóch elementów aktywnych: VideoDisplay, który odtwarza wideo oraz przycisku Play, aby użytkownicy mogli ponownie uruchomić wideo po jego zakończeniu.

Element VideoDisplay posiada atrybut, który zawiera adres URL do pliku wideo FLV. W tym przypadku pobiera URL przez stałą FlashVars, która znajduje się w tagu  lub  w kodzie HTML.

Korzystanjąc z Flex Builder, należy skompilować simplemovie.mxml do odpowiedniej pliku simplemovie.swf i przenieść go z bin do katalogu naszej strony. Tutaj umieszczamy też całe wszystkie kody PHP, które będą obsługiwać film. teraz napiszmy skrypt hostujący filmy:

simptest.php
<?php
require "DB.php";
 
$moviebase = 'http://localhost:8080/movies/';
 
$dsn = 'mysql://root@localhost/movies';
$db =& DB::connect( $dsn );
if ( PEAR::isError( $db ) ) { die($db->getMessage()); }
 
$source = null;
$movieId = 1;
if ( array_key_exists( 'movie', $_GET ) )
  $movieId = $_GET['movie'];
 
$movies = array();
$res = $db->query( 'SELECT movieId, source, title FROM movies' );
while( $row = $res->fetchrow( ) ) {
  $movies []= $row;
  if ( $row[0] == $movieId )
    $source = $row[1];
}
 
if ( $source == null )
    $source = $movies[0][1];
?>
<html>
<body>
<table>
<tr><td valign="top">
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="400"
  height="335"
  codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
<param name="movie" value="simplemovie.swf" />
<param name="quality" value="high" />
<param name="flashVars" value="movie=<?php echo( $moviebase.$source ) ?>">
<embed src="simplemovie.swf" quality="high"
  width="400" height="335" play="true"
  loop="false"
  quality="high"
  flashVars="movie=<?php echo( $moviebase.$source ) ?>"
  type="application/x-shockwave-flash"
  pluginspage="http://www.adobe.com/go/getflashplayer">
</embed>
</object>
</td><td valign="top">
<?php
foreach( $movies as $movie ) {
?>
<a href="simptest.php?movie=<?php echo( $movie[0] )?>"><?php echo( $movie[2] )?></a><br/>
<?php
}
?>
</td></tr></table>
</body>
</html>


Skrypt rozpoczyna się przez podłączenie do bazy danych i pobrania listy filmów. Teraz sprawdza on, czy został przekazany identyfikatror filmu przez zmienną movie. Jeśli tak, to zostaje on przekazany do simplemovie.swf przez parametr flashVars.

W następnej sekcji tworzy kod HTML obsługujący odtwarzacz simplemovie.swf. Zostaje też wyświetlona lista dostępnych filmów. Linki zawierają ID odpowiedniego filmu.

Kiedy otworzę stronę ładuje się pierwsze wideo. Gdy wybierzemy jakis film z listy po prawej stronie, to strona odświerzy się z załadowanym odpowiednim plikiem wideo.

I tak naprawdę nasz projekt został ukończony... ale spróbujmy go trochę rozwinąć.

Interfejs Flex, część 1

Jeśli chcemy wykorzystać technologię Flex, która pozwoli nam uzyskać ciekawy inerfejs listy, to musimy przygotować odpowiednio samą listę. Najbardziej wygodnym sposobem jest wykorzystanie języka XML. Wracając do kodu PHP, musimy wyeksportować listę z bazy danych w postaci XML. Całość pokazana jest poniżej:

movies.php
<?php
require "DB.php";
 
$moviebase = 'http://localhost:8080/movies/';
 
header( 'content-type: text/xml' );
 
$dsn = 'mysql://root@localhost/movies';
$db =& DB::connect( $dsn );
if ( PEAR::isError( $db ) ) { die($db->getMessage()); }
?>
<movies>
<?php
$res = $db->query( 'SELECT title, source, thumb, width, height FROM movies' );
while( $row = $res->fetchrow( ) ) {
?>
  <movie title="<?php echo( $row[0] ) ?>" source="<?php echo( $moviebase.$row[1] ) ?>"
   thumb="<?php echo( $moviebase.$row[2] ) ?>" width="<?php echo( $row[3] ) ?>"
   height="<?php echo( $row[4] ) ?>" />
<?php
}
?>
</movies>


Rozbudujmy teraz nasz odtwarzacz, zawarty pliku simplemovie.mxml.

mytube1.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="movieXmlData.send()">
 
<mx:HTTPService method="get" url="http://localhost:8080/movies.php" id="movieXmlData" result="onGetMovies( event )" />
 
<mx:Script>
import mx.rpc.events.ResultEvent;
import mx.controls.VideoDisplay;
import mx.controls.List;
import mx.rpc.http.HTTPService;
import mx.collections.ArrayCollection;
 
[Bindable]
private var movies : ArrayCollection = new ArrayCollection();
 
public function onGetMovies( event : ResultEvent ) : void
{
  var firstMovie : String = event.result.movies.movie[0].source.toString();
  videoPlayer.source = firstMovie;
 
  movies = event.result.movies.movie;
  movieList.selectedIndex = 0;
}
 
public function onPrevious() : void
{
  if ( movieList.selectedIndex == 0 )
    movieList.selectedIndex = movies.length - 1;
  else
    movieList.selectedIndex -= 1;
  videoPlayer.source = this.movieList.selectedItem.source.toString();
}
 
public function onPlay() : void
{
  videoPlayer.source = this.movieList.selectedItem.source.toString();
  videoPlayer.play();
}
 
public function onNext() : void
{
  if ( movieList.selectedIndex >= ( movies.length - 1 ) )
    movieList.selectedIndex = 0;
  else
    movieList.selectedIndex += 1;
  videoPlayer.source = this.movieList.selectedItem.source.toString();
}
 
public function onChange() : void
{
  videoPlayer.source = this.movieList.selectedItem.source.toString();
}
</mx:Script>
 
<mx:HBox width="100%" paddingLeft="10" paddingTop="10" paddingRight="10">
  <mx:VBox>
    <mx:VideoDisplay width="400" height="300" id="videoPlayer" complete="onNext()" />
    <mx:HBox width="100%" horizontalAlign="center">
       <mx:Button label="<<" click="onPrevious()" />
       <mx:Button label="Play" click="onPlay()" />
       <mx:Button label=">>" click="onNext()" />
    </mx:HBox>
    </mx:VBox>
    <mx:List width="100%" height="340" id="movieList"
      dataProvider="{movies}"
      change="onChange()"
      labelField="title"></mx:List>
</mx:HBox>
 
</mx:Application>


Dużą zmianą jest dodanie kodu ActionScript na początku pliku. Ten kod opisuje zachowanie interfejsu. Po pierwsze, zostaje pobrany kod w formacie XML z movies.php za pomocą mechanizmu HTTPService w funkcji onGetMovies (). Można go następnie użyć do uzyskania pierwszego filmu i rozpoczęcia odtwarzania. W onGetMovies() ustawia również zmienną lokalnych filmów, aby wyświetlić listę. Reszta metod odpowiada za obsługę poszczególnych zdarzeń interfejsu, np. kliknięcie przycisku.

Na dole pliku są obiekty Flex, które składają się na interfejs użytkownika. Pojawiły się strzałki, aby przejść do następnego i poprzedniego filmu. Lista filmów pojawia się po prawej stronie wyświetlacza wideo, w tym przypadku na liście pokazuje tylko tytuł filmu.

Skompiluj teraz wszystko w Flex Builder.

Mogę korzystać z listy po prawej stronie, aby wybrać film oraz nawigować do kolejnego lub poprzedniego filmu. W profesjonalnych serwisach wideo, takich jak YouTube na liście filmów wyświetlane są miniatury. Ułatwia to bardzo wyszukiwanie interesujących nas filmów. Spróbujmy dodać tę funkcjonalność do naszej strony.

Interfejs Flex, Część 2 - Miniatury

Aby korzystać z miniaturek na liście, musisz zmienić listę tak, aby wyświetlane były miniatury i tytuł obrazu. Na szczęście, przy użyciu  Flex'a jest to bardzo proste. Dodajmy tag <list> do pola itemRenderer.

mytube2.mxml
...
  <mx:List width="100%" height="340" id="movieList"
    dataProvider="{movies}"
    change="onChange()"
    itemRenderer="MovieItem"></mx:List>
...


Item renderer to komponent MXML, który należy utworzyć wywołując MovieItem. Tworzymy go wybierając New> MXML Component.

MovieItem.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" height="80">
  <mx:Image source="{data.thumb}" width="{data.width/3}"
     height="{data.height/3}" rotation="5" left="10" top="0" />
   <mx:Label text="{data.title}" fontWeight="bold" top="10" left="100" fontSize="18" />
</mx:Canvas>


Użyłem elementu Canvas dzięki czemu mogę umieszczać elementy wokół siebie. Następnie użyłem tagu <mx:Image> na obraz i <mx:label> na tytuł. Dla urozmiaicenia, lekko obróćmy obraz. No, może nie jest to piękny wygląd, ale na pewno o wiele ładniejszy niż tekstowa lista.

I to już koniec. Mam nadzieję, że opis był ciekawy. Zachęcam do rozbudowywania projektu. Możesz, np. dodać opisy, linki, ocenianie, listę ulubionych, logowanie lub cokolwiek innego. Ograniczeniem jest tylko twoja pomysłowość.



InformacjeRaportuj | Drukuj

Data dodania: 25-10-2017 14:59Autor:admin
Ilość wyświetleń:1142Komentarzy: 0
Komentarze
Brak komentarzy.
Dodaj komentarz
Zaloguj się, żeby móc dodawać komentarze.