diff --git a/BililiveRecorder.WPF/BililiveRecorder.WPF.csproj b/BililiveRecorder.WPF/BililiveRecorder.WPF.csproj
index f3eb15a..28935a8 100644
--- a/BililiveRecorder.WPF/BililiveRecorder.WPF.csproj
+++ b/BililiveRecorder.WPF/BililiveRecorder.WPF.csproj
@@ -144,6 +144,9 @@
ToolboxAutoFixPage.xaml
+
+ ToolboxRemuxPage.xaml
+
@@ -242,6 +245,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
@@ -287,6 +294,9 @@
Strings.Designer.cs
+
+ PreserveNewest
+
@@ -308,6 +318,9 @@
+
+ 3.3.2
+
all
runtime; build; native; contentfiles; analyzers
diff --git a/BililiveRecorder.WPF/Pages/RootPage.xaml b/BililiveRecorder.WPF/Pages/RootPage.xaml
index b9f6a4d..a020e12 100644
--- a/BililiveRecorder.WPF/Pages/RootPage.xaml
+++ b/BililiveRecorder.WPF/Pages/RootPage.xaml
@@ -102,6 +102,12 @@
+
+
+
+
+
diff --git a/BililiveRecorder.WPF/Pages/RootPage.xaml.cs b/BililiveRecorder.WPF/Pages/RootPage.xaml.cs
index 609c5cd..9fa73ec 100644
--- a/BililiveRecorder.WPF/Pages/RootPage.xaml.cs
+++ b/BililiveRecorder.WPF/Pages/RootPage.xaml.cs
@@ -53,6 +53,7 @@ namespace BililiveRecorder.WPF.Pages
AddType(typeof(AdvancedSettingsPage));
AddType(typeof(AnnouncementPage));
AddType(typeof(ToolboxAutoFixPage));
+ AddType(typeof(ToolboxRemuxPage));
this.Model = new RootModel();
this.DataContext = this.Model;
diff --git a/BililiveRecorder.WPF/Pages/ToolboxRemuxPage.xaml b/BililiveRecorder.WPF/Pages/ToolboxRemuxPage.xaml
new file mode 100644
index 0000000..0cc29d4
--- /dev/null
+++ b/BililiveRecorder.WPF/Pages/ToolboxRemuxPage.xaml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+ 用法
+
+ 1. 点击上面的转封装按钮
+ 2. 选择要转封装的 FLV 文件
+ 3. 选择 MP4 保存位置
+
+ 说明
+
+ 本工具基于 FFmpeg 实现,只提供最基本的转封装功能。
+ 只支持从 FLV 转封装到 MP4,如需其他格式请使用其他工具。
+ 转封装时会占满硬盘IO,可能导致正在进行的录播中断。
+ 转封装大文件会花一两分钟时间,请耐心等待。
+ 如果录播文件存在问题,请先用录播修复工具修复后再转封装。
+ 如果文件存在问题,转封装后就无法修复了。
+ 标准录制模式录出来的文件不需要手动修复。
+
+
+
diff --git a/BililiveRecorder.WPF/Pages/ToolboxRemuxPage.xaml.cs b/BililiveRecorder.WPF/Pages/ToolboxRemuxPage.xaml.cs
new file mode 100644
index 0000000..3ad7fef
--- /dev/null
+++ b/BililiveRecorder.WPF/Pages/ToolboxRemuxPage.xaml.cs
@@ -0,0 +1,110 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using System.Windows;
+using CliWrap;
+using CliWrap.Buffered;
+using Microsoft.WindowsAPICodePack.Dialogs;
+using Serilog;
+using WPFLocalizeExtension.Extensions;
+
+namespace BililiveRecorder.WPF.Pages
+{
+ ///
+ /// Interaction logic for ToolboxRemuxPage.xaml
+ ///
+ public partial class ToolboxRemuxPage
+ {
+ private static readonly ILogger logger = Log.ForContext();
+ private static readonly string DesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
+ private static readonly string FFmpegWorkingDirectory;
+ private static readonly string FFmpegPath;
+
+ static ToolboxRemuxPage()
+ {
+ FFmpegWorkingDirectory = Path.Combine(Path.GetDirectoryName(typeof(ToolboxRemuxPage).Assembly.Location), "lib");
+ FFmpegPath = Path.Combine(FFmpegWorkingDirectory, "miniffmpeg");
+ }
+
+ public ToolboxRemuxPage()
+ {
+ this.InitializeComponent();
+ }
+
+#pragma warning disable VSTHRD100 // Avoid async void methods
+ private async void RemuxButton_Click(object sender, RoutedEventArgs e)
+#pragma warning restore VSTHRD100 // Avoid async void methods
+ {
+ try
+ {
+ await this.RunAsync();
+ }
+ catch (Exception ex)
+ {
+ logger.Warning(ex, "转封装时发生未知错误");
+ }
+ }
+
+ private async Task RunAsync()
+ {
+ string source, target;
+
+ {
+
+ var d = new CommonOpenFileDialog()
+ {
+ Title = LocExtension.GetLocalizedValue("BililiveRecorder.WPF:Strings:Toolbox_Remux_OpenFileTitle"),
+ AllowNonFileSystemItems = false,
+ DefaultDirectory = DesktopPath,
+ DefaultExtension = "flv",
+ EnsureFileExists = true,
+ EnsurePathExists = true,
+ EnsureValidNames = true,
+ Multiselect = false,
+ };
+
+ d.Filters.Add(new CommonFileDialogFilter("FLV", "*.flv"));
+
+ if (d.ShowDialog() != CommonFileDialogResult.Ok)
+ return;
+
+ source = d.FileName;
+ }
+
+ {
+ var d = new CommonSaveFileDialog()
+ {
+ Title = LocExtension.GetLocalizedValue("BililiveRecorder.WPF:Strings:Toolbox_Remux_SaveFileTitle"),
+ AlwaysAppendDefaultExtension = true,
+ DefaultDirectory = DesktopPath,
+ DefaultExtension = "mp4",
+ EnsurePathExists = true,
+ EnsureValidNames = true,
+ InitialDirectory = Path.GetDirectoryName(source),
+ DefaultFileName = Path.GetFileNameWithoutExtension(source),
+ };
+
+ d.Filters.Add(new CommonFileDialogFilter("MP4", "*.mp4"));
+
+ if (d.ShowDialog() != CommonFileDialogResult.Ok)
+ return;
+
+ target = d.FileName;
+ }
+
+ logger.Debug("Remux starting, {Source}, {Target}", source, target);
+
+ var result = await Cli.Wrap(FFmpegPath)
+ .WithValidation(CommandResultValidation.None)
+ .WithWorkingDirectory(FFmpegWorkingDirectory)
+ .WithArguments(new[] { "-hide_banner", "-loglevel", "error", "-y", "-i", source, "-c", "copy", target })
+#if DEBUG
+ .ExecuteBufferedAsync();
+#else
+ .ExecuteAsync();
+#endif
+
+ logger.Debug("Remux completed {@Result}", result);
+ }
+ }
+}
diff --git a/BililiveRecorder.WPF/Properties/Strings.Designer.cs b/BililiveRecorder.WPF/Properties/Strings.Designer.cs
index 0928be3..b929611 100644
--- a/BililiveRecorder.WPF/Properties/Strings.Designer.cs
+++ b/BililiveRecorder.WPF/Properties/Strings.Designer.cs
@@ -1567,6 +1567,33 @@ namespace BililiveRecorder.WPF.Properties {
}
}
+ ///
+ /// Looks up a localized string similar to 选择需要转封装的 FLV 文件.
+ ///
+ public static string Toolbox_Remux_OpenFileTitle {
+ get {
+ return ResourceManager.GetString("Toolbox_Remux_OpenFileTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to 选择 MP4 文件保存位置.
+ ///
+ public static string Toolbox_Remux_SaveFileTitle {
+ get {
+ return ResourceManager.GetString("Toolbox_Remux_SaveFileTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to 转封装.
+ ///
+ public static string Toolbox_Remux_Title {
+ get {
+ return ResourceManager.GetString("Toolbox_Remux_Title", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to 工具箱.
///
diff --git a/BililiveRecorder.WPF/Properties/Strings.resx b/BililiveRecorder.WPF/Properties/Strings.resx
index 90fe731..997c3fd 100644
--- a/BililiveRecorder.WPF/Properties/Strings.resx
+++ b/BililiveRecorder.WPF/Properties/Strings.resx
@@ -647,6 +647,15 @@ Will use default setting and disable user input when checked.
录播修复
+
+ 选择需要转封装的 FLV 文件
+
+
+ 选择 MP4 文件保存位置
+
+
+ 转封装
+
工具箱
diff --git a/BililiveRecorder.WPF/Resources/IconResources.xaml b/BililiveRecorder.WPF/Resources/IconResources.xaml
index 55b35c1..7e87ed2 100644
--- a/BililiveRecorder.WPF/Resources/IconResources.xaml
+++ b/BililiveRecorder.WPF/Resources/IconResources.xaml
@@ -91,6 +91,9 @@
+
diff --git a/BililiveRecorder.WPF/lib/miniffmpeg b/BililiveRecorder.WPF/lib/miniffmpeg
new file mode 100644
index 0000000..a11b219
Binary files /dev/null and b/BililiveRecorder.WPF/lib/miniffmpeg differ