如何在播放时获取音频元数据?

时间:2015-02-06 15:54:29

标签: java concurrency javafx

我正在创建一个简单的音频播放器。除了MapChangeListener之外,侦听器事件很好。运行App时,MapChangeListener(元数据)的侦听器将同时触发并获取最后一个元数据轨道。

例如:

  • 该曲目列表有11首曲目。
  • 运行我的应用
  • 为所有曲目触发了MapChangeListener。
  • 我的应用程序中显示的元数据是最后一首曲目。

我想这样做:

  • 运行应用
  • 应仅针对当前曲目触发MapChangeListener。
  • 下一首曲目 - > MapChangeListener吧。

我已经读过媒体的getMetadata()方法在App的同一个线程中执行,因此我无法将监听器添加到 setOnPlaying(Runnable())中的元数据方法。

还在Play事件中使用 Platform.runLater()进行了尝试,但是简单无效。

我感谢任何帮助。感谢。

我的听众

final public class MetadataListener implements MapChangeListener<String, Object> {

    private PlayerControl gui;
    private static int count;

    public MetadataListener(PlayerControl gui) {
        this.gui = gui;
    }
    @Override
    public void onChanged(Change<? extends String, ? extends Object> change) {
        count++;
        if(change.wasAdded()) {
            handleMetadata(change.getKey().toString(), change.getValueAdded());
        }
    }



    private void handleMetadata(String key, Object value) {
            if(key.equals("title"))
                gui.getLblTitle().setText(value.toString());
            if(key.equals("artist"))
                gui.getLblArtist().setText(value.toString());
            if(key.equals("album"))
                gui.getLblAlbum().setText(value.toString());
            if(key.equals("year"))
                gui.getLblYear().setText(value.toString());
            if(key.equals("image"))
                gui.getImgViewAlbum().setImage((Image) value);
        }

    }

我的播放器

public void createMediaList() {
        for(String file : filterFiles()) {
            playList.add(createPlayer(file));
        }
        if(playList.isEmpty()) {
            System.out.println("No se han encontrado archivos multimedia");
            Platform.exit();
            return;
        }
    }

private MediaPlayer createPlayer(String filePath) {
        Media media = new Media(new File(dir.toString()+"/"+filePath).toURI().toString());
        MediaPlayer player = new MediaPlayer(media);
        this.attachListeners(player);
        return player;
    }



private void attachListeners(MediaPlayer player) {
        player.setOnPlaying(() -> {
            duration = player.getMedia().getDuration();
            gui.getLblTotalDuration().setText(formatCurrentDuration(duration));
            gui.getBtnPlayPause().setText(" | | ");
            updateValues();
        });
        player.currentTimeProperty().addListener((observable, oldValue, newValue) -> {
            updateValues();
        });
        player.getMedia().getMetadata().addListener(metadataListener);
        player.setOnEndOfMedia(() -> {
            player.stop();
            this.nextMedia();
        });
        //player.setOnStopped( () -> player.getMedia().getMetadata().removeListener(metadataListener));
        player.setOnPaused( () -> gui.getBtnPlayPause().setText("►"));
        player.setOnError(() -> System.out.println("Ha ocurrido un error"));
    }

protected void updateValues() {
        Label lblCurrentTime = gui.getLblCurrentTime();
        Label lblTotalDuration = gui.getLblTotalDuration();
        Slider sldPlayer = gui.getSldPlayer();
        //Slider sldVolume = gui.getSldVolume();

        if(lblCurrentTime != null && lblTotalDuration != null && sldPlayer != null && /*sldVolume != null &&*/ duration != null) {
            Platform.runLater(() -> {
                Duration currentTime = this.playList.get(currentMediaIndex).getCurrentTime();
                lblCurrentTime.setText(formatCurrentDuration(currentTime));
                sldPlayer.setDisable(duration.isUnknown());
                if(!sldPlayer.isDisabled() && duration.greaterThan(Duration.ZERO) && !sldPlayer.isValueChanging()) {
                    sldPlayer.setValue(currentTime.divide(duration).toMillis() * 100.0);
                }

            });
        }
    }

1 个答案:

答案 0 :(得分:1)

原因

  

为所有曲目

触发MapChangeListener      

我的应用程序中显示的元数据是最后一首曲目。

在您的代码中:

for(String file : filterFiles()) {
    playList.add(createPlayer(file));
}

private MediaPlayer createPlayer(String filePath) {
    Media media = new Media(new File(dir.toString()+"/"+filePath).toURI().toString());
    MediaPlayer player = new MediaPlayer(media);
    this.attachListeners(player);
    return player;
}

启动应用程序时,您将为播放列表中的所有曲目创建媒体播放器并为其添加侦听器。一旦为每个轨道重新获取元数据,所有标签都会被更新,并且这就是您只能看到最后一个轨道元数据的原因。

首先,检索有效媒体播放器列表,并调用第一首曲目:

private final List<MediaPlayer> playList = new ArrayList<>();

public void createMediaList() {
    for(String file : filterFiles()) {
        MediaPlayer player=createPlayer(file);
        if(player!=null){
            playList.add(player);
        }
    }
    if(playList.isEmpty()) {
        System.out.println("No se han encontrado archivos multimedia");
        Platform.exit();
        return;
    }
    // start first track
    nextMedia();
}

,其中

private MediaPlayer createPlayer(String filePath) {
    try{
        Media media = new Media(new File(dir+"/"+filePath).toURI().toString());
        MediaPlayer player=new MediaPlayer(media);
        return player;
    } catch(MediaException me){
        System.out.println("MediaException "+me);
    }
    return null;
}

由于并非每个文件都有效,因此在try catch中围绕媒体播放器创建很方便。

现在,nextMedia()只检索单个轨道的媒体播放器,并附加监听器。

编辑:通常,在创建媒体播放器时,使用setOnReady()开始播放很方便,但在这种情况下,所有曲目的媒体播放器都是在开始时,球员们已准备好了。

private void nextMedia(){
    MediaPlayer player=playList.get(currentMediaIndex++);
    attachListeners(player);
    if(player!=null){
        player.play();
    } else {
        nextMedia();
    }
}

当曲目准备就绪时,将检索所有元数据并更新标签:

private void attachListeners(MediaPlayer player) {
    ...
    player.getMedia().getMetadata().addListener(metadataListener);
    ...
    player.setOnEndOfMedia(() -> {
        player.getMedia().getMetadata().removeListener(metadataListener);
        player.stop();
        nextMedia();
    });
}

当曲目结束时,您的听众将再次拨打nextMedia()