如何判断vlcj中MediaDiscoverer的媒体发现进程何时完成?
如何判断vlcj MediaDiscoverer的本地音乐目录发现进程完成?
我正在用vlcj 4.8.0开发音乐播放器,想通过MediaDiscoverer组件自动查找本地包含音频文件的目录(之前用DirectoryChooser和file.listFiles(File::isDirectory)实现,现在觉得MediaDiscoverer更适配媒体场景)。
修改了vlcj示例库的MediaDiscovererTest.java来过滤出音频目录,但遇到了异步扫描的问题:代码能在发现目录时打印路径并保存到列表,但主线程会直接执行后续逻辑(比如打印列表长度),导致输出始终为0。目前只能用Thread.sleep(2000)来临时等待,但这显然不是可靠方案。
之前处理媒体解析时,可以通过MediaEventListener的mediaParsedChanged回调判断解析完成,但查遍MediaDiscoverer文档没找到类似的完成事件,请问有没有更可靠的方式判断扫描何时结束?
我的修改后代码如下:
public class MediaDiscovererTest { private static final List<String> musicDirectories = new ArrayList<>(); public static void main(String[] args) throws Exception { MediaPlayerFactory factory = new MediaPlayerFactory(); List<MediaDiscovererDescription> discoverers = factory.mediaDiscoverers().discoverers(MediaDiscovererCategory.LOCAL_DIRS); if (discoverers.isEmpty()) { return; } Iterator<MediaDiscovererDescription> iterator = discoverers.iterator(); while (iterator.hasNext()) { MediaDiscovererDescription discoverer = iterator.next(); if (discoverer.name().equals("picture_dir") || discoverer.name().equals("video_dir")) { iterator.remove(); // 仅关注音频目录 } } for (MediaDiscovererDescription description : discoverers) { final String name = description.name(); MediaDiscoverer discoverer = factory.mediaDiscoverers().discoverer(name); MediaList list = discoverer.newMediaList(); MediaListEventAdapter mediaListEventAdapter = new MediaListEventAdapter() { @Override public void mediaListItemAdded(MediaList mediaList, MediaRef item, int index) { Media newMedia = item.newMedia(); System.out.println(newMedia.info().mrl()); // 将新目录添加到列表 musicDirectories.add(newMedia.info().mrl()); newMedia.release(); } }; list.events().addMediaListEventListener(mediaListEventAdapter); discoverer.start(); // list.events().removeMediaListEventListener(mediaListEventAdapter); // discoverer.release(); // list.release(); } System.out.println(musicDirectories.size()); // 当前测试状态下,此处始终输出0 Thread.currentThread().join(); } }
解决方案
vlcj的MediaDiscoverer本身没有提供直接的扫描完成回调,但可以通过以下两种可靠方式实现同步等待:
方法1:用CountDownLatch结合超时判断(推荐)
针对一次性扫描的目录发现器(如music_dir),扫描完成后不会再发送mediaListItemAdded事件,我们可以监控新条目的添加时间,超过阈值后认为扫描完成:
public class MediaDiscovererTest { private static final List<String> musicDirectories = Collections.synchronizedList(new ArrayList<>()); private static final CountDownLatch scanLatch = new CountDownLatch(1); private static long lastItemAddedTimestamp; public static void main(String[] args) throws Exception { MediaPlayerFactory factory = new MediaPlayerFactory(); List<MediaDiscovererDescription> discoverers = factory.mediaDiscoverers().discoverers(MediaDiscovererCategory.LOCAL_DIRS); if (discoverers.isEmpty()) { return; } // 过滤非音频目录发现器 discoverers.removeIf(d -> d.name().equals("picture_dir") || d.name().equals("video_dir")); for (MediaDiscovererDescription description : discoverers) { MediaDiscoverer discoverer = factory.mediaDiscoverers().discoverer(description.name()); MediaList list = discoverer.newMediaList(); MediaListEventAdapter eventAdapter = new MediaListEventAdapter() { @Override public void mediaListItemAdded(MediaList mediaList, MediaRef item, int index) { try (Media media = item.newMedia()) { String dirPath = media.info().mrl(); System.out.println(dirPath); musicDirectories.add(dirPath); lastItemAddedTimestamp = System.currentTimeMillis(); } } }; list.events().addMediaListEventListener(eventAdapter); discoverer.start(); } // 启动扫描完成监控线程 new Thread(() -> { while (true) { long currentTime = System.currentTimeMillis(); // 2秒无新条目则判定扫描完成 if (currentTime - lastItemAddedTimestamp > 2000) { scanLatch.countDown(); break; } try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } }).start(); // 等待扫描完成 scanLatch.await(); System.out.println("扫描完成,共找到" + musicDirectories.size() + "个音乐目录"); // 释放资源 factory.release(); } }
方法2:轮询列表稳定性(简单场景适用)
通过轮询音乐目录列表的长度,当连续多次检查长度不变时,判定扫描完成:
// 在discoverer.start()之后添加轮询逻辑 for (MediaDiscovererDescription description : discoverers) { // ... 初始化发现器和事件监听逻辑 ... discoverer.start(); } // 轮询等待扫描稳定 int previousSize = -1; int stableCheckCount = 0; while (stableCheckCount < 3) { // 连续3次长度不变则停止 Thread.sleep(500); int currentSize = musicDirectories.size(); if (currentSize == previousSize) { stableCheckCount++; } else { previousSize = currentSize; stableCheckCount = 0; } } System.out.println("扫描完成,共找到" + musicDirectories.size() + "个音乐目录");
注意事项
- 必须使用同步集合(如
Collections.synchronizedList),因为mediaListItemAdded回调在异步线程中执行,避免并发修改异常。 - 不同平台的目录发现器行为有差异,超时时间可根据实际场景调整。
- 扫描完成后务必释放
MediaDiscoverer、MediaList和MediaPlayerFactory资源,防止内存泄漏。
内容的提问来源于stack exchange,提问作者GreatTusk
相关产品推荐
相关产品推荐

