JavaFX Reproducción de Audio y Video

La JavaFX Media API nos provee de las clases necesarias para la reproducción de audio y video en diversos formatos como: AAC, AIFF, WAV, MP3, para audio y FLV, MPEG-4 para video, es posible reproducir archivos locales y remotos a través de HTTP, todas las clases de esta API están incluidas en el paquete javafx.scene.media.

javafx media api (audio-video)

Clase Media

Necesitamos crear una instancia de la clase Media, esta instancia representa el archivo que deseamos reproducir, la misma contiene información como la duración, ancho, alto, etc., puede ser un archivo de video o audio, en el constructor de la clase Media indicamos el archivo usando una URL que puede apuntar a un archivo local o a una dirección HTTP.

file:///c:/developer/temp/video.mp4
http://some_host/music.mp3
jar:file:/c:/…/AudioAndVideo.jar!/carmelo/javafx/audio.mp3

Estas son las URL que podemos utilizar, la primera apunta a un archivo en el disco local, la segunda a un archivo alojado en un servidor web, y la tercera a un archivo almacenado dentro de nuestro proyecto.

Clase MediaPlayer

El objeto MediaPlayer nos permitirá controlar el recurso que estemos reproduciendo, por ejemplo, podemos: pausar, detener, iniciar la reproducción, entre otras cosas, para crear la instancia debemos indicar el objeto Media en el constructor.

Es posible detectar errores en el Media y MediaPlayer estableciendo un callback usando el método setOnError() en ambas clases, usamos getError() para obtener el error.

Clase MediaView

Un MediaView nos proporciona un control que puede ser agregado al scene, este control nos permite visualizar el objeto MediaPlayer al que esta asociado, podemos indicar este objeto usando el constructor o el método setMediaPlayer(player), en caso de ser un audio este control estará vacío.

Media media = new Media("file:///c:/developer/temp/video.mp4");
media.setOnError(() -> System.out.println("error media"));

MediaPlayer player = new MediaPlayer(media);
player.setOnError(() -> System.out.println("error player"));

MediaView view = new MediaView(player);
view.setFitHeight(600);
view.setFitWidth(800);

Este MediaView tendrá un tamaño de 800x600, si deseamos mantener el tamaño original del video establecemos los métodos setFitWidth(0) y setFitHeight(0) a cero, además disponemos del método setPreserveRatio(boolean) para indicar si deseamos mantener la relación ancho / alto.

Barra de tiempo

Vamos a crear un control Slider que nos permita mostrar y modificar el tiempo actual de reproducción, además agregamos dos Label para indicar el tiempo total y actual en minutos, arrastrando el Slider podemos modificar la posición actual del video.

Slider slider_time = new Slider();
Label actual_time = new Label("0");
Label total_time = new Label("0");

player.setOnReady(() -> {
    total_time.setText(String.format("%.2f", player.getTotalDuration().toMinutes())); 
    slider_time.setMax(player.getTotalDuration().toSeconds());
    
    slider_time.valueProperty().addListener((p, o, value) -> {
        if (slider_time.isPressed()) {
            player.seek(Duration.seconds(value.doubleValue()));
        }
    });

    player.currentTimeProperty().addListener((p, o, value) -> {
        slider_time.setValue(value.toSeconds());
        actual_time.setText(String.format("%.2f", value.toMinutes()));
    });
});

Para obtener la información de duración total del video primero debemos asegurarnos de que el MediaPlayer esta listo para ser utilizado, para ello usamos setOnReady(), el método getTotalDuration() nos devuelve la duración total del video, la propiedad currentTimeProperty indica el tiempo actual y el método seek(Duration) nos permite mover la posición actual al tiempo indicado.

Controles de reproducción

Vamos a crear los controles que nos permitirán modificar el volumen de sonido, la velocidad de reproducción, y detener, pausar o iniciar la misma.

Label lbl_volumen = new Label("Volumen");

Slider volumen = new Slider(0, 1, 0.8);
player.volumeProperty().bind(volumen.valueProperty());

Label actual_volumen = new Label("80%");
actual_volumen.textProperty().bind(player.volumeProperty().multiply(100.0).asString("%.2f %%"));

Button play  = new Button("Reproducir");
Button pause = new Button("Pausar");
Button stop  = new Button("Detener");

play.setOnAction(e -> player.play());
pause.setOnAction(e -> player.pause());
stop.setOnAction(e -> player.stop());

Label cur_rate = new Label("1x");
cur_rate.textProperty().bind(player.rateProperty().asString("%.1fx"));

