1. 程式人生 > >使用AndroidTrack播放pcm音訊

使用AndroidTrack播放pcm音訊

package com.tlinux.mp3playeraudiotrack;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.util.Log;

/**
 * Created by tlinux on 18-8-11.
 */

public class SimpleAudioOutput {

    private static final String TAG = "AudioOutputTrack"
; public static final int SAMPLES_PER_FRAME = 2; public static final int BYTES_PER_SAMPLE = 4; public static final int BYTES_PRE_FRAME = SAMPLES_PER_FRAME * BYTES_PER_SAMPLE; private AudioTrack mAudioTrack; private int mFrameRate; private int minBufferSize; public SimpleAudioOutput
() { super(); } public void start(int frameRate) { stop(); mFrameRate = frameRate; mAudioTrack = createAudioTrack(frameRate); mAudioTrack.play(); } public AudioTrack createAudioTrack(int frameRate) { int minBufferSizeBytes = AudioTrack.getMinBufferSize(frameRate, AudioFormat.CHANNEL_OUT_STEREO,AudioFormat.ENCODING_PCM_16BIT); Log.i(TAG, "AudioTrack.minBufferSize = "
+ minBufferSizeBytes + " bytes = " + (minBufferSizeBytes / BYTES_PRE_FRAME) + " frames"); int bufferSize = 8*minBufferSizeBytes/8; minBufferSize = bufferSize; int outputBufferSizeFrames = bufferSize/BYTES_PRE_FRAME; Log.i(TAG, "actual bufferSize = " + bufferSize + " bytes = " + outputBufferSizeFrames + " frames"); AudioTrack player = new AudioTrack(AudioManager.STREAM_MUSIC,mFrameRate, AudioFormat.CHANNEL_OUT_STEREO,AudioFormat.ENCODING_PCM_16BIT, bufferSize,AudioTrack.MODE_STREAM); Log.i(TAG, "created AudioTrack"); return player; } public int write(byte[] buffer, int offset, int length) { return mAudioTrack.write(buffer,offset,length); } public void stop() { if (mAudioTrack != null) { mAudioTrack.stop(); } } public int getFrameRate() { return mFrameRate; } public AudioTrack getAudioTrack() { return mAudioTrack; } public int getMinBufferSize() { return minBufferSize; } }

主要介紹AudioTrack的使用方法

 AudioTrack player = new AudioTrack(AudioManager.STREAM_MUSIC,mFrameRate,
                 AudioFormat.CHANNEL_OUT_STEREO,AudioFormat.ENCODING_PCM_16BIT,
                 bufferSize,AudioTrack.MODE_STREAM);

構造方法需要傳遞上面的幾個引數

  • AudioManager.STREAM_MUSIC 音訊的STREAM_MUSIC,系統會對不同音訊型別進行優先順序管理,另外調節音量的時候也會根據不同的STREAM型別進行調節
  • AudioFormat.CHANNEL_OUT_STEREO 表示立體聲,支援左右聲道
  • AudioFormat.ENCODING_PCM_16BIT 編碼格式,ENCODING_PCM_16BIT代表錄製的時候每一個取樣資料用16bit(2位元組表示),編碼格式佔用的位元組越多,聲音越細膩
  • bufferSize:使用 AudioTrack的getMinBufferSize(frameRate,
    AudioFormat.CHANNEL_OUT_STEREO,AudioFormat.ENCODING_PCM_16BIT) 方法計算出來的,系統會根據要設定的幀率,通道數和編碼格式計算出來一個最小支援的緩衝區大小(和系統先機制有關,後面文章會進行分析),建立AudioTrac時候,會根據傳遞的bufferSize建立緩衝區,注意如果傳遞的bufferSize小於getMinBufferSize計算出來的值,會建立不成功
  • AudioTrack.MODE_STREAM 表示以流的方式操作AudioTrak,以流的方式要使用mAudioTrack.write(buffer,offset,length) 不斷將資料寫入.另外一種模式是MODE_STATIC,這種模式是直接將資料載入進記憶體,傳遞給AudioTrack處理,由於pcm資料佔用記憶體比較大,這種模式只適合提示音等短音訊
mAudioTrack.write(buffer,offset,length)

這就是流模式寫入資料的方法,注意當底層提供的緩衝區寫滿後該方法會阻塞住(底層採用生產者消費者模型,當消費者進行一些消費後,buffer能夠完全寫入後返回)

