Skip to content

Commit

Permalink
新增处理后删除输入文件的功能;修复了最新版本ffmpeg因输出状态改变导致部分场景(如复制流)下无法获取进度的BUG
Browse files Browse the repository at this point in the history
  • Loading branch information
autodotua committed Apr 4, 2024
1 parent 5a5d976 commit 18cf13d
Show file tree
Hide file tree
Showing 11 changed files with 225 additions and 186 deletions.
2 changes: 1 addition & 1 deletion ReadMe.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

1. 确保安装了 .NET 8 SDK:
2. 确保安装了npm(Node.js):
3. 确保在根目录下(与ReadMe同级目录)的 `bin`目录中放置了ffmpeg二进制文件(shared版):[下载](https://www.ffmpeg.org/download.html) 。共有三个exe文件和若干个dll文件。已测试版本:6.1
3. 确保在根目录下(与ReadMe同级目录)的 `bin`目录中放置了ffmpeg二进制文件(shared版):[下载](https://www.ffmpeg.org/download.html) 。共有三个exe文件和若干个dll文件。已测试版本:6.1.1
4. 若要使用媒体信息查询功能,应在根目录(与ReadMe同级目录)下的 `bin`目录中放置了MediaInfo CLI可执行文件(如`MediaInfo.exe`):[下载](https://mediaarea.net/en/MediaInfo/Download)
5. 若要使用编码测试功能,应在根目录(与ReadMe同级目录)下的 `bin`目录中放置了测试视频 `test.mp4`和VMAF模型([下载](https://github.com/Netflix/vmaf/blob/master/model/vmaf_v0.6.1.json)。选取的视频宜为4K分辨率,30秒以上的长度。

Expand Down
11 changes: 6 additions & 5 deletions SimpleFFmpegGUI.Core/Dto/StatusDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class StatusDto : INotifyPropertyChanged
/// 识别FFmpeg输出的进度信息的正则
/// </summary>
private static readonly Regex rFFmpegOutput = new Regex(
@"frame= *(?<f>[0-9]+) *fps= *(?<fps>[0-9\.]+) *(q= *(?<q>[0-9\.\-]+) *)+size= *(?<size>([0-9\.a-zA-Z]+)|(N/A)) *time= *(?<time>[0-9\.\-:]+) *bitrate= *(?<b>([0-9\.a-z/]+)|(N/A)).*speed= *(?<speed>([0-9\.]+)|(N/A))x?", RegexOptions.Compiled);
@"(frame= *(?<f>[0-9]+) *fps= *(?<fps>[0-9\.]+) *(q= *(?<q>[0-9\.\-]+) *)+)?size= *(?<size>([0-9\.a-zA-Z ]+)|(N/A)) *time= *(?<time>[0-9\.\-:]+) *bitrate= *(?<b>([0-9\.a-z/]+)|(N/A)).*speed= *(?<speed>([0-9\. ]+)|(N/A))x?", RegexOptions.Compiled);

private string bitrate;

Expand Down Expand Up @@ -64,8 +64,8 @@ public StatusDto(TaskInfo task, ProgressDto progress, string lastOutput, bool pa
try
{
var match = rFFmpegOutput.Match(lastOutput);
Frame = int.Parse(match.Groups["f"].Value);
Fps = double.Parse(match.Groups["fps"].Value);
Frame = match.Groups["f"].Success ? int.Parse(match.Groups["f"].Value) : -1;
Fps = match.Groups["fps"].Success ? double.Parse(match.Groups["fps"].Value) : -1;
Size = match.Groups["size"].Value.ToUpper();
Time = TimeSpan.Parse(match.Groups["time"].Value);
if (Time < TimeSpan.Zero)
Expand All @@ -74,7 +74,7 @@ public StatusDto(TaskInfo task, ProgressDto progress, string lastOutput, bool pa
}
Bitrate = match.Groups["b"].Value;
Speed = match.Groups["speed"].Value;
Q = double.Parse(match.Groups["q"].Value);
Q = match.Groups["q"].Success ? double.Parse(match.Groups["q"].Value) : -1;

if (progress != null)
{
Expand All @@ -88,6 +88,7 @@ public StatusDto(TaskInfo task, ProgressDto progress, string lastOutput, bool pa
}
catch
{

}
}
}
Expand Down Expand Up @@ -209,6 +210,6 @@ public TimeSpan Time
get => time;
set => this.SetValueAndNotify(ref time, value, nameof(Time));
}

}
}
89 changes: 87 additions & 2 deletions SimpleFFmpegGUI.Core/Manager/FFmpegManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -259,18 +259,55 @@ public async Task RunAsync()
});


