事情是这样的
有一批音频需要压缩。这些音频主要是课文朗读。因为不是歌曲,质量要求不高,所以使用了比较低的质量,对于有些音频能压制到原来的八分之一的体积例如 (大小为78M的音频 压缩到9M)。
MP3FileProcessor.CompressAndResampleMp3(fn_old, fn);
默认使用下面的压制参数
采样率 int targetSampleRate= 8000
比特率 int bitRate=32
声道数 int channels=1
重采样质量 ResamplerQuality = 60
if (!File.Exists(inputFilePath))
throw new FileNotFoundException("输入文件不存在", inputFilePath);
if (string.IsNullOrEmpty(outputFilePath))
throw new ArgumentException("输出文件路径不能为空");
if (channels != 1 && channels != 2)
throw new ArgumentException("声道数必须为1(单声道)或2(立体声)", nameof(channels));
// 支持的采样率验证(常见MP3采样率)
int[] supportedSampleRates = { 8000, 11025, 16000, 22050, 32000, 44100, 48000 };
if (Array.IndexOf(supportedSampleRates, targetSampleRate) == -1)
throw new ArgumentException("不支持的采样率", nameof(targetSampleRate));
// 支持的比特率验证(LAME支持的常见比特率)
if (bitRate < 32 || bitRate > 320 || bitRate % 8 != 0)
throw new ArgumentException("无效的比特率,必须是32-320之间的8的倍数", nameof(bitRate));
// 确保输出目录存在
var outputDir = Path.GetDirectoryName(outputFilePath);
if (!string.IsNullOrEmpty(outputDir) && !Directory.Exists(outputDir))
Directory.CreateDirectory(outputDir);
WaveStream reader = null;
WaveStream resampledStream = null;
LameMP3FileWriter writer = null;
try
{
// 读取输入音频文件(NAudio会自动识别格式)
reader = new AudioFileReader(inputFilePath);
// 如果需要重采样或改变声道数
if (reader.WaveFormat.SampleRate != targetSampleRate ||
reader.WaveFormat.Channels != channels)
{
// 创建重采样器
var resampler = new MediaFoundationResampler(reader,
WaveFormat.CreateIeeeFloatWaveFormat(targetSampleRate, channels));
// 重采样质量设置(0-100,越高质量越好但速度越慢)
resampler.ResamplerQuality = 60;
resampledStream = new WaveProviderToStreamAdapter(resampler);
}
else
{
// 无需重采样,直接使用原始流
resampledStream = reader;
}
// 初始化LAME编码器设置
LameConfig lameConfig = new LameConfig();
lameConfig.BitRate = bitRate;
// 创建MP3写入器(内部会初始化LAME编码器)
writer = new LameMP3FileWriter(outputFilePath,
resampledStream.WaveFormat,
lameConfig);
// 缓冲区大小(根据采样率调整,确保处理效率)
var bufferSize = resampledStream.WaveFormat.AverageBytesPerSecond / 4;
var buffer = new byte[bufferSize];
int bytesRead;
// 处理音频数据
while ((bytesRead = resampledStream.Read(buffer, 0, buffer.Length)) > 0)
{
writer.Write(buffer, 0, bytesRead);
}
}
catch (Exception ex)
{
// 清理可能生成的不完整文件
if (File.Exists(outputFilePath))
File.Delete(outputFilePath);
throw new IOException("MP3处理失败", ex);
}
finally
{
// 确保资源释放
writer?.Dispose();
resampledStream?.Dispose();
reader?.Dispose();
}
代码
public class MP3FileProcessor
{
public class WaveProviderToStreamAdapter : WaveStream
{
private readonly IWaveProvider _provider;
private long _position;
public WaveProviderToStreamAdapter(IWaveProvider provider)
{
_provider = provider ?? throw new ArgumentNullException(nameof(provider));
}
public override WaveFormat WaveFormat => _provider.WaveFormat;
// 对于实时生成的流(如重采样器),长度无法预知,返回long.MaxValue
public override long Length => long.MaxValue;
public override long Position
{
get => _position;
set => _position = value; // 重采样流不支持定位,此处仅作占位
}
public override int Read(byte[] buffer, int offset, int count)
{
int bytesRead = _provider.Read(buffer, offset, count);
_position += bytesRead;
return bytesRead;
}
}
public static void CompressAndResampleMp3(string inputFilePath, string outputFilePath,
int targetSampleRate= 8000, int bitRate=32, int channels=1)
{
// 验证输入参数
if (!File.Exists(inputFilePath))
throw new FileNotFoundException("输入文件不存在", inputFilePath);
if (string.IsNullOrEmpty(outputFilePath))
throw new ArgumentException("输出文件路径不能为空");
if (channels != 1 && channels != 2)
throw new ArgumentException("声道数必须为1(单声道)或2(立体声)", nameof(channels));
// 支持的采样率验证(常见MP3采样率)
int[] supportedSampleRates = { 8000, 11025, 16000, 22050, 32000, 44100, 48000 };
if (Array.IndexOf(supportedSampleRates, targetSampleRate) == -1)
throw new ArgumentException("不支持的采样率", nameof(targetSampleRate));
// 支持的比特率验证(LAME支持的常见比特率)
if (bitRate < 32 || bitRate > 320 || bitRate % 8 != 0)
throw new ArgumentException("无效的比特率,必须是32-320之间的8的倍数", nameof(bitRate));
// 确保输出目录存在
var outputDir = Path.GetDirectoryName(outputFilePath);
if (!string.IsNullOrEmpty(outputDir) && !Directory.Exists(outputDir))
Directory.CreateDirectory(outputDir);
WaveStream reader = null;
WaveStream resampledStream = null;
LameMP3FileWriter writer = null;
try
{
// 读取输入音频文件(NAudio会自动识别格式)
reader = new AudioFileReader(inputFilePath);
// 如果需要重采样或改变声道数
if (reader.WaveFormat.SampleRate != targetSampleRate ||
reader.WaveFormat.Channels != channels)
{
// 创建重采样器
var resampler = new MediaFoundationResampler(reader,
WaveFormat.CreateIeeeFloatWaveFormat(targetSampleRate, channels));
// 重采样质量设置(0-100,越高质量越好但速度越慢)
resampler.ResamplerQuality = 60;
resampledStream = new WaveProviderToStreamAdapter(resampler);
}
else
{
// 无需重采样,直接使用原始流
resampledStream = reader;
}
// 初始化LAME编码器设置
LameConfig lameConfig = new LameConfig();
lameConfig.BitRate = bitRate;
// 创建MP3写入器(内部会初始化LAME编码器)
writer = new LameMP3FileWriter(outputFilePath,
resampledStream.WaveFormat,
lameConfig);
// 缓冲区大小(根据采样率调整,确保处理效率)
var bufferSize = resampledStream.WaveFormat.AverageBytesPerSecond / 4;
var buffer = new byte[bufferSize];
int bytesRead;
// 处理音频数据
while ((bytesRead = resampledStream.Read(buffer, 0, buffer.Length)) > 0)
{
writer.Write(buffer, 0, bytesRead);
}
}
catch (Exception ex)
{
// 清理可能生成的不完整文件
if (File.Exists(outputFilePath))
File.Delete(outputFilePath);
throw new IOException("MP3处理失败", ex);
}
finally
{
// 确保资源释放
writer?.Dispose();
resampledStream?.Dispose();
reader?.Dispose();
}
}
}
1697

被折叠的 条评论
为什么被折叠?