AudioTrack就是這麼簡單生產消費者模型等操作都在底層完成,使用者不需要考慮.

下面介紹一下如何使用ffmpeg獲取pcm裸音訊資料

ffmpeg -i jiangzhende.mp3 -f s16le  -ar 44100 -ac 2 -acodec pcm_s16le xxx.pcm 
  • -i 制定輸入檔案
  • -f 指定輸出編碼格式為16byte小端格式
  • -ar指定輸出取樣率
  • -ac 指定輸出通道數
  • acodec 指定解碼格式
  • xxx.pcm 為輸出檔案
[email protected]:~/media$ ffmpeg -i jiangzhende.mp3 -f s16le  -ar 44100 -ac 2 -acodec pcm_s16le xxx.pcm 
ffmpeg version 3.0.7-0ubuntu0.16.10.1 Copyright (c) 2000-2017 the FFmpeg developers
  built with gcc 6.2.0 (Ubuntu 6.2.0-5ubuntu12) 20161005
  configuration: --prefix=/usr --extra-version=0ubuntu0.16.10.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --cc=cc --cxx=g++ --enable-gpl --enable-shared --disable-stripping --disable-decoder=libopenjpeg --disable-decoder=libschroedinger --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmodplug --enable-libmp3lame --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-librubberband --enable-librtmp --enable-libschroedinger --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxvid --enable-libzvbi --enable-openal --enable-opengl --enable-x11grab --enable-libdc1394 --enable-libiec61883 --enable-libzmq --enable-frei0r --enable-chromaprint --enable-libx264
  libavutil      55. 17.103 / 55. 17.103
  libavcodec     57. 24.102 / 57. 24.102
  libavformat    57. 25.100 / 57. 25.100
  libavdevice    57.  0.101 / 57.  0.101
  libavfilter     6. 31.100 /  6. 31.100
  libavresample   3.  0.  0 /  3.  0.  0
  libswscale      4.  0.100 /  4.  0.100
  libswresample   2.  0.101 /  2.  0.101
  libpostproc    54.  0.100 / 54.  0.100
[mp3 @ 0x55f314cdfcc0] Skipping 0 bytes of junk at 260803.
[mjpeg @ 0x55f314ce17e0] Changing bps to 8
Input #0, mp3, from 'jiangzhende.mp3':
  Metadata:
    encoder         : Lavf56.4.101
    album           : 不要你為難
    title           : 講真的
    artist          : 曾惜
    album_artist    : 曾惜
    disc            : 1
    track           : 2
  Duration: 00:03:59.02, start: 0.025056, bitrate: 328 kb/s

Stream #0:0: Audio: mp3, 44100 Hz, stereo, s16p, 320 kb/s Stream    #0:1: Video: mjpeg, yuvj420p(pc, bt470bg/unknown/unknown), 2000x2000 [SAR 72:72 DAR 1:1], 90k tbr, 90k tbn, 90k tbc

    Metadata:
      comment         : Other
Output #0, s16le, to 'xxx.pcm':
  Metadata:
    track           : 2
    album           : 不要你為難
    title           : 講真的
    artist          : 曾惜
    album_artist    : 曾惜
    disc            : 1
    encoder         : Lavf57.25.100
    Stream #0:0: Audio: pcm_s16le, 44100 Hz, stereo, s16, 1411 kb/s
    Metadata:
      encoder         : Lavc57.24.102 pcm_s16le
Stream mapping:
  Stream #0:0 -> #0:0 (mp3 (native) -> pcm_s16le (native))
Press [q] to stop, [?] for help
size=   41171kB time=00:03:58.99 bitrate=1411.2kbits/s speed= 475x    
video:0kB audio:41171kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.000000%

Stream #0:0: Audio: mp3, 44100 Hz, stereo, s16p, 320 kb/s Stream #0:1: Video: mjpeg, yuvj420p(pc, bt470bg/unknown/unknown), 2000x2000 [SAR 72:72 DAR 1:1], 90k tbr, 90k tbn, 90k tbc
從ffmpeg的輸出可以看出,原來的mp3音訊採用44100HZ取樣率,stereo立體聲雙通道,s16p編碼格式,所以我們在進行pm3轉pcm的時候儘量採用相同的取樣率,通道數和編碼格式,以保證轉換出來的pcm音訊不失真

完整例項請參考
https://github.com/TangGee/PlayPcmByAudioTrack