update
This commit is contained in:
parent
d1787dc7e6
commit
ec0ac61133
@ -18,26 +18,49 @@ namespace VideoConcat.Models
|
||||
public class VideoModel : INotifyPropertyChanged
|
||||
{
|
||||
private int _num;
|
||||
private int _maxNum;
|
||||
private string _folderPath = "";
|
||||
private string _auditImagePath = "";
|
||||
private bool _canStart = false;
|
||||
private ObservableCollection<FolderInfo> _FolderInfos = [];
|
||||
|
||||
|
||||
public int Num
|
||||
{
|
||||
get { return _num; }
|
||||
get => _num;
|
||||
set
|
||||
{
|
||||
_num = value;
|
||||
OnPropertyChanged();
|
||||
UpdateSum();
|
||||
}
|
||||
}
|
||||
|
||||
public string AuditImagePath
|
||||
{
|
||||
get => _auditImagePath;
|
||||
set
|
||||
{
|
||||
_auditImagePath = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public int MaxNum
|
||||
{
|
||||
get => _maxNum;
|
||||
set
|
||||
{
|
||||
_maxNum = value;
|
||||
}
|
||||
}
|
||||
|
||||
public struct FolderInfo
|
||||
{
|
||||
public DirectoryInfo DirectoryInfo{set;get;}
|
||||
public DirectoryInfo DirectoryInfo { set; get; }
|
||||
public int Num { set; get; }
|
||||
|
||||
public List<string> VideoPaths { set; get; }
|
||||
public List<string> VideoPaths { set; get; }
|
||||
}
|
||||
|
||||
public ObservableCollection<FolderInfo> FolderInfos
|
||||
@ -81,11 +104,12 @@ namespace VideoConcat.Models
|
||||
|
||||
public ICommand? BtnOpenFolderCommand { get; set; }
|
||||
public ICommand? BtnStartVideoConcatCommand { get; set; }
|
||||
public ICommand? BtnChooseAuditImageCommand { get; set; }
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
@ -98,17 +122,35 @@ namespace VideoConcat.Models
|
||||
public void UpdateSum()
|
||||
{
|
||||
int _temp = 1;
|
||||
foreach (var item in FolderInfos)
|
||||
if (FolderInfos.Count > 0)
|
||||
{
|
||||
if (item.Num > 0)
|
||||
foreach (FolderInfo item in FolderInfos)
|
||||
{
|
||||
_temp *= item.Num;
|
||||
if (item.Num > 0)
|
||||
{
|
||||
_temp *= item.Num;
|
||||
}
|
||||
}
|
||||
MaxNum = _temp;
|
||||
SetCanStart();
|
||||
}
|
||||
Num = _temp;
|
||||
if(Num > 0){
|
||||
else
|
||||
{
|
||||
MaxNum = 0;
|
||||
SetCanStart();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetCanStart()
|
||||
{
|
||||
if (Num > 0 && Num <= MaxNum)
|
||||
{
|
||||
CanStart = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CanStart = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,18 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Input;
|
||||
using VideoConcat.Models;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using MessageBox = System.Windows.MessageBox;
|
||||
using System.ComponentModel;
|
||||
using VideoConcat.Common.Tools;
|
||||
using System.IO;
|
||||
using Microsoft.Expression.Drawing.Core;
|
||||
using FFMpegCore;
|
||||
using FFMpegCore.Arguments;
|
||||
|
||||
namespace VideoConcat.ViewModels
|
||||
{
|
||||
@ -32,54 +25,159 @@ namespace VideoConcat.ViewModels
|
||||
|
||||
public VideoViewModel()
|
||||
{
|
||||
VideoModel = new VideoModel();
|
||||
VideoModel.BtnOpenFolderCommand = new BtnOpenFolderCommand()
|
||||
VideoModel = new VideoModel
|
||||
{
|
||||
DoExcue = obj =>
|
||||
FolderInfos = [],
|
||||
MaxNum = 0,
|
||||
CanStart = false,
|
||||
BtnOpenFolderCommand = new Command()
|
||||
{
|
||||
FolderBrowserDialog folderBrowserDialog = new();
|
||||
if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
|
||||
DoExcue = obj =>
|
||||
{
|
||||
VideoModel.FolderPath = folderBrowserDialog.SelectedPath;
|
||||
LogUtils.Info($"获取视频文件夹,视频路径:{VideoModel.FolderPath}");
|
||||
ListFolder(VideoModel.FolderPath);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
VideoModel.BtnStartVideoConcatCommand = new BtnStartVideoConcatCommand()
|
||||
{
|
||||
DoExcue = obj =>
|
||||
{
|
||||
LogUtils.Info("开始合并视频");
|
||||
List<List<string>> combinations = [];
|
||||
List<string> currentCombination = [];
|
||||
List<List<string>> videoLists = [];
|
||||
|
||||
|
||||
VideoModel.FolderInfos.ForEach(folderInfo =>
|
||||
{
|
||||
videoLists.Add(folderInfo.VideoPaths);
|
||||
});
|
||||
|
||||
VideoCombine.GenerateCombinations(videoLists, 0, currentCombination, combinations);
|
||||
|
||||
int combinationIndex = 1;
|
||||
foreach (List<string> combination in combinations)
|
||||
{
|
||||
Console.Write($"组合 {combinationIndex++}: ");
|
||||
foreach (string video in combination)
|
||||
FolderBrowserDialog folderBrowserDialog = new();
|
||||
if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
Console.Write(video + " ");
|
||||
VideoModel.FolderPath = folderBrowserDialog.SelectedPath;
|
||||
LogUtils.Info($"获取视频文件夹,视频路径:{VideoModel.FolderPath}");
|
||||
ListFolder(VideoModel.FolderPath);
|
||||
}
|
||||
Console.WriteLine();
|
||||
FFMpeg.Join("./1.mp4",combination.ToArray());
|
||||
}
|
||||
|
||||
|
||||
Console.WriteLine($"总共有 {combinations.Count} 种拼接方案。");
|
||||
},
|
||||
BtnChooseAuditImageCommand = new Command()
|
||||
{
|
||||
DoExcue = obj =>
|
||||
{
|
||||
// 创建一个 OpenFileDialog 实例
|
||||
OpenFileDialog openFileDialog = new()
|
||||
{
|
||||
// 设置文件对话框的标题
|
||||
Title = "选择广审图片",
|
||||
// 设置文件筛选器,只允许选择文本文件和图像文件
|
||||
Filter = "图片文件[*.png;*.jpg;*.jpeg;*.bmp]|*.png;*.jpg;*.jpeg;*.bmp",
|
||||
};
|
||||
|
||||
|
||||
// 显示文件对话框并获取结果
|
||||
DialogResult result = openFileDialog.ShowDialog();
|
||||
|
||||
|
||||
// 检查用户是否点击了打开按钮
|
||||
if (result == DialogResult.OK)
|
||||
{
|
||||
// 获取用户选择的文件路径列表
|
||||
VideoModel.AuditImagePath = openFileDialog.FileName;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
BtnStartVideoConcatCommand = new Command()
|
||||
{
|
||||
DoExcue = obj =>
|
||||
{
|
||||
Task.Run(action: () =>
|
||||
{
|
||||
//开始时间
|
||||
DateTime startTime = DateTime.Now;
|
||||
|
||||
LogUtils.Info("开始合并视频");
|
||||
List<List<string>> combinations = [];
|
||||
List<string> currentCombination = [];
|
||||
List<List<string>> videoLists = [];
|
||||
|
||||
|
||||
List<Task> taskList = [];
|
||||
|
||||
VideoModel.FolderInfos.ForEach(folderInfo =>
|
||||
{
|
||||
videoLists.Add(folderInfo.VideoPaths);
|
||||
});
|
||||
|
||||
VideoCombine.GenerateCombinations(videoLists, 0, currentCombination, combinations);
|
||||
|
||||
|
||||
List<List<string>> result = [];
|
||||
Random random = new();
|
||||
|
||||
|
||||
// 复制原列表,避免修改原列表
|
||||
List<List<string>> tempList = new(combinations);
|
||||
|
||||
|
||||
for (int i = 0; i < VideoModel.Num && tempList.Count > 0; i++)
|
||||
{
|
||||
int index = random.Next(tempList.Count);
|
||||
result.Add(tempList[index]);
|
||||
tempList.RemoveAt(index);
|
||||
}
|
||||
|
||||
|
||||
foreach (List<string> combination in result)
|
||||
{
|
||||
taskList.Add(Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Directory.Exists($"{VideoModel.FolderPath}/output") == false)
|
||||
{
|
||||
Directory.CreateDirectory($"{VideoModel.FolderPath}/output");
|
||||
}
|
||||
string _outPutName = $"{VideoModel.FolderPath}/output/{random.Next(100000, 999999)}.mp4";
|
||||
|
||||
bool _isSuccess = FFMpeg.Join(_outPutName, [.. combination]);
|
||||
|
||||
|
||||
if (_isSuccess && VideoModel.AuditImagePath != "")
|
||||
{
|
||||
// 使用 FFMpegCore 执行添加图片到视频的操作
|
||||
try
|
||||
{
|
||||
// 配置 FFmpeg 二进制文件位置(如果 FFmpeg 不在系统路径中)
|
||||
// GlobalFFOptions.Configure(new FFOptions { BinaryFolder = "path/to/ffmpeg/bin" });
|
||||
string _outPutNameImg = $"{VideoModel.FolderPath}/output/{random.Next(100000, 999999)}.mp4";
|
||||
|
||||
|
||||
// 使用 FFMpegArguments 构建命令
|
||||
bool _isCoverSuccess = FFMpegArguments
|
||||
.FromFileInput(_outPutName)
|
||||
.AddFileInput(VideoModel.AuditImagePath)
|
||||
.OutputToFile(
|
||||
_outPutNameImg,
|
||||
true,
|
||||
options => options.WithCustomArgument("-filter_complex \"[0:v][1:v] overlay=0:0\" ")
|
||||
)
|
||||
.ProcessSynchronously();
|
||||
|
||||
|
||||
LogUtils.Info($"图片已成功添加到视频中,输出文件:{_outPutName}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogUtils.Error($"图片添加到视频中失败", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LogUtils.Info($"当前视频{string.Join(",", combination)}合并成功");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogUtils.Error($"视频{string.Join(",", combination)}合并失败", ex);
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
|
||||
Task.WhenAll(taskList).ContinueWith((s) =>
|
||||
{
|
||||
//结束时间
|
||||
DateTime endTime = DateTime.Now;
|
||||
LogUtils.Info($"所有视频拼接完成,用时{(endTime - startTime).TotalSeconds}秒");
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -95,10 +193,13 @@ namespace VideoConcat.ViewModels
|
||||
//获取文件夹下所有视频文件
|
||||
foreach (DirectoryInfo Folder in folders)
|
||||
{
|
||||
string[] files = Directory.GetFiles(Folder.FullName, "*.mp4");
|
||||
LogUtils.Info($"{Folder.Name}下有{files.Length}个视频文件");
|
||||
if (Folder.Name != "output")
|
||||
{
|
||||
string[] files = Directory.GetFiles(Folder.FullName, "*.mp4");
|
||||
LogUtils.Info($"{Folder.Name}下有{files.Length}个视频文件");
|
||||
|
||||
VideoModel.FolderInfos.Add(new VideoModel.FolderInfo { DirectoryInfo = Folder, Num = files.Length, VideoPaths = new List<string>(files) });
|
||||
VideoModel.FolderInfos.Add(new VideoModel.FolderInfo { DirectoryInfo = Folder, Num = files.Length, VideoPaths = new List<string>(files) });
|
||||
}
|
||||
}
|
||||
VideoModel.UpdateSum();
|
||||
}
|
||||
@ -110,20 +211,7 @@ namespace VideoConcat.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
class BtnOpenFolderCommand : ICommand
|
||||
{
|
||||
public event EventHandler? CanExecuteChanged;
|
||||
|
||||
public bool CanExecute(object? parameter) => true;
|
||||
|
||||
public void Execute(object? parameter)
|
||||
{
|
||||
DoExcue?.Invoke(parameter);
|
||||
}
|
||||
|
||||
public Action<Object?>? DoExcue { get; set; }
|
||||
}
|
||||
class BtnStartVideoConcatCommand : ICommand
|
||||
class Command : ICommand
|
||||
{
|
||||
public event EventHandler? CanExecuteChanged;
|
||||
|
||||
|
||||
@ -21,9 +21,16 @@ namespace VideoConcat.Views
|
||||
{
|
||||
if (Username.Text == "admin" && Password.Password == "123456")
|
||||
{
|
||||
|
||||
new Video().Show();
|
||||
Close();
|
||||
}
|
||||
new Video().Show();
|
||||
else
|
||||
{
|
||||
System.Windows.MessageBox.Show("用户名或者密码错误!");
|
||||
Username.Clear();
|
||||
Password.Clear();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
xmlns:wd="https://github.com/WPFDevelopersOrg/WPFDevelopers"
|
||||
xmlns:local="clr-namespace:VideoConcat.Views"
|
||||
mc:Ignorable="d"
|
||||
Title="视频拼接" Height="600" Width="800" WindowStartupLocation="CenterScreen" ResizeMode="NoResize">
|
||||
Title="视频拼接" Height="900" Width="800" ResizeMode="NoResize" WindowStartupLocation="CenterScreen">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
@ -22,7 +22,10 @@
|
||||
<Grid>
|
||||
<StackPanel>
|
||||
<StackPanel>
|
||||
<Grid VerticalAlignment="Center" Margin="10,10">
|
||||
<WrapPanel Margin="10,10">
|
||||
|
||||
|
||||
<!--<Grid VerticalAlignment="Center" Margin="10,10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="35"></RowDefinition>
|
||||
<RowDefinition Height="35"></RowDefinition>
|
||||
@ -31,14 +34,20 @@
|
||||
<ColumnDefinition Width="120"></ColumnDefinition>
|
||||
<ColumnDefinition Width="*"></ColumnDefinition>
|
||||
<ColumnDefinition Width="120"></ColumnDefinition>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label VerticalAlignment="Center" FontSize="16" Margin="5,0" BorderBrush="#7F7F7F" BorderThickness="2" Style="{StaticResource MaterialDesignLabel}" VerticalContentAlignment="Stretch">视频文件夹:</Label>
|
||||
<TextBox Grid.Column="1" Name="FoldPath" Text="{Binding VideoModel.FolderPath,Mode=TwoWay}" IsReadOnly="True" Margin="5,0" BorderBrush="#7F7F7F" BorderThickness="2" FontSize="16" VerticalContentAlignment="Center" materialDesign:HintAssist.Hint="选择视频主文件夹"/>
|
||||
<Button Grid.Column="2" Content="选择" FontSize="16" Command="{Binding VideoModel.BtnOpenFolderCommand}" Background="#40568D" BorderBrush="#7F7F7F" BorderThickness="2" ToolTip="选择含有视频的主文件夹" Style="{StaticResource MaterialDesignRaisedButton}" Margin="5,0" />
|
||||
<Label Grid.Row="1" VerticalAlignment="Center" FontSize="16" Margin="5,0" BorderBrush="#7F7F7F" BorderThickness="2" Style="{StaticResource MaterialDesignLabel}" VerticalContentAlignment="Stretch">视频个数:</Label>
|
||||
<TextBox Grid.Row="1" Grid.Column="1" Name="Num" Text="{Binding VideoModel.Num,Mode=TwoWay}" Margin="5,0" BorderBrush="#7F7F7F" BorderThickness="2" FontSize="16" VerticalContentAlignment="Center" ToolTip="请输入合成视频个数" materialDesign:HintAssist.Hint="请输入拼接视频数目"/>
|
||||
<Button Grid.Row="1" Grid.Column="2" Content="开始拼接" FontSize="16" Command="{Binding VideoModel.BtnStartVideoConcatCommand}" Background="#E54858" BorderBrush="#7F7F7F" BorderThickness="2" ToolTip="开始拼接视频" Style="{StaticResource MaterialDesignRaisedButton}" Margin="5,0" IsEnabled="{Binding VideoModel.CanStart}" Cursor="Hand"/>
|
||||
</Grid>
|
||||
</Grid.ColumnDefinitions>-->
|
||||
|
||||
<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="500" Name="FoldPath" Text="{Binding VideoModel.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 VideoModel.BtnOpenFolderCommand}" Background="#40568D" BorderBrush="#7F7F7F" BorderThickness="2" ToolTip="选择含有视频的主文件夹" Style="{StaticResource MaterialDesignRaisedButton}" Margin="5,2" />
|
||||
<Label Grid.Row="1" Width="100" VerticalAlignment="Center" FontSize="16" Margin="5,2" BorderBrush="#7F7F7F" BorderThickness="2" Style="{StaticResource MaterialDesignLabel}" VerticalContentAlignment="Stretch">选择广审:</Label>
|
||||
<TextBox Grid.Row="1" Width="500" Grid.Column="1" Text="{Binding VideoModel.AuditImagePath,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Margin="5,2" BorderBrush="#7F7F7F" BorderThickness="2" FontSize="16" VerticalContentAlignment="Center" ToolTip="请选择" materialDesign:HintAssist.Hint="请选择"/>
|
||||
<Button Grid.Row="1" Width="100" Grid.Column="2" Content="选择文件" FontSize="16" Command="{Binding VideoModel.BtnChooseAuditImageCommand}" Background="#E54858" BorderBrush="#7F7F7F" BorderThickness="2" ToolTip="选择广审" Style="{StaticResource MaterialDesignRaisedButton}" Margin="5,2"/>
|
||||
<Label Grid.Row="1" Width="100" VerticalAlignment="Center" FontSize="16" Margin="5,2" BorderBrush="#7F7F7F" BorderThickness="2" Style="{StaticResource MaterialDesignLabel}" VerticalContentAlignment="Stretch">视频个数:</Label>
|
||||
<TextBox Grid.Row="1" Width="500" Grid.Column="1" Text="{Binding VideoModel.Num,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Margin="5,2" BorderBrush="#7F7F7F" BorderThickness="2" FontSize="16" VerticalContentAlignment="Center" ToolTip="请输入合成视频个数" materialDesign:HintAssist.Hint="请输入拼接视频数目"/>
|
||||
<Button Grid.Row="1" Width="100" Grid.Column="2" Content="开始拼接" FontSize="16" Command="{Binding VideoModel.BtnStartVideoConcatCommand}" Background="#E54858" BorderBrush="#7F7F7F" BorderThickness="2" ToolTip="开始拼接视频" Style="{StaticResource MaterialDesignRaisedButton}" Margin="5,2" IsEnabled="{Binding VideoModel.CanStart}" Cursor="Hand"/>
|
||||
|
||||
<!--</Grid>-->
|
||||
</WrapPanel>
|
||||
</StackPanel>
|
||||
<StackPanel >
|
||||
<DataGrid ItemsSource="{Binding VideoModel.FolderInfos}" AutoGenerateColumns="False">
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
{
|
||||
"BinaryFolder": "./",
|
||||
"TemporaryFilesFolder": "./tmp"
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user