WPF: Add remux to toolbox

This commit is contained in:
Genteure 2021-08-10 00:49:46 +08:00
parent 7dd2afd9de
commit df8559424c
9 changed files with 211 additions and 0 deletions

View File

@ -144,6 +144,9 @@
<Compile Include="Pages\ToolboxAutoFixPage.xaml.cs">
<DependentUpon>ToolboxAutoFixPage.xaml</DependentUpon>
</Compile>
<Compile Include="Pages\ToolboxRemuxPage.xaml.cs">
<DependentUpon>ToolboxRemuxPage.xaml</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="SingleInstance.cs" />
<Compile Include="Properties\Strings.Designer.cs">
@ -242,6 +245,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Pages\ToolboxRemuxPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Resources\ConverterResources.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -287,6 +294,9 @@
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Strings.zh-Hant.resx" />
<None Include="lib\miniffmpeg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Properties\app.manifest" />
<Resource Include="ico.ico" />
</ItemGroup>
@ -308,6 +318,9 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="CliWrap">
<Version>3.3.2</Version>
</PackageReference>
<PackageReference Include="GitVersion.MsBuild" Version="5.6.6">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>

View File

@ -102,6 +102,12 @@
<ui:PathIcon Style="{StaticResource PathIconDataAutoFix}"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
<ui:NavigationViewItem l:ResxLocalizationProvider.DefaultDictionary="Strings"
Content="{l:Loc Toolbox_Remux_Title}" Tag="ToolboxRemuxPage">
<ui:NavigationViewItem.Icon>
<ui:PathIcon Style="{StaticResource PathIconDataAlphaRCircleOutline}"/>
</ui:NavigationViewItem.Icon>
</ui:NavigationViewItem>
</ui:NavigationViewItem.MenuItems>
</ui:NavigationViewItem>
</ui:NavigationView.MenuItems>

View File

@ -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;

View File

@ -0,0 +1,42 @@
<ui:Page
x:Class="BililiveRecorder.WPF.Pages.ToolboxRemuxPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ui="http://schemas.modernwpf.com/2019"
xmlns:l="https://github.com/XAMLMarkupExtensions/WPFLocalizationExtension"
l:LocalizeDictionary.DesignCulture=""
l:ResxLocalizationProvider.DefaultAssembly="BililiveRecorder.WPF"
l:ResxLocalizationProvider.DefaultDictionary="Strings"
xmlns:local="clr-namespace:BililiveRecorder.WPF.Pages"
xmlns:model="clr-namespace:BililiveRecorder.WPF.Models"
xmlns:c="clr-namespace:BililiveRecorder.WPF.Converters"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="ToolboxRemuxPage">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Margin="10" Padding="10" FontSize="20" HorizontalAlignment="Center" Content="{l:Loc Toolbox_Remux_Title}" Click="RemuxButton_Click"/>
<TextBlock Grid.Row="1" TextAlignment="Center">
用法
<LineBreak/>
1. 点击上面的转封装按钮<LineBreak/>
2. 选择要转封装的 FLV 文件<LineBreak/>
3. 选择 MP4 保存位置<LineBreak/>
<LineBreak/>
说明
<LineBreak/>
本工具基于 FFmpeg 实现,只提供最基本的转封装功能。<LineBreak/>
只支持从 FLV 转封装到 MP4如需其他格式请使用其他工具。<LineBreak/>
转封装时会占满硬盘IO可能导致正在进行的录播中断。<LineBreak/>
转封装大文件会花一两分钟时间,请耐心等待。<LineBreak/>
如果录播文件存在问题,请先用录播修复工具修复后再转封装。<LineBreak/>
如果文件存在问题,转封装后就无法修复了。<LineBreak/>
标准录制模式录出来的文件不需要手动修复。
</TextBlock>
</Grid>
</ui:Page>

View File

@ -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
{
/// <summary>
/// Interaction logic for ToolboxRemuxPage.xaml
/// </summary>
public partial class ToolboxRemuxPage
{
private static readonly ILogger logger = Log.ForContext<ToolboxRemuxPage>();
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<string>("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<string>("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);
}
}
}

View File

@ -1567,6 +1567,33 @@ namespace BililiveRecorder.WPF.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to 选择需要转封装的 FLV 文件.
/// </summary>
public static string Toolbox_Remux_OpenFileTitle {
get {
return ResourceManager.GetString("Toolbox_Remux_OpenFileTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 选择 MP4 文件保存位置.
/// </summary>
public static string Toolbox_Remux_SaveFileTitle {
get {
return ResourceManager.GetString("Toolbox_Remux_SaveFileTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 转封装.
/// </summary>
public static string Toolbox_Remux_Title {
get {
return ResourceManager.GetString("Toolbox_Remux_Title", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 工具箱.
/// </summary>

View File

@ -647,6 +647,15 @@ Will use default setting and disable user input when checked.</comment>
<data name="Toolbox_AutoFix_Title" xml:space="preserve">
<value>录播修复</value>
</data>
<data name="Toolbox_Remux_OpenFileTitle" xml:space="preserve">
<value>选择需要转封装的 FLV 文件</value>
</data>
<data name="Toolbox_Remux_SaveFileTitle" xml:space="preserve">
<value>选择 MP4 文件保存位置</value>
</data>
<data name="Toolbox_Remux_Title" xml:space="preserve">
<value>转封装</value>
</data>
<data name="Toolbox_Title" xml:space="preserve">
<value>工具箱</value>
</data>

View File

@ -91,6 +91,9 @@
<Style TargetType="ui:PathIcon" x:Key="PathIconDataBugOutline">
<Setter Property="Data" Value="M20,8H17.19C16.74,7.2 16.12,6.5 15.37,6L17,4.41L15.59,3L13.42,5.17C12.96,5.06 12.5,5 12,5C11.5,5 11.05,5.06 10.59,5.17L8.41,3L7,4.41L8.62,6C7.87,6.5 7.26,7.21 6.81,8H4V10H6.09C6.03,10.33 6,10.66 6,11V12H4V14H6V15C6,15.34 6.03,15.67 6.09,16H4V18H6.81C8.47,20.87 12.14,21.84 15,20.18C15.91,19.66 16.67,18.9 17.19,18H20V16H17.91C17.97,15.67 18,15.34 18,15V14H20V12H18V11C18,10.66 17.97,10.33 17.91,10H20V8M16,15A4,4 0 0,1 12,19A4,4 0 0,1 8,15V11A4,4 0 0,1 12,7A4,4 0 0,1 16,11V15M14,10V12H10V10H14M10,14H14V16H10V14Z"/>
</Style>
<Style TargetType="ui:PathIcon" x:Key="PathIconDataAlphaRCircleOutline">
<Setter Property="Data" Value="M9,7H13A2,2 0 0,1 15,9V11C15,11.84 14.5,12.55 13.76,12.85L15,17H13L11.8,13H11V17H9V7M11,9V11H13V9H11M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12C4,16.41 7.58,20 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4Z"/>
</Style>
<Style TargetType="ui:PathIcon" x:Key="PathIconData">
<Setter Property="Data" Value=""/>
</Style>

Binary file not shown.