stone2083

          java mp3播放器

          最近沒有系統(tǒng)學(xué)習(xí)的計劃,看了開源的YOYOPlayer(一個相當(dāng)強(qiáng)大的播放器軟件,基于java編寫),心里癢癢,比較膚淺的學(xué)習(xí)下javasound。
          javasound是比較小巧的底層api,引用網(wǎng)上的一幅 javasound體系結(jié)構(gòu)圖:


          javasound實(shí)現(xiàn): 目前使用最多的是 jdk中javax.sound組件 (包括javax.sound.sampled 和 javax.sound.midi包) 和 開源的 Tritonus(http://www.tritonus.org/)組件
          SPI:是Service Provider Interface(服務(wù)提供接口),它的作用是以插件的形式提供音頻擴(kuò)展模塊。比如,javax.sound組件中,只支持au,mid,wav等少許音頻格式,其中不包括mp3。要想支持mp3格式,那么就需要相應(yīng)的解碼器和SPI。所幸的是,已經(jīng)有相應(yīng)的開源包。
          javazoom(http://www.javazoom.net)下的jlayer,是mp3格式的解碼包。
          javazoom下的mp3spi就是spi。
          只要添加了相應(yīng)的開源組建包,可以在不修改任何一行代碼的情況下,支持其他音頻格式。這就是spi的魅力。

          簡單介紹了javasound的體系結(jié)構(gòu),下面就介紹一個簡易的mp3播放器的實(shí)現(xiàn)(所謂簡易,就是沒有界面,除了能播放mp3等文件外,就啥都不能干了 :) )

          幾個步驟:
          1)得到音頻流:
          AudioSystem.getAudioInputStream(input)
          2)得到音頻格式:
          audioInputStream.getFormat()
          3)初始化數(shù)據(jù)行信息
          數(shù)據(jù)行信息包括(受數(shù)據(jù)行支持的音頻格式;其內(nèi)部緩沖區(qū)的最小和最大大小 )
          DataLine.Info info = new DataLine.Info(SourceDataLine.class, decodedFormat);
          4)從混頻器獲得源數(shù)據(jù)行
          SourceDataLine 接口提供將音頻數(shù)據(jù)寫入數(shù)據(jù)行的緩沖區(qū)中的方法。播放或混合音頻的應(yīng)用程序應(yīng)該以足夠快的速度將數(shù)據(jù)寫入源數(shù)據(jù)行,以防緩沖區(qū)下溢(排空),下溢可能導(dǎo)致單擊時音頻數(shù)據(jù)中出現(xiàn)可感知的間斷
          SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info);
          5)將音頻數(shù)據(jù)寫入源數(shù)據(jù)行中
          line.start();
          int readLenth = 0;
          while (readLenth != -1) {
              readLenth 
          = decodedAudioStream.read(AUDIO_BUFER, 0, AUDIO_BUFER.length);
             
          if (readLenth != -1) {
                  line.write(AUDIO_BUFER, 
          0, readLenth);
              }
          }
          line.drain();
          line.stop();
          line.close();


          下面提供完整的簡易mp3播放器代碼:
          其中AudioPlayer僅僅是一個接口。
          /**
           * <pre>
           * MP3播放器實(shí)現(xiàn)
           * 線程不安全,沒有必要多個線程去啟動播放器
           * </pre>
           * 
           * 
          @author Lee Jones
           
          */
          public class Mp3Player implements AudioPlayer {

              
          private static final Log    log         = LogFactory.getLog(Mp3Player.class);

              
          private static final byte[] AUDIO_BUFER = new byte[4096];

              
          private AudioInputStream    audioStream;

              
          private AudioFormat         decodedFormat;
              
          private AudioInputStream    decodedAudioStream;

              @Override
              
          public void play(InputStream input) {
                  
          if (input == null) {
                      log.warn(
          "input stream is null");
                      
          return;
                  }
                  
          try {
                      init(input);
                      play();
                  } 
          catch (Exception e) {
                      log.error(
          "play error:", e);
                  }
              }

              @Override
              
          public void play(File file) {
                  
          if (file == null) {
                      log.warn(
          "audio file is null");
                      
          return;
                  }
                  
          try {
                      play(
          new FileInputStream(file));
                  } 
          catch (FileNotFoundException e) {
                      log.error(
          "file to inputStream error:", e);
                  }
              }

              @Override
              
          public void play(URL url) {
                  
          if (url == null) {
                      log.warn(
          "url is null");
                      
          return;
                  }
                  
          try {
                      play(url.openStream());
                  } 
          catch (IOException e) {
                      log.error(
          "url open inputStream error:", e);
                  }
              }

              
          /**
               * init
               * 
               * 
          @param input
               * 
          @throws UnsupportedAudioFileException
               * 
          @throws IOException
               
          */
              
          protected void init(InputStream input) throws UnsupportedAudioFileException, IOException {
                  initAudioStream(input);
                  initDecodedFormat();
                  initDecodedAudioStream();
              }

              
          /**
               * init audio input stream
               * 
               * 
          @param input:audio input stream
               * 
          @throws IOException
               * 
          @throws UnsupportedAudioFileException
               
          */
              
          protected void initAudioStream(InputStream input) throws UnsupportedAudioFileException, IOException {
                  audioStream 
          = AudioSystem.getAudioInputStream(input);
              }

              
          /**
               * init decoded format
               * 
               * 
          @throws UnsupportedAudioFileException
               * 
          @throws IOException
               
          */
              
          protected void initDecodedFormat() throws UnsupportedAudioFileException, IOException {
                  AudioFormat baseFormat 
          = audioStream.getFormat();
                  decodedFormat 
          = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, baseFormat.getSampleRate(), 16,
                                                  baseFormat.getChannels(), baseFormat.getChannels() 
          * 2,
                                                  baseFormat.getSampleRate(), 
          false);
              }

              
          /**
               * init decoded audio stream
               
          */
              
          protected void initDecodedAudioStream() {
                  decodedAudioStream 
          = AudioSystem.getAudioInputStream(decodedFormat, audioStream);
              }

              
          /**
               * get source data line
               * 
               * 
          @param input audio input stream
               * 
          @return
               * 
          @throws UnsupportedAudioFileException
               * 
          @throws IOException
               * 
          @throws LineUnavailableException
               
          */
              
          protected SourceDataLine getSourceDataLine() throws UnsupportedAudioFileException, IOException,
                                                          LineUnavailableException {
                  DataLine.Info info 
          = new DataLine.Info(SourceDataLine.class, decodedFormat);
                  SourceDataLine line 
          = (SourceDataLine) AudioSystem.getLine(info);
                  line.open(decodedFormat);
                  
          return line;
              }

              
          /**
               * play audio
               * 
               * 
          @throws UnsupportedAudioFileException
               * 
          @throws IOException
               * 
          @throws LineUnavailableException
               
          */
              
          protected void play() throws UnsupportedAudioFileException, IOException, LineUnavailableException {
                  SourceDataLine line 
          = getSourceDataLine();
                  line.start();
                  
          int readLenth = 0;
                  
          while (readLenth != -1) {
                      readLenth 
          = decodedAudioStream.read(AUDIO_BUFER, 0, AUDIO_BUFER.length);
                      
          if (readLenth != -1) {
                          line.write(AUDIO_BUFER, 
          0, readLenth);
                      }
                  }
                  line.drain();
                  line.stop();
                  line.close();
                  decodedAudioStream.close();
                  audioStream.close();
              }
          }


          最后附上簡易播放器:
          easy mp3 player

          啟動方式:linux用戶使用./mp3player.sh,windows用戶使用mp3player.bat啟動(需要說明的是,必須設(shè)置好JAVA_HOME和PATH,并且使用jdk5以上版本。因?yàn)閱幽_本中的指定classpath的方法需要jdk5版本以上才支持。如果是jdk1.4下的用戶,請修改啟動腳本)
          lib目錄:是簡易播放器的lib包支持
          log目錄:記錄log,如果有錯誤等情況,可查看log。
          conf目錄:因?yàn)闆]有圖形界面,所以需要把播放的mp3文件路徑手工寫入。支持兩種形式,一個是本地mp3文件,另一個是網(wǎng)絡(luò)mp3資源,分別寫入到local.txt和net.txt文件中。
          比如
          local.txt
          /home/jones/data/music/misc/xin_nian_hao.mp3
          /home/jones/data/music/misc/guo_ge.mp3
          net.txt
          http://lubai.com.cn/CGI-BIN/shuanxing.mp3
          http://lubai.com.cn/CGI-BIN/shuanxing.mp3

          因多媒體方向非自己的工作方向,所以了解的相當(dāng)膚淺。有興趣的朋友請多多指教。

          posted on 2008-02-17 21:19 stone2083 閱讀(5859) 評論(6)  編輯  收藏 所屬分類: java

          Feedback

          # re: java mp3播放器 2009-04-28 17:32 wscool

          謝謝啊,雖然簡單但對初學(xué)者是非常有幫助的……  回復(fù)  更多評論   

          # re: java mp3播放器 2011-05-15 20:45 zechou

          必須加支持MP3的SPI?  回復(fù)  更多評論   

          # re: java mp3播放器 2011-05-16 12:55 stone2083

          @zechou
          是的。需要第三方服務(wù)提供。  回復(fù)  更多評論   

          # re: java mp3播放器 2011-11-12 21:49 fangtest

          你的這個給力 謝謝樓主  回復(fù)  更多評論   

          # re: java mp3播放器 2014-12-15 19:08 lousongtao

          樓主能不能研究下, 如何調(diào)整播放MP3的速度, 我搞了一天也沒搞懂  回復(fù)  更多評論   

          # re: java mp3播放器 2014-12-16 13:17 stone2083

          @lousongtao
          音頻文件是將模擬信號采樣轉(zhuǎn)成的數(shù)字信號. 把每一秒鐘所采樣的數(shù)目稱為采樣頻率或采率. 也就是說, 聲音的速度是一定的,取決于模擬信號.
          比特率 = 每秒采樣數(shù)量 (hz) × 位深(bit) × 聲道數(shù)量
          位速是指在一個數(shù)據(jù)流中每秒鐘能通過的信息量

          從理論上說, 增加位速, 就可以實(shí)現(xiàn)快速播放的效果.
          至于api上怎么使用, 我也不知道, 你可以順著這個思路,再看看.
            回復(fù)  更多評論   

          主站蜘蛛池模板: 余干县| 拜泉县| 海南省| 东乡族自治县| 准格尔旗| 雷州市| 谷城县| 临潭县| 连江县| 汕尾市| 临漳县| 五莲县| 霸州市| 保定市| 鱼台县| 莎车县| 桦甸市| 当涂县| 佛冈县| 德阳市| 宣威市| 万载县| 昭通市| 宁明县| 衡南县| 吉安市| 萍乡市| 永吉县| 紫阳县| 吉首市| 海城市| 肃南| 普兰县| 安福县| 岑巩县| 安平县| 云浮市| 呼和浩特市| 贵定县| 玛多县| 乐平市|