视频示例:视频自动唱片点唱机

Flash Player 9 和更高版本,Adobe AIR 1.0 和更高版本

以下示例生成一个简单的视频自动唱片点唱机,它可以动态加载一组视频并按顺序播放。您可以生成一个可以让用户浏览一系列视频教程的应用程序,也可以指定在传送用户请求的视频之前应播放的广告。此示例演示了 ActionScript 3.0 的下列功能:

  • 根据视频文件的播放进度更新播放头

  • 侦听并分析视频文件的元数据

  • 处理网络流中的特定代码

  • 加载、播放、暂停和停止动态加载的 FLV

  • 根据网络流的元数据调整显示列表上视频对象的大小

若要获取此范例的应用程序文件,请参阅 www.adobe.com/go/learn_programmingAS3samples_flash_cn。“视频自动唱片点唱机”应用程序文件位于 Samples/VideoJukebox 文件夹中。该应用程序包含以下文件:

文件

说明

VideoJukebox.fla

VideoJukebox.mxml

Flex 或 Flash 的主应用程序文件(分别为 MXML 和 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 对象。

创建用户界面

若要构建用户界面,您需要将 5 个 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 属性设置为 manual,如以下代码片断所示:

positionBar.mode = ProgressBarMode.MANUAL;

最后,向显示列表中添加一个 Label 实例,并为其指定实例名称 positionLabel。此 Label 实例的值将由计时器实例设置

侦听视频对象的元数据

当 Flash Player 遇到已加载的每个视频的元数据时,会对 NetStream 对象的 client 属性调用 onMetaData() 回调处理函数。以下代码初始化一个对象并设置指定的回调处理函数:

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 对象分配给 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 对象的 code 属性,并过滤出为“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; 
    } 
}