星火微课系统客户端
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

VideoClipWindow.xaml.cs 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. using System;
  2. using System.Text.RegularExpressions;
  3. using System.Windows;
  4. using System.Windows.Input;
  5. using System.Windows.Threading;
  6. namespace XHWK.WKTool
  7. {
  8. using system;
  9. /// <summary>
  10. /// 视频剪辑
  11. /// VideoClipWindow.xaml 的交互逻辑
  12. /// </summary>
  13. public partial class VideoClipWindow
  14. {
  15. /// <summary>
  16. /// 视频地址
  17. /// </summary>
  18. string _videoPath;
  19. /// <summary>
  20. /// 视频剪辑
  21. /// </summary>
  22. public VideoClipWindow()
  23. {
  24. InitializeComponent();
  25. Width = App.W_XHMicroLessonSystemWindow.ActualWidth;
  26. Height = App.W_XHMicroLessonSystemWindow.ActualHeight;
  27. }
  28. public bool InitClipVideo(string mVideoPath)
  29. {
  30. if (FileToolsCommon.IsExistFile(mVideoPath))
  31. {
  32. _videoPath = mVideoPath;
  33. QsMovie.Source = new Uri(_videoPath);
  34. double prop = QsMovie.NaturalVideoHeight / (double)QsMovie.NaturalVideoWidth;
  35. double gridWidth = GridMovie.ActualHeight / prop;
  36. if (gridWidth <= GridMovie.ActualWidth)
  37. {
  38. QsMovie.Width = gridWidth;
  39. QsMovie.Height = GridMovie.ActualHeight;
  40. }
  41. else
  42. {
  43. QsMovie.Height = GridMovie.ActualWidth * prop;
  44. QsMovie.Width = GridMovie.ActualWidth;
  45. }
  46. DataContext = App.PageContextData;
  47. }
  48. else
  49. {
  50. return false;
  51. }
  52. return true;
  53. }
  54. /// <summary>
  55. /// 计时器
  56. /// </summary>
  57. DispatcherTimer _dispatcherTimer = new System.Windows.Threading.DispatcherTimer(); // 定义一个DT
  58. /// <summary>
  59. /// 播放/暂停
  60. /// </summary>
  61. /// <param name="sender"></param>
  62. /// <param name="e"></param>
  63. private void Play_Click(object sender, RoutedEventArgs e)
  64. {
  65. if (_isPlay)
  66. {
  67. MoviePause();
  68. }
  69. else
  70. {
  71. MoviePlay();
  72. }
  73. }
  74. /// <summary>
  75. /// 正在播放
  76. /// </summary>
  77. bool _isPlay;
  78. /// <summary>
  79. /// 播放
  80. /// </summary>
  81. public void MoviePlay()
  82. {
  83. _isPlay = true;
  84. ImgPlay.Visibility = Visibility.Collapsed;
  85. ImgPause.Visibility = Visibility.Visible;
  86. QsMovie.Play();
  87. }
  88. /// <summary>
  89. /// 暂停
  90. /// </summary>
  91. public void MoviePause()
  92. {
  93. _isPlay = false;
  94. ImgPlay.Visibility = Visibility.Visible;
  95. ImgPause.Visibility = Visibility.Collapsed;
  96. QsMovie.Pause();
  97. }
  98. /// <summary>
  99. /// slider滑动值随播放内容位置变化
  100. /// </summary>
  101. /// <param name="sender"></param>
  102. /// <param name="e"></param>
  103. private void dispatcherTimer_Tick(object sender, EventArgs e)
  104. {
  105. TimelineSlider.Value = QsMovie.Position.TotalMilliseconds; //slider滑动值随播放内容位置变化
  106. LblProgress.Content = new TimeSpan(
  107. 0,
  108. 0,
  109. 0,
  110. 0,
  111. (int)QsMovie.Position.TotalMilliseconds
  112. ).ToString(@"hh\:mm\:ss");
  113. }
  114. /// <summary>
  115. /// 拖动进度条
  116. /// </summary>
  117. /// <param name="sender"></param>
  118. /// <param name="e"></param>
  119. private void TimelineMDown(object sender, EventArgs e)
  120. {
  121. _dispatcherTimer.Stop();
  122. }
  123. /// <summary>
  124. /// 拖动进度条
  125. /// </summary>
  126. /// <param name="sender"></param>
  127. /// <param name="e"></param>
  128. private void TimelineMUp(object sender, EventArgs e)
  129. {
  130. QsMovie.Position = new TimeSpan(
  131. 0,
  132. 0,
  133. 0,
  134. 0,
  135. (int)TimelineSlider.Value
  136. );
  137. _dispatcherTimer.Start();
  138. MoviePlay();
  139. }
  140. /// <summary>
  141. /// 加载视频
  142. /// </summary>
  143. /// <param name="sender"></param>
  144. /// <param name="e"></param>
  145. private void QS_Movie_Loaded(object sender, RoutedEventArgs e)
  146. {
  147. //GridMovie.Height
  148. UcSlider.SilderWidth = (int)TimelineSlider.ActualWidth;
  149. MoviePlay();
  150. while (QsMovie.NaturalVideoWidth == 0)
  151. {
  152. System.Threading.Thread.Sleep(50);
  153. }
  154. MoviePause();
  155. //new Thread(new ThreadStart(new Action(() =>
  156. //{
  157. // Dispatcher.Invoke(() =>
  158. // {
  159. //});
  160. //}))).Start();
  161. }
  162. /// <summary>
  163. /// 关闭
  164. /// </summary>
  165. /// <param name="sender"></param>
  166. /// <param name="e"></param>
  167. private void Button_Click(object sender, RoutedEventArgs e)
  168. {
  169. //this.Close();
  170. QsMovie.Stop();
  171. _isPlay = false;
  172. ImgPlay.Visibility = Visibility.Visible;
  173. ImgPause.Visibility = Visibility.Collapsed;
  174. UcSlider.StartValue = 0;
  175. TimelineSlider.Value = 0;
  176. _dispatcherTimer.Stop();
  177. Hide();
  178. }
  179. double _statime;
  180. private void UcSlider_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  181. {
  182. //dispatcherTimer.Stop();
  183. _statime = UcSlider.StartValue;
  184. }
  185. private void UcSlider_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
  186. {
  187. if (Math.Abs(UcSlider.StartValue - _statime) > 100)
  188. {
  189. _dispatcherTimer.Stop();
  190. TimelineSlider.Value = UcSlider.StartValue;
  191. QsMovie.Position = new TimeSpan(
  192. 0,
  193. 0,
  194. 0,
  195. 0,
  196. (int)TimelineSlider.Value
  197. );
  198. _dispatcherTimer.Start();
  199. UcSlider_PreviewMouseMove(null, null);
  200. MoviePlay();
  201. }
  202. }
  203. private void UcSlider_PreviewMouseMove(object sender, MouseEventArgs e)
  204. {
  205. TxbStartTime.Text = new TimeSpan(
  206. 0,
  207. 0,
  208. 0,
  209. 0,
  210. (int)UcSlider.StartValue
  211. ).ToString(@"hh\:mm\:ss\.fff");
  212. TxbEndTime.Text = new TimeSpan(
  213. 0,
  214. 0,
  215. 0,
  216. 0,
  217. (int)UcSlider.EndValue
  218. ).ToString(@"hh\:mm\:ss\.fff");
  219. LblVideoTime.Content = new TimeSpan(
  220. 0,
  221. 0,
  222. 0,
  223. 0,
  224. ((int)UcSlider.EndValue - (int)UcSlider.StartValue)
  225. ).ToString(@"hh\:mm\:ss\.fff");
  226. //LblStartTime.Content = new TimeSpan(0, 0, 0, 0, (int)UcSlider.StartValue).ToString(@"hh\:mm\:ss");
  227. //LblEndTime.Content = new TimeSpan(0, 0, 0, 0, (int)UcSlider.EndValue).ToString(@"hh\:mm\:ss");
  228. //LblVideoTime.Content = new TimeSpan(0, 0, 0, 0, ((int)(UcSlider.EndValue - (UcSlider.EndValue % 1000)) - (int)(UcSlider.StartValue - (UcSlider.StartValue % 1000)))).ToString(@"hh\:mm\:ss");
  229. }
  230. /// <summary>
  231. /// 剪辑
  232. /// </summary>
  233. /// <param name="sender"></param>
  234. /// <param name="e"></param>
  235. private void BtnClip_Click(object sender, RoutedEventArgs e)
  236. {
  237. if ((UcSlider.EndValue - UcSlider.StartValue) < 1000)
  238. {
  239. MessageWindow.Show("剪辑时间不得小于1秒!");
  240. return;
  241. }
  242. _dispatcherTimer.Stop();
  243. MoviePause();
  244. string extension = FileToolsCommon.GetIoExtension(_videoPath);
  245. string fileName = FileToolsCommon.GetIoFileNameNoExtension(_videoPath);
  246. System.Windows.Forms.SaveFileDialog saveDg = new System.Windows.Forms.SaveFileDialog();
  247. saveDg.Filter = @"(*" + extension + @")|*" + extension; // + "|(*.MP4)|*.MP4";
  248. //saveDg.FileName = tableName + DateTime.Now.ToString("yyyy-MM-dd_hh-mm-ss") + "";
  249. saveDg.FileName = fileName + "剪辑";
  250. saveDg.AddExtension = true;
  251. saveDg.RestoreDirectory = true;
  252. if (saveDg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
  253. {
  254. string filePath = saveDg.FileName;
  255. //duration.ToString(@"dd\.hh\:mm\:ss");
  256. TimeSpan startTp = new TimeSpan(
  257. 0,
  258. 0,
  259. 0,
  260. 0,
  261. (int)UcSlider.StartValue
  262. );
  263. string startTime = startTp.ToString(@"hh\:mm\:ss\.fff");
  264. TimeSpan endTp = new TimeSpan(
  265. 0,
  266. 0,
  267. 0,
  268. 0,
  269. (int)UcSlider.EndValue
  270. );
  271. string endTime = endTp.ToString(@"hh\:mm\:ss\.fff");
  272. App.FFmpeg.ClipVideo(
  273. _videoPath,
  274. startTime,
  275. endTime,
  276. filePath
  277. );
  278. MessageBoxResult br = MessageWindow.Show(
  279. "剪辑完成是否打开文件夹?",
  280. "剪辑",
  281. MessageBoxButton.OKCancel
  282. );
  283. if (br == MessageBoxResult.OK)
  284. {
  285. //System.Diagnostics.Process.Start(FileToolsCommon.GetDirectoryName(filePath));
  286. System.Diagnostics.Process.Start("explorer.exe", "/select," + filePath);
  287. }
  288. }
  289. }
  290. /// <summary>
  291. /// 输入开始时间
  292. /// </summary>
  293. /// <param name="sender"></param>
  294. /// <param name="e"></param>
  295. private void TxbStartTime_LostFocus(object sender, RoutedEventArgs e)
  296. {
  297. //判断是否为时间格式
  298. if (!TimeStrRegularJudg(TxbStartTime.Text))
  299. {
  300. MessageWindow.Show("请输入正确的时间格式:hh:mm:ss.fff");
  301. return;
  302. }
  303. TimeSpan time = ConvertToTimeSpan(TxbStartTime.Text);
  304. if (time.TotalMilliseconds > UcSlider.EndValue)
  305. {
  306. MessageWindow.Show("开始时间不能大于结束时间!");
  307. return;
  308. }
  309. if (time.TotalMilliseconds > QsMovie.NaturalDuration.TimeSpan.TotalMilliseconds - 1000 || time.TotalMilliseconds > UcSlider.EndValue - 1000)
  310. {
  311. MessageWindow.Show("剪辑时间不能小于1秒!");
  312. return;
  313. }
  314. UcSlider.StartValue = time.TotalMilliseconds;
  315. UcSlider_PreviewMouseLeftButtonUp(null, null);
  316. }
  317. /// <summary>
  318. /// 输入结束时间
  319. /// </summary>
  320. /// <param name="sender"></param>
  321. /// <param name="e"></param>
  322. private void TxbEndTime_LostFocus(object sender, RoutedEventArgs e)
  323. {
  324. //判断是否为时间格式
  325. if (!TimeStrRegularJudg(TxbEndTime.Text))
  326. {
  327. MessageWindow.Show("请输入正确的时间格式:hh:mm:ss.fff");
  328. return;
  329. }
  330. TimeSpan time = ConvertToTimeSpan(TxbEndTime.Text);
  331. if (time.TotalMilliseconds < UcSlider.StartValue)
  332. {
  333. MessageWindow.Show("结束时间不能小于开始时间!");
  334. return;
  335. }
  336. if (time.TotalMilliseconds < UcSlider.StartValue + 1000)
  337. {
  338. MessageWindow.Show("剪辑时间不能小于1秒!");
  339. return;
  340. }
  341. if (time.TotalMilliseconds > QsMovie.NaturalDuration.TimeSpan.TotalMilliseconds)
  342. {
  343. MessageWindow.Show("结束时间不能超出视频总时长!");
  344. return;
  345. }
  346. UcSlider.EndValue = time.TotalMilliseconds;
  347. UcSlider_PreviewMouseLeftButtonUp(null, null);
  348. }
  349. /// <summary>
  350. /// string转TimeSpan
  351. /// </summary>
  352. /// <param name="str"></param>
  353. /// <returns></returns>
  354. public TimeSpan ConvertToTimeSpan(string str)
  355. {
  356. int day = 0;
  357. int hour = 0;
  358. int min = 0;
  359. int sec = 0;
  360. int mil = 0;
  361. string[] strArray1 = str.Split(':');
  362. try
  363. {
  364. if (strArray1[0].Contains("."))
  365. {
  366. string[] strArray2 = strArray1[0].Split('.');
  367. day = Convert.ToInt32(strArray2[0]);
  368. hour = Convert.ToInt32(strArray2[1]);
  369. }
  370. else
  371. {
  372. day = 0;
  373. hour = Convert.ToInt32(strArray1[0]);
  374. }
  375. min = Convert.ToInt32(strArray1[1]);
  376. if (strArray1[2].Contains("."))
  377. {
  378. string[] strArray3 = strArray1[2].Split('.');
  379. sec = Convert.ToInt32(strArray3[0]);
  380. mil = Convert.ToInt32(strArray3[1]);
  381. }
  382. else
  383. {
  384. sec = Convert.ToInt32(strArray1[2]);
  385. }
  386. }
  387. catch (Exception)
  388. {
  389. // ignored
  390. }
  391. return new TimeSpan(
  392. day,
  393. hour,
  394. min,
  395. sec,
  396. mil
  397. );
  398. }
  399. /// <summary>
  400. /// 判断是否为时间格式
  401. /// </summary>
  402. /// <param name="str"></param>
  403. /// <returns></returns>
  404. public bool TimeStrRegularJudg(string str)
  405. {
  406. try
  407. {
  408. Regex reg = new Regex(@"^((20|21|22|23|[0-1]?\d):[0-5]?\d:[0-5]?\d.\d\d\d)$");
  409. return reg.IsMatch(str);
  410. }
  411. catch (Exception)
  412. {
  413. return false;
  414. }
  415. }
  416. /// <summary>
  417. /// 鼠标点击移动
  418. /// </summary>
  419. /// <param name="sender"></param>
  420. /// <param name="e"></param>
  421. private void Title_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  422. {
  423. DragMove();
  424. }
  425. /// <summary>
  426. /// 启动定时器 同步进度条和视频进度
  427. /// </summary>
  428. /// <param name="sender"></param>
  429. /// <param name="e"></param>
  430. private void Element_MediaOpened(object sender, RoutedEventArgs e)
  431. {
  432. TimelineSlider.Maximum = QsMovie.NaturalDuration.TimeSpan.TotalMilliseconds; //设置slider最大值
  433. UcSlider.Maximum = QsMovie.NaturalDuration.TimeSpan.TotalMilliseconds;
  434. UcSlider.StartValue = 0;
  435. UcSlider.EndValue = QsMovie.NaturalDuration.TimeSpan.TotalMilliseconds;
  436. UcSlider_PreviewMouseMove(null, null);
  437. _dispatcherTimer.Tick += dispatcherTimer_Tick; //超过计时间隔时发生
  438. _dispatcherTimer.Interval = new TimeSpan(
  439. 0,
  440. 0,
  441. 0,
  442. 0,
  443. 500
  444. ); //DT间隔
  445. _dispatcherTimer.Start(); //DT启动
  446. #region 调整视频大小
  447. double prop = QsMovie.NaturalVideoHeight / (double)QsMovie.NaturalVideoWidth;
  448. double gridWidth = GridMovie.ActualHeight / prop;
  449. if (gridWidth <= GridMovie.ActualWidth)
  450. {
  451. QsMovie.Width = gridWidth;
  452. QsMovie.Height = GridMovie.ActualHeight;
  453. }
  454. else
  455. {
  456. QsMovie.Height = GridMovie.ActualWidth * prop;
  457. QsMovie.Width = GridMovie.ActualWidth;
  458. }
  459. #endregion
  460. }
  461. }
  462. }