android - 使用 LAME 将原始 PCM 文件转换为 MP3 会返回失真的音频
问题描述
我有从 base64 字符串生成的原始 PCM 文件。这是返回的 API 响应的链接。
然后我从这个字符串创建一个 PCM 文件,之后我使用 LAME 库将它转换为 MP3。
这是处理转换的代码:
companion object {
init {
System.loadLibrary("mp3lame")
}
}
private external fun initEncoder(numChannels: Int, sampleRate: Int, bitRate: Int, mode: Int, quality: Int)
private external fun destroyEncoder()
private external fun encodeFile(sourcePath: String, targetPath: String): Int
val NUM_CHANNELS = 1
val SAMPLE_RATE = 16000
val BITRATE = 128
val MODE = 3
val QUALITY = 0
fun createAudioFromBase64AndGetPath(inputBase64: String, outputFileName: String) {
initEncoder(NUM_CHANNELS, SAMPLE_RATE, BITRATE, MODE, QUALITY)
val path: String = "newFile.wav"
try {
val decoded = Base64.decode(inputBase64, Base64.NO_WRAP)
try {
val fileRaw = File(Environment.getExternalStorageDirectory().toString() + "/$outputFileName.pcm")
val fileEncoded = File(Environment.getExternalStorageDirectory().toString() + "/$outputFileName.mp3")
val os = FileOutputStream(fileRaw, true)
os.write(decoded)
os.close()
val result = encodeFile(fileRaw!!.absolutePath, fileEncoded!!.absolutePath)
if (result == 0) {
Log.d ("encoded to ", fileEncoded!!.name)
}
destroyEncoder()
} catch (e: Exception) {
Log.e ("decode ", "first catch", e)
e.printStackTrace()
}
} catch (e: Exception) {
e.printStackTrace()
Log.d ("decode ", "2nd catch", e)
}
}
音频听起来像这样。
我尝试浏览 C 库文件,这些文件解释了initEncoder的不同变量选项的含义,我已经摆弄了但没有任何改变。
为了尝试在每次编译应用程序时没有延迟的情况下解决此问题,我使用 base64 字符串并使用在线转换器 (Motobit) 将其转换为 PCM 文件。然后,我使用了一个非常漂亮(免费)的 mac 转换器,称为 XLD 来测试这些转换,而不必每次都编译应用程序,看看我是否能弄清楚发生了什么,或者我是否只是使用了错误的组合initEncoder 的变量。
我注意到的第一件事是我必须选择“打开原始 PCM (bin+cue)...”选项才能打开从 motobit 下载的 pcm 文件。
下一个难题,似乎是关键部分,是我只能在 Endian 框中选择“Little”时正确转换音频(没有噪音)。问题是,回到我的应用程序中,我无法找出如何或者是否可以访问和更改 LAME 库中的此属性。
为清楚起见,我从这里使用包装器:https ://developer.samsung.com/technical-doc/view.do?v=T000000090
解决方案
如果您感到绝望,您可以随时自己切换字节顺序:
for (i in decoded.indices step 2)
{
val swap = decoded[i]
decoded[i] = decoded[i + 1]
decoded[i + 1] = swap
}
...因为Base64.decode()
返回一个字节数组,我假设您使用的是 16 位音频。
我自己找不到initEncoder()
文档。
推荐阅读
- python - 多个 .shift() 操作相互覆盖
- symfony - 在 symfony 中访问存储库
- java - 如何在 spring-mvc 应用程序中设置动态日志级别?
- android - Ionic 3 上的 OneSignal 推送通知:未订阅所有包含的播放器
- scala - 带有 Option/Some 的 scala Map 给出匹配错误
- typescript - 铸造泛型 - 打字稿
- bash - Sed 范围和删除最后一个匹配行
- ruby-on-rails - Rails 应用程序上的静态 PDF 文件在部署时未显示在网站上
- perl - 在 perl 中解析字符串的最佳方法
- java - 在Android中以意图发送地图数据?