You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android MediaCodec解码AAC音频文件输出0字节问题求助

AAC解码输出0字节问题排查与修复

以下是代码中存在的核心问题及对应修复方案:

1. 缺少AAC解码必需的编码特定数据(CSD)

AAC解码器需要编码时的配置信息(如音频配置文件、采样率索引等)才能正常工作,这些数据通常封装在ADTS头中,或通过MediaFormat的KEY_CODEC_CONFIG(即CSD-0)传递。你的代码仅设置了基础格式参数,解码器无法解析输入数据,导致无输出。

  • 修复:如果输入是带ADTS头的AAC文件,确保解码器自动识别;如果是裸AAC(无ADTS),需从编码生成的MediaFormat中提取CSD-0数据,添加到解码用的MediaFormat:
    // 假设编码时保存了csd0数据,示例:
    // val csd0 = encodeFormat.getByteBuffer("csd-0")
    // format.setByteBuffer("csd-0", csd0)
    

2. 输入Buffer数据写入与提交错误

  • 你直接将整个bufferSize长度的tmpBuffer写入inputBuffer,但实际readCount才是真实读取的有效字节数,多余的无效数据会干扰解码器。
  • queueInputBuffer的第三个参数应该是实际写入的字节数readCount,而非bufferSize,否则解码器会处理不存在的数据。
  • 修复:
    if (dequeueBufferIndex >= 0) {
        val inputBuffer = decoder.getInputBuffer(dequeueBufferIndex)
        inputBuffer?.clear() // 清空buffer避免残留数据
        readCount = fileInput?.read(tmpBuffer) ?: -1
        val flag = if (readCount < 0) {
            MediaCodec.BUFFER_FLAG_END_OF_STREAM
        } else {
            inputBuffer?.put(tmpBuffer, 0, readCount)
            0
        }
        decoder.queueInputBuffer(dequeueBufferIndex, 0, if (readCount >=0) readCount else 0, System.currentTimeMillis(), flag)
    }
    

3. 输出Buffer处理逻辑错误

  • 不能仅依赖outputBuffer?.remaining()获取有效数据长度,应使用MediaCodec.BufferInfo.size字段,这是解码器返回的真实有效数据大小。
  • releaseOutputBuffer的第二个参数是音频播放时的渲染标记,解码到文件无需此参数,传入时间戳是错误用法,应传false。
  • 修复:
    val bufferInfo = MediaCodec.BufferInfo()
    val outputBufferId = decoder.dequeueOutputBuffer(bufferInfo, aSecond)
    if (outputBufferId >= 0) {
        val outputBuffer = decoder.getOutputBuffer(outputBufferId)
        if (bufferInfo.size > 0) {
            val outPutBuffer = ByteArray(bufferInfo.size)
            outputBuffer?.get(outPutBuffer)
            fileOutput?.write(outPutBuffer)
        }
        decoder.releaseOutputBuffer(outputBufferId, false)
        // 检测流结束
        if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
            break
        }
    }
    

4. 循环与状态处理不完整

  • 当dequeueInputBuffer返回-1(无可用输入buffer)时,你直接跳过输出处理,会导致解码数据堆积或丢失,需确保每次循环都尝试处理输出。
  • 未处理dequeueOutputBuffer返回的INFO_OUTPUT_FORMAT_CHANGED(输出格式变化)和INFO_TRY_AGAIN_LATER(需重试)状态。
  • 修复:分离输入输出处理逻辑,覆盖所有状态:
    var readCount = fileInput?.read(tmpBuffer) ?: -1
    var isInputDone = false
    while (true) {
        // 处理输入
        if (!isInputDone) {
            val dequeueBufferIndex = decoder.dequeueInputBuffer(aSecond)
            if (dequeueBufferIndex >= 0) {
                val inputBuffer = decoder.getInputBuffer(dequeueBufferIndex)
                inputBuffer?.clear()
                val flag = if (readCount < 0) {
                    isInputDone = true
                    MediaCodec.BUFFER_FLAG_END_OF_STREAM
                } else {
                    inputBuffer?.put(tmpBuffer, 0, readCount)
                    0
                }
                decoder.queueInputBuffer(dequeueBufferIndex, 0, if (readCount >=0) readCount else 0, System.currentTimeMillis(), flag)
                if (!isInputDone) {
                    readCount = fileInput?.read(tmpBuffer) ?: -1
                }
            }
        }
        // 处理输出
        val bufferInfo = MediaCodec.BufferInfo()
        val outputBufferId = decoder.dequeueOutputBuffer(bufferInfo, aSecond)
        when {
            outputBufferId >= 0 -> {
                val outputBuffer = decoder.getOutputBuffer(outputBufferId)
                if (bufferInfo.size > 0) {
                    val outBuffer = ByteArray(bufferInfo.size)
                    outputBuffer?.get(outBuffer)
                    fileOutput?.write(outBuffer)
                }
                decoder.releaseOutputBuffer(outputBufferId, false)
                if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                    break
                }
            }
            outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED -> {
                // 可在此获取解码后的音频格式,如采样率、声道数等
                val outputFormat = decoder.outputFormat
            }
            outputBufferId == MediaCodec.INFO_TRY_AGAIN_LATER -> {
                // 暂时无输出,继续循环
            }
        }
    }
    

内容的提问来源于stack exchange,提问作者cao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 03:18:12