我正在使用 flutter_ffmpeg_kit_full 包向我的视频添加字幕。首先我循环遍历所有单词并创建一个 srt 文件并将其存储在临时文件夹中。
Future<String> _createSrtFile() async {
String filePath = await getSrtOutputFilePath();
final file = File(filePath);
final buffer = StringBuffer();
for (int i = 0; i < widget.words.length; i++) {
final word = widget.words[i];
final startTime = _formatSrtTime(word['startTime'].toDouble());
final endTime = _formatSrtTime(word['endTime'].toDouble());
final text = word['word'];
buffer.writeln('${i + 1}');
buffer.writeln('$startTime --> $endTime');
buffer.writeln('$text');
buffer.writeln('');
}
await file.writeAsString(buffer.toString());
return filePath;
}
String _formatSrtTime(double seconds) {
final int hours = seconds ~/ 3600;
final int minutes = ((seconds % 3600) ~/ 60);
final int secs = (seconds % 60).toInt();
final int millis = ((seconds - secs) * 1000).toInt() % 1000;
return '${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}:${secs.toString().padLeft(2, '0')},${millis.toString().padLeft(3, '0')}';
}
然后我创建一个 future 函数来使用 ffmpeg 命令处理导出
Future<void> _exportVideo() async {
final hasPermission = await _requestStoragePermission();
if (!hasPermission) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Storage permission denied')));
return;
}
setState(() {
_isProcessing = true;
_outputFilePath = "";
});
try {
final srtFilePath = await _createSrtFile();
String videoPath = widget.videoFile!.path;
String _outputPath = await getOutputFilePath();
final command =
'-i $videoPath -vf "drawtext="text=\'Stack Overflow\':fontcolor=white:fontsize=24:box=1:[email protected]:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2"" -codec:a copy $_outputPath';
// final cmd = [
// '-i',
// videoPath,
// '-preset',
// 'ultrafast',
// '-vf',
// 'subtitles=$srtFilePath:force_style=\'Fontname=Roboto Bold,FontSize=30,MarginV=70,PrimaryColour=ffffff,OutlineColour=000000\'',
// _outputPath
// ];
// FFmpegKit.executeWithArguments(cmd)
print('Executing FFmpeg command: $command');
await FFmpegKit.execute(command).then((session) async {
final returnCode = await session.getReturnCode();
final output = await session.getOutput();
final failStackTrace = await session.getFailStackTrace();
print('FFmpeg Output: $output');
if (failStackTrace != null) {
print('FFmpeg Fail StackTrace: $failStackTrace');
}
if (ReturnCode.isSuccess(returnCode)) {
setState(() {
_outputFilePath = _outputPath;
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Export successful!')));
} else {
final logs = await session.getLogsAsString();
print('FFmpeg Logs: $logs');
ScaffoldMessenger.of(context)
.showSnackBar(const SnackBar(content: Text('Export failed!')));
}
});
} catch (e) {
print('Error: $e');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Export failed with error: $e')));
} finally {
setState(() {
_isProcessing = false;
});
}
}
我导出时没有字幕,效果很好。但问题是当我尝试使用字幕时。我不知道我犯了什么错,但这段代码无法导出。你能帮我一下吗?这也是 srt 和视频本身的路径。
Future<String> getOutputFilePath() async {
final Directory? downloadsDir = await getDownloadsDirectory();
final timestamp = DateTime.now().millisecondsSinceEpoch;
final name = "output-$timestamp.avi";
return '${downloadsDir!.path}/$name'; // Save in downloads folder
}
Future<String> getSrtOutputFilePath() async {
final Directory? downloadsDir = await getDownloadsDirectory();
final timestamp = DateTime.now().millisecondsSinceEpoch;
final name = "caption-$timestamp.srt";
return '${downloadsDir!.path}/$name'; // Save in downloads folder
}
我认为文本部分正在添加叠加层。尝试下面的部分,看看这是否适合您。
Future<void> _exportVideo() async {
final hasPermission = await _requestStoragePermission();
if (!hasPermission) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Storage permission denied')));
return;
}
setState(() {
_isProcessing = true;
_outputFilePath = "";
});
try {
final srtFilePath = await _createSrtFile();
String videoPath = widget.videoFile!.path;
String _outputPath = await getOutputFilePath();
// Use the correct FFmpeg command for adding subtitles
final command = '-i $videoPath -vf subtitles=$srtFilePath -c:a copy $_outputPath';
print('Executing FFmpeg command: $command');
await FFmpegKit.execute(command).then((session) async {
final returnCode = await session.getReturnCode();
final output = await session.getOutput();
final failStackTrace = await session.getFailStackTrace();
print('FFmpeg Output: $output');
if (failStackTrace != null) {
print('FFmpeg Fail StackTrace: $failStackTrace');
}
if (ReturnCode.isSuccess(returnCode)) {
setState(() {
_outputFilePath = _outputPath;
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Export successful!')));
} else {
final logs = await session.getLogsAsString();
print('FFmpeg Logs: $logs');
ScaffoldMessenger.of(context)
.showSnackBar(const SnackBar(content: Text('Export failed!')));
}
});
} catch (e) {
print('Error: $e');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Export failed with error: $e')));
} finally {
setState(() {
_isProcessing = false;
});
}
}
命令已更改我已删除了绘图文本部分。