You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaFX+VLCJ播放列表:后台获取媒体时长及报错修复

问题描述

我用JavaFX+VLCJ开发媒体播放器,需要在播放列表ListView中显示单个媒体时长与总时长,目标格式如下:

1> my_visiting_video.mp4 | 01:21:35
2> avengers_end_game.flv | 02:13:40

TotalDuration: 03:35:15

基础播放功能正常,但后台线程获取时长时遇到三个问题:

  • Xlib线程未初始化错误,提示需传入--no-xlib参数
  • JavaFX线程异常:操作不在FX应用线程中
  • 运行时弹出额外的播放窗口

相关代码

DMediaPlayer.java(播放核心类)

import uk.co.caprica.vlcj.factory.MediaPlayerFactory;
import uk.co.caprica.vlcj.javafx.videosurface.ImageViewVideoSurface;
import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer;
import javafx.scene.image.ImageView;
import java.io.FileNotFoundException;

public class DMediaPlayer implements MediaPlayerInterface {

    private ImageView mediaView;
    private final MediaPlayerFactory mediaPlayerFactory;
    private final EmbeddedMediaPlayer embeddedMediaPlayer;

    public DMediaPlayer() {
        this.mediaPlayerFactory = new MediaPlayerFactory();
        this.embeddedMediaPlayer = mediaPlayerFactory.mediaPlayers().newEmbeddedMediaPlayer();
        
        this.mediaView = new ImageView();
        this.mediaView.setPreserveRatio(true);

        embeddedMediaPlayer.videoSurface().set(new ImageViewVideoSurface(this.mediaView));
    }

    @Override
    public void load(String filePath) throws FileNotFoundException {
        embeddedMediaPlayer.media().startPaused(filePath);
        embeddedMediaPlayer.controls().setPosition(0f);
    }

    @Override
    public ImageView getMediaView(){
        return mediaView;
    }
}

updatePlayList方法(后台获取时长逻辑)

File[] mediaList; // 已在构造方法中初始化
private void updatePlayList(){
    CompletableFuture.runAsync(() -> {
        long totalDur = 0;
        MediaPlayerFactory factory = new MediaPlayerFactory();
        EmbeddedMediaPlayer player = factory.mediaPlayers().newEmbeddedMediaPlayer();
        for (int i = 0; i < mediaList.length; i++){
            long mediaDur = 0;
            
            player.media().startPaused(mediaList[i].getAbsolutePath());
            mediaDur = player.status().length();
            totalDur += mediaDur;
            drawer.addItem(
                    (i+1) + "> " +
                    mediaList[i].getName().substring(0, 25) + "..." +
                    " | " + millisToDuration(mediaDur)
            );
        }
        drawer.getTotalDuration().setText("Total Duration: " + totalDur);
    });
}

报错信息

../include/vlc_xlib.h:46:vlc_xlib_init: Xlib not initialized for threads.
This process is probably using LibVLC incorrectly.
Pass "--no-xlib" to libvlc_new() to fix this.

Exception in thread "ForkJoinPool.commonPool-worker-3" java.lang.IllegalStateException: Not on FX application thread; currentThread = ForkJoinPool.commonPool-worker-3
    at javafx.graphics@19/com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:299)
    ...

解决方案

1. 修复Xlib线程错误

创建MediaPlayerFactory时传入--no-xlib参数,禁用Xlib依赖——后台线程仅需解析元数据,无需视频渲染相关的X11功能:

MediaPlayerFactory factory = new MediaPlayerFactory("--no-xlib");

2. 修复JavaFX线程异常

所有更新JavaFX UI控件的操作(如drawer.addItem、setText)必须在FX应用线程执行,用Platform.runLater()包裹这些操作:

// 后台计算完成后,将UI更新逻辑放入Platform.runLater
Platform.runLater(() -> {
    drawer.addItem(/* 列表项文本 */);
    drawer.getTotalDuration().setText(/* 总时长文本 */);
});

3. 消除额外播放窗口

无需使用带UI渲染的EmbeddedMediaPlayer,改用HeadlessMediaPlayer(无头播放器,仅处理媒体元数据/逻辑,无UI输出),彻底避免弹出额外窗口:

HeadlessMediaPlayer player = factory.mediaPlayers().newHeadlessMediaPlayer();

4. 更优的时长获取方案(推荐)

直接解析媒体元数据,无需启动播放器,效率更高:
通过MediaPlayerFactory的media().newMedia()创建媒体对象,解析元数据获取时长,无需初始化播放器实例:

import javafx.application.Platform;
import uk.co.caprica.vlcj.factory.MediaPlayerFactory;
import uk.co.caprica.vlcj.media.Media;
import java.util.ArrayList;
import java.util.List;

File[] mediaList; // 已在构造方法中初始化
private void updatePlayList(){
    CompletableFuture.runAsync(() -> {
        long totalDur = 0;
        MediaPlayerFactory factory = new MediaPlayerFactory("--no-xlib");
        List<String> playlistItems = new ArrayList<>();
        
        for (int i = 0; i < mediaList.length; i++){
            File mediaFile = mediaList[i];
            Media media = factory.media().newMedia(mediaFile.getAbsolutePath());
            media.parse(); // 同步解析元数据
            
            long mediaDur = media.info().duration();
            totalDur += mediaDur;
            
            // 构造列表项文本,避免文件名过长截断异常
            String fileName = mediaFile.getName();
            String displayName = fileName.length() > 25 ? fileName.substring(0,25) + "..." : fileName;
            String itemText = (i+1) + "> " + displayName + " | " + millisToDuration(mediaDur);
            playlistItems.add(itemText);
            
            media.release(); // 释放媒体资源
        }
        
        // 统一在FX线程更新UI
        final long finalTotal = totalDur;
        Platform.runLater(() -> {
            playlistItems.forEach(drawer::addItem);
            drawer.getTotalDuration().setText("Total Duration: " + millisToDuration(finalTotal));
        });
        
        factory.release(); // 释放工厂资源
    });
}

内容的提问来源于stack exchange,提问作者Chrishdev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 11:45:25