if (task.RealOutput != null && File.Exists(task.RealOutput) && task.Arguments.SyncModifiedTime)
if (task.RealOutput != null && File.Exists(task.RealOutput) && task.Arguments.ProcessedOptions?.SyncModifiedTime == true)
{
try
{
File.SetLastWriteTime(task.RealOutput, File.GetLastWriteTime(task.Inputs[^1].FilePath));
var time = File.GetLastWriteTime(task.Inputs[^1].FilePath);
File.SetLastWriteTime(task.RealOutput, time);
logger.Info(task, $"已设置输出文件的修改时间为{time}");
}
catch (Exception ex)
{
logger.Error(task, "修改输出文件的修改时间失败:" + ex.Message);
}
}

if (task.Inputs.Count > 0 && task.Arguments.ProcessedOptions?.DeleteInputFiles == true)
{
DriveInfo[] allDrives = DriveInfo.GetDrives();
foreach (var file in task.Inputs)
{
if (File.Exists(file.FilePath))
{
try
{
bool canDeleteToRecycleBin = false;
bool deleted = false;
if (OperatingSystem.IsWindows())
{
var root = Path.GetPathRoot(Path.GetFullPath(file.FilePath));
canDeleteToRecycleBin = allDrives.First(p => p.Name == root).DriveType == DriveType.Fixed;
}
if (canDeleteToRecycleBin)
{
deleted = RecycleBin.DeleteToRecycleBin(file.FilePath);
logger.Info(task, $"已将输入文件{file.FilePath}移至回收站");
}
if (!deleted)
{
File.Delete(file.FilePath);
logger.Info(task, $"已彻底删除输入文件{file.FilePath}");
}
}
catch (Exception ex)
{
logger.Error(task, $"删除输入文件{file.FilePath}失败:{ex.Message}");
}
}
}
}

logger.Info(task, "完成任务");
}
finally
Expand Down Expand Up @@ -640,4 +677,52 @@ private async Task RunCustomProcessAsync(CancellationToken cancellationToken)
await RunAsync(task.Arguments.Extra, null, cancellationToken);
}
}

public class RecycleBin
{
// 定义 SHFileOperation 函数的结构体
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct SHFILEOPSTRUCT
{
public IntPtr hwnd;
public uint wFunc;
public string pFrom;
public string pTo;
public ushort fFlags;
public int fAnyOperationsAborted;
public IntPtr hNameMappings;
public string lpszProgressTitle;
}

// 定义 SHFileOperation 函数的操作类型
private const uint FO_DELETE = 0x0003;
private const ushort FOF_ALLOWUNDO = 0x0040;

// 调用 SHFileOperation 函数
[DllImport("Shell32.dll", CharSet = CharSet.Unicode)]
private static extern int SHFileOperation(ref SHFILEOPSTRUCT FileOp);

// 删除文件到回收站
public static bool DeleteToRecycleBin(string filePath)
{
// 准备 SHFILEOPSTRUCT 结构体
SHFILEOPSTRUCT fileOp = new SHFILEOPSTRUCT();
fileOp.wFunc = FO_DELETE;
fileOp.pFrom = filePath + '\0'; // 文件路径必须以空字符结尾
fileOp.fFlags = FOF_ALLOWUNDO;

// 调用 SHFileOperation 函数
int result = SHFileOperation(ref fileOp);

// 检查结果
if (result == 0)
{
return true;
}
else
{
return false;
}
}
}
}
5 changes: 1 addition & 4 deletions SimpleFFmpegGUI.Core/Model/OutputArguments.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,6 @@ public VideoCodeArguments Video
set => this.SetValueAndNotify(ref video, value, nameof(Video));
}

/// <summary>
/// 将输出文件的修改时间设置为最后一个输入文件的修改时间
/// </summary>
public bool SyncModifiedTime { get; set; }
public ProcessedOptions ProcessedOptions { get; set; } = new ProcessedOptions();
}
}
15 changes: 15 additions & 0 deletions SimpleFFmpegGUI.Core/Model/ProcessedOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace SimpleFFmpegGUI.Model
{
public class ProcessedOptions
{
/// <summary>
/// 将输出文件的修改时间设置为最后一个输入文件的修改时间
/// </summary>
public bool SyncModifiedTime { get; set; }

/// <summary>
/// 处理后删除输入文件。若可以,将删除到回收站。
/// </summary>
public bool DeleteInputFiles { get; set; }
}
}
18 changes: 9 additions & 9 deletions SimpleFFmpegGUI.WPF/Pages/AddTaskPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
<ui:AppBarButton
Click="AddInputButton_Click"
IsEnabled="{Binding CanAddFile}"
Label="新增输入文件">
Label="新增">
<ui:AppBarButton.Icon>
<ui:FontIcon Glyph="&#xECC8;" />
</ui:AppBarButton.Icon>
Expand All @@ -82,11 +82,11 @@
Click="BrowseAndAddInputButton_Click"
Icon="OpenFile"
IsEnabled="{Binding CanAddFile}"
Label="浏览并新增输入文件" />
Label="浏览" />
<ui:AppBarButton
Click="ClearFilesButton_Click"
Icon="Clear"
Label="清空输入文件" />
Label="清空" />
<ui:AppBarSeparator />
<ui:AppBarButton
Click="SaveToPresetButton_Click"
Expand All @@ -96,7 +96,7 @@

