1. 程式人生 > >android 音訊裁剪(1)—MP3裁剪

android 音訊裁剪(1)—MP3裁剪

=====原創不易,請尊重每一位原創,讓我們更有分享的動力,轉載請註明=====

轉載連結

若有朋友需要WAV 音訊裁剪,可以參考我的另外一篇博文——wav 音訊裁剪http://blog.csdn.net/daltsoftware/article/details/71480664
在android開發中,一說到音視訊,程式設計師第一反應肯定是FFMpeg,但是FFMpeg這個庫,又複雜,又效能差,如果只想簡單的要個音訊裁剪的功能,就要去引入這麼大的庫,完全不值得。然而自從android api 16之後谷歌就開始在音視訊方面進行佈局,android 18之後繼續豐富音視訊編碼庫,讓很多android app在不依賴於繁瑣jni就能進行一些基礎的音視訊開發。下面將是基於android api16的對mp3檔案進行裁剪的程式碼例子。當前由於時間問題,先分享最主流的mp3格式的音訊裁剪,以後有時間會分享更多其他音訊方面的經驗。

  //適當的調整SAMPLE_SIZE可以更加精確的裁剪音樂
  private static final int SAMPLE_SIZE = 1024 * 200;

  @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
  public static boolean clip(String inputPath, String outputPath, int start, int end){
      MediaExtractor extractor = null;
      BufferedOutputStream outputStream = null
; try { extractor = new MediaExtractor(); extractor.setDataSource(inputPath); int track = getAudioTrack(extractor); if(track < 0){ return false; } //選擇音訊軌道 extractor.selectTrack(track); outputStream = new
BufferedOutputStream( new FileOutputStream(outputPath), SAMPLE_SIZE); start = start * 1000; end = end * 1000; //跳至開始裁剪位置 extractor.seekTo(start, MediaExtractor.SEEK_TO_PREVIOUS_SYNC); while (true){ ByteBuffer buffer = ByteBuffer.allocate(SAMPLE_SIZE); int sampleSize = extractor.readSampleData(buffer, 0); long timeStamp = extractor.getSampleTime(); // >= 1000000是要裁剪停止和指定的裁剪結尾不小於1秒,否則可能產生需要9秒音訊 //裁剪到只有8.6秒,大多數音樂播放器是向下取整,這樣對於播放器變成了8秒, // 所以要裁剪比9秒多一秒的邊界 if(timeStamp > end && timeStamp - end >= 1000000){ break; } if(sampleSize <= 0){ break; } byte[] buf = new byte[sampleSize]; buffer.get(buf, 0, sampleSize); //寫入檔案 outputStream.write(buf); //音軌資料往前讀 extractor.advance(); } } catch (IOException e) { e.printStackTrace(); }finally { if(extractor != null){ extractor.release(); } if(outputStream != null){ try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } return true; } /** * 獲取音訊資料軌道 * @param extractor * @return */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private static int getAudioTrack(MediaExtractor extractor) { for(int i = 0; i < extractor.getTrackCount(); i++){ MediaFormat format = extractor.getTrackFormat(i); String mime = format.getString(MediaFormat.KEY_MIME); if(mime.startsWith("audio")){ return i; } } return -1; }

裁剪音樂的步驟在註釋中已經寫得很明白了,其實用上面簡單的程式碼就能實現音訊裁剪了,而且裁剪的音訊經過多項硬指標測試是沒有問題的。但可能還是有人會懷疑用上述方法是否得到一個“真正”mp3檔案。絕大部分情況下,產品經理的需求都是希望裁剪後的音樂除了長度之外,其他的都和原始音訊一樣,以防不同的播放器由於編解碼庫的差異,導致播放失敗的情況。下面的程式碼是用來提取音訊的關鍵資料,來比較裁剪之後的音訊和原始音訊的關鍵資料是否一樣。

@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private static void printMusicFormat(String musicPath){
    try {
        MediaExtractor extractor = new MediaExtractor();
        extractor.setDataSource(musicPath);
        MediaFormat format = extractor.getTrackFormat(getAudioTrack(extractor));
        Log.i("music", "位元速率:" + format.getInteger(MediaFormat.KEY_BIT_RATE));
        Log.i("music", "軌道數:" + format.getInteger(MediaFormat.KEY_CHANNEL_COUNT));
        Log.i("music", "取樣率:" + format.getInteger(MediaFormat.KEY_SAMPLE_RATE));
    } catch (IOException e) {
        e.printStackTrace();
    }
}

通過反覆驗證,通過以上方法裁剪的音訊除了時間長度之外,其他格式資料都和原始音訊一樣,裁剪的音訊在各種平臺(android, IOS, windows,mac)都能正常的播放和使用。