Android中MP3转Int16格式PCM及播放问题求助
解决MP3转Int16 PCM后播放噪音的问题
你的问题核心是对Int16(16位)PCM格式的理解偏差:Int16 PCM是用两个连续字节组合成一个16位整数来表示一个音频采样值,而不是把单个byte单独转成Int后写入文本。你当前的代码既破坏了16位数据的结构,又把二进制音频转成了文本格式,播放器自然无法识别,只能输出噪音。
错误原因拆解
- Int16是16位数据,需要两个8位byte才能组成一个有效采样值,单个byte转Int完全丢失了另一半数据
- 直接写入
i.toString()+" "是把数值转成了文本字符,不是播放器需要的二进制PCM数据
正确的Int16 PCM处理与写入方法
下面针对两种常见场景给出正确实现:
场景1:获取Int16数值用于处理,同时保存可播放的PCM文件
先把解码后的byte数组转成ShortArray(Kotlin中short对应16位整数),处理后再转回byte数组写入文件:
override fun onOutputBufferAvailable(codec: MediaCodec, index: Int, info: MediaCodec.BufferInfo) { Log.d(TAG, "onOutputBufferAvailable") val buffer = mediaCodec.getOutputBuffer(index) ?: return val byteArray = ByteArray(info.size - info.offset) val bufferPosition = buffer.position() // 读取解码后的原始byte数据 buffer.get(byteArray) buffer.position(bufferPosition) mediaCodec.releaseOutputBuffer(index, true) // 将byte数组转成Int16(ShortArray):MP3解码后的PCM通常是小端字节序(低字节在前) val shortArray = ShortArray(byteArray.size / 2) for (i in shortArray.indices) { // 两个byte拼接成16位short:高字节左移8位,和低字节做或运算 shortArray[i] = ((byteArray[2*i+1].toInt() shl 8) or (byteArray[2*i].toInt() and 0xFF)).toShort() } // ------------------------------ // 这里可以对shortArray进行自定义数据处理 // ------------------------------ // 将处理后的ShortArray转回byte数组,写入文件(可直接用播放器播放) val outputBytes = ByteArray(shortArray.size * 2) for (i in shortArray.indices) { outputBytes[2*i] = (shortArray[i].toInt() and 0xFF).toByte() outputBytes[2*i+1] = (shortArray[i].toInt() shr 8 and 0xFF).toByte() } fos.write(outputBytes) }
场景2:直接播放Int16格式的PCM数据
如果不需要保存文件,而是要直接播放ShortArray格式的PCM,可以用AudioTrack实现:
// 先初始化AudioTrack,参数必须和解码后的PCM完全匹配 val sampleRate = 44100 // 替换为你实际解码得到的采样率 val channelConfig = AudioFormat.CHANNEL_OUT_STEREO // 单声道用CHANNEL_OUT_MONO val audioFormat = AudioFormat.ENCODING_PCM_16BIT val bufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) val audioTrack = AudioTrack( AudioManager.STREAM_MUSIC, sampleRate, channelConfig, audioFormat, bufferSize, AudioTrack.MODE_STREAM ) // 在得到shortArray后,直接写入AudioTrack播放 audioTrack.play() audioTrack.write(shortArray, 0, shortArray.size)
关键注意事项
- 字节序:MP3解码后的PCM基本都是小端字节序,拼接byte时要保证低字节在前、高字节在后
- 参数一致性:播放时的采样率、声道数必须和解码输出的PCM参数完全一致,否则会出现速度异常或噪音
- 数据类型:Int16对应Kotlin的
short类型,不要用int直接存储单个byte,避免高位数据丢失
内容的提问来源于stack exchange,提问作者hushed_voice
相关产品推荐
相关产品推荐

