FFProbe.cs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. using System;
  2. using System.Diagnostics;
  3. using System.IO;
  4. using System.Threading.Tasks;
  5. using MediaBrowser.Common.Logging;
  6. using MediaBrowser.Common.Serialization;
  7. using MediaBrowser.Model.Entities;
  8. namespace MediaBrowser.Controller.FFMpeg
  9. {
  10. /// <summary>
  11. /// Runs FFProbe against a media file and returns metadata.
  12. /// </summary>
  13. public static class FFProbe
  14. {
  15. public async static Task<FFProbeResult> Run(Audio item, string outputCachePath)
  16. {
  17. // Use try catch to avoid having to use File.Exists
  18. try
  19. {
  20. using (FileStream stream = File.OpenRead(outputCachePath))
  21. {
  22. return JsonSerializer.DeserializeFromStream<FFProbeResult>(stream);
  23. }
  24. }
  25. catch (FileNotFoundException)
  26. {
  27. }
  28. await Run(item.Path, outputCachePath);
  29. using (FileStream stream = File.OpenRead(outputCachePath))
  30. {
  31. return JsonSerializer.DeserializeFromStream<FFProbeResult>(stream);
  32. }
  33. }
  34. private async static Task Run(string input, string output)
  35. {
  36. ProcessStartInfo startInfo = new ProcessStartInfo();
  37. startInfo.CreateNoWindow = true;
  38. startInfo.UseShellExecute = false;
  39. // Must consume both or ffmpeg may hang due to deadlocks. See comments below.
  40. startInfo.RedirectStandardOutput = true;
  41. startInfo.RedirectStandardError = true;
  42. startInfo.FileName = Kernel.Instance.ApplicationPaths.FFProbePath;
  43. startInfo.WorkingDirectory = Kernel.Instance.ApplicationPaths.FFMpegDirectory;
  44. startInfo.Arguments = string.Format("\"{0}\" -v quiet -print_format json -show_streams -show_format", input);
  45. //Logger.LogInfo(startInfo.FileName + " " + startInfo.Arguments);
  46. Process process = new Process();
  47. process.StartInfo = startInfo;
  48. FileStream stream = new FileStream(output, FileMode.Create);
  49. try
  50. {
  51. process.Start();
  52. // MUST read both stdout and stderr asynchronously or a deadlock may occurr
  53. // If we ever decide to disable the ffmpeg log then you must uncomment the below line.
  54. process.BeginErrorReadLine();
  55. await process.StandardOutput.BaseStream.CopyToAsync(stream);
  56. process.WaitForExit();
  57. stream.Dispose();
  58. if (process.ExitCode != 0)
  59. {
  60. Logger.LogInfo("FFProbe exited with code {0} for {1}", process.ExitCode, input);
  61. }
  62. }
  63. catch (Exception ex)
  64. {
  65. Logger.LogException(ex);
  66. stream.Dispose();
  67. // Hate having to do this
  68. try
  69. {
  70. process.Kill();
  71. }
  72. catch
  73. {
  74. }
  75. File.Delete(output);
  76. }
  77. finally
  78. {
  79. process.Dispose();
  80. }
  81. }
  82. }
  83. }