Flutter音频编码插件dart_lame的使用

Flutter音频编码插件dart_lame的使用

功能

  • 将WAV(PCM-16 或 PCM IEEE Double)编码为MP3。

开始使用

要使用此库,您必须在系统上安装libmp3lame。请确保以下库在您的系统上可用或将其放置在程序的工作目录下:

  • Windows: mp3lame.dll
  • Linux: libmp3lame.so
  • macOS: libmp3lame.dylib

另外,您可以手动加载libmp3lame:

import 'dart:ffi' as ffi;
import 'package:dart_lame/dart_lame.dart' as lame;

class CustomLoader extends lame.LameLibraryLoader {
  @override
  ffi.DynamicLibrary load() {
    return ffi.DynamicLibrary.open("path_to_libmp3lame");
  }
}

lame.lameLoader = CustomLoader(); 

对于Flutter用户,请使用flutter_lame代替。

使用示例

import 'dart:io';
import 'dart:typed_data';

import 'package:dart_lame/dart_lame.dart';

final File f = File("output.mp3");
final IOSink sink = f.openWrite();
final LameMp3Encoder encoder = LameMp3Encoder(sampleRate: 44100, numChannels: 2);

Float64List leftChannelSamples;
Float64List rightChannelSamples;
// 获取来自文件或麦克风的样本。

final mp3Frame = await encoder.encode(
  leftChannel: leftChannelSamples,
  rightChannel: rightChannelSamples);
sink.add(mp3Frame);
// 继续直到所有样本已编码

// 最后,刷新编码器缓冲区
final lastMp3Frame = await encoder.flush();
sink.add(lastMp3Frame);

完整示例

对于完整的示例,请查看/example文件夹中的代码。

示例代码

import 'dart:async';
import 'dart:io';
import 'dart:typed_data';

import 'package:args/args.dart';
import 'package:dart_lame/dart_lame.dart';
import 'package:wav/wav.dart';

void main(List<String> arguments) async {
  print("dart_lame example");

  final parser = ArgParser()
    ..addOption("format",
        abbr: "f",
        allowed: ["wav", "pcm16"],
        help:
            "输入文件格式。注意:如果格式为pcm16,则仅接受单声道文件",
        defaultsTo: "wav")
    ..addOption("sample-rate",
        abbr: "s",
        help:
            "输入文件的采样率。如果输入格式为pcm16,则为必需项")
    ..addOption("input", abbr: "i", help: "输入文件", mandatory: true)
    ..addOption("output",
        abbr: "o", help: "输出mp3文件", defaultsTo: "output.mp3");
  final argResults = parser.parse(arguments);
  print('LAME版本: ${getLameVersion()}');

  final String inputPath = argResults["input"];
  print("输入文件: $inputPath");

  print("编码中...");

  final String outputPath = argResults["output"];
  final File f = File(outputPath);
  final IOSink sink = f.openWrite();
  try {
    if (argResults["format"] == "wav") {
      final wav = await Wav.readFile(inputPath);
      await encodeWav(wav, sink);
    } else {
      String? sampleRate = argResults["sample-rate"];
      if (sampleRate == null) {
        throw ArgumentError("--sample-rate 是必需的");
      }
      await encodePcm(inputPath, sink, int.parse(sampleRate));
    }
  } finally {
    sink.close();
  }

  print("成功编码mp3文件: ${f.absolute}");
}

Future encodeWav(Wav wav, IOSink sink) async {
  final encoder = LameMp3Encoder(
      sampleRate: wav.samplesPerSecond, numChannels: wav.channels.length);
  try {
    final left = wav.channels[0];
    Float64List? right;
    if (wav.channels.length > 1) {
      right = wav.channels[1];
    }

    for (int i = 0; i < left.length; i += wav.samplesPerSecond) {
      final mp3Frame = await encoder.encodeDouble(
          leftChannel: left.sublist(i, i + wav.samplesPerSecond),
          rightChannel: right?.sublist(i, i + wav.samplesPerSecond));
      sink.add(mp3Frame);
    }
    sink.add(await encoder.flush());
  } finally {
    encoder.close();
  }
}