<ui:AppBarButton
Click="AddToRemoteHostButton_Click"
Label="创建到远程主机">
Label="提交到远程">
<ui:AppBarButton.Icon>
<ui:FontIcon Glyph="&#xE836;" />
</ui:AppBarButton.Icon>
Expand All @@ -105,13 +105,13 @@
Click="AddToQueueButton_Click"
Icon="Add"
Label="创建任务" />
<ui:AppBarButton
Click="AddToQueueButton_Click"
Icon="Add"
Label="创建并启动"
Tag="queue" />
<ui:AppBarSeparator />
<ui:CommandBar.SecondaryCommands>
<ui:AppBarButton
Click="AddToQueueButton_Click"
Icon="Add"
Label="创建任务并启动队列"
Tag="queue" />
<ui:AppBarToggleButton
Icon="Clear"
IsChecked="{Binding Source={x:Static r:Config.Instance}, Path=ClearFilesAfterAddTask}"
Expand Down
6 changes: 5 additions & 1 deletion SimpleFFmpegGUI.WPF/Panels/CodeArgumentsPanel.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -405,8 +405,12 @@
TextWrapping="Wrap" />
<CheckBox
Content="同步文件修改时间"
IsChecked="{Binding SyncModifiedTime}"
IsChecked="{Binding ProcessedOptions.SyncModifiedTime}"
ToolTip="将输出文件的修改时间设置为最后一个输入文件的修改时间" />
<CheckBox
Content="完成后删除输入文件"
IsChecked="{Binding ProcessedOptions.DeleteInputFiles}"
ToolTip="在处理完成后删除所有输入文件(优先删除到回收站)" />
</ui:SimpleStackPanel>
</GroupBox>
</ui:SimpleStackPanel>
Expand Down
16 changes: 7 additions & 9 deletions SimpleFFmpegGUI.WPF/Panels/CodeArgumentsPanel.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,7 @@ public class CodeArgumentsPanelViewModel : INotifyPropertyChanged

private FormatArgumentWithSwitch format = new FormatArgumentWithSwitch();

private bool syncModifiedTime;

private ProcessedOptions processedOptions = new ProcessedOptions();
private TaskType type;

private VideoArgumentsWithSwitch video = new VideoArgumentsWithSwitch();
Expand Down Expand Up @@ -278,14 +277,13 @@ public FormatArgumentWithSwitch Format

public IEnumerable PixelFormats { get; } = new[] { "yuv420p", "yuvj420p", "yuv422p", "yuvj422p", "rgb24", "gray", "yuv420p10le" };

public IEnumerable Sizes { get; } = new[] { "-1:2160", "-1:1440", "-1:1080", "-1:720", "-1:576", "-1:480" };

public bool SyncModifiedTime
public ProcessedOptions ProcessedOptions
{
get => syncModifiedTime;
set => this.SetValueAndNotify(ref syncModifiedTime, value, nameof(SyncModifiedTime));
get => processedOptions;
set => this.SetValueAndNotify(ref processedOptions, value, nameof(ProcessedOptions));
}

public IEnumerable Sizes { get; } = new[] { "-1:2160", "-1:1440", "-1:1080", "-1:720", "-1:576", "-1:480" };
public VideoArgumentsWithSwitch Video
{
get => video;
Expand Down Expand Up @@ -325,7 +323,7 @@ public OutputArguments GetArguments()
Format = Format.Format,
Combine = Combine,
Extra = Extra,
SyncModifiedTime = SyncModifiedTime,
ProcessedOptions = ProcessedOptions,
DisableVideo = VideoOutputStrategy == ChannelOutputStrategy.Disable,
DisableAudio = audioOutputStrategy == ChannelOutputStrategy.Disable,
};
Expand Down Expand Up @@ -353,8 +351,8 @@ public void Update(TaskType type, OutputArguments argument = null)
Format = new FormatArgumentWithSwitch() { Format = argument.Format };
Format.Update();
Combine = argument.Combine;
ProcessedOptions = argument.ProcessedOptions ?? new ProcessedOptions();
Extra = argument.Extra;
SyncModifiedTime = argument.SyncModifiedTime;
}
}
}
Expand Down
Loading

0 comments on commit 18cf13d

Please sign in to comment.