Feature: add AudioTrackController

pull/209/head
xufuji456 3 years ago
parent a1276b776e
commit 60611bcda6
  1. 146
      AndroidMedia/src/main/java/com/frank/androidmedia/controller/AudioTrackController.kt
  2. 5
      AndroidMedia/src/main/java/com/frank/androidmedia/controller/MediaDecodeController.kt
  3. 5
      AndroidMedia/src/main/java/com/frank/androidmedia/controller/MediaMuxController.kt

@ -0,0 +1,146 @@
package com.frank.androidmedia.controller
import android.media.*
import android.os.SystemClock
import android.util.Log
import java.lang.Exception
/**
* 1. Using MediaExtractor to demux audio.
* 2. Using MediaCodec to decode audio.
* 3. Using AudioTrack to play audio.
* See also AAduio, oboe, openSL ES.
*
* @author frank
* @date 2022/3/21
*/
open class AudioTrackController {
companion object {
val TAG: String = AudioTrackController::class.java.simpleName
private const val DEQUEUE_TIME = (10 * 1000).toLong()
private const val SLEEP_TIME: Long = 20
}
private var audioTrack: AudioTrack? = null
private var mediaCodec: MediaCodec? = null
private var mediaExtractor: MediaExtractor? = null
private fun parseAudioFormat(path: String): MediaFormat? {
mediaExtractor = MediaExtractor()
try {
mediaExtractor?.setDataSource(path)
for (i in 0 until mediaExtractor!!.trackCount) {
val mediaFormat = mediaExtractor!!.getTrackFormat(i)
val mimeType = mediaFormat.getString(MediaFormat.KEY_MIME)
if (mimeType != null && mimeType.startsWith("audio")) {
mediaExtractor!!.selectTrack(i)
return mediaFormat
}
}
} catch (e: Exception) {
Log.e(TAG, "parseAudioFormat err=$e")
}
return null
}
private fun initMediaCodec(mediaFormat: MediaFormat): Boolean {
val mimeType = mediaFormat.getString(MediaFormat.KEY_MIME)
mediaCodec = MediaCodec.createDecoderByType(mimeType)
return try {
mediaCodec!!.configure(mediaFormat, null, null, 0)
mediaCodec!!.start()
true
} catch (e: Exception) {
Log.e(TAG, "initMediaCodec err=$e")
false
}
}
private fun initAudioTrack(mediaFormat: MediaFormat): Boolean {
val sampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE)
val channelCount = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT)
val channelConfig = if (channelCount == 1) {
AudioFormat.CHANNEL_OUT_MONO
} else {
AudioFormat.CHANNEL_OUT_STEREO
}
val audioFormat = AudioFormat.ENCODING_PCM_16BIT
val bufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat)
Log.e(TAG, "sampleRate=$sampleRate, channelCount=$channelCount, bufferSize=$bufferSize")
try {
audioTrack = AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, channelConfig, audioFormat, bufferSize, AudioTrack.MODE_STREAM)
audioTrack!!.play()
// audioTrack!!.attachAuxEffect()
} catch (e: Exception) {
Log.e(TAG, "initAudioTrack err=$e")
return false
}
return true
}
private fun release() {
if (mediaExtractor != null) {
mediaExtractor!!.release()
mediaExtractor = null
}
if (mediaCodec != null) {
mediaCodec!!.release()
mediaCodec = null
}
if (audioTrack != null) {
audioTrack!!.release()
audioTrack = null
}
}
fun playAudio(path: String) {
val data = ByteArray(10 * 1024)
var finished = false
val bufferInfo = MediaCodec.BufferInfo()
val mediaFormat = parseAudioFormat(path) ?: return release()
var result = initMediaCodec(mediaFormat)
if (!result) {
return release()
}
result = initAudioTrack(mediaFormat)
if (!result) {
return release()
}
while (!finished) {
val inputIndex = mediaCodec!!.dequeueInputBuffer(DEQUEUE_TIME)
if (inputIndex >= 0) {
val inputBuffer = mediaCodec!!.getInputBuffer(inputIndex)
// demux
val sampleSize = mediaExtractor!!.readSampleData(inputBuffer!!, 0)
Log.e(TAG, "sampleSize=$sampleSize")
// decode
if (sampleSize < 0) {
mediaCodec!!.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM)
finished = true
} else {
mediaCodec!!.queueInputBuffer(inputIndex, 0, sampleSize, mediaExtractor!!.sampleTime, mediaExtractor!!.sampleFlags)
mediaExtractor!!.advance()
}
}
val outputIndex = mediaCodec!!.dequeueOutputBuffer(bufferInfo, DEQUEUE_TIME)
// play
if (outputIndex >= 0) {
val outputBuffer = mediaCodec!!.getOutputBuffer(outputIndex)
val size = outputBuffer!!.limit()
Log.e(TAG, "outputIndex=$outputIndex, position=" + outputBuffer.position() + " ,limit=" + size)
outputBuffer.get(data, outputBuffer.position(), size)
audioTrack!!.write(data, 0, size)
mediaCodec!!.releaseOutputBuffer(outputIndex, false)
SystemClock.sleep(SLEEP_TIME)
}
}
release()
}
}

@ -209,7 +209,6 @@ open class MediaDecodeController(val mSurface: Surface, val mFilePath: String, v
mediaCodec!!.configure(mediaFormat, mSurface, null, 0)
mediaCodec!!.start()
val bufferInfo = MediaCodec.BufferInfo()
val inputBuffers = mediaCodec!!.inputBuffers
while (!isInterrupted) {
if (!isPreviewing) {
@ -219,8 +218,8 @@ open class MediaDecodeController(val mSurface: Surface, val mFilePath: String, v
//dequeue from input buffer
val inputIndex = mediaCodec!!.dequeueInputBuffer(DEQUEUE_TIME)
if (inputIndex >= 0) {
val inputBuffer = inputBuffers[inputIndex]
val sampleSize = mediaExtractor!!.readSampleData(inputBuffer, 0)
val inputBuffer = mediaCodec!!.getInputBuffer(inputIndex)
val sampleSize = mediaExtractor!!.readSampleData(inputBuffer!!, 0)
//enqueue to input buffer
if (sampleSize < 0) {
mediaCodec!!.queueInputBuffer(inputIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM)

@ -57,7 +57,6 @@ open class MediaMuxController {
while (!finished) {
val sampleSize = mediaExtractor.readSampleData(inputBuffer, 0)
Log.i("MediaMuxerController", "sampleIndex=" + mediaExtractor.sampleTrackIndex + ",sampleSize=" + sampleSize)
if (sampleSize > 0) {
bufferInfo.size = sampleSize
bufferInfo.flags = mediaExtractor.sampleFlags
@ -75,14 +74,14 @@ open class MediaMuxController {
}
} catch (e: Exception) {
Log.e("MediaMuxerController", "mux error=$e")
Log.e("MediaMuxController", "mux error=$e")
happenError = true
} finally {
try {
mediaMuxer.release()
mediaExtractor.release()
} catch (e1: Exception) {
Log.e("MediaMuxerController", "release error=$e1")
Log.e("MediaMuxController", "release error=$e1")
}
return !happenError
}

Loading…
Cancel
Save