简体   繁体   English

JavaFX MediaPlayer无法播放M4A文件

[英]JavaFX MediaPlayer not playing M4A files

Given the following code: 给出以下代码:

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);
    }
}

The audio file ( audio.ext ) is supposed to play when I click on the screen. 当我单击屏幕时,应该播放音频文件( audio.ext )。 I can get MP3 files and WAV files to play audio. 我可以获取MP3文件和WAV文件来播放音频。 However when I try the same code using an M4A file, the audio does not play. 但是,当我使用M4A文件尝试相同的代码时,音频无法播放。

I noticed some interesting cases when modifying the code slightly to fix the problem. 在稍微修改代码以解决问题时,我注意到一些有趣的情况。

Case 1: Making the MediaPlayer an instance variable instead of a local variable. 情况1:将MediaPlayer设置为实例变量而不是局部变量。

If I make the MediaPlayer object ( mp ) an instance variable and initialize it in the setOnMouseClicked block, the audio plays as it should and I have no issues. 如果我将MediaPlayer对象( mp )设置为实例变量并在setOnMouseClicked块中对其进行初始化,则音频setOnMouseClicked播放,并且没有问题。

Case 2: Adding the following code to the end of the setOnMouseClicked block: 情况2:将以下代码添加到setOnMouseClicked块的末尾:

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

If I do this, then the audio plays as it should, and the screen does not visually change (ie, adding the MediaView object to the StackPane does not visually alter it). 如果执行此操作,则音频将MediaView应有的方式播放,并且屏幕不会在视觉上发生变化(即,将MediaView对象添加到StackPane不会在视觉上对其进行更改)。


My question is: Why does this happen, and is there any way to get the audio to play without having to use these workarounds? 我的问题是:为什么会发生这种情况,并且有什么方法可以使音频播放而无需使用这些替代方法?

One suspicion I have is that an external reference to the object is necessary for the MediaPlayer to work. 我有一种怀疑是,要使MediaPlayer正常工作,必须对该对象进行外部引用。 In Case 1, the instance variable served as the external reference, and in Case 2, the StackPane held a reference to the MediaView which in turn had a reference to the MediaPlayer . 在案例1中,实例变量用作外部引用,在案例2中, StackPane持有对MediaView的引用,而该MediaView又具有对MediaPlayer的引用。 However, this does not explain why this only occurs with M4A files and not MP3 or WAV files. 但是,这不能解释为什么仅在M4A文件而不是MP3WAV文件中发生这种情况。 Perhaps MediaPlayer treats M4A files as video files instead of audio files for some reason. 出于某种原因,也许MediaPlayerM4A文件视为视频文件而不是音频文件。 However, this is all speculation and I do not know for sure why this is occurring. 但是,所有这些都是推测,我不确定为什么会这样。

When you don't store a reference to an object, the Java garbage collector can clean it up when the reference goes out of scope. 当您不存储对对象的引用时,当引用超出范围时,Java垃圾收集器可以清除该对象。

From How Garbage Collection Works : 垃圾收集的工作原理

垃圾收集器

When you add the code: 添加代码时:

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

A reference to the media player is retained in the MediaView and the StackPane, so the media player is not garbage collected. MediaView和StackPane中保留了对媒体播放器的引用,因此不会对垃圾回收媒体播放器。 However, when you don't have the code that retains the reference, then the MediaPlayer can be garbage collected at any time. 但是,如果您没有保留引用的代码,则可以随时垃圾回收MediaPlayer。

Also note the MediaPlayer javadoc : 另请注意MediaPlayer javadoc

The operation of a MediaPlayer is inherently asynchronous. MediaPlayer的操作本质上是异步的。 A player is not prepared to respond to commands quasi-immediately until its status has transitioned to MediaPlayer.Status.READY, which in effect generally occurs when media pre-roll completes. 在播放器的状态转换为MediaPlayer.Status.READY之前,播放器不准备准立即响应命令,通常在媒体预滚动完成时会发生这种情况。

Because the operation is asynchronous, if you don't store a reference to the MediaPlayer, then the code can be subject to a race condition , where the garbage collector cleans up the MediaPlayer before the MediaPlayer completes playing your media. 因为该操作是异步的,所以如果您不存储对MediaPlayer的引用,则代码可能会遇到争用情况 ,即垃圾收集器会在MediaPlayer完成播放媒体之前清理MediaPlayer。 By the nature of race conditions, the behavior of code that is subject to them is unpredictable, which is usually an undesirable feature. 根据竞争条件的性质,受其影响的代码的行为是不可预测的,这通常是不受欢迎的功能。

As to why MP3 and WAV files are playing without you retaining a reference to the MediaPlayer, that could be just luck. 至于为什么在没有保留对MediaPlayer的引用的情况下播放MP3和WAV文件的原因,这可能很幸运。 The garbage collection can occur at any time that you no longer have a reference to the MediaPlayer. 在您不再引用MediaPlayer的任何时候都可能发生垃圾回收。 So playing Media in a MediaPlayer that you don't retain a reference to isn't a behavior I would rely on. 因此,在MediaPlayer中播放您不保留引用的Media并不是我要依靠的行为。 Instead, it would be best to retain a reference to the MediaPlayer at least until it has completed playing its associated media. 相反,最好至少保留对MediaPlayer的引用,直到它完成播放其关联的媒体为止。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM