2011-11-29 2 views
3

그래서 실행 가능한 jar로 바꾸고 싶은 Java 응용 프로그램이 있습니다. JMF의 클래스 경로에서 미디어 리소스를로드하는 방법

나는

jar cvfm jarname.jar manifest.txt *.class *.gif *.wav 

그래서 사용하여 항아리를 만들 ...이 응용 프로그램에서 JMF를 사용하고, 나는 사운드 파일이 제대로 작동 얻을 수없는 것, 모든 사운드 파일은 내부에 넣어 얻을 항아리, 및 코드에서, 나는

Player player = Manager.createPlayer(ClassName.class.getResource("song1.wav")); 

항아리 내 바탕 화면에, 나는 그것을 실행하려고 할 때,이 예외가 발생하여 플레이어를 만드는 오전 :

javax.media.NoPlayerException: Cannot find a Player for :jar:file:/C:/Users/Pojo/ 
Desktop/jarname.jar!/song1.wav 

... IOException이 발생하지 않으므로 적어도 파일 자체를 찾는 것으로 보입니다. 나는의 getResource을 사용하기 전에

또한,이 같은 그것을 가지고하는 데 사용 :

Player player = Manager.createPlayer(new File("song1.wav").toURL()); 

하고 그것을 잘 놀고 있었다, 그래서 나는 아무것도 사운드 파일 자체에 이상이없는 것을 알고있다.

File 메서드 대신이 메서드로 전환하려고하는 이유는 사운드 파일을 jar 파일 자체에 패키지화하고 해당 형제가 될 필요가 없기 때문입니다. song1.wav 응용 프로그램의 런타임 클래스 경로에있는 항아리의 루트에있는 경우 작동

+0

소리에 JMF를 사용하는 이유는 무엇입니까? javax.sound.샘플링 된 'API는 1.3 이후 J2SE의 일부였습니다. –

+0

@Andrew Thompson Clip 외에 javax.sound.sampled에 다른 것이 있습니까? 왜냐하면 나는 Clip을 사용하려고 시도했기 때문에 너무 크고 Clip이 약 1MB보다 큰 것을 거절하기 때문에이 파일들에 대해 작동하지 않을 것입니다. – Pojo

+0

* "Clip은 약 1MB보다 큰 어떤 것도 재생하지 않습니다."* A) You 아마 MP3 형식으로 변환해야 할 것입니다, 그래서 그들은 (일반적으로) WAV보다 작을 것입니다. B) 그렇게하면 JMF의'mp3plugin.jar'가 MP3를 디코딩하는 데 필요하지만 전체 JMF는 디코딩하지 않아도됩니다. C) 오라클의 'Clip'구현은 44.1 KHz 16 비트 스테레오의 최대 1 초를 처리 할 수 ​​있지만 큰 오디오를 처리하는 두 가지 다른 방법이 있습니다. 1) [BigClip] (http://stackoverflow.com/questions/5667454/playing-audio-file-in-java-application/5668510#5668510) 2) 스트림을로드하고 청크로 청크를 재생합니다. –

답변

2

새로운 솔루션 :

첫째, Seekable를 구현하는 SourceStream가 필요 반환 사용자 정의 DataSource 클래스 : 다음

package com.ziesemer.test; 

import java.io.Closeable; 
import java.io.IOException; 
import java.io.InputStream; 
import java.net.JarURLConnection; 
import java.net.URL; 
import java.util.jar.JarEntry; 
import java.util.jar.JarFile; 

import javax.media.Duration; 
import javax.media.MediaLocator; 
import javax.media.Time; 
import javax.media.protocol.ContentDescriptor; 
import javax.media.protocol.PullDataSource; 
import javax.media.protocol.PullSourceStream; 
import javax.media.protocol.Seekable; 

/** 
* @author Mark A. Ziesemer 
* <a href="http://www.ziesemer.com.">&lt;www.ziesemer.com&gt;</a> 
*/ 
public class JarDataSource extends PullDataSource{ 

    protected JarURLConnection conn; 
    protected ContentDescriptor contentType; 
    protected JarPullSourceStream[] sources; 
    protected boolean connected; 

    public JarDataSource(URL url) throws IOException{ 
     setLocator(new MediaLocator(url)); 
     connected = false; 
    } 

    @Override 
    public PullSourceStream[] getStreams(){ 
     return sources; 
    } 

    @Override 
    public void connect() throws IOException{ 
     conn = (JarURLConnection)getLocator().getURL().openConnection(); 
     conn.connect(); 
     connected = true; 

     JarFile jf = conn.getJarFile(); 
     JarEntry je = jf.getJarEntry(conn.getEntryName()); 

     String mimeType = conn.getContentType(); 
     if(mimeType == null){ 
      mimeType = ContentDescriptor.CONTENT_UNKNOWN; 
     } 
     contentType = new ContentDescriptor(ContentDescriptor.mimeTypeToPackageName(mimeType)); 

     sources = new JarPullSourceStream[1]; 
     sources[0] = new JarPullSourceStream(jf, je, contentType); 
    } 

    @Override 
    public String getContentType(){ 
     return contentType.getContentType(); 
    } 

    @Override 
    public void disconnect(){ 
     if(connected){ 
      try{ 
       sources[0].close(); 
      }catch(IOException e){ 
       e.printStackTrace(); 
      } 
      connected = false; 
     } 
    } 

    @Override 
    public void start() throws IOException{ 
     // Nothing to do. 
    } 

    @Override 
    public void stop() throws IOException{ 
     // Nothing to do. 
    } 

    @Override 
    public Time getDuration(){ 
     return Duration.DURATION_UNKNOWN; 
    } 

    @Override 
    public Object[] getControls(){ 
     return new Object[0]; 
    } 

    @Override 
    public Object getControl(String controlName){ 
     return null; 
    } 

    protected class JarPullSourceStream implements PullSourceStream, Seekable, Closeable{ 

     protected final JarFile jarFile; 
     protected final JarEntry jarEntry; 
     protected final ContentDescriptor type; 

     protected InputStream stream; 
     protected long position; 

     public JarPullSourceStream(JarFile jarFile, JarEntry jarEntry, ContentDescriptor type) throws IOException{ 
      this.jarFile = jarFile; 
      this.jarEntry = jarEntry; 
      this.type = type; 
      this.stream = jarFile.getInputStream(jarEntry); 
     } 

     @Override 
     public ContentDescriptor getContentDescriptor(){ 
      return type; 
     } 

     @Override 
     public long getContentLength(){ 
      return jarEntry.getSize(); 
     } 

     @Override 
     public boolean endOfStream(){ 
      return position < getContentLength(); 
     } 

     @Override 
     public Object[] getControls(){ 
      return new Object[0]; 
     } 

     @Override 
     public Object getControl(String controlType){ 
      return null; 
     } 

     @Override 
     public boolean willReadBlock(){ 
      if(endOfStream()){ 
       return true; 
      } 
      try{ 
       return stream.available() == 0; 
      }catch(IOException e){ 
       return true; 
      } 
     } 

     @Override 
     public int read(byte[] buffer, int offset, int length) throws IOException{ 
      int read = stream.read(buffer, offset, length); 
      position += read; 
      return read; 
     } 

     @Override 
     public long seek(long where){ 
      try{ 
       if(where < position){ 
        stream.close(); 
        stream = jarFile.getInputStream(jarEntry); 
        position = 0; 
       } 
       long skip = where - position; 
       while(skip > 0){ 
        long skipped = stream.skip(skip); 
        skip -= skipped; 
        position += skipped; 
       } 
      }catch(IOException ioe){ 
       // Made a best effort. 
       ioe.printStackTrace(); 
      } 
      return position; 
     } 

     @Override 
     public long tell(){ 
      return position; 
     } 

     @Override 
     public boolean isRandomAccess(){ 
      return true; 
     } 

     @Override 
     public void close() throws IOException{ 
      try{ 
       stream.close(); 
      }finally{ 
       jarFile.close(); 
      } 
     } 

    } 

} 

, 위의 정의 다 타 소스는 플레이어를 만드는 데 사용되며, ControllerListener 루프에 플레이어의 원인에 추가됩니다 사용자 정의 데이터 소스없이, JMF 다시 처음으로 추구하는 반복적으로 시도하는

package com.ziesemer.test; 

import java.net.URL; 

import javax.media.ControllerEvent; 
import javax.media.ControllerListener; 
import javax.media.EndOfMediaEvent; 
import javax.media.Manager; 
import javax.media.Player; 
import javax.media.Time; 

/** 
* @author Mark A. Ziesemer 
* <a href="http://www.ziesemer.com.">&lt;www.ziesemer.com&gt;</a> 
*/ 
public class JmfTest{ 
    public static void main(String[] args) throws Exception{ 
     URL url = JmfTest.class.getResource("Test.wav"); 
     JarDataSource jds = new JarDataSource(url); 
     jds.connect(); 
     final Player player = Manager.createPlayer(jds); 

     player.addControllerListener(new ControllerListener(){ 
      @Override 
      public void controllerUpdate(ControllerEvent ce){ 
       if(ce instanceof EndOfMediaEvent){ 
        player.setMediaTime(new Time(0)); 
        player.start(); 
       } 
      } 
     }); 
     player.start(); 
    } 
} 

주 -하지만 실패하고 결국 포기한다. 이는 ControllerListener과 같은 디버깅에서 볼 수 있으며, 각 시도에 대해 여러 이벤트가 수신됩니다.

또는 (당신이 내 이전의 대답에 언급 한) 루프에 MediaPlayer 접근 방식 사용 : 다시

package com.ziesemer.test; 

import java.net.URL; 

import javax.media.Manager; 
import javax.media.Player; 
import javax.media.bean.playerbean.MediaPlayer; 

/** 
* @author Mark A. Ziesemer 
* <a href="http://www.ziesemer.com.">&lt;www.ziesemer.com&gt;</a> 
*/ 
public class JmfTest{ 
    public static void main(String[] args) throws Exception{ 
     URL url = JmfTest.class.getResource("Test.wav"); 
     JarDataSource jds = new JarDataSource(url); 
     jds.connect(); 
     final Player player = Manager.createPlayer(jds); 

     MediaPlayer mp = new MediaPlayer(); 
     mp.setPlayer(player); 
     mp.setPlaybackLoop(true); 
     mp.start(); 
    } 
} 

을 좀 더 Javadoc과 및 로깅을 사용할 수 있습니다 (이 생산 준비 코드를 고려하지 것 등 .)하지만 테스트되고 작동하며 (Java 1.6) 사용자의 요구를 잘 충족해야합니다.

즐거운 성탄절, 그리고 즐거운 성탄절!

+0

고맙습니다, Z 씨! 나 한테 다시 한번 왔어! (이번에는 진짜)^_^ – Pojo

+0

@ziesemer 스레드 "main"의 예외 java.lang.ClassCastException : sun.net.www.protocol.file.FileURLConnection을 java.net.JarURLConnection에 캐스팅 할 수 없음 \t com.JarDataSource.connect (JarDataSource.java:39) \t com.JmfTest.main (JmfTest.java:20) – Srivathsan

+0

@Srivathsan - 제공된 코드를 사용하고 있습니까? JDK 버전은 무엇입니까? – ziesemer

0
Manager.createPlayer(this.getClass().getResource("/song1.wav")); 

.

+0

'this.getClass()'여야합니까? 클래스 이름 .class를 사용할 수 없습니까? – Pojo

+1

코멘트를 추가하고 * "당신이 그것을 시도했을 때 어떤 일이 일어 났습니까?"라고 묻는 것을 기다리는 것보다 빨리 시도 할 수있었습니다 *. –

+0

Tsk. 요즘 바보 같은 똑똑한 사람들 ... 글쎄, 나는 둘 다 시도했다. 어느 쪽도 효과가 없었다. – Pojo

3

이 생산 코드는 거리가 멀다는하지만,이 (가 실제로 아직 아무것도 재생 최대 유선 아니에요하지만) 어떤 런타임 예외를 해결 보인다 :

import javax.media.Manager; 
import javax.media.Player; 
import javax.media.protocol.URLDataSource; 

// ... 

URL url = JmfTest.class.getResource("song1.wav"); 
System.out.println("url: " + url); 
URLDataSource uds = new URLDataSource(url); 
uds.connect(); 
Player player = Manager.createPlayer(uds); 
+0

아! Ziesemer 씨를 다시 한번 고맙습니다. 내 프로젝트를 저장했습니다. 내가 너에게 경의를 표한다. <3 – Pojo

+0

기다려, 기다려. MediaPlayer에서 setPlaybackLoop (true)을 명시 적으로 호출하여 사운드 파일이 더 이상 반복되지 않는 것으로 나타났습니다. 그들은 한 번 재생하고 다시들은 적이 없습니다. 그들은 무한 루프를 반복해야합니다 ... – Pojo

+0

실제 재생하고 소리를 반복하는 추가 코드를 포함시켜주십시오. – ziesemer

관련 문제