Skip to content

Commit fad9ca6

Browse files
committed
Add option to select FFmpeg decoding mode
We have 4 options here: - Automatic - Automatic with System Decoder - Force System Decoder - Force FFmpeg Software Decoder
1 parent 081400f commit fad9ca6

11 files changed

Lines changed: 280 additions & 6 deletions

File tree

CollapseLauncher/Classes/GameManagement/ImageBackground/ImageBackgroundManager.FFmpeg.cs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using CollapseLauncher.Helper;
22
using CollapseLauncher.Helper.StreamUtility;
3+
using FFmpegInteropX;
34
using Hi3Helper;
45
using Hi3Helper.Shared.Region;
56
using System;
@@ -33,8 +34,11 @@ public partial class ImageBackgroundManager
3334
{
3435
#region Shared/Static Properties and Fields
3536

36-
private const string GlobalIsUseFFmpegConfigKey = "GlobalIsUseFFmpeg";
37-
private const string GlobalFFmpegCustomPathConfigKey = "GlobalFFmpegCustomPath";
37+
private const string GlobalIsUseFFmpegConfigKey = "GlobalIsUseFFmpeg";
38+
private const string GlobalFFmpegCustomPathConfigKey = "GlobalFFmpegCustomPath";
39+
private const string GlobalFFmpegDecodingModeConfigKey = "GlobalFFmpegDecodingMode";
40+
41+
public VideoDecoderMode[] AvailableFFmpegDecodingModes => field ??= Enum.GetValues<VideoDecoderMode>();
3842

3943
public bool GlobalIsUseFFmpeg
4044
{
@@ -68,6 +72,31 @@ public bool GlobalIsFFmpegCurrentlyUsed
6872
}
6973
}
7074

75+
public VideoDecoderMode GlobalFFmpegDecodingMode
76+
{
77+
get
78+
{
79+
string? value = LauncherConfig.GetAppConfigValue(GlobalFFmpegDecodingModeConfigKey);
80+
if (Enum.TryParse<VideoDecoderMode>(value, out var result))
81+
{
82+
return result;
83+
}
84+
85+
return default;
86+
}
87+
set
88+
{
89+
if (!Enum.IsDefined<VideoDecoderMode>(value))
90+
{
91+
value = default;
92+
}
93+
94+
string valueStr = value.ToString();
95+
LauncherConfig.SetAndSaveConfigValue(GlobalFFmpegDecodingModeConfigKey, valueStr);
96+
OnPropertyChanged();
97+
}
98+
}
99+
71100
#endregion
72101

73102
public void RefreshFFmpegBinding()

CollapseLauncher/Classes/GameManagement/ImageBackground/ImageBackgroundManager.Loaders.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,11 @@ private void SpawnImageLayer(Uri? overlayFilePath,
198198
layerElement.IsVideoAutoplay = WindowUtility.CurrentWindowIsVisible;
199199
}
200200

201+
layerElement.BindProperty(LayeredBackgroundImage.FfmpegDecoderModeProperty,
202+
this,
203+
nameof(GlobalFFmpegDecodingMode),
204+
bindingMode: BindingMode.OneWay);
205+
201206
layerElement.BindProperty(LayeredBackgroundImage.ParallaxHoverSourceProperty,
202207
this,
203208
nameof(GlobalParallaxHoverSource),

CollapseLauncher/Classes/GameManagement/ImageBackground/ImageBackgroundManager.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
using CollapseLauncher.Helper.Image;
33
using CollapseLauncher.Helper.LauncherApiLoader.HoYoPlay;
44
using CollapseLauncher.Helper.Metadata;
5+
using CollapseLauncher.Interfaces;
56
using CollapseLauncher.Interfaces.Class;
67
using CollapseLauncher.XAMLs.Theme.CustomControls;
8+
using Google.Protobuf.WellKnownTypes;
79
using Hi3Helper.SentryHelper;
810
using Hi3Helper.Shared.Region;
911
using Microsoft.UI.Xaml;
@@ -27,7 +29,8 @@ namespace CollapseLauncher.GameManagement.ImageBackground;
2729

2830
[GeneratedBindableCustomProperty]
2931
public partial class ImageBackgroundManager
30-
: NotifyPropertyChanged
32+
: NotifyPropertyChanged,
33+
INotifyAllPropertyChanged
3134
{
3235
internal static ImageBackgroundManager Shared => field ??= new ImageBackgroundManager();
3336

@@ -612,6 +615,12 @@ public void ResetContexts()
612615
Interlocked.Exchange(ref _previousContextHash, 0);
613616
ImageContextSources.Clear();
614617
}
618+
619+
void INotifyAllPropertyChanged.NotifyAllChanged()
620+
{
621+
OnPropertyChanged(nameof(GlobalFFmpegDecodingMode));
622+
OnPropertyChanged(nameof(AvailableFFmpegDecodingModes));
623+
}
615624
}
616625

