視訊範例:視訊點播機

Flash Player 9 以及更新的版本,Adobe AIR 1.0 以及更新的版本

下列範例會建立簡單的視訊點唱機,它能動態地載入要依序播放的視訊清單。這讓您建立的應用程式可讓使用者瀏覽一系列的視訊教學課程,或者指定在傳遞使用者要求的視訊之前,應該播放哪些廣告。這個範例將示範下列 ActionScript 3.0 的功能:

  • 根據視訊檔案的播放進度來更新播放磁頭

  • 偵聽和剖析視訊檔案的中繼資料

  • 以網路串流處理特定的程式碼

  • 載入、播放、暫停和停止動態載入的 FLV

  • 根據網路串流的中繼資料,調整顯示清單上視訊物件的大小

若要取得此樣本的應用程式檔案,請參閱 www.adobe.com/go/learn_programmingAS3samples_flash_tw。您可以在 Samples/VideoJukebox 資料夾中找到「視訊點唱機」應用程式檔案,此應用程式是由下列檔案組成:

檔案

說明

VideoJukebox.fla

VideoJukebox.mxml

主應用程式檔案,在 Flex 中為 MXML,在 Flash 中為 FLA。

VideoJukebox.as

提供應用程式主要功能的類別。

playlist.xml

列出哪些視訊檔案將載入視訊點唱機的檔案。

載入外部視訊播放清單檔案

外部 playlist.xml 檔案會指定要載入哪些視訊,以及要播放它們的順序。為了載入 XML 檔案,您必須使用 URLLoader 物件以及 URLRequest 物件,如下列程式碼所示:

uldr = new URLLoader(); 
uldr.addEventListener(Event.COMPLETE, xmlCompleteHandler); 
uldr.load(new URLRequest(PLAYLIST_XML_URL));

此程式碼是置於 VideoJukebox 類別的建構函式中,因此在執行其它程式碼之前會先載入檔案。一旦 XML 檔案載入完成,就會呼叫 xmlCompleteHandler() 方法,以便將外部檔案剖析為 XML 物件,如下列程式碼所示:

private function xmlCompleteHandler(event:Event):void 
{ 
    playlist = XML(event.target.data); 
    videosXML = playlist.video; 
    main(); 
}

playlist XML 物件包含來自外部檔案的原始 XML,而視訊 XML 則是一種 XMLList 物件,只包含視訊節點。在下列程式碼片段中可以看到樣本 playlist.xml 檔案:

<videos> 
    <video url="video/caption_video.flv" /> 
    <video url="video/cuepoints.flv" /> 
    <video url="video/water.flv" /> 
</videos>

最後,xmlCompleteHandler() 方法會呼叫 main() 方法,它會在顯示清單上設定各種組件實體,並設定用來載入外部 FLV 檔的 NetConnection 與 NetStream 物件。

建立使用者介面

若要建立使用者介面,您必須拖曳五個 Button 實體到顯示清單上,並為它們指定下列實體名稱:playButtonpauseButtonstopButtonbackButtonforwardButton

對於每一個 Button 實體,您都必須指定其 click 事件的處理常式,如下列程式碼片段所示:

playButton.addEventListener(MouseEvent.CLICK, buttonClickHandler); 
pauseButton.addEventListener(MouseEvent.CLICK, buttonClickHandler); 
stopButton.addEventListener(MouseEvent.CLICK, buttonClickHandler); 
backButton.addEventListener(MouseEvent.CLICK, buttonClickHandler); 
forwardButton.addEventListener(MouseEvent.CLICK, buttonClickHandler);

buttonClickHandler() 方法會使用 switch 陳述式判斷按下的是哪個按鈕實體,如下列程式碼所示:

private function buttonClickHandler(event:MouseEvent):void 
{ 
    switch (event.currentTarget) 
    { 
        case playButton: 
            ns.resume(); 
            break; 
        case pauseButton: 
            ns.togglePause(); 
            break; 
        case stopButton: 
            ns.pause(); 
            ns.seek(0); 
            break; 
        case backButton: 
            playPreviousVideo(); 
            break; 
        case forwardButton: 
            playNextVideo(); 
            break; 
    } 
}

接下來,將 Slider 實體加入至顯示清單,並為它指定實體名稱為 volumeSlider。下列程式碼會將滑動軸實體的 liveDragging 屬性設定為 true,並為滑動軸實體的 change 事件定義事件偵聽程式:

volumeSlider.value = volumeTransform.volume; 
volumeSlider.minimum = 0; 
volumeSlider.maximum = 1; 
volumeSlider.snapInterval = 0.1; 
volumeSlider.tickInterval = volumeSlider.snapInterval; 
volumeSlider.liveDragging = true; 
volumeSlider.addEventListener(SliderEvent.CHANGE, volumeChangeHandler);

將 ProgressBar 實體加入至顯示清單,並為它指定實體名稱為 positionBar。將此實體的 mode 屬性設定為手動,如下列程式碼片段所示:

positionBar.mode = ProgressBarMode.MANUAL;

最後,將 Label 實體加入至顯示清單,並為它指定實體名稱為 positionLabel。計時器實體將會設定這個 Label 實體的值。

偵聽視訊物件的中繼資料

