mirror of
https://github.com/unclshura/splitter.git
synced 2026-06-21 16:12:01 +00:00
UI for SingleJob added.
This commit is contained in:
parent
ad418e18a9
commit
e18d043b78
@ -17,6 +17,7 @@
|
||||
|
||||
<Application.Styles>
|
||||
<FluentTheme/>
|
||||
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
|
||||
</Application.Styles>
|
||||
|
||||
</Application>
|
||||
15
Splitter-UI/Models/ParameterEntry.cs
Normal file
15
Splitter-UI/Models/ParameterEntry.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace Splitter_UI.Models;
|
||||
|
||||
public partial class ParameterEntry : ObservableObject
|
||||
{
|
||||
public string Key { get; }
|
||||
[ObservableProperty] private string _value;
|
||||
|
||||
public ParameterEntry(string key, string value)
|
||||
{
|
||||
Key = key;
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
@ -9,9 +9,9 @@ public sealed class FileJobFactory : IFileJobFactory
|
||||
_services = services;
|
||||
}
|
||||
|
||||
public FileJobViewModel Create(SingleJob job)
|
||||
public JobViewModel Create(SingleJob job)
|
||||
{
|
||||
// Resolve a fresh VM + fresh services
|
||||
return ActivatorUtilities.CreateInstance<FileJobViewModel>(_services, job);
|
||||
return ActivatorUtilities.CreateInstance<JobViewModel>(_services, job);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,5 +6,5 @@ namespace Splitter_UI.Services;
|
||||
|
||||
public interface IFileJobFactory
|
||||
{
|
||||
FileJobViewModel Create(SingleJob job);
|
||||
JobViewModel Create(SingleJob job);
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="12.0.3" />
|
||||
<PackageReference Include="Avalonia.Controls.DataGrid" Version="12.0.0" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="12.0.3" />
|
||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="12.0.3" />
|
||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="12.0.3" />
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
using Avalonia.Media.Imaging;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace Splitter_UI.ViewModels;
|
||||
|
||||
public partial class FileJobViewModel : ObservableObject
|
||||
{
|
||||
public SingleJob Job { get; }
|
||||
public VideoInfo? Probe { get; set; }
|
||||
public PreviewData? Preview { get; set; }
|
||||
public ProgressInfo? Progress { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
private Bitmap? _thumbnail;
|
||||
|
||||
public string FileName { get; set; }
|
||||
|
||||
|
||||
[ObservableProperty]
|
||||
private string _suggestedAction = "";
|
||||
|
||||
private readonly IThumbnailService _thumbnails;
|
||||
private readonly IFileProbeService _fileProbe;
|
||||
|
||||
public FileJobViewModel(SingleJob job, IThumbnailService thumbnails, IFileProbeService fileProbe)
|
||||
{
|
||||
Job = job;
|
||||
_thumbnails = thumbnails;
|
||||
_fileProbe = fileProbe;
|
||||
|
||||
FileName = Path.GetFileName(job.InputFile);
|
||||
|
||||
_ = Task.Run( LoadThumbnailAsync );
|
||||
}
|
||||
|
||||
private async Task LoadThumbnailAsync()
|
||||
{
|
||||
Probe = await _fileProbe.ProbeAsync(Job);
|
||||
Thumbnail = await _thumbnails.CreateThumbnailAsync(Job.InputFile, Probe);
|
||||
SuggestedAction = Probe.Rotation == 0 ? "crop" : "rotate";
|
||||
}
|
||||
}
|
||||
@ -7,20 +7,20 @@ namespace Splitter_UI.ViewModels;
|
||||
public partial class FileListViewModel : ObservableObject
|
||||
{
|
||||
private readonly IFileJobFactory _factory;
|
||||
public ObservableCollection<FileJobViewModel> Files { get; } = [];
|
||||
public ObservableCollection<FileJobViewModel> SelectedFiles { get; } = [];
|
||||
public ObservableCollection<JobViewModel> Files { get; } = [];
|
||||
public ObservableCollection<JobViewModel> SelectedFiles { get; } = [];
|
||||
|
||||
[ObservableProperty]
|
||||
private FileJobViewModel? _selected;
|
||||
private JobViewModel? _selected;
|
||||
|
||||
public event Action<FileJobViewModel?>? SelectedFileChanged;
|
||||
public event Action<JobViewModel?>? SelectedFileChanged;
|
||||
|
||||
public FileListViewModel(IFileJobFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
partial void OnSelectedChanged(FileJobViewModel? value)
|
||||
partial void OnSelectedChanged(JobViewModel? value)
|
||||
=> SelectedFileChanged?.Invoke(value);
|
||||
|
||||
[RelayCommand]
|
||||
|
||||
@ -8,13 +8,18 @@ namespace Splitter_UI.ViewModels;
|
||||
public partial class InspectorPaneViewModel : ObservableObject
|
||||
{
|
||||
[ObservableProperty]
|
||||
private FileJobViewModel? _selected;
|
||||
private JobViewModel? _selected;
|
||||
|
||||
public List<string> DetectModes =>
|
||||
[
|
||||
"face", "body", "none"
|
||||
];
|
||||
|
||||
public List<int> RotationAngles =>
|
||||
[
|
||||
0, 90, 180, 270
|
||||
];
|
||||
|
||||
[RelayCommand]
|
||||
private void ApplyOverrides()
|
||||
{
|
||||
@ -22,4 +27,26 @@ public partial class InspectorPaneViewModel : ObservableObject
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
public IRelayCommand RotateLeftCommand { get; }
|
||||
public IRelayCommand RotateRightCommand { get; }
|
||||
|
||||
public InspectorPaneViewModel()
|
||||
{
|
||||
RotateLeftCommand = new RelayCommand(() => AdjustRotation(-90));
|
||||
RotateRightCommand = new RelayCommand(() => AdjustRotation(+90));
|
||||
}
|
||||
|
||||
private void AdjustRotation(int delta)
|
||||
{
|
||||
if (Selected?.Job == null)
|
||||
return;
|
||||
|
||||
var r = Selected.Job.Rotate ?? 0;
|
||||
r = (r + delta) % 360;
|
||||
if (r < 0) r += 360;
|
||||
|
||||
Selected.Rotate = r;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
156
Splitter-UI/ViewModels/JobViewModel.cs
Normal file
156
Splitter-UI/ViewModels/JobViewModel.cs
Normal file
@ -0,0 +1,156 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using Avalonia.Media.Imaging;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace Splitter_UI.ViewModels;
|
||||
|
||||
public partial class JobViewModel : ObservableObject
|
||||
{
|
||||
public SingleJob Job { get; }
|
||||
public VideoInfo? Probe { get; set; }
|
||||
public PreviewData? Preview { get; set; }
|
||||
public ProgressInfo? Progress { get; set; }
|
||||
|
||||
[ObservableProperty]
|
||||
private Bitmap? _thumbnail;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _suggestedAction = "";
|
||||
|
||||
private readonly IThumbnailService _thumbnails;
|
||||
private readonly IFileProbeService _fileProbe;
|
||||
|
||||
public string FileName => Path.GetFileName(Job.InputFile);
|
||||
|
||||
public ObservableCollection<ParameterEntry> ParametersList { get; }
|
||||
= new();
|
||||
|
||||
public string CropText
|
||||
{
|
||||
get => Job.Crop is { } c ? $"{c.width},{c.height}" : "";
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
Job.Crop = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var parts = value.Split(',');
|
||||
if (parts.Length == 2 &&
|
||||
int.TryParse(parts[0], out var w) &&
|
||||
int.TryParse(parts[1], out var h))
|
||||
Job.Crop = (w, h);
|
||||
}
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public string GravitateText
|
||||
{
|
||||
get => Job.GravitateTo is { } p ? $"{p.X:F3},{p.Y:F3}" : "";
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
Job.GravitateTo = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var parts = value.Split(',');
|
||||
if (parts.Length == 2 &&
|
||||
float.TryParse(parts[0], out var x) &&
|
||||
float.TryParse(parts[1], out var y))
|
||||
Job.GravitateTo = new Point2f(x, y);
|
||||
}
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public string PassthroughText
|
||||
{
|
||||
get => string.Join(' ', Job.Passthrough);
|
||||
set
|
||||
{
|
||||
Job.Passthrough = string.IsNullOrWhiteSpace(value)
|
||||
? Array.Empty<string>()
|
||||
: value.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public int? Rotate
|
||||
{
|
||||
get => Job.Rotate;
|
||||
set
|
||||
{
|
||||
Job.Rotate = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public JobViewModel(SingleJob job, IThumbnailService thumbnails, IFileProbeService fileProbe)
|
||||
{
|
||||
Job = job;
|
||||
_thumbnails = thumbnails;
|
||||
_fileProbe = fileProbe;
|
||||
|
||||
ParametersList.Add(new ParameterEntry("DropoutToleranceFrames", ""));
|
||||
ParametersList.Add(new ParameterEntry("EmaFactor", ""));
|
||||
ParametersList.Add(new ParameterEntry("CameraEasing", ""));
|
||||
ParametersList.Add(new ParameterEntry("LostFreezeFrames", ""));
|
||||
ParametersList.Add(new ParameterEntry("RotationDetectorSampleCount", ""));
|
||||
ParametersList.Add(new ParameterEntry("RotationDetectorSampleLength", ""));
|
||||
ParametersList.Add(new ParameterEntry("RotationDetectorFrameWidth", ""));
|
||||
ParametersList.Add(new ParameterEntry("RotationDetectorFrameHeight", ""));
|
||||
|
||||
foreach (var entry in ParametersList)
|
||||
{
|
||||
entry.PropertyChanged += OnParameterChanged;
|
||||
}
|
||||
|
||||
ParametersList.CollectionChanged += OnParametersCollectionChanged;
|
||||
|
||||
|
||||
_ = Task.Run( LoadThumbnailAsync );
|
||||
}
|
||||
|
||||
private async Task LoadThumbnailAsync()
|
||||
{
|
||||
Probe = await _fileProbe.ProbeAsync(Job);
|
||||
Thumbnail = await _thumbnails.CreateThumbnailAsync(Job.InputFile, Probe);
|
||||
SuggestedAction = Probe.Rotation == 0 ? "crop" : "rotate";
|
||||
}
|
||||
|
||||
private void OnParameterChanged(object? sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (sender is ParameterEntry p && e.PropertyName == nameof(ParameterEntry.Value))
|
||||
{
|
||||
Job.Parameters[p.Key] = p.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnParametersCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (e.NewItems != null)
|
||||
{
|
||||
foreach (ParameterEntry p in e.NewItems)
|
||||
{
|
||||
Job.Parameters[p.Key] = p.Value;
|
||||
p.PropertyChanged += OnParameterChanged;
|
||||
}
|
||||
}
|
||||
|
||||
if (e.OldItems != null)
|
||||
{
|
||||
foreach (ParameterEntry p in e.OldItems)
|
||||
{
|
||||
Job.Parameters.Remove(p.Key);
|
||||
p.PropertyChanged -= OnParameterChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -5,7 +5,7 @@ namespace Splitter_UI.ViewModels;
|
||||
public partial class PreviewPaneViewModel : ObservableObject
|
||||
{
|
||||
[ObservableProperty]
|
||||
private FileJobViewModel? _selected;
|
||||
private JobViewModel? _selected;
|
||||
|
||||
public PreviewPaneViewModel()
|
||||
{
|
||||
|
||||
@ -51,7 +51,7 @@
|
||||
</ListBox.Styles>
|
||||
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:FileJobViewModel">
|
||||
<DataTemplate x:DataType="vm:JobViewModel">
|
||||
<Border x:Name="ItemRoot"
|
||||
Margin="0"
|
||||
Padding="0"
|
||||
|
||||
@ -1,42 +1,156 @@
|
||||
<UserControl
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="Splitter_UI.Views.InspectorPane"
|
||||
xmlns:vm="clr-namespace:Splitter_UI.ViewModels"
|
||||
x:DataType="vm:InspectorPaneViewModel">
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="Splitter_UI.Views.InspectorPane"
|
||||
xmlns:vm="clr-namespace:Splitter_UI.ViewModels"
|
||||
x:DataType="vm:InspectorPaneViewModel">
|
||||
|
||||
<Border Background="#252525" Padding="12">
|
||||
<StackPanel Spacing="8">
|
||||
<ScrollViewer>
|
||||
<StackPanel Spacing="2">
|
||||
|
||||
<TextBlock Text="Parameters" FontSize="18" Margin="0,0,0,10"/>
|
||||
<TextBlock Text="Parameters" FontSize="10" Margin="0,0,0,10" FontWeight="Bold"/>
|
||||
|
||||
<!-- InputFile -->
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Text="{Binding Selected.FileName}" Width="360" Margin="0,0,0,10" FontStyle="Italic"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Rotate -->
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Text="Rotate" Width="120"/>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
|
||||
<Button Width="24" Height="24"
|
||||
Padding="0"
|
||||
Command="{Binding RotateLeftCommand}">
|
||||
<TextBlock FontFamily="{StaticResource FontAwesome}"
|
||||
Text=""
|
||||
FontSize="12"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0,-1,0,0"/>
|
||||
</Button>
|
||||
|
||||
<Button Width="24" Height="24"
|
||||
Padding="0"
|
||||
Command="{Binding RotateRightCommand}">
|
||||
<TextBlock FontFamily="{StaticResource FontAwesome}"
|
||||
Text=""
|
||||
FontSize="12"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0,-1,0,0"/>
|
||||
</Button>
|
||||
|
||||
|
||||
<!-- Angle display -->
|
||||
<TextBlock Text="{Binding Selected.Rotate}"
|
||||
Width="40"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Mask -->
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Text="Mask" Width="120"/>
|
||||
<TextBox Text="{Binding Selected.Job.Mask}" Width="260"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- OutputFolder -->
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Text="Output Folder" Width="120"/>
|
||||
<TextBox Text="{Binding Selected.Job.OutputFolder}" Width="260"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Crop -->
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Text="Crop (w,h)" Width="120"/>
|
||||
<TextBox Text="{Binding Selected.CropText}" Width="160"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- GravitateTo -->
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Text="GravitateTo" Width="120"/>
|
||||
<TextBox Text="{Binding Selected.GravitateText}" Width="160"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Detect -->
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Text="Detect" Width="120"/>
|
||||
<ComboBox ItemsSource="{Binding DetectModes}"
|
||||
SelectedItem="{Binding Selected.Job.Detect}"
|
||||
Width="160"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- OverrideTargetDuration -->
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Text="Target Duration" Width="120"/>
|
||||
<NumericUpDown Value="{Binding Selected.Job.OverrideTargetDuration}" Width="120"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- RotateAuto -->
|
||||
<CheckBox Content="Rotate Auto"
|
||||
IsChecked="{Binding Selected.Job.RotateAuto}"/>
|
||||
|
||||
<!-- ForceFixed -->
|
||||
<CheckBox Content="Force Fixed Duration"
|
||||
IsChecked="{Binding Selected.Job.ForceFixed}"/>
|
||||
|
||||
<!-- SingleThreaded -->
|
||||
<CheckBox Content="Single Threaded"
|
||||
IsChecked="{Binding Selected.Job.SingleThreaded}"/>
|
||||
|
||||
<!-- Debug -->
|
||||
<CheckBox Content="Debug Mode"
|
||||
IsChecked="{Binding Selected.Job.Debug}"/>
|
||||
|
||||
<!-- Parameters dictionary -->
|
||||
<TextBlock Text="Advanced Parameters" FontSize="10" Margin="0,10,0,0" FontWeight="Bold"/>
|
||||
|
||||
<DataGrid ItemsSource="{Binding Selected.ParametersList}"
|
||||
AutoGenerateColumns="False"
|
||||
HeadersVisibility="Column"
|
||||
Height="160">
|
||||
|
||||
<DataGrid.Columns>
|
||||
|
||||
<DataGridTextColumn Header="Key"
|
||||
Binding="{Binding Key}"
|
||||
Width="*"/>
|
||||
|
||||
<DataGridTemplateColumn Header="Value" Width="2*">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Value}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
|
||||
<DataGridTemplateColumn.CellEditingTemplate>
|
||||
<DataTemplate>
|
||||
<TextBox Text="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellEditingTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
|
||||
<!-- Passthrough -->
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Text="Passthrough" Width="120"/>
|
||||
<TextBox Text="{Binding Selected.PassthroughText}" Width="260"/>
|
||||
</StackPanel>
|
||||
|
||||
<Button Content="Apply to Selected"
|
||||
Command="{Binding ApplyOverridesCommand}"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,10,0,0"/>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Text="Rotate:" Width="100"/>
|
||||
<NumericUpDown Value="{Binding Selected.Job.Rotate}" Width="120"/>
|
||||
</StackPanel>
|
||||
<!--
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Text="Crop:" Width="100"/>
|
||||
<TextBox Text="{Binding Selected.CropText}" Width="200"/>
|
||||
</StackPanel>
|
||||
-->
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Text="Detect:" Width="100"/>
|
||||
<ComboBox ItemsSource="{Binding DetectModes}"
|
||||
SelectedItem="{Binding Selected.Job.Detect}"
|
||||
Width="200"/>
|
||||
</StackPanel>
|
||||
|
||||
<CheckBox Content="Force Fixed Duration"
|
||||
IsChecked="{Binding Selected.Job.ForceFixed}"/>
|
||||
|
||||
<CheckBox Content="Debug Mode"
|
||||
IsChecked="{Binding Selected.Job.Debug}"/>
|
||||
|
||||
<Button Content="Apply to Selected"
|
||||
Command="{Binding ApplyOverridesCommand}"
|
||||
Margin="0,10,0,0"/>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</UserControl>
|
||||
|
||||
@ -4,21 +4,93 @@ namespace splitter;
|
||||
|
||||
public class SingleJob
|
||||
{
|
||||
/// <summary>
|
||||
/// File path of the input video. This is required for each job and should be
|
||||
/// set to a valid video file path. The splitter will read this file, analyze it,
|
||||
/// and split it into segments based on the specified parameters.
|
||||
/// The output segments will be saved in the OutputFolder with names
|
||||
/// derived from this input file and the Mask pattern if provided.
|
||||
/// </summary>
|
||||
public string InputFile { get; set; } = null!;
|
||||
/// <summary>
|
||||
/// Output folder where the split segments will be saved. This should be set
|
||||
/// to a valid directory path.
|
||||
/// </summary>
|
||||
public string OutputFolder { get; set; } = null!;
|
||||
/// <summary>
|
||||
/// Crop parameters. Width and height for cropping the video. If set, the
|
||||
/// splitter will crop the video to the specified dimensions while tracking the subject.
|
||||
/// </summary>
|
||||
public (int width, int height)? Crop { get; set; }
|
||||
/// <summary>
|
||||
/// The fallback point to gravitate towards when tracking the subject. Coordinates are normalized (0.0 to 1.0).
|
||||
/// By default , the splitter gravitates towards the center of the frame (0.5, 0.5).
|
||||
/// Setting this allows you to bias the tracking towards a specific area of the frame,
|
||||
/// such as left-center (0.2, 0.5) or top-right (0.8, 0.2). This can be useful for
|
||||
/// videos where the subject tends to be off-center or for creative framing choices.
|
||||
/// </summary>
|
||||
public Point2f? GravitateTo { get; set; }
|
||||
/// <summary>
|
||||
/// Destination file mask.
|
||||
/// </summary>
|
||||
public string? Mask { get; set; }
|
||||
/// <summary>
|
||||
/// Instead of producing the output, just generate debug frames with tracking
|
||||
/// overlay to visually verify that the tracking is working correctly.
|
||||
/// </summary>
|
||||
public bool Debug { get; set; }
|
||||
/// <summary>
|
||||
/// Type of detector to use for tracking. Supported values are: face (UltraFace),
|
||||
/// body (YoloOnnx, default), none (no tracking, just a center point).
|
||||
/// </summary>
|
||||
public string? Detect { get; set; }
|
||||
/// <summary>
|
||||
/// Set starget segments length explicitly. By default, the splitter calculates segment
|
||||
/// lengths to be equal and not exceed 58 seconds.
|
||||
/// </summary>
|
||||
public double? OverrideTargetDuration { get; set; }
|
||||
/// <summary>
|
||||
/// Parameters to pass thru to ffmpeg. These are specified after "--" in the command
|
||||
/// line and are passed directly to the ffmpeg command line for each segment.
|
||||
/// </summary>
|
||||
public string[] Passthrough { get; set; } = [];
|
||||
/// <summary>
|
||||
/// Debugging parameter. Instead of text UI putput lines in plain text.
|
||||
/// This is useful when the output is being piped to a file or another program,
|
||||
/// or when the user prefers a simpler log format without progress bars and dynamic updates.
|
||||
/// </summary>
|
||||
public bool PlainText { get; set; }
|
||||
/// <summary>
|
||||
/// Debugging parameter. Just show estimated segments length, count, and other info
|
||||
/// without actually performing the splitting.
|
||||
/// </summary>
|
||||
public bool EstimateOnly { get; set; }
|
||||
/// <summary>
|
||||
/// Do not adapt segment length. When set, the splitter will use the exact
|
||||
/// segment duration specified by --duration for all segments except possibly
|
||||
/// the last one, which may be shorter.
|
||||
/// </summary>
|
||||
public bool ForceFixed { get; set; }
|
||||
/// <summary>
|
||||
/// Use single thread for operations. When set, the splitter will not run
|
||||
/// multiple ffmpeg processes in parallel.
|
||||
/// </summary>
|
||||
public bool SingleThreaded { get; set; }
|
||||
/// <summary>
|
||||
/// Rotation angle: 90, 180, or 270 degrees. This is useful for videos that
|
||||
/// have incorrect orientation metadata.
|
||||
/// </summary>
|
||||
public int? Rotate { get; set; }
|
||||
/// <summary>
|
||||
/// Autodetect if rotation is needed. Not very reliable but can work for some videos.
|
||||
/// Uses edge orientation statistics to determine if the video is rotated and
|
||||
/// applies the appropriate rotation if needed.
|
||||
/// </summary>
|
||||
public bool RotateAuto { get; set; }
|
||||
/// <summary>
|
||||
/// Override internal parameters. This allows you to set custom parameters for the
|
||||
/// object detector or rotation detector.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> Parameters { get; set; } = [];
|
||||
|
||||
public void Override<T>(ref T member, string name)
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<BuildNumber>0</BuildNumber>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- DEBUG CONFIGURATION -->
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user