617626
[GeneratedBindableCustomProperty]
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace CollapseLauncher.Interfaces;
6+
7+
public interface INotifyAllPropertyChanged
8+
{
9+
void NotifyAllChanged();
10+
}

CollapseLauncher/XAMLs/MainApp/Pages/SettingsPage.xaml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
xmlns:innerConfig="using:Hi3Helper.Shared.Region"
1616
xmlns:localWindowSize="using:CollapseLauncher.WindowSize"
1717
xmlns:localeSourceGen="using:Hi3Helper.LocaleSourceGen"
18+
xmlns:ffmpegInterop="using:FFmpegInteropX"
1819
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
1920
xmlns:plugins="using:CollapseLauncher.Plugins"
2021
Loaded="Page_Loaded"
@@ -35,6 +36,9 @@
3536
<conv:BooleanToIsEnabledOpacityConverter x:Key="BooleanToIsEnabledOpacityConverter" />
3637
<conv:NullableVisibilityConverter x:Key="NullableVisibilityConverter" />
3738
<conv:RemoveNewLineStringConverter x:Key="RemoveNewLineStringConverter" />
39+
<conv:FFmpegVideoDecoderModeToIndexConverter x:Key="FFmpegVideoDecoderModeToIndexConverter" />
40+
<conv:FFmpegVideoDecoderModeToHelpLocaleConverter x:Key="FFmpegVideoDecoderModeToHelpLocaleConverter" />
41+
<conv:ObjectToLocaleKvpConverter x:Key="ObjectToLocaleKvpConverter" />
3842
</Page.Resources>
3943
<Grid>
4044
<ScrollViewer>
@@ -450,6 +454,57 @@
450454
</Grid>
451455
</StackPanel>
452456
</Grid>
457+
<ComboBox x:Name="VideoCodecFfmpegDecodingMethod"
458+
CornerRadius="14"
459+
IsEnabled="{Binding GlobalIsFFmpegAvailable, Mode=OneWay, Converter={StaticResource BooleanVisibilityConverter}}"
460+
ItemsSource="{Binding AvailableFFmpegDecodingModes, Mode=OneWay}"
461+
Margin="0,8,0,0"
462+
Visibility="{Binding ElementName=VideoCodecUseFfmpeg, Path=IsOn, Mode=OneWay, Converter={StaticResource BooleanVisibilityConverter}}"
463+
SelectedIndex="{Binding GlobalFFmpegDecodingMode, Mode=TwoWay, Converter={StaticResource FFmpegVideoDecoderModeToIndexConverter}}">
464+
<ComboBox.ItemTemplate>
465+
<DataTemplate x:DataType="ffmpegInterop:VideoDecoderMode">
466+
<TextBlock Text="{x:Bind helper:Locale.Current.Lang._DictKvpFFmpegDecodingMode, Mode=OneWay, Converter={StaticResource ObjectToLocaleKvpConverter}, ConverterParameter={Binding}}"
467+
ToolTipService.ToolTip="{Binding Converter={StaticResource FFmpegVideoDecoderModeToHelpLocaleConverter}, Mode=OneWay, ConverterParameter='Tooltip'}"/>
468+
</DataTemplate>
469+
</ComboBox.ItemTemplate>
470+
<ComboBox.Header>
471+
<StackPanel Orientation="Horizontal"
472+
Spacing="8">
473+
<TextBlock Text="{x:Bind helper:Locale.Current.Lang._SettingsPage.VideoBackground_FFmpegVideoDecodingMethod, Mode=OneWay}"/>
474+
<Button Width="24"
475+
Height="24"
476+
Padding="0"
477+
CornerRadius="4"
478+
Style="{ThemeResource AcrylicButtonStyle}">
479+
<Button.Content>
480+
<FontIcon FontFamily="{ThemeResource FontAwesome}"
481+
FontSize="10"
482+
Glyph="&#x3f;" />
483+
</Button.Content>
484+
<Button.Flyout>
485+
<Flyout Placement="Right">
486+
<ItemsRepeater ItemsSource="{Binding AvailableFFmpegDecodingModes, Mode=OneWay}"
487+
Margin="0,-8">
488+
<ItemsRepeater.ItemTemplate>
489+
<DataTemplate x:DataType="ffmpegInterop:VideoDecoderMode">
490+
<StackPanel MaxWidth="420"
491+
Margin="0,8"
492+
Spacing="4">
493+
<TextBlock Style="{ThemeResource BodyLargeStrongTextBlockStyle}"
494+
Text="{Binding Converter={StaticResource FFmpegVideoDecoderModeToHelpLocaleConverter}, Mode=OneWay}"
495+
TextWrapping="Wrap"/>
496+
<TextBlock Text="{Binding Converter={StaticResource FFmpegVideoDecoderModeToHelpLocaleConverter}, Mode=OneWay, ConverterParameter='Tooltip'}"
497+
TextWrapping="Wrap"/>
498+
</StackPanel>
499+
</DataTemplate>
500+
</ItemsRepeater.ItemTemplate>
501+
</ItemsRepeater>
502+
</Flyout>
503+
</Button.Flyout>
504+
</Button>
505+
</StackPanel>
506+
</ComboBox.Header>
507+
</ComboBox>
453508
</StackPanel>
454509
<TextBlock Margin="0,16,0,8"
455510
Style="{ThemeResource SubtitleTextBlockStyle}"

