2013-01-12 2 views
5

그래서 저는 1 주일 동안 이것을 찾고 있었고 모든 문제는 비슷하게 보였지만 아무도 똑같은 문제를 정확하게 묻지는 않았습니다. 성공하지 원하는 듣는 사람없이 javafx 미디어 메타 데이터를 얻는 방법

는 원시인 스타일을 설명했다.. 나는 메타 데이터를 사용하여 목록을 만들려고 해요

  1. 을 내가 다 대화로 열고 내가에 파일을 넣어 하나 이상의 MP3
  2. 을 선택 ArrayList<File>
  3. I lo 연산 루프 추출물 메타 데이터에 대한 향상된이 ("아티스트"와 같은) 메타 데이터에 대한 미디어 변수를
  4. 에서 정보를 사용하여 파일 내가 문제가

예를 들어 ArrayList에에 저장할 것입니다하지만

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

: 리스너는 ArrayList<String> 그것에 아무것도 하나 개의 객체를 가진 결과 향상된 루프가 완료되면 방법을 작동 여기

은 샘플입니다 청취자를 추가하여 미디어 소스 메타 데이터를 읽는 다른 방법은 해당 정보를 mediaplayer .setOnReady(); 여기

공용 클래스 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); 
       }
미디어 플레이어 .setOnReady()가 새 스레드를 만들고 루프가 주요 응용 프로그램 스레드, 루프가 다른 스레드가 만들어지기 전에 잠시 기다려야하고 메타 데이터를 추출 할 수 있으며 .setOnReady()에는
 synchronized(obj){ 
        obj.notify; 
       }
이 있으므로 주 스레드를 깨우므로 루프 다음 항목으로 이동할 수 있습니다

나는 이것이 최선의 해결책은 아니라고 인정하지만 파일 목록에서 JavaFx 미디어 메타 데이터를 읽는 방법에 대해 더 나은 방법을 가지고있는 사람이면 누구나 환영합니다. 전체 Netbeans 프로젝트는 여기에서 찾을 수 있습니다 https://docs.google.com/file/d/0BxDEmOcXqnCLSTFHbTVFcGIzT1E/edit?usp=sharing

더하기 메타 데이터 사용을 제거하는 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(); 
      } 
     } 
    } 
} 

그러나,하는 자바 FX 스레드에서 initializeMetaData를 호출하지 않는 다른 스레드가 교착 상태로 실행됩니다.

추신 : 정말 그와 같은 해결 방법을 만들어야한다는 것은 정말 우스 꽝입니다. 앞으로 Media가이 작업을 수행하는 initialize() 메소드를 제공하기를 바랍니다.

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를을 만들어보다 훨씬 청소기입니다 : 그 문제에

0

내 솔루션이 있었다.

사용 예제 :

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