Future encodePcm(String inputPath, IOSink sink, int sampleRate) async {
  final encoder = LameMp3Encoder(sampleRate: sampleRate, numChannels: 1);

  final File inputFile = File(inputPath);
  final Completer readCompleter = Completer();
  final Completer encodeCompleter = Completer();

  int counter = 0;

  final StreamSubscription<List<int>> sub = inputFile.openRead().listen(
      (event) async {
    counter++;
    final Uint8List mp3frame = await encoder.encode(
        leftChannel: Uint8List.fromList(event).buffer.asInt16List());
    sink.add(mp3frame);
    counter--;

    if (readCompleter.isCompleted) {
      if (counter == 0) {
        encodeCompleter.complete();
      }
    }
  },
      onDone: () => readCompleter.complete(),
      onError: (e) => readCompleter.completeError(e));

  try {
    await readCompleter.future;
    await encodeCompleter.future;
    final lastMp3Frame = await encoder.flush();
    sink.add(lastMp3Frame);
  } finally {
    sub.cancel();
    encoder.close();
  }
}

更多关于Flutter音频编码插件dart_lame的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter音频编码插件dart_lame的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


dart_lame 是一个用于 Flutter 的音频编码插件,它允许你将原始的 PCM 音频数据编码为 MP3 格式。这个插件是基于 LAME 库的,LAME 是一个开源的 MP3 编码器。

以下是如何在 Flutter 项目中使用 dart_lame 插件的步骤:

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 dart_lame 依赖:

dependencies:
  flutter:
    sdk: flutter
  dart_lame: ^0.2.0  # 请检查最新版本

然后运行 flutter pub get 来安装依赖。

2. 导入库

在你的 Dart 文件中导入 dart_lame 库:

import 'package:dart_lame/dart_lame.dart';

3. 初始化编码器

你需要初始化一个 LameEncoder 对象来开始编码音频数据。你可以指定采样率、通道数、比特率等参数。

final encoder = LameEncoder(
  sampleRate: 44100,  // 采样率 (Hz)
  numChannels: 2,     // 通道数 (1 为单声道,2 为立体声)
  bitRate: 128,       // 比特率 (kbps)
);

4. 编码音频数据

你可以使用 encoder.encode 方法将 PCM 音频数据编码为 MP3 格式。这个方法接受一个 List<int> 类型的 PCM 数据,并返回一个 List<int> 类型的 MP3 数据。

List<int> pcmData = ...;  // 你的 PCM 音频数据
List<int> mp3Data = encoder.encode(pcmData);

5. 结束编码

在编码完成后,你需要调用 encoder.close 方法来释放资源并获取最终的 MP3 数据。

List<int> finalMp3Data = encoder.close();

6. 保存或处理 MP3 数据

你可以将 finalMp3Data 保存为文件或进行其他处理。

import 'dart:io';

void saveMp3File(List<int> mp3Data, String filePath) {
  final file = File(filePath);
  file.writeAsBytesSync(mp3Data);
}

saveMp3File(finalMp3Data, 'output.mp3');

完整示例

以下是一个完整的示例,展示如何使用 dart_lame 将 PCM 音频数据编码为 MP3 文件:

import 'package:dart_lame/dart_lame.dart';
import 'dart:io';

void main() async {
  // 假设你有一个 PCM 文件
  final pcmFile = File('input.pcm');
  final pcmData = await pcmFile.readAsBytes();

  // 初始化编码器
  final encoder = LameEncoder(
    sampleRate: 44100,
    numChannels: 2,
    bitRate: 128,
  );

  // 编码 PCM 数据
  List<int> mp3Data = encoder.encode(pcmData);

  // 结束编码并获取最终的 MP3 数据
  List<int> finalMp3Data = encoder.close();

  // 保存 MP3 文件
  final mp3File = File('output.mp3');
  await mp3File.writeAsBytes(finalMp3Data);

  print('MP3 文件已保存');
}
回到顶部