CollapseLauncher/XAMLs/MainApp/Pages/SettingsPage.xaml.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
using CollapseLauncher.XAMLs.Theme.ContentDialog;
2020
using CollapseLauncher.XAMLs.Theme.CustomControls;
2121
using CommunityToolkit.WinUI;
22+
using FFmpegInteropX;
2223
using Hi3Helper;
2324
using Hi3Helper.EncTool;
2425
using Hi3Helper.Plugin.Core.Management;
@@ -57,6 +58,7 @@
5758
using static Hi3Helper.Logger;
5859
using static Hi3Helper.Shared.Region.LauncherConfig;
5960
using CollapseUIExt = CollapseLauncher.Extension.UIElementExtensions;
61+
using CollapseLauncher.Interfaces;
6062

6163
// ReSharper disable AsyncVoidMethod
6264
// ReSharper disable SwitchStatementHandlesSomeKnownEnumValuesWithDefault
@@ -93,6 +95,8 @@ public sealed partial class SettingsPage : Page
9395
private List<string> DialogMethodNames { get; }
9496
public string SelectedDialogMethodName { get; set; }
9597

98+
private EnumToIndexConverter<VideoDecoderMode> _ffmpegDecodingModeConverter = StaticConverter<EnumToIndexConverter<VideoDecoderMode>>.Shared;
99+
96100
#nullable enable
97101
private string? _previousSearchQuery;
98102
#nullable restore
@@ -799,6 +803,10 @@ private void LanguageSelector_SelectionChanged(object sender, SelectionChangedEv
799803
string selectedKey = Locale.Current.Lang.LanguageID;
800804
PluginManager.SetPluginLocaleId(selectedKey);
801805

806+
((INotifyAllPropertyChanged)ImageBackgroundManager.Shared).NotifyAllChanged();
807+
CustomDnsConnectionTypeComboBox.UpdateLayout();
808+
CustomDnsProviderListComboBox.UpdateLayout();
809+
VideoCodecFfmpegDecodingMethod.UpdateLayout();
802810
InitializeSettingsSearch();
803811
}
804812

