Se precisar de incorporar um leitor multimídia na sua aplicação de ambiente de trabalho Java, existem várias opções para fazer isso:
- Você pode utilizar a API JavaFX Media para implementar toda a funcionalidade necessária do leitor multimídia.
- O Java Media Framework, um pouco desatualizado mas ainda funcional, pode ser uma solução.
- Você pode integrar uma biblioteca Java de terceiros, como o VLCJ, que envolve a funcionalidade de um leitor multimídia nativo.
Cada uma delas tem os seus prós e contras:
A abordagem da JavaFX Media API é multiplataforma e pode ser utilizada em Windows, Linux e macOS. O funciona bem para JavaFX. Contudo, se utilizar Swing ou SWT, necessitará de pontes como JFXPanel
e FXCanvas
.
Para envolver a funcionalidade de um leitor multimídia nativo é necessário um conjunto separado para cada plataforma, uma vez que um leitor pode simplesmente não suportar todas as plataformas necessárias. Por exemplo, o VLCJ não é compatível com o Linux. Além disso, poderá ser necessário instalar na plataforma de destino os codecs de vídeo e áudio em falta para reproduzir vários formatos multimídia.
Utilizar as capacidades do navegador Web
Hoje em dia, nós consumimos a maior parte do conteúdo de mídias através de navegadores Web. Funcionam em várias plataformas e podem reproduzir vários formatos de áudio e vídeo. Além disso, dispõem de todas as funções necessárias para reproduzir conteúdos multimídia. Por que razão não utilizar o poder de um navegador Web para reproduzir conteúdos multimídia em uma aplicação de ambiente de trabalho Java?
Neste artigo, eu descreverei mais uma maneira de construir um media player Java multiplataforma que pode usar em seu aplicativo Java Swing, JavaFX, ou SWT. Eu vou:
- Integrar um controle de navegador Web numa aplicação Java Swing simples utilizando JxBrowser.
- Carregar a página Web HTML que reproduzirá o vídeo necessário utilizando as capacidades HTML5.
- Controlar a reprodução através de comandos JavaScript que serão chamados diretamente a partir do código Java.
O JxBrowser é uma biblioteca Java comercial que lhe permite aproveitar o poder do Chromium em aplicações Java Swing, JavaFX e SWT de plataforma cruzada. É mais adequada para empresas que desenvolvem e vendem soluções de software baseadas na tecnologia Java.
No passado, estávamos habituados ao Flash Player apresentando o conteúdo multimídia de todos os tipos em uma página Web. Ele era muito popular, mas chegou ao fim da sua vida em Dezembro de 2020. Atualmente, foi completamente substituído pelas APIs de vídeo e áudio HTML5.
Existem duas formas de reproduzir conteúdos multimídia utilizando as APIs:
- Trabalhar diretamente com as APIs de vídeo e áudio HTML5.
- Utilizar uma biblioteca JavaScript de terceiros, como Plyr, Video.js, etc.
Em este artigo, vou utilizar a biblioteca Plyr — um dos leitores multimídia HTML5 mais populares. É bastante simples e fácil para integrar.
Implementação
Vamos criar um programa de demonstração que demonstra como construir um media player Java multiplataforma usando a biblioteca Plyr JS e JxBrowser.
Em primeiro lugar, precisamos criar uma página HTML (media.html
) na qual incluímos a biblioteca JS , incorporamos um leitor de vídeo e configuramos a localização do arquivo de vídeo MP4 de destino:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Java Media Player</title>
<link rel="stylesheet" href="<https://cdn.plyr.io/3.6.8/plyr.css>"/>
</head>
<body style="margin:0">
<video id="player"
controls
crossorigin
playsinline
data-poster="<https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg>">
<source src="<https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-720p.mp4>"
type="video/mp4"/>
</video>
<script src="<https://cdn.plyr.io/3.6.8/plyr.js>" crossorigin="anonymous"></script>
</body>
</html>
Em seguida, temos que criar uma aplicação Java Swing simples que mostre um JFrame com o navegador Web e controles de reprodução:
JFrame frame = new JFrame("Java Media Player");
frame.add(new MediaPlayer(), BorderLayout.CENTER);
frame.setVisible(true);
O componente MediaPlayer
contém o navegador Web e os controles de reprodução. Ele tem a seguinte lógica de inicialização:
engine = Engine.newInstance(
EngineOptions.newBuilder(HARDWARE_ACCELERATED)
// Nesta demonstração carregamos um arquivo de vídeo MP4, por isso temos de
// ativar as características proprietárias correspondentes
// que estão desativadas por padrão.
.enableProprietaryFeature(ProprietaryFeature.H_264)
.enableProprietaryFeature(ProprietaryFeature.AAC)
// Ativar a possibilidade de reproduzir vídeo
// programaticamente a partir de JavaScript sem interação do usuário
// numa página web.
.enableAutoplay()
.build());
Browser browser = engine.newBrowser();
// Injeta uma instância de JsPlayer em JavaScript para chamar
// os seus métodos a partir de JavaScript para informar sobre eventos do player.
browser.set(InjectJsCallback.class, params -> {
Frame frame = params.frame();
JsObject window = frame.executeJavaScript("window");
if (window != null) {
player = new JsPlayer(frame);
window.putProperty("java", player);
}
return Response.proceed();
});
// Obtém o caminho absoluto para o arquivo media.html com o vídeo JS
// player, carrega-o e espera até o arquivo estar completamente carregado, para
// podermos construir os controles UI do player.
URL resource = MediaPlayer.class.getResource("/media.html");
if (resource != null) {
browser.navigation().loadUrlAndWait(resource.toString());
}
// Criar um controle visual Swing que apresentará o conteúdo da página Web
// com vídeo.
BrowserView view = BrowserView.newInstance(browser);
view.setPreferredSize(new Dimension(1280, 720));
// Incorporar o controle no Java Swing Frame.
setLayout(new BorderLayout());
add(view, BorderLayout.CENTER);
add(playbackControls(), BorderLayout.SOUTH);
Deixem-me explicar o que faço nesta lógica de inicialização. No código acima, eu configuro a instância Engine
, equivalente à aplicação Google Chrome, com várias opções:
- Ativar as funcionalidades proprietárias H264 e AAC para poder reproduzir vídeo MP4;
- Permitir a possibilidade de reproduzir vídeo de forma programática a partir do JavaScript sem interação do usuário na página Web.
Em seguida, crio uma instância do browser
, equivalente a uma aba do Chrome, e carrego o arquivomedia.html
. Para apresentar o conteúdo do arquivo HTML crio um controle Swing BrowserView
e insiro-o em uma frame Java.
Na aplicação de demonstração, decidi utilizar a seguinte funcionalidade do leitor multimídia:
- Reproduzir e pausar;
- Silenciar e ativar o som;
- Alterar o volume;
- Obter a duração do vídeo em segundos;
- Receber notificações quando o tempo de reprodução atual for alterado;
- Definir o tempo de reprodução atual.
Para cada uma das funcionalidades de reprodução descritas, crio um controlo GUI Java Swing correspondente, de modo que o painel de reprodução final tenha o seguinte aspecto:
Agora, preciso associar estes controles à funcionalidade correspondente do leitor multimédia JS. Por exemplo, quando clico no botão Reproduzir, preciso invocar a função player.play()
JS. Para fazer isso, eu uso a API JxBrowser correspondente:
frame.executeJavaScript("player.play()");
Para receber notificações do JavaScript quando a reprodução for alterada, preciso definir uma classe Java pública com os métodos públicos marcados com a anotação @JsAccessible
, conforme mostrado abaixo:
public final class JsPlayer {
@JsAccessible
public void onTimeUpdated(double currentTime) {
listeners.forEach(listener -> listener.accept(currentTime));
}
}
Vamos também criar uma instância desta classe e injetá-la no JavaScript utilizando a seguinte API JxBrowser:
browser.set(InjectJsCallback.class, params -> {
Frame frame = params.frame();
JsObject window = frame.executeJavaScript("window");
if (window != null) {
player = new JsPlayer(frame);
window.putProperty("java", player);
}
return Response.proceed();
});
Os métodos anotados com @JsAccessible
são “visíveis” para JavaScript e podem ser invocados quando um evento correspondente tiver sido acionado.
No arquivomedia.html
, tenho que adicionar o código JavaScript que notificará o lado Java sobre diferentes eventos de reprodução:
<script>
player.on('timeupdate', event => {
java.onTimeUpdated(player.currentTime);
});
player.on('volumechange', event => {
java.onVolumeChanged(player.volume, player.muted);
});
player.on('play', event => { java.onPlaybackStarted(); });
player.on('pause', event => { java.onPlaybackPaused(); });
</script>
O código-fonte completo do programa e media.html
está disponível em GitHub.
Resultados
Se compilar e executar o programa, verá o seguinte resultado:
O JxBrowser é multiplataforma, pois esta abordagem funcionará em todas as plataformas sem esforço extra da sua parte.
Conclusão
A funcionalidade de vídeo HTML5 é suficiente para construir um leitor multimídia personalizado para reproduzir a maioria dos formatos populares de vídeo e áudio em várias plataformas.
Espero que a abordagem descrita neste artigo seja útil para você. Aguardamos com expectativa os seus comentários e sugestões.