【问题标题】:javafx UNKNOWN duration on Media object媒体对象上的 javafx UNKNOWN 持续时间
【发布时间】:2014-11-29 23:14:51
【问题描述】:

我是 Java 和 JavaFX 的新手,过去几年我一直在使用 QT 在 Python 上进行开发,现在我正在使用 Java 和 JavaFX 进行开发。

我正在开发一个程序,可以在用户设定的时间播放音乐文件,然后停止。因此,我需要从媒体对象获取持续时间,以便告诉音频何时停止(基于用户时间输入),但是,媒体对象上的 getDuration() 方法总是返回 UNKNOWN。

我在 Windows 8.1 和 openSuSE 13.2(都有相同的问题)上使用 JDK8u25(最新的稳定版本):

File filestring = new File("my/file/dir/file.mp3")
Media file = new Media(filestring.toURI().toString());
file.getDuration(); // Returns UNKNOWN on both wav and mp3 files
file.getDuration().toMinutes()) // Also tested with toHours() toSeconds(), toMilli()...
// Above returns NaN because the file's duration is unknown

作为一个测试,我把我的整个 mp3 音乐收藏(1000 多首带有 CBR 和 VBR 的歌曲)并让 java 遍历每个文件,他们都说持续时间是未知的。我还尝试了来自多个不同来源的 wav 文件(只是为了确保它不是 mp3 格式),看看它是否改变了……什么都没有;持续时间只有 UNKNOWN。我还检查了标签是否到位,每个其他程序都表示这些文件的文件属性中的长度或持续时间是好的。

奇怪的是,当我将 Media 对象传递给 MediaPlayer 时,文件可以完美播放。虽然我可以使用外部库来获取长度,但是看到整个程序使用 java 和 javafx 库,这会更容易和更精简。

任何帮助将不胜感激。

【问题讨论】:

    标签: java audio javafx media


    【解决方案1】:

    如果您阅读 Media 类的 javadoc,它说您应该等待媒体播放器准备好:

    媒体信息是异步获取的,因此不一定在类实例化后立即可用。但是,如果实例已与 MediaPlayer 关联并且该播放器已转换为 Status.READY 状态,则所有信息都应该可用

    所以你只需要创建一个MediaPlayer 的实例并监听Status.READY

        File filestring = new File("my/file/dir/file.mp3");
        Media file = new Media(filestring.toURI().toString());  
    
        MediaPlayer mediaPlayer = new MediaPlayer(file);
    
        mediaPlayer.setOnReady(new Runnable() {
    
            @Override
            public void run() {
    
                System.out.println("Duration: "+file.getDuration().toSeconds());
    
                // display media's metadata
                for (Map.Entry<String, Object> entry : file.getMetadata().entrySet()){
                    System.out.println(entry.getKey() + ": " + entry.getValue());
                }
    
                // play if you want
                mediaPlayer.play();
            }
        });
    

    【讨论】:

    • 回答了我的问题。有用。谢谢!为了澄清,我在这里理解这一点......当媒体文件被传递到 MediaPlayer 时,它被声明为 Status.READY(以及能够获得的信息)?或者当它调用 setonReady 方法时?
    • 还有我可以调用的方法将该媒体文件设置为 status.READY 而无需等待 java 设置它?当我将语句放在 run() 方法覆盖(如上所述)中时,它可以工作(我得到持续时间和元数据),但是在它返回 UNKNOWN 之后甚至对持续时间进行调用
    • runnable 不会立即被调用。当媒体准备好时调用它。这可能需要几毫秒到几分钟。您需要等待媒体准备好获取信息!
    • 正如@Tobi 所说,您必须等待就绪状态。如果您有兴趣了解文件列表的持续时间,您可以执行一项任务来遍历所有文件。对于每个文件,它应该创建一个媒体播放器,等待就绪状态,然后获取持续时间并移动到下一个。
    • 一切都好。多谢你们。我试图在创建媒体对象后立即使用持续时间,所以我稍微重构了我的程序,让 java 有时间准备好媒体,我一切都很好
    【解决方案2】:

    媒体似乎需要一些时间才能完全初始化。在 getDuration 行之前添加一个线程睡眠,然后重试!

    【讨论】:

      【解决方案3】:

      提到和接受的答案是正确的,因此在mediaplayer 准备好之前您无法访问或获取总持续时间,您应该使用mediaPlayer.setOnReady()...

      但有时您需要以更快的方式了解 mp3 文件的总时长。在这种情况下,您可以使用像 Apache Tika 这样的第三方库。要使用它,您可以将以下依赖项导入您的 pom.xml 文件:

      <!-- Apache Tika: detects and extracts metadata and text from a variety of files -->
      <dependency>
          <groupId>org.apache.tika</groupId>
          <artifactId>tika-core</artifactId>
          <version>2.0.0</version>
      </dependency>
      
      
      <!--Apache Tika AudioVideo Parser Module-->
      <dependency>
          <groupId>org.apache.tika</groupId>
          <artifactId>tika-parser-audiovideo-module</artifactId>
          <version>2.0.0</version>
      </dependency>
      

      您可以找到媒体文件的持续时间如下:

      InputStream input = new FileInputStream(browsedFile.getFilePath());
      ContentHandler handler = new DefaultHandler();
      Metadata metadata = new Metadata();
      Parser parser = new Mp3Parser();
      ParseContext parseCtx = new ParseContext();
      parser.parse(input, handler, metadata, parseCtx);
      input.close();
      Long duration = Long.parseLong(metadata.get("xmpDM:duration").split("\\.")[0]);
      

      当然,您可以将其格式化为更易于阅读的格式:

      String formattedDuration = String.format("%02d:%02d:%02d", duration / 3600, (duration % 3600) / 60, (duration % 60));
      

      【讨论】:

        猜你喜欢
        • 2018-04-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多