class PlayAAC : Activity() {
val TAG: String = "PlayAAC"
val aacPath: String = "/sdcard/test/test.aac"
val streamType: Int = AudioManager.STREAM_MUSIC
val streamRate: Int = 22050
val channelConfig: Int = AudioFormat.CHANNEL_CONFIGURATION_MONO
val audioFormat: Int = AudioFormat.ENCODING_PCM_16BIT
val model: Int = AudioTrack.MODE_STREAM
var buffSize: Int = 0
lateinit var track: AudioTrack
lateinit var textView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pcm)
textView = findViewById(R.id.txt) as TextView
textView.setText("播放aac")
Thread {
try {
initExtractor(aacPath)
} catch (e: Exception) {
e.printStackTrace()
}
}.start()
}
private fun initExtractor(fileStr: String) {
try {
buffSize = AudioTrack.getMinBufferSize(streamRate, channelConfig, audioFormat)
track = AudioTrack(streamType, streamRate, channelConfig, audioFormat, buffSize, model)
track.play()
val mediaExtractor = MediaExtractor()
mediaExtractor.setDataSource(fileStr)
var audioIndex = -1
var hasAudio = false
for (i in 0 until mediaExtractor.trackCount) {
var format: MediaFormat = mediaExtractor.getTrackFormat(i)
var mine: String = format.getString(MediaFormat.KEY_MIME)
if (mine.startsWith("audio")) {
audioIndex = i
hasAudio = true
break
}
}
if (hasAudio) {
mediaExtractor.selectTrack(audioIndex)
Thread {
getPCMfromMp4(mediaExtractor, audioIndex)
Log.e(TAG, "finish")
}.start()
}
} catch (e: Exception) {
e.printStackTrace()
}
}
/**
* 单纯得到PCM文件
*/
private fun getPCMfromMp4(extractor: MediaExtractor, index: Int) {
try {
val mediaFormat: MediaFormat = extractor.getTrackFormat(index)
Log.e(TAG, "mediaFormat=$mediaFormat")
mediaFormat.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm")
mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 2)
mediaFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, 22050)
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 96000)
mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, 2)
val audioCodec = MediaCodec.createDecoderByType("audio/mp4a-latm")
audioCodec.configure(mediaFormat, null, null, 0)
audioCodec.start()
val inputBuff = audioCodec.inputBuffers
val outputBuff = audioCodec.outputBuffers
val inputInfo = MediaCodec.BufferInfo()
val outputInfo = MediaCodec.BufferInfo()
var isOverCode = false
while (!isOverCode) {
val inputIndex = audioCodec.dequeueInputBuffer(10000)
if (inputIndex >= 0) {
val byteBuffer = inputBuff[inputIndex]
byteBuffer.clear()
val sampleSize = extractor.readSampleData(byteBuffer, 0)
if (sampleSize <= 0) {
audioCodec.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM)
} else {
inputInfo.offset = 0
inputInfo.size = sampleSize
inputInfo.flags = MediaCodec.BUFFER_FLAG_KEY_FRAME
inputInfo.presentationTimeUs = extractor.sampleTime
audioCodec.queueInputBuffer(
inputIndex,
0,
inputInfo.size,
inputInfo.presentationTimeUs,
0
)
extractor.advance()
}
}
var outPutIndex = audioCodec.dequeueOutputBuffer(outputInfo, 10000)
while (outPutIndex >= 0) {
val dataBuff: ByteBuffer = outputBuff[outPutIndex]
val chumkPcm = ByteArray(outputInfo.size)
dataBuff.get(chumkPcm)
dataBuff.clear()
track.write(chumkPcm, 0, chumkPcm.size)
audioCodec.releaseOutputBuffer(outPutIndex, false)
outPutIndex = audioCodec.dequeueOutputBuffer(outputInfo, 10000)
if ((outputInfo.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
track.stop()
track.release()
extractor.release()
audioCodec.stop()
audioCodec.release()
isOverCode = true
}
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
override fun onDestroy() {
super.onDestroy()
}