diff --git a/MediaBrowser.Api/HttpHandlers/AudioHandler.cs b/MediaBrowser.Api/HttpHandlers/AudioHandler.cs index 294a5b7afc..51d7ba06ae 100644 --- a/MediaBrowser.Api/HttpHandlers/AudioHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/AudioHandler.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Net; using System.Threading.Tasks; +using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Logging; using MediaBrowser.Common.Net; using MediaBrowser.Common.Net.Handlers; @@ -241,16 +242,26 @@ namespace MediaBrowser.Api.HttpHandlers Process process = new Process(); process.StartInfo = startInfo; + // FFMpeg writes debug info to StdErr. This is useful when debugging so let's put it in the log directory. + FileStream logStream = new FileStream(Path.Combine(ApplicationPaths.LogDirectoryPath, "ffmpeg-" + Guid.NewGuid().ToString() + ".txt"), FileMode.Create); + try { process.Start(); // MUST read both stdout and stderr asynchronously or a deadlock may occurr - process.BeginErrorReadLine(); + // If we ever decide to disable the ffmpeg log then you must uncomment the below line. + //process.BeginErrorReadLine(); + + Task errorTask = Task.Run(async () => { await process.StandardError.BaseStream.CopyToAsync(logStream); }); await process.StandardOutput.BaseStream.CopyToAsync(stream); process.WaitForExit(); + + await errorTask; + + Logger.LogInfo("FFMpeg exited with code " + process.ExitCode); } catch (Exception ex) { @@ -258,6 +269,7 @@ namespace MediaBrowser.Api.HttpHandlers } finally { + logStream.Dispose(); process.Dispose(); } } diff --git a/MediaBrowser.Api/HttpHandlers/VideoHandler.cs b/MediaBrowser.Api/HttpHandlers/VideoHandler.cs index 1b5c50c38a..0b556b886a 100644 --- a/MediaBrowser.Api/HttpHandlers/VideoHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/VideoHandler.cs @@ -54,6 +54,21 @@ namespace MediaBrowser.Api.HttpHandlers return false; } + private string GetFFMpegOutputFormat(string outputFormat) + { + if (outputFormat.Equals("mkv", StringComparison.OrdinalIgnoreCase)) + { + return "matroska"; + } + + return outputFormat; + } + + private int GetOutputAudioStreamIndex(string outputFormat) + { + return 0; + } + /// /// Creates arguments to pass to ffmpeg /// @@ -62,8 +77,61 @@ namespace MediaBrowser.Api.HttpHandlers List audioTranscodeParams = new List(); string outputFormat = GetOutputFormat(); - outputFormat = "matroska"; - return "-i \"" + LibraryItem.Path + "\" -vcodec copy -acodec copy -f " + outputFormat + " -"; + + int audioStreamIndex = GetOutputAudioStreamIndex(outputFormat); + + List maps = new List(); + + // Add the video stream + maps.Add("-map 0:0"); + + // Add the audio stream + if (audioStreamIndex != -1) + { + maps.Add("-map 0:" + (1 + audioStreamIndex)); + } + + // Add all the subtitle streams + for (int i = 0; i < LibraryItem.Subtitles.Count(); i++) + { + maps.Add("-map 0:" + (1 + LibraryItem.AudioStreams.Count() + i)); + + } + + return string.Format("-i \"{0}\" {1} {2} {3} -f {4} -", + LibraryItem.Path, + string.Join(" ", maps.ToArray()), + GetVideoArguments(), + GetAudioArguments(), + GetFFMpegOutputFormat(outputFormat) + ); + } + + private string GetVideoArguments() + { + return "-c:v copy"; + } + + private string GetAudioArguments() + { + return "-c:a copy"; + } + + private string GetSubtitleArguments() + { + string args = ""; + + for (int i = 0; i < LibraryItem.Subtitles.Count(); i++) + { + if (i > 0) + { + args += " "; + } + args += "-c:s copy"; + + } + + return args; } } }