當 Flash Player 遇到每個載入視訊的中繼資料時,就會針對 NetStream 物件的 client 屬性呼叫 onMetaData() 回呼處理常式。下列程式碼會初始化 Object,並設定指定的回呼處理常式:

client = new Object(); 
client.onMetaData = metadataHandler;

metadataHandler() 方法會將其資料複製到程式碼前面部分所定義的 meta 屬性。這可讓您在整個應用程式中隨時存取目前視訊的中繼資料。接下來,會調整「舞台」上視訊物件的大小,以符合從中繼資料傳回的尺寸。最後,會移動 positionBar 進度列實體,並根據目前播放的視訊大小調整大小。下列程式碼包含整個 metadataHandler() 方法:

private function metadataHandler(metadataObj:Object):void 
{ 
    meta = metadataObj; 
    vid.width = meta.width; 
    vid.height = meta.height; 
    positionBar.move(vid.x, vid.y + vid.height); 
    positionBar.width = vid.width; 
}

動態載入 視訊

若要動態載入各個視訊,應用程式必須使用 NetConnection 與 NetStream 物件。下列程式碼會建立 NetConnection 物件,並將 null 傳遞給 connect() 方法。透過指定 null,Flash Player 會連接至本機伺服器上的視訊,而不會連接至伺服器,如 Flash Media Server。

下列程式碼會建立 NetConnection 與 NetStream 實體、為 netStatus 事件定義事件偵聽程式,並將 client Object 指定給 client 屬性:

nc = new NetConnection(); 
nc.connect(null); 
 
ns = new NetStream(nc); 
ns.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler); 
ns.client = client;

每次變更視訊狀態時,就會呼叫 netStatusHandler() 方法。這包括當視訊開始或停止播放、正在緩衝或是如果找不到視訊串流時。下列程式碼會列出 netStatusHandler() 事件:

private function netStatusHandler(event:NetStatusEvent):void 
{ 
    try 
    { 
        switch (event.info.code) 
        { 
            case "NetStream.Play.Start": 
                t.start(); 
                break; 
            case "NetStream.Play.StreamNotFound": 
            case "NetStream.Play.Stop": 
                t.stop(); 
                playNextVideo(); 
                break; 
        } 
    }  
    catch (error:TypeError)  
    { 
        // Ignore any errors. 
    } 
}

上述程式碼會評估 info 物件的程式碼屬性,並將程式碼篩選為「NetStream.Play.Start」、「NetStream.Play.StreamNotFound」或「NetStream.Play.Stop」。其它所有程式碼將會遭忽略。如果網路串流已開始,程式碼就會啟動 Timer 實體並更新播放磁頭。如果找不到或無法停止網路串流,就會停止 Timer 實體,而且應用程式會嘗試播放在播放清單中的下一個視訊。

每次 Timer 執行時,positionBar 進度列實體會呼叫 ProgressBar 類別的 setProgress() 方法以更新其目前的位置,而 positionLabel Label 實體則會以目前視訊的已經過時間及總時間來更新。

private function timerHandler(event:TimerEvent):void 
{ 
    try 
    { 
        positionBar.setProgress(ns.time, meta.duration); 
        positionLabel.text = ns.time.toFixed(1) + " of " meta.duration.toFixed(1) + " seconds"; 
    }  
    catch (error:Error) 
    { 
        // Ignore this error. 
    } 
}

控制視訊的音量

您可以設定 NetStream 物件的 soundTransform 屬性,針對動態載入的視訊控制音量。視訊點唱機應用程式可讓您變更 volumeSlider Slider 實體的值以修改音量。下列程式碼將說明如何變更音量,方法是將 Slider 組件的值指定給 SoundTransform 物件,而該物件會設定為 NetStream 物件的 soundTransform 屬性:

private function volumeChangeHandler(event:SliderEvent):void 
{ 
    volumeTransform.volume = event.value; 
    ns.soundTransform = volumeTransform; 
}

控制視訊播放

當視訊到達視訊串流的結尾或是使用者跳到上一個或下一個視訊時,應用程式的其餘部分就會控制視訊播放。

下列方法會從目前選取的索引之 XMLList 擷取視訊 URL:

private function getVideo():String 
{ 
    return videosXML[idx].@url; 
}

playVideo() 方法會呼叫 NetStream 物件的 play() 方法以載入目前選取的視訊:

private function playVideo():void 
{ 
    var url:String = getVideo(); 
    ns.play(url); 
}

playPreviousVideo() 方法會遞減目前的視訊索引、呼叫 playVideo() 方法以載入新視訊檔案,並將進度列設定成可以看見:

private function playPreviousVideo():void 
{ 
    if (idx > 0) 
    { 
        idx--; 
        playVideo(); 
        positionBar.visible = true; 
    } 
}

最後一個方法 playNextVideo() 會遞增視訊索引並呼叫 playVideo() 方法。如果目前的視訊是播放清單中的最後一個視訊,就會呼叫 Video 物件的 clear() 方法,而進度列實體的 visible 屬性會設定為 false

private function playNextVideo():void 
{ 
    if (idx < (videosXML.length() - 1)) 
    { 
        idx++; 
        playVideo(); 
        positionBar.visible = true; 
    } 
    else 
    { 
        idx++; 
        vid.clear(); 
        positionBar.visible = false; 
    } 
}