使用 Lame 将混合波流转换为 mp3

Posted

技术标签:

【中文标题】使用 Lame 将混合波流转换为 mp3【英文标题】:Mixed wave stream to mp3 using Lame 【发布时间】:2013-08-10 14:31:08 【问题描述】:
.......
.......

var mixer = new WaveMixerStream32();
mixer.AutoStop = true;

var messageOffset = background.TotalTime;
var messageOffsetted = new WaveOffsetStream(message, 
                                         TimeSpan.FromSeconds(10), 
                                         TimeSpan.Zero,message.TotalTime.Subtract(TimeSpan.FromSeconds(10)));             

var background32 = new WaveChannel32(background);
background32.PadWithZeroes = false;
background32.Volume = 0.6f;               
mixer.AddInputStream(background32);

var message32 = new WaveChannel32(messageOffsetted);
message32.PadWithZeroes = false;
message32.Volume = 0.3f;
mixer.AddInputStream(message32);

var ws = new Wave32To16Stream(mixer);

我们正在尝试混合多个 mp3 和 wave 文件以最终创建一个 MP3。

示例:5 个源文件(3 个 mp3,2 个波形文件)

我们将每个流的输入提供给 WaveMixerStream32,最后使用 Wave32To16Stream

我们需要将此最终流转换为 MP3。为此,我们使用 LAME 并将流传递给 EncodeMixedStreamAsMp3 返回错误“文件格式无效”。

经过研究,我们发现混合波流中缺少RIFF标头。

如何将 RIFF 添加到基于多个源(MP3 和 WAVE)生成的混合波流中?

【问题讨论】:

【参考方案1】:

NAudio WaveStream 是具有指定格式的样本数据流,而不是 LAME 所期望的 RIFF WAV 文件。要将其转换为 RIFF WAV 文件,您需要添加 RIFF 标头等。 NAudio.Wave.WaveFileWriter 类就是这样做的。

如果您正在处理不会占用内存的小输出文件,您可以执行一些简单的操作,例如(假设 Yeti 的 LAME 包装器或类似的):

(代码于 2013 年 8 月 19 日更新):

public byte[] EncodeMP3(IWaveProvider ws, uint bitrate = 128)

    // Setup encoder configuration
    WaveLib.WaveFormat fmt = new WaveLib.WaveFormat(ws.WaveFormat.SampleRate, ws.WaveFormat.BitsPerSample, ws.WaveFormat.Channels);
    Yeti.Lame.BE_CONFIG beconf = new Yeti.Lame.BE_CONFIG(fmt, bitrate);

    // Encode WAV to MP3
    int blen = ws.WaveFormat.AverageBytesPerSecond;
    byte[] buffer = new byte[blen];
    byte[] mp3data = null;

    using (MemoryStream mp3strm = new MemoryStream())
    using (Mp3Writer mp3wri = new Mp3Writer(mp3strm, fmt, beconf))
    
        int rc;
        while ((rc = ws.Read(buffer, 0, blen)) > 0)
            mp3wri.Write(buffer, 0, rc);
        mp3data = mp3strm.ToArray();
    
    return mp3data;

-- 更新:设置MP3编码参数

使用Yeti LAME 包装器,您可以通过传入BE_CONFIG 结构来指定MP3 编码参数,如下所示:

WaveLib.WaveFormat fmt = new WaveLib.WaveFormat(ws.WaveFormat.SampleRate, ws.WaveFormat.BitsPerSample, ws.WaveFormat.Channels);

Yeti.Lame.BE_CONFIG beconf = new Yeti.Lame.BE_CONFIG(fmt, 64);
using (MemoryStream mp3strm = new MemoryStream())
using (Mp3Writer mp3wri = new Mp3Writer(mp3strm, fmt, beconf))

...

BE_CONFIG 构造函数采用WaveLib.WaveFormat 和可选的以 Kb/s 为单位的 CBR 比特率。如果您未指定比特率,则默认为 128Kb/s 输出。如果您不向Mp3Writer 提供配置,它会从WaveFormat 创建一个默认配置。

上面的代码创建了一个BE_CONFIG,输出速率设置为64Kb/s。如果您想要不同的比特率,只需指定它来代替new Yeti.Lame.BE_CONFIG(fmt, 64); 中的64

BE_CONFIG 包含许多其他选项,其中大部分您永远不会使用。查看(略显粗略的)文档here。

【讨论】:

嗨@Corey,我还有一个问题。我能够获得 128 kbps 比特率的 mp3 输出。现在我希望输出为 64 kbps。有没有办法做到这一点。我用谷歌搜索了它,但我几乎找不到任何解决方案。 您需要使用正确的配置设置 Mp3Writer。我将添加一些代码... 非常感谢!!我明白了。 嗨@Corey,您的代码在 mp3 和波流上运行良好,但是当我在 NVorbis.NAudiosupport.VorbisWaveReader 的帮助下在您的函数中使用 ogg 流时,我在歌曲播放缓慢时得到噪音输出也不清楚。请纠正我哪里出错了。我在 WaveLib.WaveFormat 中使用了每个样本 16 位,因为我的 ogg 每个样本提供 32 位。 @sainathsagar 您需要在混合之前将所有输入转换为相同的格式,因此您的解码后的 ogg 需要转换为 16 位。 VorbisWaveReader 是一个 WaveStream,你可以使用 NAudio.Wave.Wave32To16Stream 来包装它,给你一个 16 位的 WaveStream 来编码。

以上是关于使用 Lame 将混合波流转换为 mp3的主要内容,如果未能解决你的问题,请参考以下文章

编写一个简单的 python 脚本,使用 lame 将特定文件夹中的所有 .wav 文件转换为 .mp3

NAudio lame 将文本转换为 mp3 在服务器 c# Web 应用程序上无法正常工作?

录音文件lame转换MP3相关配置

录音文件lame转换MP3相关配置

vs2010音频文件压缩 调用lame_enc.dll将WAV格式转换成MP3

PHP - 将 .wav 文件转换为 .mp3?