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
相关产品推荐
相关产品推荐

