diff options
| author | Luke <luke.pulverenti@gmail.com> | 2013-02-20 17:10:49 -0800 |
|---|---|---|
| committer | Luke <luke.pulverenti@gmail.com> | 2013-02-20 17:10:49 -0800 |
| commit | 845554722efaed872948a9e0f7202e3ef52f1b6e (patch) | |
| tree | 534ab2d11fe4824ed303bb01e885b330631b657e /MediaBrowser.Controller/FFMpeg | |
| parent | 2f142263f080f7b012a0ec2095d350ccf75b49b7 (diff) | |
| parent | 14bbb6804718ef78a8118fe750896ba679e3b6cb (diff) | |
Merge pull request #1 from MediaBrowser/Repo
Repo
Diffstat (limited to 'MediaBrowser.Controller/FFMpeg')
| -rw-r--r-- | MediaBrowser.Controller/FFMpeg/FFProbe.cs | 137 | ||||
| -rw-r--r-- | MediaBrowser.Controller/FFMpeg/FFProbeResult.cs | 119 | ||||
| -rw-r--r-- | MediaBrowser.Controller/FFMpeg/ffmpeg.exe.REMOVED.git-id | 1 | ||||
| -rw-r--r-- | MediaBrowser.Controller/FFMpeg/ffprobe.exe.REMOVED.git-id | 1 | ||||
| -rw-r--r-- | MediaBrowser.Controller/FFMpeg/readme.txt | 3 |
5 files changed, 261 insertions, 0 deletions
diff --git a/MediaBrowser.Controller/FFMpeg/FFProbe.cs b/MediaBrowser.Controller/FFMpeg/FFProbe.cs new file mode 100644 index 0000000000..f16f0142d6 --- /dev/null +++ b/MediaBrowser.Controller/FFMpeg/FFProbe.cs @@ -0,0 +1,137 @@ +using MediaBrowser.Common.Logging;
+using MediaBrowser.Common.Serialization;
+using MediaBrowser.Controller.Entities;
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Controller.FFMpeg
+{
+ /// <summary>
+ /// Runs FFProbe against a media file and returns metadata.
+ /// </summary>
+ public static class FFProbe
+ {
+ /// <summary>
+ /// Runs FFProbe against an Audio file, caches the result and returns the output
+ /// </summary>
+ public static FFProbeResult Run(BaseItem item, string cacheDirectory)
+ {
+ string cachePath = GetFfProbeCachePath(item, cacheDirectory);
+
+ // Use try catch to avoid having to use File.Exists
+ try
+ {
+ return GetCachedResult(cachePath);
+ }
+ catch (FileNotFoundException)
+ {
+ }
+ catch (Exception ex)
+ {
+ Logger.LogException(ex);
+ }
+
+ FFProbeResult result = Run(item.Path);
+
+ if (result != null)
+ {
+ // Fire and forget
+ CacheResult(result, cachePath);
+ }
+
+ return result;
+ }
+
+ /// <summary>
+ /// Gets the cached result of an FFProbe operation
+ /// </summary>
+ private static FFProbeResult GetCachedResult(string path)
+ {
+ return ProtobufSerializer.DeserializeFromFile<FFProbeResult>(path);
+ }
+
+ /// <summary>
+ /// Caches the result of an FFProbe operation
+ /// </summary>
+ private static async void CacheResult(FFProbeResult result, string outputCachePath)
+ {
+ await Task.Run(() =>
+ {
+ try
+ {
+ ProtobufSerializer.SerializeToFile(result, outputCachePath);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogException(ex);
+ }
+ }).ConfigureAwait(false);
+ }
+
+ private static FFProbeResult Run(string input)
+ {
+ var startInfo = new ProcessStartInfo { };
+
+ startInfo.CreateNoWindow = true;
+
+ startInfo.UseShellExecute = false;
+
+ // Must consume both or ffmpeg may hang due to deadlocks. See comments below.
+ startInfo.RedirectStandardOutput = true;
+ startInfo.RedirectStandardError = true;
+
+ startInfo.FileName = Kernel.Instance.ApplicationPaths.FFProbePath;
+ startInfo.WorkingDirectory = Kernel.Instance.ApplicationPaths.FFMpegDirectory;
+ startInfo.Arguments = string.Format("\"{0}\" -v quiet -print_format json -show_streams -show_format", input);
+
+ //Logger.LogInfo(startInfo.FileName + " " + startInfo.Arguments);
+
+ var process = new Process { };
+ process.StartInfo = startInfo;
+
+ process.EnableRaisingEvents = true;
+
+ process.Exited += ProcessExited;
+
+ try
+ {
+ process.Start();
+
+ // MUST read both stdout and stderr asynchronously or a deadlock may occurr
+ // If we ever decide to disable the ffmpeg log then you must uncomment the below line.
+ process.BeginErrorReadLine();
+
+ return JsonSerializer.DeserializeFromStream<FFProbeResult>(process.StandardOutput.BaseStream);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogException(ex);
+
+ // Hate having to do this
+ try
+ {
+ process.Kill();
+ }
+ catch
+ {
+ }
+
+ return null;
+ }
+ }
+
+ static void ProcessExited(object sender, EventArgs e)
+ {
+ (sender as Process).Dispose();
+ }
+
+ private static string GetFfProbeCachePath(BaseItem item, string cacheDirectory)
+ {
+ string outputDirectory = Path.Combine(cacheDirectory, item.Id.ToString().Substring(0, 1));
+
+ return Path.Combine(outputDirectory, item.Id + "-" + item.DateModified.Ticks + ".pb");
+ }
+ }
+}
diff --git a/MediaBrowser.Controller/FFMpeg/FFProbeResult.cs b/MediaBrowser.Controller/FFMpeg/FFProbeResult.cs new file mode 100644 index 0000000000..db7c9dd3c5 --- /dev/null +++ b/MediaBrowser.Controller/FFMpeg/FFProbeResult.cs @@ -0,0 +1,119 @@ +using System.Collections.Generic;
+using ProtoBuf;
+
+namespace MediaBrowser.Controller.FFMpeg
+{
+ /// <summary>
+ /// Provides a class that we can use to deserialize the ffprobe json output
+ /// Sample output:
+ /// http://stackoverflow.com/questions/7708373/get-ffmpeg-information-in-friendly-way
+ /// </summary>
+ [ProtoContract]
+ public class FFProbeResult
+ {
+ [ProtoMember(1)]
+ public MediaStream[] streams { get; set; }
+
+ [ProtoMember(2)]
+ public MediaFormat format { get; set; }
+ }
+
+ /// <summary>
+ /// Represents a stream within the output
+ /// A number of properties are commented out to improve deserialization performance
+ /// Enable them as needed.
+ /// </summary>
+ [ProtoContract]
+ public class MediaStream
+ {
+ [ProtoMember(1)]
+ public int index { get; set; }
+
+ [ProtoMember(2)]
+ public string profile { get; set; }
+
+ [ProtoMember(3)]
+ public string codec_name { get; set; }
+
+ [ProtoMember(4)]
+ public string codec_long_name { get; set; }
+
+ [ProtoMember(5)]
+ public string codec_type { get; set; }
+
+ //public string codec_time_base { get; set; }
+ //public string codec_tag { get; set; }
+ //public string codec_tag_string { get; set; }
+ //public string sample_fmt { get; set; }
+
+ [ProtoMember(6)]
+ public string sample_rate { get; set; }
+
+ [ProtoMember(7)]
+ public int channels { get; set; }
+
+ //public int bits_per_sample { get; set; }
+ //public string r_frame_rate { get; set; }
+
+ [ProtoMember(8)]
+ public string avg_frame_rate { get; set; }
+
+ //public string time_base { get; set; }
+ //public string start_time { get; set; }
+
+ [ProtoMember(9)]
+ public string duration { get; set; }
+
+ [ProtoMember(10)]
+ public string bit_rate { get; set; }
+
+ [ProtoMember(11)]
+ public int width { get; set; }
+
+ [ProtoMember(12)]
+ public int height { get; set; }
+
+ //public int has_b_frames { get; set; }
+ //public string sample_aspect_ratio { get; set; }
+
+ [ProtoMember(13)]
+ public string display_aspect_ratio { get; set; }
+
+ //public string pix_fmt { get; set; }
+ //public int level { get; set; }
+
+ [ProtoMember(14)]
+ public Dictionary<string, string> tags { get; set; }
+ }
+
+ [ProtoContract]
+ public class MediaFormat
+ {
+ [ProtoMember(1)]
+ public string filename { get; set; }
+
+ [ProtoMember(2)]
+ public int nb_streams { get; set; }
+
+ [ProtoMember(3)]
+ public string format_name { get; set; }
+
+ [ProtoMember(4)]
+ public string format_long_name { get; set; }
+
+ [ProtoMember(5)]
+ public string start_time { get; set; }
+
+ [ProtoMember(6)]
+ public string duration { get; set; }
+
+ [ProtoMember(7)]
+ public string size { get; set; }
+
+ [ProtoMember(8)]
+ public string bit_rate { get; set; }
+
+ [ProtoMember(9)]
+ public Dictionary<string, string> tags { get; set; }
+ }
+}
diff --git a/MediaBrowser.Controller/FFMpeg/ffmpeg.exe.REMOVED.git-id b/MediaBrowser.Controller/FFMpeg/ffmpeg.exe.REMOVED.git-id new file mode 100644 index 0000000000..73a37bd556 --- /dev/null +++ b/MediaBrowser.Controller/FFMpeg/ffmpeg.exe.REMOVED.git-id @@ -0,0 +1 @@ +84ac1c51e84cfbfb20e7b96c9f1a4442a8cfadf2
\ No newline at end of file diff --git a/MediaBrowser.Controller/FFMpeg/ffprobe.exe.REMOVED.git-id b/MediaBrowser.Controller/FFMpeg/ffprobe.exe.REMOVED.git-id new file mode 100644 index 0000000000..682ead74d1 --- /dev/null +++ b/MediaBrowser.Controller/FFMpeg/ffprobe.exe.REMOVED.git-id @@ -0,0 +1 @@ +331e241e29f1b015e303b301c17c37883e39f39d
\ No newline at end of file diff --git a/MediaBrowser.Controller/FFMpeg/readme.txt b/MediaBrowser.Controller/FFMpeg/readme.txt new file mode 100644 index 0000000000..cdb039bdca --- /dev/null +++ b/MediaBrowser.Controller/FFMpeg/readme.txt @@ -0,0 +1,3 @@ +This is the 32-bit static build of ffmpeg, located at:
+
+http://ffmpeg.zeranoe.com/builds/
\ No newline at end of file |
