当前位置: 首页 > news >正文

AI助力,制作视频裁剪软件

1. 视频裁剪软件套路多

最近再做一些测试,经常需要录屏什么的,有时候录制的时长视频,需要裁剪,比如去掉开头一些帧或者结尾的一些帧,就想保留关键点。但是网上下的一些软件,打开一用都是要付费的。所以想着手撸一个吧。。。

2. AI选择

比如chatgpt,豆包,kimi,deepseek等。个人比较推荐chatgpt,,理由??没有

3. 关键代码

 AI生成后,直接修改下细节就可以用

using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.IO;
using System.Diagnostics;
using Microsoft.Win32;namespace VideoTools
{public partial class MainWindow : Window{private DispatcherTimer timer;private bool isPlaying = false;private bool isUserSeeking = false;private TimeSpan frameStep = TimeSpan.FromSeconds(0.04); // 约25帧/秒private TimeSpan startTime = TimeSpan.Zero;private TimeSpan endTime = TimeSpan.Zero;private string ffmpegPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "FFmpeg", "ffmpeg.exe");public MainWindow(){InitializeComponent();// 初始化计时器用于更新进度条和时间显示timer = new DispatcherTimer();timer.Interval = TimeSpan.FromMilliseconds(30); // 更频繁更新以显示毫秒变化timer.Tick += Timer_Tick;// 媒体状态改变事件mediaElement.MediaOpened += MediaElement_MediaOpened;mediaElement.MediaEnded += MediaElement_MediaEnded;mediaElement.MediaFailed += MediaElement_MediaFailed;// 检查FFmpeg是否可用CheckFFmpegAvailability();}// 检查FFmpeg是否可用private void CheckFFmpegAvailability(){try{if (!File.Exists(ffmpegPath)){exportStatusText.Text = "错误: 未找到FFmpeg。请确保ffmpeg.exe已包含在应用程序目录中。";exportButton.IsEnabled = false;return;}// 测试运行Process.Start(new ProcessStartInfo{FileName = ffmpegPath,Arguments = "-version",UseShellExecute = false,CreateNoWindow = true,WindowStyle = ProcessWindowStyle.Hidden});exportStatusText.Text = "";//"FFmpeg已就绪";}catch (Exception ex){exportStatusText.Text = $"错误: 无法运行FFmpeg - {ex.Message}";exportButton.IsEnabled = false;}}// 计时器事件,更新进度条和时间显示private void Timer_Tick(object sender, EventArgs e){if (mediaElement.NaturalDuration.HasTimeSpan && !isUserSeeking){progressSlider.Value = mediaElement.Position.TotalSeconds;currentTimeText.Text = FormatTime(mediaElement.Position);}}// 媒体打开事件private void MediaElement_MediaOpened(object sender, RoutedEventArgs e){if (mediaElement.NaturalDuration.HasTimeSpan){var duration = mediaElement.NaturalDuration.TimeSpan;progressSlider.Maximum = duration.TotalSeconds;totalTimeText.Text = FormatTime(duration);statusText.Visibility = Visibility.Collapsed;// 启用控制按钮playPauseButton.IsEnabled = true;backwardButton.IsEnabled = true;forwardButton.IsEnabled = true;progressSlider.IsEnabled = true;setStartTimeButton.IsEnabled = true;setEndTimeButton.IsEnabled = true;// 重置剪辑时间startTime = TimeSpan.Zero;endTime = duration;startTimeText.Text = "开始: " + FormatTime(startTime);endTimeText.Text = "结束: " + FormatTime(endTime);// 开始更新进度(仅在播放时更新)if (isPlaying)timer.Start();}}// 设置开始时间按钮点击事件private void SetStartTimeButton_Click(object sender, RoutedEventArgs e){if (mediaElement.Source != null && mediaElement.NaturalDuration.HasTimeSpan){startTime = mediaElement.Position;if (startTime >= endTime){endTime = startTime.Add(TimeSpan.FromSeconds(1));if (endTime > mediaElement.NaturalDuration.TimeSpan)endTime = mediaElement.NaturalDuration.TimeSpan;endTimeText.Text = "结束: " + FormatTime(endTime);}startTimeText.Text = "开始: " + FormatTime(startTime);exportButton.IsEnabled = true;exportStatusText.Text = "";}}// 设置结束时间按钮点击事件private void SetEndTimeButton_Click(object sender, RoutedEventArgs e){if (mediaElement.Source != null && mediaElement.NaturalDuration.HasTimeSpan){endTime = mediaElement.Position;if (endTime <= startTime){startTime = endTime.Subtract(TimeSpan.FromSeconds(1));if (startTime < TimeSpan.Zero)startTime = TimeSpan.Zero;startTimeText.Text = "开始: " + FormatTime(startTime);}endTimeText.Text = "结束: " + FormatTime(endTime);exportButton.IsEnabled = true;exportStatusText.Text = "";}}// 导出按钮点击事件private void ExportButton_Click(object sender, RoutedEventArgs e){if (mediaElement.Source != null && mediaElement.NaturalDuration.HasTimeSpan){// 检查开始和结束时间是否有效if (startTime >= endTime){MessageBox.Show("开始时间必须小于结束时间", "错误",MessageBoxButton.OK, MessageBoxImage.Error);return;}// 显示保存文件对话框SaveFileDialog saveFileDialog = new SaveFileDialog{Filter = "视频文件|*.mp4;*.avi;*.mkv;*.wmv|所有文件|*.*",Title = "保存剪辑后的视频",DefaultExt = "mp4"};if (saveFileDialog.ShowDialog() == true){string outputFilePath = saveFileDialog.FileName;ExportVideoClip(outputFilePath);}}}// ✅ 集成导出进度到 ProgressBar(需配合前台 XAML 修改)// ✅ 修改点:将进度值通过 Dispatcher.Invoke 更新至 UI 控件private void ExportVideoClip(string outputFilePath){try{PausePlayback();string inputFilePath = string.Empty;TimeSpan duration = TimeSpan.Zero;Dispatcher.Invoke(() =>{exportStatusText.Text = "正在导出视频片段 (0%)...";exportButton.IsEnabled = false;inputFilePath = mediaElement.Source?.LocalPath ?? string.Empty;duration = endTime - startTime;// 初始化进度条(XAML 中需要定义 exportProgressBar)if (exportProgressBar != null){exportProgressBar.Minimum = 0;exportProgressBar.Maximum = 100;exportProgressBar.Value = 0;exportProgressBar.Visibility = Visibility.Visible;}});if (string.IsNullOrWhiteSpace(inputFilePath) || !File.Exists(inputFilePath)){Dispatcher.Invoke(() =>{exportStatusText.Text = "导出失败: 无效的输入文件路径";exportButton.IsEnabled = true;});return;}if (duration.TotalMilliseconds <= 0){Dispatcher.Invoke(() =>{exportStatusText.Text = "导出失败: 选择的时间区间无效";exportButton.IsEnabled = true;});return;}System.Threading.Thread exportThread = new System.Threading.Thread(() =>{try{string arguments = $"-ss {FormatTimeForFFmpeg(startTime)} -i \"{inputFilePath}\" -t {FormatTimeForFFmpeg(duration)} -y -movflags +faststart -preset ultrafast \"{outputFilePath}\"";ProcessStartInfo startInfo = new ProcessStartInfo{FileName = ffmpegPath,Arguments = arguments,UseShellExecute = false,CreateNoWindow = true,RedirectStandardOutput = true,RedirectStandardError = true};using (Process process = new Process { StartInfo = startInfo }){process.Start();while (!process.StandardError.EndOfStream){string line = process.StandardError.ReadLine();if (line != null && line.Contains("time=")){var match = System.Text.RegularExpressions.Regex.Match(line, @"time=(\d{2}):(\d{2}):(\d{2})\.(\d+)");if (match.Success){var t = new TimeSpan(int.Parse(match.Groups[1].Value),int.Parse(match.Groups[2].Value),int.Parse(match.Groups[3].Value)) +TimeSpan.FromMilliseconds(int.Parse(match.Groups[4].Value.PadRight(3, '0')));double progress = Math.Min(100.0, t.TotalMilliseconds / duration.TotalMilliseconds * 100);Dispatcher.Invoke(() =>{exportStatusText.Text = $"正在导出视频片段 ({progress:F1}%)...";if (exportProgressBar != null)exportProgressBar.Value = progress;});}}}process.WaitForExit();Dispatcher.Invoke(() =>{exportProgressBar.Visibility = Visibility.Collapsed;if (process.ExitCode == 0 && File.Exists(outputFilePath) && new FileInfo(outputFilePath).Length > 0){exportStatusText.Text = "导出成功!";MessageBox.Show($"视频片段已成功导出到:\n{outputFilePath}","导出完成", MessageBoxButton.OK, MessageBoxImage.Information);}else{exportStatusText.Text = "导出失败";MessageBox.Show("导出失败,请检查FFmpeg输出", "错误", MessageBoxButton.OK, MessageBoxImage.Error);}exportButton.IsEnabled = true;});}}catch (Exception ex){Dispatcher.Invoke(() =>{exportProgressBar.Visibility = Visibility.Collapsed;exportStatusText.Text = "导出失败";exportButton.IsEnabled = true;MessageBox.Show($"导出视频时出错:\n{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);});}});exportThread.IsBackground = true;exportThread.Start();}catch (Exception ex){Dispatcher.Invoke(() =>{exportStatusText.Text = "导出失败";exportButton.IsEnabled = true;MessageBox.Show($"导出视频时出错:\n{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);});}}// 格式化时间为FFmpeg可用的格式 (HH:MM:SS.mmm)private string FormatTimeForFFmpeg(TimeSpan time){return time.ToString(@"hh\:mm\:ss\.fff");}// 媒体播放结束事件private void MediaElement_MediaEnded(object sender, RoutedEventArgs e){PausePlayback();mediaElement.Position = TimeSpan.Zero;UpdateTimeDisplay();}// 媒体播放失败事件private void MediaElement_MediaFailed(object sender, ExceptionRoutedEventArgs e){MessageBox.Show($"视频播放失败: {e.ErrorException.Message}", "错误",MessageBoxButton.OK, MessageBoxImage.Error);statusText.Text = "视频加载失败";statusText.Visibility = Visibility.Visible;PausePlayback();}// 窗口拖放事件private void Window_Drop(object sender, DragEventArgs e){if (e.Data.GetDataPresent(DataFormats.FileDrop)){string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);if (files.Length > 0){OpenVideoFile(files[0]);}}}// 窗口拖入事件private void Window_DragEnter(object sender, DragEventArgs e){if (e.Data.GetDataPresent(DataFormats.FileDrop)){string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);if (files.Length == 1 && IsVideoFile(files[0])){e.Effects = DragDropEffects.Copy;}else{e.Effects = DragDropEffects.None;}}else{e.Effects = DragDropEffects.None;}e.Handled = true;}// 打开视频文件private void OpenVideoFile(string filePath){try{if (File.Exists(filePath) && IsVideoFile(filePath)){// 停止当前播放PausePlayback();// 加载新视频mediaElement.Source = new Uri(filePath);mediaElement.LoadedBehavior = MediaState.Manual;StartPlayback();statusText.Text = "加载中...";statusText.Visibility = Visibility.Visible;}else{MessageBox.Show("请选择有效的视频文件", "错误",MessageBoxButton.OK, MessageBoxImage.Error);}}catch (Exception ex){MessageBox.Show($"打开视频时出错: {ex.Message}", "错误",MessageBoxButton.OK, MessageBoxImage.Error);}}// 检查文件是否为视频文件private bool IsVideoFile(string filePath){string extension = System.IO.Path.GetExtension(filePath).ToLower();string[] videoExtensions = { ".mp4", ".avi", ".mkv", ".wmv", ".mov", ".flv", ".webm" };return Array.IndexOf(videoExtensions, extension) >= 0;}// 播放/暂停按钮点击事件private void PlayPauseButton_Click(object sender, RoutedEventArgs e){if (mediaElement.Source != null){if (isPlaying)PausePlayback();elseStartPlayback();}}// 开始播放private void StartPlayback(){mediaElement.Play();playPauseButton.Content = "❚❚";isPlaying = true;timer.Start();}// 暂停播放private void PausePlayback(){mediaElement.Pause();playPauseButton.Content = "▶";isPlaying = false;timer.Stop();}// 后退一帧按钮点击事件private void BackwardButton_Click(object sender, RoutedEventArgs e){if (mediaElement.Source != null){bool wasPlaying = isPlaying;if (wasPlaying) PausePlayback();var newPosition = mediaElement.Position - frameStep;if (newPosition < TimeSpan.Zero)newPosition = TimeSpan.Zero;mediaElement.Position = newPosition;UpdateTimeDisplay();if (wasPlaying) StartPlayback();}}// 前进一帧按钮点击事件private void ForwardButton_Click(object sender, RoutedEventArgs e){if (mediaElement.Source != null && mediaElement.NaturalDuration.HasTimeSpan){bool wasPlaying = isPlaying;if (wasPlaying) PausePlayback();var newPosition = mediaElement.Position + frameStep;if (newPosition > mediaElement.NaturalDuration.TimeSpan)newPosition = mediaElement.NaturalDuration.TimeSpan;mediaElement.Position = newPosition;UpdateTimeDisplay();if (wasPlaying) StartPlayback();}}// 进度条值改变事件private void ProgressSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e){if (mediaElement.Source != null && progressSlider.IsEnabled){if (Mouse.LeftButton == MouseButtonState.Pressed || isUserSeeking){isUserSeeking = true;mediaElement.Position = TimeSpan.FromSeconds(progressSlider.Value);UpdateTimeDisplay();}}}// 鼠标释放事件,结束用户拖动private void ProgressSlider_MouseUp(object sender, MouseButtonEventArgs e){isUserSeeking = false;}// 更新时间显示private void UpdateTimeDisplay(){currentTimeText.Text = FormatTime(mediaElement.Position);}// 格式化时间显示(精确到毫秒)private string FormatTime(TimeSpan time){if (time.TotalHours >= 1)return time.ToString(@"hh\:mm\:ss\.fff");else if (time.TotalMinutes >= 1)return time.ToString(@"mm\:ss\.fff");elsereturn time.ToString(@"ss\.fff");}}
}

视频裁剪工具,视频浏览,支持各类视频文件-*.mp4;*.avi;*.mkv;*.wmv播放,支持视频裁剪,完全免费使用资源-CSDN文库 

相关文章:

  • Spring Cloud Sleuth与Zipkin深度整合指南:微服务链路追踪实战
  • 大剧院订座系统源码,大剧院订票,大剧院场馆租赁,大剧院订票系统完整源码
  • Day 31 训练
  • PowerBI切片器美化
  • 深入解析Spring Boot与JUnit 5集成测试的最佳实践
  • 云原生安全基石:深度解析HTTPS协议(从原理到实战)
  • 【2025】ubuntu22.04 docker安装全过程
  • 历年华中科技大学保研上机真题
  • 用神经网络对信贷项目进行预测
  • win主机,Ubuntu,IMX6ULL开发板网络通讯
  • 计算机视觉---YOLOv1
  • DeepSeek 赋能金融量化交易:从技术突破到实战革新
  • C 语言学习笔记
  • LabVIEW实战项目推荐与学习建议
  • Python训练营打卡Day36
  • MyBatis实战指南(三)MyBatis常用配置详解(XML配置,环境配置,类型别名,属性与映射器)
  • HarmonyOS NEXT 技术特性:分布式软总线技术架构
  • Python 学习日记 day26
  • 《JavaScript 性能优化:从原理到实战的全面指南》
  • C# 怎么做chat柱状图能实现不同的颜色,还带游标
  • 海口网站制作案例/烟台seo快速排名
  • 建设公司网站价格/百度人工申诉客服电话
  • 一是加强了网站建设/成都最新消息今天
  • 定制网站开发公司/河南郑州网站推广优化外包
  • 同安建设局网站/南昌seo
  • 网站类型/今日舆情热点