懒人记时 代码仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

114 regels
3.3 KiB

  1. using AppTime.Properties;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Drawing;
  6. using System.Drawing.Imaging;
  7. using System.IO;
  8. using System.IO.MemoryMappedFiles;
  9. using System.IO.Pipes;
  10. using System.Linq;
  11. using System.Text;
  12. using System.Threading;
  13. using System.Threading.Tasks;
  14. using System.Windows.Forms;
  15. using static AppTime.Recorder;
  16. namespace AppTime
  17. {
  18. class Ffmpeg
  19. {
  20. static Process lastFfmpeg;
  21. public static void KillLastFfmpeg()
  22. {
  23. if (lastFfmpeg != null && !lastFfmpeg.HasExited)
  24. {
  25. Utils.Try(() => lastFfmpeg.Kill());
  26. lastFfmpeg = null;
  27. }
  28. }
  29. public static byte[] Snapshot(string file, TimeSpan time)
  30. {
  31. var args = $@"-loglevel quiet -ss {time} -i ""{file}"" -y -frames 1 -q:v 2 -f image2 -";
  32. var info = new ProcessStartInfo(@"ffmpeg\ffmpeg.exe", args)
  33. {
  34. RedirectStandardOutput = true,
  35. RedirectStandardError = true,
  36. RedirectStandardInput = true,
  37. UseShellExecute = false,
  38. CreateNoWindow = true,
  39. WorkingDirectory = Path.GetDirectoryName(Application.ExecutablePath)
  40. };
  41. var p = lastFfmpeg = Process.Start(info);
  42. var output = p.StandardOutput.BaseStream;
  43. var data = new List<byte>();
  44. var b = output.ReadByte();
  45. while (b != -1)
  46. {
  47. data.Add((byte)b);
  48. b = output.ReadByte();
  49. }
  50. return data.ToArray();
  51. }
  52. public static void Save(string file, params Frame[] images)
  53. {
  54. if (images.Length == 0)
  55. {
  56. return;
  57. }
  58. var rate = images.Length / ((images.Last().Time - images.First().Time).TotalSeconds + 1);
  59. var crf = Settings.Default.ImageQuality;//0-质量最高 63-质量最低 实测40质量也不错且体积较小
  60. var tempfile = Path.Combine(Path.GetDirectoryName(file), Path.GetFileNameWithoutExtension(file) + ".tmp");
  61. var args = $@"-loglevel quiet -f image2pipe -r {rate} -i - -vcodec libx264 -crf {crf} -f matroska -y ""{tempfile}""";
  62. var info = new ProcessStartInfo(@"ffmpeg\ffmpeg.exe", args)
  63. {
  64. RedirectStandardOutput = true,
  65. RedirectStandardError = true,
  66. RedirectStandardInput = true,
  67. UseShellExecute = false,
  68. CreateNoWindow = true,
  69. WorkingDirectory = Path.GetDirectoryName(Application.ExecutablePath)
  70. };
  71. var p = Process.Start(info);
  72. p.PriorityClass = ProcessPriorityClass.BelowNormal;
  73. foreach (var i in images)
  74. {
  75. p.StandardInput.BaseStream.Write(i.Data, 0, i.Data.Length);
  76. }
  77. p.StandardInput.Close();
  78. p.WaitForExit();
  79. if (File.Exists(file))
  80. {
  81. File.Delete(file);
  82. }
  83. File.Move(tempfile, file);
  84. }
  85. }
  86. public class Frame
  87. {
  88. public TimeSpan Time;
  89. public byte[] Data;
  90. public Frame(TimeSpan time, byte[] data)
  91. {
  92. this.Time = time;
  93. this.Data = data;
  94. }
  95. }
  96. }