首页 > 解决方案 > 使用 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

标签: androidkotlinmp3pcmlame

解决方案


如果您感到绝望,您可以随时自己切换字节顺序:

for (i in decoded.indices step 2)
{
    val swap = decoded[i]
    decoded[i] = decoded[i + 1]
    decoded[i + 1] = swap
}

...因为Base64.decode()返回一个字节数组,我假设您使用的是 16 位音频。

我自己找不到initEncoder()文档。


推荐阅读