使用AndroidTrack播放pcm音訊
阿新 • • 發佈:2018-11-17
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音訊不失真