Android mediaCodec+audioTrack+mediaExtractor播放aac


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()
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值