CollapseLauncher/XAMLs/MainApp/ValueConverters.cs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using CollapseLauncher.Helper;
33
using CollapseLauncher.Helper.Metadata;
44
using CollapseLauncher.Plugins;
5+
using FFmpegInteropX;
56
using Hi3Helper;
67
using Hi3Helper.Data;
78
using Hi3Helper.EncTool;
@@ -19,6 +20,7 @@
1920
using System.Collections;
2021
using System.Collections.Generic;
2122
using System.IO;
23+
using System.Linq;
2224
using System.Net.Http;
2325
using System.Numerics;
2426
using System.Threading;
@@ -1212,4 +1214,112 @@ public object ConvertBack(object value, Type targetType, object parameter, strin
12121214
throw new NotImplementedException();
12131215
}
12141216
}
1217+
1218+
public partial class ObjectToLocaleKvpConverter : IValueConverter
1219+
{
1220+
public object? Convert(object? value, Type targetType, object? parameter, string language)
1221+
{
1222+
if (value is not Dictionary<string, string> asKvp)
1223+
{
1224+
return parameter;
1225+
}
1226+
1227+
string? paramStr = parameter?.ToString();
1228+
if (paramStr == null ||
1229+
!asKvp.TryGetValue(paramStr, out string? localizedValue))
1230+
{
1231+
return parameter;
1232+
}
1233+
1234+
return localizedValue;
1235+
}
1236+
1237+
public object ConvertBack(object value, Type targetType, object parameter, string language)
1238+
=> throw new NotImplementedException();
1239+
}
1240+
1241+
public partial class FFmpegVideoDecoderModeToLocalizedConverter : IValueConverter
1242+
{
1243+
public object? Convert(object? value, Type targetType, object parameter, string language)
1244+
{
1245+
if (value is not VideoDecoderMode asEnum)
1246+
{
1247+
return value;
1248+
}
1249+
1250+
Dictionary<string, string> dict = [];
1251+
string enumStr = asEnum.ToString();
1252+
1253+
if (!dict.TryGetValue(enumStr, out string? localedString))
1254+
{
1255+
return enumStr;
1256+
}
1257+
1258+
return localedString;
1259+
}
1260+
1261+
public object ConvertBack(object value, Type targetType, object parameter, string language)
1262+
=> throw new NotImplementedException();
1263+
}
1264+
1265+
public partial class FFmpegVideoDecoderModeToHelpLocaleConverter : IValueConverter
1266+
{
1267+
public object? Convert(object? value, Type targetType, object parameter, string language)
1268+
{
1269+
if (value is not VideoDecoderMode asEnum)
1270+
{
1271+
return value;
1272+
}
1273+
1274+
bool isConvertTooltip = parameter is string parameterStr &&
1275+
parameterStr.Equals("Tooltip", StringComparison.OrdinalIgnoreCase);
1276+
1277+
var lang = Locale.Current.Lang;
1278+
1279+
Dictionary<string, string> dict = (isConvertTooltip ? lang?._DictKvpFFmpegDecodingModeTooltip : lang?._DictKvpFFmpegDecodingMode) ?? [];
1280+
string enumStr = asEnum.ToString();
1281+
1282+
if (!dict.TryGetValue(enumStr, out string? localedString))
1283+
{
1284+
return lang?._Misc?.DescriptionNotAvailable ?? enumStr;
1285+
}
1286+
1287+
return localedString;
1288+
}
1289+
1290+
public object ConvertBack(object value, Type targetType, object parameter, string language)
1291+
=> throw new NotImplementedException();
1292+
}
1293+
1294+
public partial class FFmpegVideoDecoderModeToIndexConverter : EnumToIndexConverter<VideoDecoderMode>;
1295+
1296+
public partial class EnumToIndexConverter<TEnum> : IValueConverter
1297+
where TEnum : struct, Enum
1298+
{
1299+
private static List<TEnum> _enums = [.. Enum.GetValues<TEnum>()];
1300+
1301+
public object? Convert(object? value, Type targetType, object parameter, string language)
1302+
{
1303+
if (value is not TEnum asEnum ||
1304+
!Enum.IsDefined<TEnum>(asEnum))
1305+
{
1306+
asEnum = default;
1307+
}
1308+
1309+
int indexOf = _enums.IndexOf(asEnum);
1310+
return indexOf < 0 || indexOf > _enums.Count - 1 ? default : indexOf;
1311+
}
1312+
1313+
public object ConvertBack(object value, Type targetType, object parameter, string language)
1314+
{
1315+
if (value is not int asIndex ||
1316+
asIndex < 0 ||
1317+
asIndex > _enums.Count - 1)
1318+
{
1319+
return default(TEnum);
1320+
}
1321+
1322+
return _enums[asIndex];
1323+
}
1324+
}
12151325
}

CollapseLauncher/XAMLs/Theme/CustomControls/LayeredBackgroundImage.Events.Loaders.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,8 @@ private static async Task<bool> LoadVideoFromSourceAsync(
377377
MaxDecoderThreads = (uint)Environment.ProcessorCount,
378378
VideoOutputAllow10bit = true,
379379
VideoOutputAllowBgra8 = true,
380-
VideoOutputAllowNv12 = true
380+
VideoOutputAllowNv12 = true,
381+
VideoDecoderMode = instance.FfmpegDecoderMode
381382
}
382383
};
383384

CollapseLauncher/XAMLs/Theme/CustomControls/LayeredBackgroundImage.Properties.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#nullable enable
2+
using FFmpegInteropX;
23
using Hi3Helper.Data;
34
using Microsoft.UI.Xaml;
45
using Microsoft.UI.Xaml.Media;
@@ -30,6 +31,12 @@ public bool UseFfmpegDecoder
3031
set => SetValue(UseFfmpegDecoderProperty, value);
3132
}
3233

34+
public VideoDecoderMode FfmpegDecoderMode
35+
{
36+
get => (VideoDecoderMode)GetValue(FfmpegDecoderModeProperty);
37+
set => SetValue(FfmpegDecoderModeProperty, value);
38+
}
39+
3340
public bool IsAudioEnabled
3441
{
3542
get => (bool)GetValue(IsAudioEnabledProperty);
@@ -254,6 +261,12 @@ private bool IsUseStaticBackgroundUsed
254261
typeof(LayeredBackgroundImage),
255262
new PropertyMetadata(false));
256263

264+
public static readonly DependencyProperty FfmpegDecoderModeProperty =
265+
DependencyProperty.Register(nameof(FfmpegDecoderMode),
266+
typeof(VideoDecoderMode),
267+
typeof(LayeredBackgroundImage),
268+
new PropertyMetadata(VideoDecoderMode.Automatic));
269+
257270
public static readonly DependencyProperty AudioVolumeProperty =
258271
DependencyProperty.Register(nameof(AudioVolume),
259272
typeof(double),

0 commit comments

Comments
 (0)