【问题标题】:JavaFX MediaPlayer not playing M4A filesJavaFX MediaPlayer 不播放 M4A 文件
【发布时间】:2016-12-20 07:53:19
【问题描述】:

给定以下代码:

import java.io.File;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        StackPane stackPane = new StackPane();
        stackPane.setOnMouseClicked((event) -> {
            String path = "audio.ext";
            Media media = new Media(new File(path).toURI().toString());
            MediaPlayer mp = new MediaPlayer(media);
            mp.setAutoPlay(true);
        });
        stage.setScene(new Scene(stackPane));
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

当我点击屏幕时,音频文件 (audio.ext) 应该会播放。我可以获得MP3 文件和WAV 文件来播放音频。但是,当我使用 M4A 文件尝试相同的代码时,音频无法播放。

在稍微修改代码以解决问题时,我注意到了一些有趣的案例。

案例 1:使 MediaPlayer 成为实例变量而不是局部变量。

如果我将 MediaPlayer 对象 (mp) 设为实例变量并在 setOnMouseClicked 块中对其进行初始化,音频会正常播放,我没有任何问题。

案例 2:在 setOnMouseClicked 块的末尾添加以下代码:

MediaView mv = new MediaView(mp);
stackPane.getChildren().add(mv);

如果我这样做,那么音频会按应有的方式播放,并且屏幕不会在视觉上发生变化(即,将 MediaView 对象添加到 StackPane 不会在视觉上改变它)。


我的问题是:为什么会发生这种情况,有什么方法可以在不使用这些解决方法的情况下播放音频?

我的一个怀疑是MediaPlayer 工作需要对该对象的外部引用。在案例 1 中,实例变量用作外部引用,在案例 2 中,StackPane 持有对 MediaView 的引用,而 MediaView 又引用了 MediaPlayer。但是,这并不能解释为什么这只发生在 M4A 文件而不是 MP3WAV 文件中。也许MediaPlayer 出于某种原因将M4A 文件视为视频文件而不是音频文件。但是,这都是猜测,我不确定为什么会发生这种情况。

【问题讨论】:

    标签: java audio javafx javasound


    【解决方案1】:

    当您不存储对对象的引用时,Java 垃圾收集器可以在引用超出范围时对其进行清理。

    来自How Garbage Collection Works

    添加代码时:

    MediaPlayer mp = new MediaPlayer(media);
    MediaView mv = new MediaView(mp);
    stackPane.getChildren().add(mv);
    

    MediaView 和 StackPane 中保留了对媒体播放器的引用,因此媒体播放器不会被垃圾回收。但是,当您没有保留引用的代码时,MediaPlayer 可以随时被垃圾回收。

    还要注意MediaPlayer javadoc

    MediaPlayer 的操作本质上是异步的。播放器在其状态转换为 MediaPlayer.Status.READY 之前不会准立即响应命令,这实际上通常发生在媒体预卷完成时。

    由于操作是异步的,如果您不存储对 MediaPlayer 的引用,那么代码可能会受到race condition 的约束,其中垃圾收集器会在 MediaPlayer 完成播放您的媒体之前清理 MediaPlayer。由于竞态条件的性质,受它们影响的代码行为是不可预测的,这通常是一个不受欢迎的特性。

    至于为什么 MP3 和 WAV 文件在您没有保留对 MediaPlayer 的引用的情况下播放,这可能只是运气。垃圾收集可以在您不再引用 MediaPlayer 的任何时候发生。因此,在您不保留引用的 MediaPlayer 中播放媒体不是我所依赖的行为。相反,最好至少保留对 MediaPlayer 的引用,直到它完成播放其关联媒体为止。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-25
      • 1970-01-01
      • 1970-01-01
      • 2012-05-09
      • 2013-12-03
      相关资源
      最近更新 更多