寬帶、媒體、電影、圖像和聲音等技術(shù)的出現(xiàn)推動(dòng)了 Web 2.0 的發(fā)展。了解如何把多媒體與 PHP 和 Asynchronous JavaScript™ + XML(Ajax)結(jié)合起來(lái)創(chuàng)造令人耳目一新的體驗(yàn)。
如果問哪一個(gè)網(wǎng)站最能代表 Web 應(yīng)用程序的新潮流,多數(shù)人會(huì)回答 YouTube。這個(gè)網(wǎng)站不僅僅積極接納新技術(shù)營(yíng)造出夢(mèng)幻效果,而且改變了我們對(duì)多媒體的看法,改變了我們和媒體的關(guān)系。許多故事在以傳統(tǒng)媒體渠道傳播之前就已經(jīng)出現(xiàn)在 YouTube 上了,當(dāng)它們不再流傳時(shí),YouTube 就會(huì)像全世界的一個(gè)巨大的 Tivo,記錄著曾經(jīng)發(fā)生的點(diǎn)點(diǎn)滴滴。
媒體分享正在改變世界,而且從技術(shù)的觀點(diǎn)來(lái)說(shuō),這并不難做到。本文介紹如何在 Web 視頻托管應(yīng)用程序上增加一個(gè) Ajax 前端。
首先來(lái)看網(wǎng)站,網(wǎng)站上有一個(gè)電影列表可供選擇 — 一個(gè)不用改變頁(yè)面就能選擇不同電影的網(wǎng)站。頁(yè)面代碼如 清單 1 所示。
清單 1. index.html
<html> <head> <script src="prototype.js"></script> </head> <body> <div id="movieHost"> </div> <div id="movieList"> </div> <script> function setMovie( url ) { $('movieHost').innerHTML = ''; var elEmbed = document.createElement( 'embed' ); elEmbed.src = url; $('movieHost').appendChild( elEmbed ); } new Ajax.Request( 'movies.xml', { method: 'get', onSuccess: function( transport ) { var movieTags = transport.responseXML.getElementsByTagName( 'movie' ); $('movieList').innerHTML = ''; var bFirst = true; for( var b = 0; b < movieTags.length; b++ ) { var url = movieTags[b].getAttribute('url'); var title = movieTags[b].getAttribute('title'); if ( bFirst ) { setMovie( url ); bFirst = false; } var html = '<a href="javascript:void setMovie(\''+url+'\');">'; html += title+'</a><br/>'; $('movieList').innerHTML += html; } } } ); </script> </body> </html> |
該頁(yè)面使用 Prototype.js 這個(gè)很棒的 JavaScript 庫(kù)向 movies.xml 數(shù)據(jù)源發(fā)送 Ajax 請(qǐng)求。返回?cái)?shù)據(jù)后通過 getElementsByTagName()
方法查找所有電影標(biāo)簽。對(duì)每個(gè)電影標(biāo)簽,代碼檢索 URL 和標(biāo)題。如果檢索的標(biāo)簽是列表中的第一部電影,腳本立即開始放映這部電影。否則添加一個(gè) anchor 標(biāo)簽作為 movieList <div>
的電影選擇器。
電影選擇器 anchor 調(diào)用 setMovie()
函數(shù)打開指定的電影。播放電影的方法很簡(jiǎn)單,首先將 movieHost <div>
標(biāo)簽置空,即刪除原來(lái)的電影。然后將內(nèi)容設(shè)置為 <embed>
標(biāo)簽,其 URL 由電影列表指定。
<embed>
標(biāo)簽是在頁(yè)面中播放電影最簡(jiǎn)單的方法,但是存在跨瀏覽器的問題。另一種辦法是同時(shí)使用 <object>
和 <embed>
標(biāo)簽(還有一種辦法,即使用 Macromedia Flash Player:本文稍后 再討論)。
這個(gè)簡(jiǎn)單的例子中,movies.xml 只是一個(gè)平面文件,包含一些我自己的家庭短片的引用。該文件如 清單 2 所示。
清單 2. movies.xml
<movies> <movie url="spider.mov" title="Spider" /> <movie url="swing.mov" title="Swing Set" /> <movie url="water.mov" title="Water Splash" /> </movies> |
打開該頁(yè)面時(shí),顯示的結(jié)果如 圖 1 所示。
圖 1. 簡(jiǎn)單的電影列表頁(yè)面

