update
This commit is contained in:
parent
da5f023390
commit
a28d3cac8e
@ -26,7 +26,8 @@ namespace VideoConcat.Models
|
||||
|
||||
private string _folderPath = "";
|
||||
private string _helpInfo = "";
|
||||
private bool _canStart = false;
|
||||
private bool _canExtractFrame = false;
|
||||
private bool _canModify = false;
|
||||
private bool _isCanOperate = false;
|
||||
private bool _isStart = false;
|
||||
private string[] _videos = [];
|
||||
@ -102,18 +103,28 @@ namespace VideoConcat.Models
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanStart
|
||||
public bool CanExtractFrame
|
||||
{
|
||||
get { return _canStart; }
|
||||
get { return _canExtractFrame; }
|
||||
set
|
||||
{
|
||||
_canStart = value;
|
||||
OnPropertyChanged(nameof(CanStart));
|
||||
_canExtractFrame = value;
|
||||
OnPropertyChanged(nameof(CanExtractFrame));
|
||||
}
|
||||
}
|
||||
public bool CanModify
|
||||
{
|
||||
get { return _canModify; }
|
||||
set
|
||||
{
|
||||
_canModify = value;
|
||||
OnPropertyChanged(nameof(CanModify));
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand? BtnOpenFolderCommand { get; set; }
|
||||
public ICommand? BtnStartVideoConcatCommand { get; set; }
|
||||
public ICommand? BtnStartVideoModifyCommand { get; set; }
|
||||
public ICommand? BtnChooseAuditImageCommand { get; set; }
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
@ -132,13 +143,14 @@ namespace VideoConcat.Models
|
||||
|
||||
public void SetCanStart()
|
||||
{
|
||||
CanExtractFrame = false;
|
||||
if (videos.Length > 0)
|
||||
{
|
||||
CanStart = true;
|
||||
CanModify = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CanStart = false;
|
||||
CanModify = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,14 +75,14 @@ namespace VideoConcat.Services.Video
|
||||
int totalFram = (int)(totalDuration * frameRate);
|
||||
|
||||
var random = new Random();
|
||||
var randomFrame = random.Next(1, (int)totalDuration);
|
||||
|
||||
var randomFrame = random.Next(20, (int)totalDuration);
|
||||
|
||||
//return RemoveVideoFrame(inputPath, outputPath, randomFrame);
|
||||
|
||||
|
||||
string videoPart1 = Path.Combine(tempDir, $"{Guid.NewGuid()}.mp4");
|
||||
string videoPart2 = Path.Combine(tempDir, $"{Guid.NewGuid()}.mp4");
|
||||
bool hasSubVideo1 = SubVideo(inputPath, videoPart1, 0, randomFrame-0.016);
|
||||
bool hasSubVideo1 = SubVideo(inputPath, videoPart1, 0, randomFrame - 0.016);
|
||||
bool hasSubVideo2 = SubVideo(inputPath, videoPart2, randomFrame, totalDuration);
|
||||
if (!hasSubVideo1 || !hasSubVideo2)
|
||||
{
|
||||
@ -116,6 +116,27 @@ namespace VideoConcat.Services.Video
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 通过修改视频元数据(添加注释)改变MD5
|
||||
/// </summary>
|
||||
public static bool ModifyByMetadata(string inputPath, string outputPath, string comment = "JSY")
|
||||
{
|
||||
// 添加或修改视频元数据中的注释信息
|
||||
return FFMpegArguments
|
||||
.FromFileInput(inputPath)
|
||||
.OutputToFile(outputPath, true, options => options
|
||||
//.WithVideoCodec("copy") // 直接复制视频流,不重新编码
|
||||
//.WithAudioCodec("copy") // 直接复制音频流
|
||||
.CopyChannel()
|
||||
.WithCustomArgument($"-metadata comment=\"{comment}_{Guid.NewGuid()}\"") // 添加唯一注释
|
||||
)
|
||||
.ProcessSynchronously();
|
||||
}
|
||||
|
||||
|
||||
public static bool SubVideo(string inputPath, string outputPath, Double startSec, Double endSec)
|
||||
{
|
||||
return FFMpegArguments
|
||||
@ -138,7 +159,7 @@ namespace VideoConcat.Services.Video
|
||||
return FFMpeg.Join(outPutPath, videoParts);
|
||||
}
|
||||
|
||||
public async Task<bool> ProcessVideo(string inputPath,string outputPath, string tempDir)
|
||||
public async Task<bool> ProcessVideo(string inputPath, string outputPath, string tempDir)
|
||||
{
|
||||
// 1. 获取视频信息
|
||||
IMediaAnalysis mediaInfo = await FFProbe.AnalyseAsync(inputPath);
|
||||
@ -220,5 +241,23 @@ namespace VideoConcat.Services.Video
|
||||
opt.WithCustomArgument("-c copy -shortest -y"))
|
||||
.ProcessAsynchronously();
|
||||
}
|
||||
|
||||
|
||||
public static bool RemoveVideoFrame(string inputPath, string outputPath, int frameToRemove)
|
||||
{
|
||||
// 使用FFMpegArguments构建转换流程
|
||||
return FFMpegArguments
|
||||
.FromFileInput(inputPath)
|
||||
.OutputToFile(outputPath, true, options => options
|
||||
// 使用select过滤器排除指定帧(帧序号从0开始)
|
||||
.WithCustomArgument($"select=not(eq(n\\,{frameToRemove}))")
|
||||
|
||||
// $"not(eq(n\\,{frameToRemove}))"); // 注意:在C#中需要转义反斜杠
|
||||
//// 保持其他编码参数
|
||||
.WithVideoCodec("libx264")
|
||||
.WithAudioCodec("copy") // 如果不需要处理音频,直接复制
|
||||
)
|
||||
.ProcessSynchronously();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,7 +35,8 @@ namespace VideoConcat.ViewModels
|
||||
{
|
||||
ExtractWindowModel = new ExtractWindowModel
|
||||
{
|
||||
CanStart = false,
|
||||
CanExtractFrame = false,
|
||||
CanModify = false,
|
||||
IsStart = false,
|
||||
IsCanOperate = true,
|
||||
|
||||
@ -76,7 +77,7 @@ namespace VideoConcat.ViewModels
|
||||
var remover = new VideoProcess();
|
||||
// 删除4秒处的帧(需根据实际帧位置调整)
|
||||
string _tmpPath = Path.GetDirectoryName(video) ?? "";
|
||||
string _tmpFileName = $"{(new Random()).Next(10000,99999)}{Path.GetFileName(video)}";
|
||||
string _tmpFileName = $"{(new Random()).Next(10000, 99999)}{Path.GetFileName(video)}";
|
||||
|
||||
string outPath = Path.Combine(_tmpPath, "out");
|
||||
if (!Path.Exists(outPath))
|
||||
@ -94,6 +95,53 @@ namespace VideoConcat.ViewModels
|
||||
_tasks.Add(_task);
|
||||
});
|
||||
|
||||
Task.WhenAll(_tasks).ContinueWith((task) =>
|
||||
{
|
||||
ExtractWindowModel.HelpInfo = "全部完成!";
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
BtnStartVideoModifyCommand = new Command()
|
||||
{
|
||||
DoExcue = obj =>
|
||||
{
|
||||
ExtractWindowModel.HelpInfo = "";
|
||||
|
||||
|
||||
SemaphoreSlim semaphore = new(10); // Limit to 3 threads
|
||||
|
||||
List<Task> _tasks = [];
|
||||
|
||||
ExtractWindowModel.videos.ForEach(async (video) =>
|
||||
{
|
||||
await semaphore.WaitAsync(); // Wait when more than 3 threads are running
|
||||
var _task = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// 实例化并调用
|
||||
var remover = new VideoProcess();
|
||||
// 删除4秒处的帧(需根据实际帧位置调整)
|
||||
string _tmpPath = Path.GetDirectoryName(video) ?? "";
|
||||
string _tmpFileName = $"{(new Random()).Next(10000, 99999)}{Path.GetFileName(video)}";
|
||||
|
||||
string outPath = Path.Combine(_tmpPath, "out");
|
||||
if (!Path.Exists(outPath))
|
||||
{
|
||||
Directory.CreateDirectory(outPath);
|
||||
}
|
||||
|
||||
VideoProcess.ModifyByMetadata(video, $"{_tmpPath}\\out\\modify{_tmpFileName}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
semaphore.Release(); // Work is done, signal to semaphore that more work is possible
|
||||
}
|
||||
});
|
||||
_tasks.Add(_task);
|
||||
});
|
||||
|
||||
Task.WhenAll(_tasks).ContinueWith((task) =>
|
||||
{
|
||||
ExtractWindowModel.HelpInfo = "全部完成!";
|
||||
|
||||
@ -29,9 +29,10 @@
|
||||
<Border>
|
||||
<WrapPanel>
|
||||
<Label VerticalAlignment="Center" Width="100" FontSize="16" Margin="5,2" BorderBrush="#7F7F7F" BorderThickness="2" Style="{StaticResource MaterialDesignLabel}" VerticalContentAlignment="Stretch">视频文件夹:</Label>
|
||||
<TextBox Grid.Column="1" Width="650" Name="FoldPath" Text="{Binding ExtractWindowModel.FolderPath,Mode=TwoWay}" IsReadOnly="True" Margin="5,2" BorderBrush="#7F7F7F" BorderThickness="2" FontSize="16" VerticalContentAlignment="Center" materialDesign:HintAssist.Hint="选择包含需要处理的视频文件夹"/>
|
||||
<Button Grid.Column="2" Width="100" Content="选择" FontSize="16" Command="{Binding ExtractWindowModel.BtnOpenFolderCommand}" Background="#40568D" BorderBrush="#7F7F7F" BorderThickness="2" ToolTip="选择含有视频的主文件夹" Style="{StaticResource MaterialDesignRaisedButton}" Margin="5,2" IsEnabled="{Binding ExtractWindowModel.IsCanOperate}"/>
|
||||
<Button Grid.Column="3" Width="100" Content="处理" FontSize="16" Command="{Binding ExtractWindowModel.BtnStartVideoConcatCommand}" Background="#3B94FE" BorderBrush="#7F7F7F" BorderThickness="2" ToolTip="开始处理视频" Style="{StaticResource MaterialDesignRaisedButton}" Margin="5,2,0,2" IsEnabled="{Binding ExtractWindowModel.CanStart}"/>
|
||||
<TextBox Grid.Column="1" Width="600" Name="FoldPath" Text="{Binding ExtractWindowModel.FolderPath,Mode=TwoWay}" IsReadOnly="True" Margin="5,2" BorderBrush="#7F7F7F" BorderThickness="2" FontSize="16" VerticalContentAlignment="Center" materialDesign:HintAssist.Hint="选择包含需要处理的视频文件夹"/>
|
||||
<Button Grid.Column="2" Width="80" Content="选择" FontSize="16" Command="{Binding ExtractWindowModel.BtnOpenFolderCommand}" Background="#40568D" BorderBrush="#7F7F7F" BorderThickness="2" ToolTip="选择含有视频的主文件夹" Style="{StaticResource MaterialDesignRaisedButton}" Margin="5,2" IsEnabled="{Binding ExtractWindowModel.IsCanOperate}"/>
|
||||
<Button Grid.Column="3" Width="80" Content="抽帧" FontSize="16" Command="{Binding ExtractWindowModel.BtnStartVideoConcatCommand}" Background="#3B94FE" BorderBrush="#7F7F7F" BorderThickness="2" ToolTip="开始处理视频" Style="{StaticResource MaterialDesignRaisedButton}" Margin="5,2,0,2" IsEnabled="{Binding ExtractWindowModel.CanExtractFrame}"/>
|
||||
<Button Grid.Column="4" Width="80" Content="修改" FontSize="16" Command="{Binding ExtractWindowModel.BtnStartVideoConcatCommand}" Background="#3B94FE" BorderBrush="#7F7F7F" BorderThickness="2" ToolTip="开始处理视频" Style="{StaticResource MaterialDesignRaisedButton}" Margin="5,2,0,2" IsEnabled="{Binding ExtractWindowModel.CanModify}"/>
|
||||
</WrapPanel>
|
||||
</Border>
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
mc:Ignorable="d"
|
||||
Width="1100" Height="800" WindowStartupLocation="CenterScreen"
|
||||
ResizeMode="NoResize"
|
||||
ResizeMode="CanMinimize"
|
||||
Title="工具">
|
||||
<Window.Resources>
|
||||
<Style x:Key="BottomButton" TargetType="Button">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user