2013-01-12 19 views
5

quindi ho cercato questo per una settimana e ho letto tutti i problemi simili, ma nessuno sembrava chiedere lo stesso problema del mio esattamente (prova il reverse engineering con un'altra soluzione simile a quella che ho vogliono senza successocome ottenere i metadati dei media javafx senza listener

spiegato stile cavernicolo:.. sto cercando di creare l'elenco utilizzando i metadati

  1. apro una finestra di dialogo a più e selezionare più di un mp3
  2. ho messo il file in un ArrayList<File>
  3. I lo op se i file con una maggiore ciclo for ed estratto di metadati utilizzando una variabile mezzi
  4. Le informazioni per i metadati (come "artista") è quello che voglio salvare in un ArrayList per esempio

il problema è che l'ascoltatore funziona solo modo dopo il ciclo maggiore è terminato con conseguente ArrayList<String> avente un oggetto con niente in esso

ecco un esempio:

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 

risposta

3

la l'altro modo per leggere i metadati di una fonte multimediale con l'aggiunta di un listener è estrarre le informazioni nel mediaplayer .setOnReady(); qui è una parte ad esempio della classe controller java

public class uiController implementa 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) 
      } 
     } 
    }); 
} 

}

le poche modifiche che hanno fatto viene utilizzato un ObservableList per memorizzare il nome dell'artista dai metadati

nel codice si trova questo

 synchronized(obj){ 
        obj.wait(100); 
       }
lo faccio perché il mediaplayer .setOnReady() crea un nuovo thread e il ciclo è in il thread dell'applicazione principale, Il ciclo deve attendere un po 'di tempo prima che venga creato l'altro thread e siamo in grado di estrarre i metadati, e nel .setOnReady() c'è un
 synchronized(obj){ 
        obj.notify; 
       }
per riattivare il thread principale e quindi il ciclo è in grado di passare alla voce successiva

Ammetto che questa potrebbe non essere la soluzione migliore per farlo, ma sono gradita a chiunque abbia un modo migliore di leggere i metadati dei media JavaFx da un elenco di file Il progetto Netbeans può essere trovato qui https://docs.google.com/file/d/0BxDEmOcXqnCLSTFHbTVFcGIzT1E/edit?usp=sharing

plus hanno creato una piccola applicazione MediaPlayer utilizzando JavaFX che espelle l'uso dei metadati https://docs.google.com/file/d/0BxDEmOcXqnCLR1Z0VGN4ZlJkbUU/edit?usp=sharing

0

È possibile utilizzare la seguente funzione per recuperare i metadati per un dato oggetto media:

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

Tuttavia, non chiamare initializeMetaData da un thread JavaFX, altrimenti il ​​filo si imbatte in una situazione di stallo.

PS: È davvero ridicolo che si debba costruire una simile soluzione alternativa. Spero che in futuro Media fornisca un metodo initialize() che fa questo lavoro.

0

La mia soluzione a questo problema è stato questo:

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

potrebbe non essere il modo migliore ma è modo più pulito rispetto alla creazione di un nuovo MediaPlayer per file.

Esempio di utilizzo:

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