问题:在使用cmd窗口执行以上命令时(cmd中参数前面要加 ffmpeg 注意文件位置),可以成功处理,但在运行WPF测试的时候,发现只有一个大小为0kb的新文件生成,但迟迟不见处理。给人一种假死的现象。而当关掉调试的WPF程序时,过几秒钟,貌似ffmpeg.exe 又起作用了,文件处理成功了。这个不得其解.
原因:process.WaitForExit(); 这句执行会造成程序一直处于等待状态。于是,抱着试试看的态度,注释了这一句。当然,程序不再等待外部进程完成执行,proces.Close(); 这一句也要注释一下,测试结果成功!
<Application x:Class="VideoWatermark.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:VideoWatermark"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml"/>
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
<Window x:Class="VideoWatermark.MainWindow"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:VideoWatermark"
Icon="ico.ico"
mc:Ignorable="d"
ResizeMode="CanMinimize"
Title="VideoWatermark" Height="500" Width="815">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="300"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="800"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBox x:Name="VideosPathTextBox" Style="{StaticResource TextBoxExtend}" hc:InfoElement.TitlePlacement="Left" hc:InfoElement.Title="视频文件:" Width="600" VerticalAlignment="Center" IsEnabled="False"/>
<Button Style="{StaticResource ButtonPrimary}" Width="85" Content="选择文件" Click="SelectVideoButton_Click"/>
</StackPanel>
<StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBox x:Name="TxtWatermarkPath" Style="{StaticResource TextBoxExtend}" hc:InfoElement.TitlePlacement="Left" hc:InfoElement.Title="图片水印:" Width="600" VerticalAlignment="Center" IsEnabled="False"/>
<Button Style="{StaticResource ButtonPrimary}" Width="85" Content="选择水印" Click="Button_WatermarkClick"/>
</StackPanel>
<StackPanel Grid.Row="2" Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
<Button Style="{StaticResource ButtonPrimary}" Width="335" Content="开始" Click="Button_AddWatermarkButton_Click" Margin="0,0,10,0"/>
<Button Style="{StaticResource ButtonPrimary}" Width="335" Content="清空" Click="Button_ClearList_Click"/>
</StackPanel>
<StackPanel Grid.Row="3" Grid.Column="0" Orientation="Vertical" VerticalAlignment="Top" HorizontalAlignment="Center">
<ListView x:Name="VideosListView" ItemsSource="{Binding DataList}" >
<ListView.View>
<GridView>
<GridViewColumn Width="80" Header="序号" DisplayMemberBinding="{Binding Index}"/>
<GridViewColumn Width="500" Header="名称" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Width="80" Header="状态" DisplayMemberBinding="{Binding Remark}"/>
</GridView>
</ListView.View>
</ListView>
<Border x:Name="NoDataBorder" Style="{StaticResource BorderRegion}" Visibility="Visible">
<TextBlock Text="没有数据" Height="200" HorizontalAlignment="Center" Foreground="#000000"/>
</Border>
</StackPanel>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.IO;
using Microsoft.Win32;
using VideoWatermark.Models;
using System.Diagnostics;
namespace VideoWatermark
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public ObservableCollection<VideoItem> DataList { get; set; } = new ObservableCollection<VideoItem>();
public MainWindow()
{
InitializeComponent();
DataList = new ObservableCollection<VideoItem>(); // 初始化DataList
DataContext = this;
}
private void SelectVideoButton_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog
{
Multiselect = true,
Filter = "Video files (*.mp4;*.avi;*.wmv)|*.mp4;*.avi|All files (*.*)|*.*"
};
if (openFileDialog.ShowDialog() == true)
{
// 获取已在DataList中的文件名
var existingFiles = DataList.Select(v => v.Name).ToList();
// 将选中的文件路径添加到文本框,同时避免重复
List<string> newFiles = new List<string>();
int index = DataList.Count + 1; // 计算新的起始序号
foreach (string fileName in openFileDialog.FileNames)
{
string justFileName = Path.GetFileName(fileName);
if (!existingFiles.Contains(justFileName))
{
newFiles.Add(fileName);
// 只有当文件不在列表中时,才添加到DataList
DataList.Add(new VideoItem
{
Index = index++,
Name = justFileName,
Remark = "待处理"
});
}
}
// 更新文本框
if (newFiles.Any())
{
string existingText = VideosPathTextBox.Text;
if (!string.IsNullOrEmpty(existingText))
{
VideosPathTextBox.Text += ";";
}
VideosPathTextBox.Text += string.Join(";", newFiles);
}
UpdateNoDataVisibility();
// 更新ListView
VideosListView.ItemsSource = null;
VideosListView.ItemsSource = DataList;
}
}
private void Button_WatermarkClick(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "图片文件|*.png;*.jpg;*.jpeg|所有文件|*.*";
if (openFileDialog.ShowDialog() == true)
{
TxtWatermarkPath.Text = openFileDialog.FileName;
}
}
private void Button_ClearList_Click(object sender, RoutedEventArgs e)
{
DataList.Clear();
VideosPathTextBox.Text = string.Empty;
VideosListView.ItemsSource = null;
VideosListView.ItemsSource = DataList;
UpdateNoDataVisibility();
HandyControl.Controls.MessageBox.Show(this, "列表已清空", "提示");
}
private async void Button_AddWatermarkButton_Click(object sender, RoutedEventArgs e)
{
string watermarkImage = TxtWatermarkPath.Text;
string[] videoFiles = VideosPathTextBox.Text.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
// 检查是否导入了视频文件
if (videoFiles.Length == 0)
{
HandyControl.Controls.MessageBox.Show(this, "请先导入视频文件!", "缺少视频");
return;
}
// 检查是否导入了水印图片
if (string.IsNullOrWhiteSpace(watermarkImage) || !File.Exists(watermarkImage))
{
HandyControl.Controls.MessageBox.Show(this, "请先导入水印图片!", "缺少水印");
return;
}
foreach (string videoFile in videoFiles)
{
// 检查视频文件是否存在
if (!File.Exists(videoFile))
{
UpdateVideoItemStatus(Path.GetFileName(videoFile), "文件不存在");
continue; // 跳过不存在的文件
}
UpdateVideoItemStatus(Path.GetFileName(videoFile), "正在处理");
await Task.Run(() => RunFFmpegProcess(videoFile, watermarkImage));
// 更新视频状态为 "已完成"
UpdateVideoItemStatus(Path.GetFileName(videoFile), "已完成");
}
HandyControl.Controls.MessageBox.Show(this, "所有添加水印操作完成!", "提示");
}
private void RunFFmpegProcess(string videoFile, string watermarkImage)
{
string outputVideo = Path.Combine(Path.GetDirectoryName(videoFile), "watermarked_" + Path.GetFileName(videoFile));
// 在这里编写使用 FFmpeg 添加水印的代码
string ffmpegArgs = $"-i \"{videoFile}\" -i \"{watermarkImage}\" -filter_complex \"overlay=x='mod(main_h/0.8*ceil(t),main_w)':y='mod(main_w/3*ceil(t/2),main_h)'\" \"{outputVideo}\"";
// 请确保你已经正确配置 FFmpeg.AutoGen,并且有 FFmpeg 的可执行文件
//string ffmpegPath = @"C:\Users\az102\ Visual Studio Source\repos\VideoWatermark\VideoWatermark\FFmpeg\ffmpeg.exe"; // 请根据实际路径配置 FFmpeg 可执行文件路径
string ffmpegPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "FFmpeg", "ffmpeg.exe");
Process process = new Process();
process.StartInfo.FileName = ffmpegPath;
process.StartInfo.Arguments = $"-i \"{videoFile}\" -i \"{watermarkImage}\" -filter_complex \"overlay=x='mod(main_h/0.8*ceil(t),main_w)':y='mod(main_w/3*ceil(t/2),main_h)'\" \"{outputVideo}\"";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;
process.Start();
process.WaitForExit();
process.Close();
}
private void UpdateVideoItemStatus(string fileName, string status)
{
var videoItem = DataList.FirstOrDefault(v => v.Name == fileName);
if (videoItem != null)
{
Application.Current.Dispatcher.Invoke(() =>
{
videoItem.Remark = status;
});
}
}
private void UpdateNoDataVisibility()
{
if (DataList.Count > 0)
{
NoDataBorder.Visibility = Visibility.Collapsed;
}
else
{
NoDataBorder.Visibility = Visibility.Visible;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
namespace VideoWatermark.Models
{
public class VideoItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int Index { get; set; }
private string name;
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged("Name");
}
}
private string remark;
public string Remark
{
get { return remark; }
set
{
remark = value;
OnPropertyChanged("Remark");
}
}
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}