Button inc_rate  = new Button(">>");
Button dec_rate  = new Button("<<");

// los valores validos para setRate van de 0 a 8
inc_rate.setOnAction(e -> player.setRate(player.getRate() + 1));
dec_rate.setOnAction(e -> player.setRate(player.getRate() - 1));

HBox.setHgrow(volumen, Priority.ALWAYS);
HBox panel = new HBox(
        play, pause, stop, 
        dec_rate, cur_rate, inc_rate, 
        lbl_volumen, volumen, actual_volumen);

panel.setSpacing(10.0);
panel.setAlignment(Pos.CENTER);

Usaremos un control Slider para modificar el volumen de sonido, este es un valor porcentual que va de 0 a 1, solamente enlazamos la propiedad volumeProperty del MediaPlayer con la propiedad valueProperty del Slider.

Para iniciar, pausar y detener la reproducción usaremos los correspondientes métodos de la clase MediaPlayer: play(), pause(), stop(), creamos un botón para cada una de estas acciones.

La velocidad de reproducción la podemos establecer mediante el método setRate(Double) donde podemos indicar un valor entre 0 y 8 para la velocidad deseada.

Obtener Metadatos

Los metadatos son información que puede o no estar presente en el archivo que estemos reproduciendo, en un archivo de audio la información puede ser la siguiente: artista, álbum, genero, fecha, imagen, etc.

player.setOnReady(() -> {
     media.getMetadata().forEach((k, v) -> System.out.println(k + ", " + v));
}

El método getMetadata() de la clase Media no devuelve un ObservableMap<String, Object> que contiene los metadatos si están presentes, debemos tener presente que la informacion puede ser de distintos tipos, por ejemplo: la clave artist se asocia a un valor tipo String que representa el nombre del artista, por otro lado la clave image se asociará a un valor de tipo javafx.scene.image.Image que representa la imagen miniatura asignada al archivo.

Reproducir clip de audio

Si deseamos reproducir un sonido corto de una manera simple, por ejemplo: emitir un sonido al hacer clic sobre un botón, es preferible optar por la clase AudioClip diseñada para este propósito, en su constructor indicamos la url del archivo a reproducir y usamos los métodos play() y stop() para iniciar o detener la reproducción, esta clase también nos permite controlar el volumen, balance, velocidad y otras.  

AudioClip audio = new AudioClip("file:///c:/developer/temp/audio.mp3");
audio.play();
audio.setVolume(0.85);

Proyecto en GitHub: Reproducción de Audio y Video

Comentarios

  1. player.seek(Duration.seconds(value.doubleValue()));
    en esta parte del codigo para reproducir el video al tiempo donde se desea con el slider, me marca un error, me podrias decir como funciona el metodo seek(), te lo agradeseria mucho saludos

    ResponderEliminar
    Respuestas
    1. player.seek(Duration.seconds(60)) con este código la reproducción actual se movería a los 60 segundos.

      Eliminar
  2. si tengo , mi archivo mp3 en el mismo paquete que mi codigo como podria hacer para ejecutar mi audio,he tratado de usar
    AudioClip audio = new AudioClip(new File("04-nickelback-animals.mp3").toURI().toString());
    pero me sale error, si me pudieras ayudar te lo agradeceria mucho, tu post ha sido de mucha ayuda .

    ResponderEliminar
  3. Buenas tardes estoy utilizando sceneBuilder para hacer lo de la barra de tiempo pero tengo un problema no se que evento utilizar para que funcione con el mouse el codigo le tengo de la siguiente manera:
    No se si el metodo public void clicked este bien.
    @FXML
    public void clicked() {


    mediaplayer.setOnReady(() -> {
    total_time.setText(String.format("%.2f",mediaplayer.getTotalDuration().toMinutes()));
    red.setMax(mediaplayer.getTotalDuration().toSeconds());

    red.valueProperty().addListener((p, o, value) -> {
    if (red.isPressed()) {
    mediaplayer.seek(Duration.seconds(value.doubleValue()));
    }
    });

    mediaplayer.currentTimeProperty().addListener((p, o, value) -> {
    red.setValue(value.toSeconds());
    actual_time.setText(String.format("%.2f", value.toMinutes()));
    });
    });
    }

    ResponderEliminar

Publicar un comentario

Temas relacionados

Entradas populares de este blog

tkinter Grid

Conectar SQL Server con Java

Controles y Contenedores JavaFX 8 - I

Histogramas OpenCV Python