最上方是一部由 <embed>
標(biāo)簽播放的電影,下面是其他影片列表。點(diǎn)擊其中的任何鏈接,正在播放的電影就變成所選擇的電影。
顯然,這個(gè)系統(tǒng)不適合大型的視頻資料庫(kù),還需要對(duì)影片列表進(jìn)行某種搜索。
![]() ![]() |
![]()
|
要添加搜索功能,必須添加一個(gè)搜索框,如 清單 3 所示。其中增加了搜索輸入字段 q
。
清單 3. 添加搜索功能
<html> <head> <script src="prototype.js"></script> </head> <body> <table><tr><td valign="top"> <input type="text" id="q" onkeyup="search()"> <div id="movieList"> </div> </td><td valign="top"> <div id="movieHost"> </div> </td> </tr></table> <script> function setMovie( url ) { $('movieHost').innerHTML = ''; var elEmbed = document.createElement( 'embed' ); elEmbed.src = url; $('movieHost').appendChild( elEmbed ); } function search() { new Ajax.Request( 'search.php?q='+escape($('q').value), { method: 'get', onSuccess: function( transport ) { var movieTags = transport.responseXML.getElementsByTagName( 'movie' ); $('movieList').innerHTML = ''; var bFirst = true; for( var b = 0; b < movieTags.length; b++ ) { var url = movieTags[b].getAttribute('url'); var title = movieTags[b].getAttribute('title'); if ( bFirst ) { setMovie( url ); bFirst = false; } var html = '<a href="javascript:void setMovie(\''+url+'\');">'; html += title+'</a><br/>'; $('movieList').innerHTML += html; } } } ); } </script> </body> </html> |
在 key-up 事件中指定 search()
方法將被調(diào)用。search()
方法和 Ajax.Request
調(diào)用類似,除了向 search.php 頁(yè)面?zhèn)鬟f查詢字符串。search.php 腳本返回和原來(lái)相同的 XML 格式,因此不需要修改 XML 解析的代碼。
我承認(rèn)對(duì)于自己的習(xí)慣來(lái)說(shuō),key-up 上的 search()
函數(shù)反映有點(diǎn)太快。理想情況下,系統(tǒng)應(yīng)該在執(zhí)行搜索之前等待一秒左右以便輸入完整的搜索文本,避免列表不停地閃爍。使用 window.setTimeout()
方法很容易實(shí)現(xiàn)這種行為。
清單 4 顯示了經(jīng)過修改的 search.php 腳本。
清單 4. search.php
<?php header( 'content-type: text/xml' ); $movies = array(); $movies['spider.mov'] = 'Spider'; $movies['swing.mov'] = 'Swing Set'; $movies['water.mov'] = 'Water Splash'; ?> <movies> <?php foreach( $movies as $k => $v ) { if ( strlen( $_GET['q'] ) > 0 && preg_match( '/'.$_GET['q'].'/i', $v ) ) { ?> <movie url="<?php echo($k) ?>" title="<?php echo($v) ?>" /> <?php } } ?> </movies> |
腳本一開始建立了一個(gè)數(shù)組保存全部電影。為了簡(jiǎn)化起見,這里對(duì)電影進(jìn)行了硬編碼。實(shí)際應(yīng)用的時(shí)候這些元素很可能取自電影清單的數(shù)據(jù)庫(kù)。
接下來(lái)的代碼遍歷列表,把搜索查詢的正則表達(dá)式應(yīng)用于每個(gè)電影的標(biāo)題。如果匹配則輸出包含 URL 和名稱的 <movie>
標(biāo)簽。
打開頁(yè)面并輸入 s
,將看到 圖 2 所示的頁(yè)面。
圖 2. 簡(jiǎn)單的電影查詢頁(yè)面

如果按下 Delete 建并輸入 water
,就會(huì)看到 圖 3 所示的頁(yè)面。
圖 3. 搜索與 “water” 相關(guān)的電影的查詢頁(yè)面

