2013-01-12 39 views
5

所以我一直在寻找这个一个星期的时间,然后阅读所有类似的问题,但都没有像我一样问完全相同的问题(尝试反向工程其他类似于我的解决方案希望没有成功如何在没有监听器的情况下获得javafx媒体元数据

解释穴居人的风格:。我试图使用元数据来创建列表

  1. 我有一个多对话框打开,并选择一个以上的MP3
  2. 我把文件中的一个ArrayList<File>
  3. I lo OP虽然增强的for循环和提取元数据使用媒体变量
  4. 的信息的元数据(如“艺术家”)的文件是什么,我想在一个ArrayList保存例如

问题听者只能方式增强循环结束后导致 ArrayList<String>具有什么也没有一个对象

这里是一个示例:

ArrayList<String> al; 
String path; 
public void open(){ 
    files=chooser.showOpenMultipleDialog(new Stage()); 
    for(File f:files){    
     path=f.getPath(); 
     Media media = new Media("file:/"+path.replace("\\", "/").replace(" ", "%20")); 
     al= new ArrayList<String>(); 
     media.getMetadata().addListener(new MapChangeListener<String, Object>() {     
      public void onChanged(Change<? extends String, ? extends Object> change) { 
       if (change.wasAdded()) { 
        if (change.getKey().equals("artist")) { 
         al.add((String) change.getValueAdded()); 
        } 
       } 
      } 
     }); 
    }//close for loop 
    //then i want to see the size of al like this 
    system.out.println(al.size()); 
    //then it returns 1 no matter how much file i selected 
    //when i system out "al" i get an empty string 

回答

3

的通过添加侦听器来读取媒体源元数据的其他方式是在mediaplayer .setOnReady()中提取该信息;这里是java控制器类

公共类uiController实现Initializable {

@FXML private Label label; 
@FXML private ListView<String> lv; 
@FXML private AnchorPane root; 
@FXML private Button button; 

private ObservableList<String> ol= FXCollections.observableArrayList(); 
private List<File> selectedFiles; 
private final Object obj= new Object(); 

@Override 
public void initialize(URL url, ResourceBundle rb) { 
    assert button != null : "fx:id=\"button\" was not injected: check your FXML file 'ui.fxml'."; 
    assert label != null : "fx:id=\"label\" was not injected: check your FXML file 'ui.fxml'."; 
    assert lv != null : "fx:id=\"lv\" was not injected: check your FXML file 'ui.fxml'."; 
    assert root != null : "fx:id=\"root\" was not injected: check your FXML file 'ui.fxml'."; 

    // initialize your logic here: all @FXML variables will have been injected 
    lv.setItems(ol); 
} 

@FXML private void open(ActionEvent event) { 
    FileChooser.ExtensionFilter extention= new FileChooser.ExtensionFilter("Music Files", "*.mp3","*.m4a","*.aif","*.wav","*.m3u","*.m3u8"); 
    FileChooser fc= new FileChooser(); 
    fc.setInitialDirectory(new File(System.getenv("userprofile"))); 
    fc.setTitle("Select File(s)"); 
    fc.getExtensionFilters().add(extention); 
    selectedFiles =fc.showOpenMultipleDialog(root.getScene().getWindow()); 
    if(selectedFiles != null &&!selectedFiles.isEmpty()){ 
     listFiles(); 
    } 
} 
/** 
* Convert each fie selected to its URI 
*/ 
private void listFiles(){ 
    try { 
     for (File file : selectedFiles) { 
      readMetaData(file.toURI().toString()); 
      synchronized(obj){ 
       obj.wait(100); 
      } 
     } 
    } catch (InterruptedException ex) { 
    } 
    System.gc(); 
} 
/** 
* Read a Media source metadata 
* Note: Sometimes the was unable to extract the metadata especially when 
* i have selected large number of files reasons i don't known why 
* @param mediaURI Media file URI 
*/ 
private void readMetaData(String mediaURI){ 
    final MediaPlayer mp= new MediaPlayer(new Media(mediaURI)); 
    mp.setOnReady(new Runnable() { 

     @Override 
     public void run() { 
      String artistName=(String) mp.getMedia().getMetadata().get("artist"); 
      ol.add(artistName); 
      synchronized(obj){//this is required since mp.setOnReady creates a new thread and our loopp in the main thread 
       obj.notify();// the loop has to wait unitl we are able to get the media metadata thats why use .wait() and .notify() to synce the two threads(main thread and MediaPlayer thread) 
      } 
     } 
    }); 
} 

}的例子部分

,都使得使用了ObservableList到艺术家的名字从元数据存储的一些变化

在代码中,你会发现这

 synchronized(obj){ 
        obj.wait(100); 
       }
我这样做是因为mediaplayer .setOnReady()创建一个新的线程和循环是在主应用程序线程,循环必须等待一段时间才能创建其他线程,并且我们能够提取元数据,并且在.setOnReady()中有一个唤醒主线程的循环,因此循环是能够移动到下一个项目

我承认这可能不是最好的解决方案,但欢迎任何谁有更好的方法如何从文件列表中读取JavaFx媒体元数据 完整Netbeans项目可以在这里找到https://docs.google.com/file/d/0BxDEmOcXqnCLSTFHbTVFcGIzT1E/edit?usp=sharing

plus已经创建了一个使用JavaFX的小型MediaPlayer应用程序,该应用程序展示了元数据的使用https://docs.google.com/file/d/0BxDEmOcXqnCLR1Z0VGN4ZlJkbUU/edit?usp=sharing

0

您可以使用下面的函数来检索的元数据对于一个给定的媒体对象:

public static void initializeMetaData(Media media) { 
    final Ref<Boolean> ready = new Ref<>(false); 

    MediaPlayer mediaPlayer = new MediaPlayer(media); 
    mediaPlayer.setOnReady(() -> { 
     synchronized (ready) { 
      ready.set(false); 
      ready.notify(); 
     } 
    }); 

    synchronized (ready) { 
     if (!ready.get()) { 
      try { 
       ready.wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

但是,不要从一个JavaFX线程中调用initializeMetaData,否则线程运行陷入僵持。

PS:真的很可笑,人们必须建立这样的解决方法。我希望将来Media将提供一个完成这项工作的initialize()方法。

0

我对这个问题的解决办法是这样的:

public class MediaListener implements MapChangeListener<String, Object> 
{ 
    public String title = null; 
    public String artist = null; 
    public String album = null; 

    private final Consumer<MediaListener> handler; 
    private boolean handled = false; 

    public MediaListener(Consumer<MediaListener> handler) 
    { 
     this.handler = handler; 
    } 

    @Override 
    public void onChanged(MapChangeListener.Change<? extends String, ?> ch) 
    { 
     if (ch.wasAdded()) 
     { 
      String key = ch.getKey(); 
      switch (key) 
      { 
       case "title": 
        title = (String) ch.getValueAdded(); 
        break; 
       case "artist": 
        artist = (String) ch.getValueAdded(); 
        break; 
       case "album": 
        album = (String) ch.getValueAdded(); 
        break; 
      } 

      if (!handled && title != null && artist != null && album != null) 
      { 
       handler.accept(this); 
       handled = true; 
      } 
     } 
    } 
} 

它可能不是最好的方式,但它比创建每个文件的一个新的MediaPlayer的方式清洁。

实例:

Media media = Util.createMedia(path); 
media.getMetadata().addListener(new MediaListener((data) -> 
{ 
    // Use the data object to access the media 
})); 
相关问题