Ejemplo de vídeo: Video Jukebox

Flash Player 9 y posterior, Adobe AIR 1.0 y posterior

En el ejemplo siguiente se crea un jukebox de vídeo que carga dinámicamente una lista de vídeos que se reproducirán en orden secuencial. Con ello, se crea una aplicación que permite que el usuario examine una serie de tutoriales de vídeo, o tal vez especifica los anuncios que se deben reproducir antes de publicar el vídeo solicitado del usuario. Este ejemplo muestra las siguientes características de ActionScript 3.0:

  • Actualizar una cabeza lectora según el progreso de reproducción de un archivo de vídeo

  • Detectar y analizar los metadatos de un archivo de vídeo

  • Controlar códigos específicos en un objeto NetStream

  • Cargar, reproducir, pausar y detener un archivo FLV cargado dinámicamente

  • Cambiar el tamaño de un objeto Video en la lista de visualización según los metadatos del objeto NetStream

Para obtener los archivos de la aplicación de este ejemplo, consulte www.adobe.com/go/learn_programmingAS3samples_flash_es. Los archivos de la aplicación Video Jukebox se encuentran en la carpeta Samples/VideoJukebox. La aplicación consta de los siguientes archivos:

Archivo

Descripción

VideoJukebox.fla

o

VideoJukebox.mxml

Archivo principal de la aplicación Flex (MXML) o Flash (FLA).

VideoJukebox.as

Clase que proporciona la funcionalidad principal de la aplicación.

playlist.xml

Archivo que muestra los archivos de vídeo que se cargarán en el jukebox de vídeo.

Carga de un archivo de lista de reproducción de vídeo externo

El archivo playlist.xml externo especifica los vídeos que se cargarán y el orden en que se reproducirán. Para cargar el archivo XML, se debe utilizar un objeto URLLoader y un objeto URLRequest, tal como se muestra en el código siguiente:

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

Este código se coloca en el constructor de la clase VideoJukebox para que el archivo se cargue antes de ejecutar otro código. En cuanto el archivo XML termine de cargarse, se llama al método xmlCompleteHandler(), que analiza el archivo externo en un objeto XML, tal como se muestra en el código siguiente:

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

El objeto XML playlist contiene el código XML sin procesar del archivo externo, mientras que videosXML es un objeto XMLList que solo incluye los nodos de vídeo. En el siguiente fragmento se muestra un archivo playlist.xml de ejemplo:

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

Por último, el método xmlCompleteHandler() llama al método main(), que configura las diferentes instancias de componente de la lista de reproducción, así como los objetos NetConnection y NetStream, que se utilizan para cargar los archivos FLV externos.

Creación de la interfaz de usuario

Para crear la interfaz de usuario, es necesario arrastrar cinco instancias de Button a la lista de visualización y asignarles los nombres de instancia siguientes: playButton, pauseButton, stopButton, backButton y forwardButton.

Para cada una de estas instancias de Button, deberá asignar un controlador para el evento click, tal como se muestra en el fragmento siguiente:

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);

El método buttonClickHandler() utiliza una sentencia switch para determinar la instancia de Button en la que se ha hecho clic, tal como se muestra en el código siguiente:

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; 
    } 
}

A continuación, añada una instancia de Slider a la lista de visualización y asígnele el nombre volumeSlider. En el código siguiente se establece la propiedad liveDragging de la instancia de Slider en true y se define un detector de eventos para el evento change de dicha instancia:

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);

Añada una instancia de ProgressBar a la lista de visualización y asígnele el nombre positionBar. Establezca su propiedad mode en manual, tal como se muestra en el fragmento siguiente:

positionBar.mode = ProgressBarMode.MANUAL;

Finalmente, añada una instancia de Label a la lista de visualización y asígnele el nombre positionLabel. La instancia de Timer establecerá el valor de la instancia Label.

Detección de los metadatos de un objeto Video

Cuando Flash Player encuentra metadatos para los vídeos cargados, se llama al controlador callback onMetaData() en la propiedad client del objeto NetStream. En el código siguiente se inicializa un objeto y se configura el controlador callback especificado:

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

El método metadataHandler() copia sus datos en la propiedad meta, definida anteriormente en el código. Esto permite acceder a los metadatos del vídeo actual en cualquier momento y en toda la aplicación. A continuación, se ajusta el tamaño del objeto Video del escenario para que coincida con las dimensiones que devuelven los metadatos. Por último, se desplaza la instancia de ProgressBar positionBar, cuyo tamaño se ajusta según el tamaño del vídeo que se reproduce en ese momento. El código siguiente contiene todo el método 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; 
}

Carga dinámica de un vídeo

Para cargar dinámicamente cada uno de los vídeos, la aplicación utiliza un objeto NetConnection y un objeto NetStream. En el código siguiente se crea un objeto NetConnection y se pasa el valor null al método connect(). Si se especifica null, Flash Player se conecta a un vídeo del servidor local en lugar de conectarse a un servidor, como Flash Media Server.

En el código siguiente se crean las instancias de NetConnection y NetStream, se define un detector de eventos para el evento netStatus y se asigna el objeto client a la propiedad client.

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

Se llama al método netStatusHandler() cuando se cambia el estado del vídeo. Esto también se aplica cuando un vídeo inicia o detiene la reproducción, almacena en búfer, o bien si no se encuentra un flujo de vídeo. El código siguiente muestra el evento 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. 
    } 
}

El código anterior evalúa la propiedad de código del objeto info y filtra si el código es "NetStream.Play.Start", "NetStream.Play.StreamNotFound" o "NetStream.Play.Stop". Los otros códigos se omitirán. Si el objeto NetStream inicia el código, se inicia la instancia de Timer que actualiza la cabeza lectora. Si el objeto NetStream no se puede encontrar o se detiene, la instancia de Timer se detiene y la aplicación intenta reproducir el siguiente vídeo de la lista de reproducción.

Cada vez que se ejecuta Timer, la instancia de ProgressBar positionBar actualiza su posición actual llamando al método setProgress() de la clase ProgressBar, y la instancia de Label positionLabel se actualiza con el tiempo transcurrido y el tiempo total del vídeo actual.

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. 
    } 
}

Control del volumen de vídeo

Se puede controlar el volumen del vídeo cargado dinámicamente estableciendo la propiedad soundTransform del objeto NetStream. La aplicación de jukebox de vídeo permite modificar el nivel de volumen cambiando el valor volumeSlider de la instancia Slider. En el código siguiente se muestra cómo se puede cambiar el nivel de volumen asignando el valor del componente Slider a un objeto SoundTransform, que se establece en la propiedad soundTransform del objeto NetStream:

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

Control de la reproducción de vídeo

El resto de la aplicación controla la reproducción de vídeo cuando este alcanza el final del flujo de vídeo, o bien cuando el usuario salta al vídeo anterior o siguiente.

En el método siguiente se recupera el URL de vídeo del objeto XMLList para el índice seleccionado en ese momento:

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

El método playVideo() llama al método play() del objeto NetStream para cargar el vídeo seleccionado actualmente:

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

El método playPreviousVideo() reduce el índice de vídeo actual, llama al método playVideo() para cargar el nuevo archivo de vídeo y establece la instancia de ProgressBar en visible:

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

El método final, playNextVideo(), incrementa el índice de vídeo y llama al método playVideo(). Si el vídeo actual es el último de la lista de reproducción, se llama al método clear() del objeto Video y la propiedad visible de la instancia de ProgressBar se establece en false:

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