雖然本文主要討論如何使用 Dynamic HTML(DHTML)和 Ajax 建立前端應(yīng)用程序,但視頻共享網(wǎng)站決不是這么簡(jiǎn)單。
![]() ![]() |
![]()
|
先暫時(shí)離開實(shí)踐問題討論一些更具理論性的東西,視頻共享中更加復(fù)雜的問題。涉及到三個(gè)主要問題:
- 如何存儲(chǔ)和傳輸視頻
- 如何處理不同的視頻格式
- 如何從上傳文件中獲得縮略圖和視頻信息
視頻存儲(chǔ)是一個(gè)實(shí)實(shí)在在的問題 — 特別是對(duì)于小應(yīng)用程序而言視頻文件非常大,需要大容量的硬盤空間來(lái)存儲(chǔ)。將其傳遞給客戶還面臨著帶寬的挑戰(zhàn)。可以自己購(gòu)買設(shè)備安裝到托管設(shè)施中。或者使用 Amazon S3 這樣的服務(wù),只需很低的價(jià)格就能上傳任何資料(數(shù)據(jù)庫(kù)備份、圖片、電影等等)到 Amazon 數(shù)據(jù)中心,以及提供給其他客戶。和建立數(shù)據(jù)中心的大量投資相比可以先考慮一下這些服務(wù)。
下一個(gè)問題 — 視頻格式 — 提出了一個(gè)有趣的挑戰(zhàn)。存在多種視頻格式,沒有任何一種播放器能支持所有格式。事實(shí)上多數(shù)播放器只能處理自己挑選的視頻格式。為了方便用戶,也許最好以某種格式為標(biāo)準(zhǔn)然后將所有傳來(lái)的視頻都轉(zhuǎn)化成這種格式。有一種非常方便的工具,即命令行應(yīng)用程序 FFmpeg。它不僅能把一種視頻格式轉(zhuǎn)化成另一種,還能拾取畫面的快照從而為用戶提供視頻縮略圖。
選擇何種視頻格式作為標(biāo)準(zhǔn)可能很麻煩。目前 Flash 視頻具有明顯的優(yōu)勢(shì),但是 Windows Media®,特別是隨著 Microsoft Silverlight(原來(lái)的 WPF/Everywhere)的發(fā)布,正在贏得越來(lái)越多的支持。FFmpeg 幾乎能將任何影片格式轉(zhuǎn)化成 Flash 視頻格式,這一點(diǎn)很吸引人。而且有一些免費(fèi)和開源的 Flash 播放器很容易嵌入到網(wǎng)站上。將這些播放器和上述代碼結(jié)合起來(lái)就能建立一個(gè)完整的、以 Ajax 為前端的端到端視頻分享解決方案。
但 Web 上不僅僅有視頻,圖像共享也很重要。
![]() ![]() |
![]()
|
清單 5 顯示了一個(gè)簡(jiǎn)單的基于 DHTML 的幻燈片,數(shù)據(jù)來(lái)自 XML 文件。
清單 5. index.html
<html> <head> <script src="prototype.js"></script> </head> <body bgcolor="black"> <div style="text-align:center;"> <img id="imgItem" src="" style="display:none;"><br> <div id="imgTitle" style="color:white;font-family:arial;font-size:24pt;"> </div> </div> <script> var g_images = []; var g_slideIndex = 0; function showSlide() { $('imgTitle').hide(); $('imgItem').hide(); var height = 600; var width = ( height / g_images[ g_slideIndex ].height ) * g_images[ g_slideIndex ].width; $('imgItem').src = g_images[ g_slideIndex ].src; $('imgItem').width = width; $('imgItem').height = height; $('imgTitle').innerHTML = g_images[ g_slideIndex ].title; $('imgTitle').show(); $('imgItem').show(); g_slideIndex++; if ( g_slideIndex >= g_images.length ) g_slideIndex = 0; } new Ajax.Request( 'images.xml', { method: 'get', onSuccess: function( transport ) { var imageTags = transport.responseXML.getElementsByTagName( 'image' ); for( var b = 0; b < imageTags.length; b++ ) { g_images.push( { src: imageTags[b].getAttribute('src'), title: imageTags[b].getAttribute('title'), width: imageTags[b].getAttribute('width'), height: imageTags[b].getAttribute('height') } ); } showSlide(); window.setInterval( showSlide, 5000 ); } } ); </script> </body> </html> |
![]() |
|
上述代碼需要用到 Prototype.js JavaScript 庫(kù)。利用 Ajax.Request
對(duì)象獲得要顯示的圖片列表。然后解析返回的 XML 代碼,獲得圖片的 URL、寬、高和標(biāo)題。然后調(diào)用 showSlide()
函數(shù)得到幻燈片顯示效果。設(shè)置的計(jì)時(shí)器每五秒切換到下一張幻燈片。
幻燈片放映通過包含當(dāng)前圖片的 <image>
標(biāo)簽和標(biāo)題 <div>
標(biāo)簽實(shí)現(xiàn)。所謂放映只不過是隱藏當(dāng)前的圖片和標(biāo)題,將圖片來(lái)源和標(biāo)題文本設(shè)置為新幻燈片的內(nèi)容并顯示。如果需要某種淡入淡出效果,建議使用 Scriptaculous 庫(kù)中的 Effects
類,它是構(gòu)建在 Prototype.js 上的。
清單 6 顯示了數(shù)據(jù)圖像文件。
清單 6. images.xml
<images> <image src="images/megan1_875_700.jpg" title="Megan" width="875" height="700" /> <image src="images/oso1_875_700.jpg" title="Oso 1" width="875" height="700" /> <image src="images/oso2_873_700.jpg" title="Oso 2" width="873" height="700" /> </images> |
這里雖然使用了硬編碼,但使用 PHP 腳本很容易生成 XML 代碼。幻燈片放映如 圖 4 所示。
圖 4. 簡(jiǎn)單的幻燈片放映

注意:我以前介紹過一個(gè)更加精細(xì)的幻燈片放映版本(要獲得相關(guān)鏈接,參見參考資料)。現(xiàn)在這個(gè)版本的區(qū)別在于使用了 Prototype.js 庫(kù),各幻燈片之間的切換更簡(jiǎn)單。
![]() ![]() |
![]()
|
像 Flikr 和 YouTube 之類的網(wǎng)站僅僅顯示了 Web 上的多媒體應(yīng)用的巨大潛能的冰山一角。本文介紹了一些非常簡(jiǎn)便的視頻和圖片瀏覽的實(shí)現(xiàn),可用于您自己的項(xiàng)目。如果有效,請(qǐng)參加 developerWorks Ajax 論壇(參見 參考資料)告訴我您取得的成功。