From 532af874522aaa46dc1cec66789632aafeda1849 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 26 Nov 2015 23:34:11 -0500 Subject: update qsv encoding --- MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index 912110c04..98e4a58a6 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -359,7 +359,7 @@ namespace MediaBrowser.MediaEncoding.Encoder /// System.String. protected string GetVideoDecoder(EncodingJob state) { - if (string.Equals(GetEncodingOptions().HardwareVideoDecoder, "qsv", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(GetEncodingOptions().HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { if (state.VideoStream != null && !string.IsNullOrWhiteSpace(state.VideoStream.Codec)) { -- cgit v1.2.3 From 3060b0c5e98583d390c7acb634f57af90f9e1954 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 10 Dec 2015 23:48:28 -0500 Subject: update sorting menus --- MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs index 692fe2b6a..cf776b3f7 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs @@ -502,7 +502,7 @@ namespace MediaBrowser.MediaEncoding.Encoder { return "libx264"; } - if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase) || string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)) { return "libx265"; } -- cgit v1.2.3 From 02938e7bcb0459a44dfa6c9e7dfa2a04be3467be Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 12 Dec 2015 01:49:03 -0500 Subject: update keyframe setting --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 2 + MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs | 42 +----- .../Playback/Progressive/VideoService.cs | 1 + .../MediaEncoding/MediaInfoRequest.cs | 1 - MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 157 +-------------------- .../Configuration/ServerConfiguration.cs | 2 - MediaBrowser.Model/Entities/MediaStream.cs | 3 - .../MediaInfo/FFProbeVideoInfo.cs | 3 +- .../Persistence/SqliteItemRepository.cs | 23 +-- MediaBrowser.WebDashboard/Api/DashboardService.cs | 5 + 10 files changed, 15 insertions(+), 224 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index a940be763..eacd7999c 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -2178,6 +2178,8 @@ namespace MediaBrowser.Api.Playback inputModifier += " " + videoDecoder; } + //inputModifier += " -noaccurate_seek"; + return inputModifier; } diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index 3724c8868..c6abffd07 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -291,25 +291,6 @@ namespace MediaBrowser.Api.Playback.Hls private double[] GetSegmentLengths(StreamState state) { var result = new List(); - if (state.VideoRequest != null) - { - var encoder = GetVideoEncoder(state); - - if (string.Equals(encoder, "copy", StringComparison.OrdinalIgnoreCase)) - { - var videoStream = state.VideoStream; - if (videoStream.KeyFrames != null && videoStream.KeyFrames.Count > 0) - { - foreach (var frame in videoStream.KeyFrames) - { - var seconds = TimeSpan.FromMilliseconds(frame).TotalSeconds; - seconds -= result.Sum(); - result.Add(seconds); - } - return result.ToArray(); - } - } - } var ticks = state.RunTimeTicks ?? 0; @@ -936,27 +917,8 @@ namespace MediaBrowser.Api.Playback.Hls protected override bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream) { - if (videoStream.KeyFrames == null || videoStream.KeyFrames.Count == 0) - { - Logger.Debug("Cannot stream copy video due to missing keyframe info"); - return false; - } - - var previousSegment = 0; - foreach (var frame in videoStream.KeyFrames) - { - var length = frame - previousSegment; - - // Don't allow really long segments because this could result in long download times - if (length > 10000) - { - Logger.Debug("Cannot stream copy video due to long segment length of {0}ms", length); - return false; - } - previousSegment = frame; - } - - return base.CanStreamCopyVideo(request, videoStream); + return false; + //return base.CanStreamCopyVideo(request, videoStream); } } } \ No newline at end of file diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs index d79040dd4..519bfa8d8 100644 --- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs +++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs @@ -100,6 +100,7 @@ namespace MediaBrowser.Api.Playback.Progressive { // Comparison: https://github.com/jansmolders86/mediacenterjs/blob/master/lib/transcoding/desktop.js format = " -f mp4 -movflags frag_keyframe+empty_moov"; + //format = " -avoid_negative_ts disabled -start_at_zero -copyts -f mp4 -movflags frag_keyframe+empty_moov"; } var threads = GetNumberOfThreads(state, string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase)); diff --git a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs index 24df7b885..ca0c2fdbb 100644 --- a/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs +++ b/MediaBrowser.Controller/MediaEncoding/MediaInfoRequest.cs @@ -15,7 +15,6 @@ namespace MediaBrowser.Controller.MediaEncoding public IIsoMount MountedIso { get; set; } public VideoType VideoType { get; set; } public List PlayableStreamFileNames { get; set; } - public bool ExtractKeyFrameInterval { get; set; } public MediaInfoRequest() { diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index c8361ea04..a61b15ac5 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -135,9 +135,7 @@ namespace MediaBrowser.MediaEncoding.Encoder var inputFiles = MediaEncoderHelpers.GetInputArgument(FileSystem, request.InputPath, request.Protocol, request.MountedIso, request.PlayableStreamFileNames); - var extractKeyFrameInterval = request.ExtractKeyFrameInterval && request.Protocol == MediaProtocol.File && request.VideoType == VideoType.VideoFile; - - return GetMediaInfoInternal(GetInputArgument(inputFiles, request.Protocol), request.InputPath, request.Protocol, extractChapters, extractKeyFrameInterval, + return GetMediaInfoInternal(GetInputArgument(inputFiles, request.Protocol), request.InputPath, request.Protocol, extractChapters, GetProbeSizeArgument(inputFiles, request.Protocol), request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken); } @@ -171,18 +169,16 @@ namespace MediaBrowser.MediaEncoding.Encoder /// The primary path. /// The protocol. /// if set to true [extract chapters]. - /// if set to true [extract key frame interval]. /// The probe size argument. /// if set to true [is audio]. /// Type of the video. /// The cancellation token. /// Task{MediaInfoResult}. - /// + /// ffprobe failed - streams and format are both null. private async Task GetMediaInfoInternal(string inputPath, string primaryPath, MediaProtocol protocol, bool extractChapters, - bool extractKeyFrameInterval, string probeSizeArgument, bool isAudio, VideoType videoType, @@ -262,31 +258,6 @@ namespace MediaBrowser.MediaEncoding.Encoder var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol); - if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue) - { - if (ConfigurationManager.Configuration.EnableVideoFrameByFrameAnalysis && mediaInfo.Size.HasValue) - { - foreach (var stream in mediaInfo.MediaStreams) - { - if (EnableKeyframeExtraction(mediaInfo, stream)) - { - try - { - stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - - } - catch (Exception ex) - { - _logger.ErrorException("Error getting key frame interval", ex); - } - } - } - } - } - return mediaInfo; } catch @@ -300,132 +271,8 @@ namespace MediaBrowser.MediaEncoding.Encoder _ffProbeResourcePool.Release(); } } - - throw new ApplicationException(string.Format("FFProbe failed for {0}", inputPath)); - } - - private bool EnableKeyframeExtraction(MediaSourceInfo mediaSource, MediaStream videoStream) - { - if (videoStream.Type == MediaStreamType.Video && string.Equals(videoStream.Codec, "h264", StringComparison.OrdinalIgnoreCase) && - !videoStream.IsInterlaced && - !(videoStream.IsAnamorphic ?? false)) - { - var audioStreams = mediaSource.MediaStreams.Where(i => i.Type == MediaStreamType.Audio).ToList(); - - // If it has aac audio then it will probably direct stream anyway, so don't bother with this - if (audioStreams.Count == 1 && string.Equals(audioStreams[0].Codec, "aac", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - return true; - } - return false; - } - - private async Task> GetKeyFrames(string inputPath, int videoStreamIndex, CancellationToken cancellationToken) - { - inputPath = inputPath.Split(new[] { ':' }, 2).Last().Trim('"'); - - const string args = "-show_packets -print_format compact -select_streams v:{1} -show_entries packet=flags -show_entries packet=pts_time \"{0}\""; - - var process = new Process - { - StartInfo = new ProcessStartInfo - { - CreateNoWindow = true, - UseShellExecute = false, - - // Must consume both or ffmpeg may hang due to deadlocks. See comments below. - RedirectStandardOutput = true, - RedirectStandardError = true, - FileName = FFProbePath, - Arguments = string.Format(args, inputPath, videoStreamIndex.ToString(CultureInfo.InvariantCulture)).Trim(), - - WindowStyle = ProcessWindowStyle.Hidden, - ErrorDialog = false - }, - - EnableRaisingEvents = true - }; - - _logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); - - using (process) - { - var start = DateTime.UtcNow; - - process.Start(); - - var lines = new List(); - - try - { - process.BeginErrorReadLine(); - - await StartReadingOutput(process.StandardOutput.BaseStream, lines, cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - if (cancellationToken.IsCancellationRequested) - { - throw; - } - } - - process.WaitForExit(); - - _logger.Info("Keyframe extraction took {0} seconds", (DateTime.UtcNow - start).TotalSeconds); - //_logger.Debug("Found keyframes {0}", string.Join(",", lines.ToArray())); - return lines; - } } - private async Task StartReadingOutput(Stream source, List keyframes, CancellationToken cancellationToken) - { - try - { - using (var reader = new StreamReader(source)) - { - var text = await reader.ReadToEndAsync().ConfigureAwait(false); - - var lines = StringHelper.RegexSplit(text, "[\r\n]+"); - foreach (var line in lines) - { - if (string.IsNullOrWhiteSpace(line)) - { - continue; - } - - var values = line.Split('|') - .Where(i => !string.IsNullOrWhiteSpace(i)) - .Select(i => i.Split('=')) - .Where(i => i.Length == 2) - .ToDictionary(i => i[0], i => i[1]); - - string flags; - if (values.TryGetValue("flags", out flags) && string.Equals(flags, "k", StringComparison.OrdinalIgnoreCase)) - { - string pts_time; - double frameSeconds; - if (values.TryGetValue("pts_time", out pts_time) && double.TryParse(pts_time, NumberStyles.Any, CultureInfo.InvariantCulture, out frameSeconds)) - { - var ms = frameSeconds * 1000; - keyframes.Add(Convert.ToInt32(ms)); - } - } - } - } - } - catch (OperationCanceledException) - { - throw; - } - catch (Exception ex) - { - _logger.ErrorException("Error reading ffprobe output", ex); - } - } /// /// The us culture /// diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 5666a32be..08f7f89e3 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -209,8 +209,6 @@ namespace MediaBrowser.Model.Configuration public bool EnableWindowsShortcuts { get; set; } - public bool EnableVideoFrameByFrameAnalysis { get; set; } - public bool EnableDateLastRefresh { get; set; } public string[] Migrations { get; set; } diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index 79d1df911..d089f0aa9 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -233,8 +233,5 @@ namespace MediaBrowser.Model.Entities /// /// null if [is cabac] contains no value, true if [is cabac]; otherwise, false. public bool? IsCabac { get; set; } - - [IgnoreDataMember] - public List KeyFrames { get; set; } } } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index 5a87e7628..4744b3729 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -170,8 +170,7 @@ namespace MediaBrowser.Providers.MediaInfo VideoType = item.VideoType, MediaType = DlnaProfileType.Video, InputPath = item.Path, - Protocol = protocol, - ExtractKeyFrameInterval = true + Protocol = protocol }, cancellationToken).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 6b834bbf2..1d3ac293e 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -127,7 +127,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false); var createMediaStreamsTableCommand - = "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, IsCabac BIT NULL, KeyFrames TEXT NULL, CodecTag TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))"; + = "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, IsCabac BIT NULL, CodecTag TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))"; string[] queries = { @@ -385,7 +385,6 @@ namespace MediaBrowser.Server.Implementations.Persistence "IsAnamorphic", "RefFrames", "IsCabac", - "KeyFrames", "CodecTag" }; @@ -2683,15 +2682,6 @@ namespace MediaBrowser.Server.Implementations.Persistence _saveStreamCommand.GetParameter(index++).Value = stream.RefFrames; _saveStreamCommand.GetParameter(index++).Value = stream.IsCabac; - if (stream.KeyFrames == null || stream.KeyFrames.Count == 0) - { - _saveStreamCommand.GetParameter(index++).Value = null; - } - else - { - _saveStreamCommand.GetParameter(index++).Value = string.Join(",", stream.KeyFrames.Select(i => i.ToString(CultureInfo.InvariantCulture)).ToArray()); - } - _saveStreamCommand.GetParameter(index++).Value = stream.CodecTag; _saveStreamCommand.Transaction = transaction; @@ -2848,16 +2838,7 @@ namespace MediaBrowser.Server.Implementations.Persistence if (!reader.IsDBNull(26)) { - var frames = reader.GetString(26); - if (!string.IsNullOrWhiteSpace(frames)) - { - item.KeyFrames = frames.Split(',').Select(i => int.Parse(i, CultureInfo.InvariantCulture)).ToList(); - } - } - - if (!reader.IsDBNull(27)) - { - item.CodecTag = reader.GetString(27); + item.CodecTag = reader.GetString(26); } return item; diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index d24a4a3de..c16c63578 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -303,6 +303,11 @@ namespace MediaBrowser.WebDashboard.Api var mode = request.Mode; + if (string.Equals(mode, "cordova", StringComparison.OrdinalIgnoreCase)) + { + _fileSystem.DeleteFile(Path.Combine(path, "scripts", "registrationservices.js")); + } + // Try to trim the output size a bit var bowerPath = Path.Combine(path, "bower_components"); DeleteFilesByExtension(bowerPath, ".log"); -- cgit v1.2.3 From 949d23f06aeff62f1cd38ddf074b89a1307eedb0 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 19 Dec 2015 12:45:50 -0500 Subject: fix merge conflict --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 346 ++++++++++++++++++++- 1 file changed, 344 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index a61b15ac5..1dc1a4215 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -135,7 +135,9 @@ namespace MediaBrowser.MediaEncoding.Encoder var inputFiles = MediaEncoderHelpers.GetInputArgument(FileSystem, request.InputPath, request.Protocol, request.MountedIso, request.PlayableStreamFileNames); - return GetMediaInfoInternal(GetInputArgument(inputFiles, request.Protocol), request.InputPath, request.Protocol, extractChapters, + var extractKeyFrameInterval = request.ExtractKeyFrameInterval && request.Protocol == MediaProtocol.File && request.VideoType == VideoType.VideoFile; + + return GetMediaInfoInternal(GetInputArgument(inputFiles, request.Protocol), request.InputPath, request.Protocol, extractChapters, extractKeyFrameInterval, GetProbeSizeArgument(inputFiles, request.Protocol), request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken); } @@ -169,16 +171,18 @@ namespace MediaBrowser.MediaEncoding.Encoder /// The primary path. /// The protocol. /// if set to true [extract chapters]. + /// if set to true [extract key frame interval]. /// The probe size argument. /// if set to true [is audio]. /// Type of the video. /// The cancellation token. /// Task{MediaInfoResult}. - /// ffprobe failed - streams and format are both null. + /// private async Task GetMediaInfoInternal(string inputPath, string primaryPath, MediaProtocol protocol, bool extractChapters, + bool extractKeyFrameInterval, string probeSizeArgument, bool isAudio, VideoType videoType, @@ -258,6 +262,43 @@ namespace MediaBrowser.MediaEncoding.Encoder var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol); + var videoStream = mediaInfo.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video); + + if (videoStream != null) + { + var isInterlaced = await DetectInterlaced(mediaInfo, videoStream, inputPath, probeSizeArgument).ConfigureAwait(false); + + if (isInterlaced) + { + videoStream.IsInterlaced = true; + } + } + + if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue) + { + if (ConfigurationManager.Configuration.EnableVideoFrameByFrameAnalysis && mediaInfo.Size.HasValue) + { + foreach (var stream in mediaInfo.MediaStreams) + { + if (EnableKeyframeExtraction(mediaInfo, stream)) + { + try + { + stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken).ConfigureAwait(false); + } + catch (OperationCanceledException) + { + + } + catch (Exception ex) + { + _logger.ErrorException("Error getting key frame interval", ex); + } + } + } + } + } + return mediaInfo; } catch @@ -271,8 +312,309 @@ namespace MediaBrowser.MediaEncoding.Encoder _ffProbeResourcePool.Release(); } } + + throw new ApplicationException(string.Format("FFProbe failed for {0}", inputPath)); + } + + private async Task DetectInterlaced(MediaSourceInfo video, MediaStream videoStream, string inputPath, string probeSizeArgument) + { + if (video.Protocol != MediaProtocol.File) + { + return false; + } + + var formats = (video.Container ?? string.Empty).Split(',').ToList(); + + // Take a shortcut and limit this to containers that are likely to have interlaced content + if (!formats.Contains("ts", StringComparer.OrdinalIgnoreCase) && + !formats.Contains("mpegts", StringComparer.OrdinalIgnoreCase) && + !formats.Contains("wtv", StringComparer.OrdinalIgnoreCase)) + { + return false; + } + + var args = "{0} -i {1} -map 0:v:{2} -filter:v idet -frames:v 500 -an -f null /dev/null"; + + var process = new Process + { + StartInfo = new ProcessStartInfo + { + CreateNoWindow = true, + UseShellExecute = false, + + // Must consume both or ffmpeg may hang due to deadlocks. See comments below. + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + FileName = FFMpegPath, + Arguments = string.Format(args, probeSizeArgument, inputPath, videoStream.Index.ToString(CultureInfo.InvariantCulture)).Trim(), + + WindowStyle = ProcessWindowStyle.Hidden, + ErrorDialog = false + }, + + EnableRaisingEvents = true + }; + + _logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); + var idetFoundInterlaced = false; + + using (var processWrapper = new ProcessWrapper(process, this, _logger)) + { + try + { + StartProcess(processWrapper); + } + catch (Exception ex) + { + _logger.ErrorException("Error starting ffprobe", ex); + + throw; + } + + try + { + process.BeginOutputReadLine(); + + using (var reader = new StreamReader(process.StandardError.BaseStream)) + { + while (!reader.EndOfStream) + { + var line = await reader.ReadLineAsync().ConfigureAwait(false); + + if (line.StartsWith("[Parsed_idet", StringComparison.OrdinalIgnoreCase)) + { + var idetResult = AnalyzeIdetResult(line); + + if (idetResult.HasValue) + { + if (!idetResult.Value) + { + return false; + } + + idetFoundInterlaced = true; + } + } + } + } + + } + catch + { + StopProcess(processWrapper, 100, true); + + throw; + } + } + + return idetFoundInterlaced; + } + + private bool? AnalyzeIdetResult(string line) + { + // As you can see, the filter only guessed one frame as progressive. + // Results like this are pretty typical. So if less than 30% of the detections are in the "Undetermined" category, then I only consider the video to be interlaced if at least 65% of the identified frames are in either the TFF or BFF category. + // In this case (310 + 311)/(622) = 99.8% which is well over the 65% metric. I may refine that number with more testing but I honestly do not believe I will need to. + // http://awel.domblogger.net/videoTranscode/interlace.html + var index = line.IndexOf("detection:", StringComparison.OrdinalIgnoreCase); + + if (index == -1) + { + return null; + } + + line = line.Substring(index).Trim(); + var parts = line.Split(' ').Where(i => !string.IsNullOrWhiteSpace(i)).Select(i => i.Trim()).ToList(); + + if (parts.Count < 2) + { + return null; + } + double tff = 0; + double bff = 0; + double progressive = 0; + double undetermined = 0; + double total = 0; + + for (var i = 0; i < parts.Count - 1; i++) + { + var part = parts[i]; + + if (string.Equals(part, "tff:", StringComparison.OrdinalIgnoreCase)) + { + tff = GetNextPart(parts, i); + total += tff; + } + else if (string.Equals(part, "bff:", StringComparison.OrdinalIgnoreCase)) + { + bff = GetNextPart(parts, i); + total += tff; + } + else if (string.Equals(part, "progressive:", StringComparison.OrdinalIgnoreCase)) + { + progressive = GetNextPart(parts, i); + total += progressive; + } + else if (string.Equals(part, "undetermined:", StringComparison.OrdinalIgnoreCase)) + { + undetermined = GetNextPart(parts, i); + total += undetermined; + } + } + + if (total == 0) + { + return null; + } + + if ((undetermined / total) >= .3) + { + return false; + } + + if (((tff + bff) / total) >= .65) + { + return true; + } + + return false; + } + + private int GetNextPart(List parts, int index) + { + var next = parts[index + 1]; + + int value; + if (int.TryParse(next, NumberStyles.Any, CultureInfo.InvariantCulture, out value)) + { + return value; + } + return 0; } + private bool EnableKeyframeExtraction(MediaSourceInfo mediaSource, MediaStream videoStream) + { + if (videoStream.Type == MediaStreamType.Video && string.Equals(videoStream.Codec, "h264", StringComparison.OrdinalIgnoreCase) && + !videoStream.IsInterlaced && + !(videoStream.IsAnamorphic ?? false)) + { + var audioStreams = mediaSource.MediaStreams.Where(i => i.Type == MediaStreamType.Audio).ToList(); + + // If it has aac audio then it will probably direct stream anyway, so don't bother with this + if (audioStreams.Count == 1 && string.Equals(audioStreams[0].Codec, "aac", StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + return true; + } + return false; + } + + private async Task> GetKeyFrames(string inputPath, int videoStreamIndex, CancellationToken cancellationToken) + { + inputPath = inputPath.Split(new[] { ':' }, 2).Last().Trim('"'); + + const string args = "-show_packets -print_format compact -select_streams v:{1} -show_entries packet=flags -show_entries packet=pts_time \"{0}\""; + + var process = new Process + { + StartInfo = new ProcessStartInfo + { + CreateNoWindow = true, + UseShellExecute = false, + + // Must consume both or ffmpeg may hang due to deadlocks. See comments below. + RedirectStandardOutput = true, + RedirectStandardError = true, + FileName = FFProbePath, + Arguments = string.Format(args, inputPath, videoStreamIndex.ToString(CultureInfo.InvariantCulture)).Trim(), + + WindowStyle = ProcessWindowStyle.Hidden, + ErrorDialog = false + }, + + EnableRaisingEvents = true + }; + + _logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); + + using (process) + { + var start = DateTime.UtcNow; + + process.Start(); + + var lines = new List(); + + try + { + process.BeginErrorReadLine(); + + await StartReadingOutput(process.StandardOutput.BaseStream, lines, cancellationToken).ConfigureAwait(false); + } + catch (OperationCanceledException) + { + if (cancellationToken.IsCancellationRequested) + { + throw; + } + } + + process.WaitForExit(); + + _logger.Info("Keyframe extraction took {0} seconds", (DateTime.UtcNow - start).TotalSeconds); + //_logger.Debug("Found keyframes {0}", string.Join(",", lines.ToArray())); + return lines; + } + } + + private async Task StartReadingOutput(Stream source, List keyframes, CancellationToken cancellationToken) + { + try + { + using (var reader = new StreamReader(source)) + { + var text = await reader.ReadToEndAsync().ConfigureAwait(false); + + var lines = StringHelper.RegexSplit(text, "[\r\n]+"); + foreach (var line in lines) + { + if (string.IsNullOrWhiteSpace(line)) + { + continue; + } + + var values = line.Split('|') + .Where(i => !string.IsNullOrWhiteSpace(i)) + .Select(i => i.Split('=')) + .Where(i => i.Length == 2) + .ToDictionary(i => i[0], i => i[1]); + + string flags; + if (values.TryGetValue("flags", out flags) && string.Equals(flags, "k", StringComparison.OrdinalIgnoreCase)) + { + string pts_time; + double frameSeconds; + if (values.TryGetValue("pts_time", out pts_time) && double.TryParse(pts_time, NumberStyles.Any, CultureInfo.InvariantCulture, out frameSeconds)) + { + var ms = frameSeconds * 1000; + keyframes.Add(Convert.ToInt32(ms)); + } + } + } + } + } + catch (OperationCanceledException) + { + throw; + } + catch (Exception ex) + { + _logger.ErrorException("Error reading ffprobe output", ex); + } + } /// /// The us culture /// -- cgit v1.2.3 From 6ea8ef9107275bfddf41bb88a10e913762f868d2 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 19 Dec 2015 12:48:42 -0500 Subject: restore changes --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 157 +--- .../MediaBrowser.ServerApplication.csproj | 805 +++++++++++++++++++-- MediaBrowser.sln | 4 + 3 files changed, 733 insertions(+), 233 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 1dc1a4215..be43079c5 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -135,9 +135,7 @@ namespace MediaBrowser.MediaEncoding.Encoder var inputFiles = MediaEncoderHelpers.GetInputArgument(FileSystem, request.InputPath, request.Protocol, request.MountedIso, request.PlayableStreamFileNames); - var extractKeyFrameInterval = request.ExtractKeyFrameInterval && request.Protocol == MediaProtocol.File && request.VideoType == VideoType.VideoFile; - - return GetMediaInfoInternal(GetInputArgument(inputFiles, request.Protocol), request.InputPath, request.Protocol, extractChapters, extractKeyFrameInterval, + return GetMediaInfoInternal(GetInputArgument(inputFiles, request.Protocol), request.InputPath, request.Protocol, extractChapters, GetProbeSizeArgument(inputFiles, request.Protocol), request.MediaType == DlnaProfileType.Audio, request.VideoType, cancellationToken); } @@ -171,18 +169,16 @@ namespace MediaBrowser.MediaEncoding.Encoder /// The primary path. /// The protocol. /// if set to true [extract chapters]. - /// if set to true [extract key frame interval]. /// The probe size argument. /// if set to true [is audio]. /// Type of the video. /// The cancellation token. /// Task{MediaInfoResult}. - /// + /// ffprobe failed - streams and format are both null. private async Task GetMediaInfoInternal(string inputPath, string primaryPath, MediaProtocol protocol, bool extractChapters, - bool extractKeyFrameInterval, string probeSizeArgument, bool isAudio, VideoType videoType, @@ -274,31 +270,6 @@ namespace MediaBrowser.MediaEncoding.Encoder } } - if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue) - { - if (ConfigurationManager.Configuration.EnableVideoFrameByFrameAnalysis && mediaInfo.Size.HasValue) - { - foreach (var stream in mediaInfo.MediaStreams) - { - if (EnableKeyframeExtraction(mediaInfo, stream)) - { - try - { - stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - - } - catch (Exception ex) - { - _logger.ErrorException("Error getting key frame interval", ex); - } - } - } - } - } - return mediaInfo; } catch @@ -312,8 +283,6 @@ namespace MediaBrowser.MediaEncoding.Encoder _ffProbeResourcePool.Release(); } } - - throw new ApplicationException(string.Format("FFProbe failed for {0}", inputPath)); } private async Task DetectInterlaced(MediaSourceInfo video, MediaStream videoStream, string inputPath, string probeSizeArgument) @@ -493,128 +462,6 @@ namespace MediaBrowser.MediaEncoding.Encoder return 0; } - private bool EnableKeyframeExtraction(MediaSourceInfo mediaSource, MediaStream videoStream) - { - if (videoStream.Type == MediaStreamType.Video && string.Equals(videoStream.Codec, "h264", StringComparison.OrdinalIgnoreCase) && - !videoStream.IsInterlaced && - !(videoStream.IsAnamorphic ?? false)) - { - var audioStreams = mediaSource.MediaStreams.Where(i => i.Type == MediaStreamType.Audio).ToList(); - - // If it has aac audio then it will probably direct stream anyway, so don't bother with this - if (audioStreams.Count == 1 && string.Equals(audioStreams[0].Codec, "aac", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - return true; - } - return false; - } - - private async Task> GetKeyFrames(string inputPath, int videoStreamIndex, CancellationToken cancellationToken) - { - inputPath = inputPath.Split(new[] { ':' }, 2).Last().Trim('"'); - - const string args = "-show_packets -print_format compact -select_streams v:{1} -show_entries packet=flags -show_entries packet=pts_time \"{0}\""; - - var process = new Process - { - StartInfo = new ProcessStartInfo - { - CreateNoWindow = true, - UseShellExecute = false, - - // Must consume both or ffmpeg may hang due to deadlocks. See comments below. - RedirectStandardOutput = true, - RedirectStandardError = true, - FileName = FFProbePath, - Arguments = string.Format(args, inputPath, videoStreamIndex.ToString(CultureInfo.InvariantCulture)).Trim(), - - WindowStyle = ProcessWindowStyle.Hidden, - ErrorDialog = false - }, - - EnableRaisingEvents = true - }; - - _logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); - - using (process) - { - var start = DateTime.UtcNow; - - process.Start(); - - var lines = new List(); - - try - { - process.BeginErrorReadLine(); - - await StartReadingOutput(process.StandardOutput.BaseStream, lines, cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - if (cancellationToken.IsCancellationRequested) - { - throw; - } - } - - process.WaitForExit(); - - _logger.Info("Keyframe extraction took {0} seconds", (DateTime.UtcNow - start).TotalSeconds); - //_logger.Debug("Found keyframes {0}", string.Join(",", lines.ToArray())); - return lines; - } - } - - private async Task StartReadingOutput(Stream source, List keyframes, CancellationToken cancellationToken) - { - try - { - using (var reader = new StreamReader(source)) - { - var text = await reader.ReadToEndAsync().ConfigureAwait(false); - - var lines = StringHelper.RegexSplit(text, "[\r\n]+"); - foreach (var line in lines) - { - if (string.IsNullOrWhiteSpace(line)) - { - continue; - } - - var values = line.Split('|') - .Where(i => !string.IsNullOrWhiteSpace(i)) - .Select(i => i.Split('=')) - .Where(i => i.Length == 2) - .ToDictionary(i => i[0], i => i[1]); - - string flags; - if (values.TryGetValue("flags", out flags) && string.Equals(flags, "k", StringComparison.OrdinalIgnoreCase)) - { - string pts_time; - double frameSeconds; - if (values.TryGetValue("pts_time", out pts_time) && double.TryParse(pts_time, NumberStyles.Any, CultureInfo.InvariantCulture, out frameSeconds)) - { - var ms = frameSeconds * 1000; - keyframes.Add(Convert.ToInt32(ms)); - } - } - } - } - } - catch (OperationCanceledException) - { - throw; - } - catch (Exception ex) - { - _logger.ErrorException("Error reading ffprobe output", ex); - } - } /// /// The us culture /// diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj index 5813dcac5..382bb1c61 100644 --- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj +++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj @@ -22,7 +22,7 @@ DEBUG;TRACE prompt 4 - true + false AnyCPU @@ -64,8 +64,9 @@ False ..\packages\CommonIO.1.0.0.5\lib\net45\CommonIO.dll - - ..\packages\ImageMagickSharp.1.0.0.16\lib\net45\ImageMagickSharp.dll + + False + ..\packages\ImageMagickSharp.1.0.0.17\lib\net45\ImageMagickSharp.dll ..\packages\MediaBrowser.IsoMounting.3.0.69\lib\net45\MediaBrowser.IsoMounter.dll @@ -176,230 +177,878 @@ x86\SQLite.Interop.dll PreserveNewest - + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + PreserveNewest - + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest - + PreserveNewest diff --git a/MediaBrowser.sln b/MediaBrowser.sln index d0fbd743e..a9b5020ec 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -12,6 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Performance2.psess = Performance2.psess Performance3.psess = Performance3.psess Performance4.psess = Performance4.psess + Performance5.psess = Performance5.psess EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget (2)", ".nuget (2)", "{E60FB157-87E2-4A41-8B04-27EA49B63B4D}" @@ -520,4 +521,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection EndGlobal -- cgit v1.2.3 From 8d6acbbc680299851192f7f68fae3cc07c87d3f8 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 19 Dec 2015 12:50:44 -0500 Subject: adjust logging --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index be43079c5..6f6f2b6a4 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -325,7 +325,7 @@ namespace MediaBrowser.MediaEncoding.Encoder EnableRaisingEvents = true }; - _logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); + _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); var idetFoundInterlaced = false; using (var processWrapper = new ProcessWrapper(process, this, _logger)) -- cgit v1.2.3 From 4595c3854c397dd57a75db491c3d8f15acea1cc1 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 19 Dec 2015 13:02:32 -0500 Subject: update interlaced detection formats --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 6f6f2b6a4..9f23a305a 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -295,7 +295,9 @@ namespace MediaBrowser.MediaEncoding.Encoder var formats = (video.Container ?? string.Empty).Split(',').ToList(); // Take a shortcut and limit this to containers that are likely to have interlaced content - if (!formats.Contains("ts", StringComparer.OrdinalIgnoreCase) && + if (!formats.Contains("vob", StringComparer.OrdinalIgnoreCase) && + !formats.Contains("m2ts", StringComparer.OrdinalIgnoreCase) && + !formats.Contains("ts", StringComparer.OrdinalIgnoreCase) && !formats.Contains("mpegts", StringComparer.OrdinalIgnoreCase) && !formats.Contains("wtv", StringComparer.OrdinalIgnoreCase)) { -- cgit v1.2.3 From 255747337a4b6017e35ce1b58192076bb3a90c61 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 19 Dec 2015 13:23:13 -0500 Subject: fix merge conflict --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 9f23a305a..f44d922d5 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -258,17 +258,17 @@ namespace MediaBrowser.MediaEncoding.Encoder var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol); - var videoStream = mediaInfo.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video); + //var videoStream = mediaInfo.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video); - if (videoStream != null) - { - var isInterlaced = await DetectInterlaced(mediaInfo, videoStream, inputPath, probeSizeArgument).ConfigureAwait(false); + //if (videoStream != null) + //{ + // var isInterlaced = await DetectInterlaced(mediaInfo, videoStream, inputPath, probeSizeArgument).ConfigureAwait(false); - if (isInterlaced) - { - videoStream.IsInterlaced = true; - } - } + // if (isInterlaced) + // { + // videoStream.IsInterlaced = true; + // } + //} return mediaInfo; } -- cgit v1.2.3 From 3c433e95b9ea8b0b19a1a1315ae19d1c7fca0e88 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 19 Dec 2015 13:29:53 -0500 Subject: update interlaced detection --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 35 ++++++++++++---------- 1 file changed, 19 insertions(+), 16 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index f44d922d5..dedacccfa 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -258,17 +258,17 @@ namespace MediaBrowser.MediaEncoding.Encoder var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol); - //var videoStream = mediaInfo.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video); + var videoStream = mediaInfo.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video); - //if (videoStream != null) - //{ - // var isInterlaced = await DetectInterlaced(mediaInfo, videoStream, inputPath, probeSizeArgument).ConfigureAwait(false); + if (videoStream != null) + { + var isInterlaced = await DetectInterlaced(mediaInfo, videoStream, inputPath, probeSizeArgument).ConfigureAwait(false); - // if (isInterlaced) - // { - // videoStream.IsInterlaced = true; - // } - //} + if (isInterlaced) + { + videoStream.IsInterlaced = true; + } + } return mediaInfo; } @@ -294,14 +294,17 @@ namespace MediaBrowser.MediaEncoding.Encoder var formats = (video.Container ?? string.Empty).Split(',').ToList(); - // Take a shortcut and limit this to containers that are likely to have interlaced content - if (!formats.Contains("vob", StringComparer.OrdinalIgnoreCase) && - !formats.Contains("m2ts", StringComparer.OrdinalIgnoreCase) && - !formats.Contains("ts", StringComparer.OrdinalIgnoreCase) && - !formats.Contains("mpegts", StringComparer.OrdinalIgnoreCase) && - !formats.Contains("wtv", StringComparer.OrdinalIgnoreCase)) + // If the video codec is not some form of mpeg, then take a shortcut and limit this to containers that are likely to have interlaced content + if ((videoStream.Codec ?? string.Empty).IndexOf("mpeg", StringComparison.OrdinalIgnoreCase) == -1) { - return false; + if (!formats.Contains("vob", StringComparer.OrdinalIgnoreCase) && + !formats.Contains("m2ts", StringComparer.OrdinalIgnoreCase) && + !formats.Contains("ts", StringComparer.OrdinalIgnoreCase) && + !formats.Contains("mpegts", StringComparer.OrdinalIgnoreCase) && + !formats.Contains("wtv", StringComparer.OrdinalIgnoreCase)) + { + return false; + } } var args = "{0} -i {1} -map 0:v:{2} -filter:v idet -frames:v 500 -an -f null /dev/null"; -- cgit v1.2.3 From 59277211c7482e00a58cc74fc67068dab594d863 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 19 Dec 2015 13:33:40 -0500 Subject: update interlaced detection --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index dedacccfa..f436ca3a0 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -292,11 +292,11 @@ namespace MediaBrowser.MediaEncoding.Encoder return false; } - var formats = (video.Container ?? string.Empty).Split(',').ToList(); - // If the video codec is not some form of mpeg, then take a shortcut and limit this to containers that are likely to have interlaced content if ((videoStream.Codec ?? string.Empty).IndexOf("mpeg", StringComparison.OrdinalIgnoreCase) == -1) { + var formats = (video.Container ?? string.Empty).Split(',').ToList(); + if (!formats.Contains("vob", StringComparer.OrdinalIgnoreCase) && !formats.Contains("m2ts", StringComparer.OrdinalIgnoreCase) && !formats.Contains("ts", StringComparer.OrdinalIgnoreCase) && -- cgit v1.2.3 From 2841eba20211c36c17d602e4cc2392bdcf0e33ad Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 24 Dec 2015 15:06:52 -0500 Subject: fixes #1310 - Downscaling 1280x720 to 720x404 --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 5 ++++- .../Encoder/EncodingJobFactory.cs | 5 ++++- MediaBrowser.Model/Dlna/ResolutionNormalizer.cs | 23 ++++++++++++++++++---- 3 files changed, 27 insertions(+), 6 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 7939a5976..9eb0f7d45 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1623,7 +1623,10 @@ namespace MediaBrowser.Api.Playback if (state.OutputVideoBitrate.HasValue) { - var resolution = ResolutionNormalizer.Normalize(state.OutputVideoBitrate.Value, + var resolution = ResolutionNormalizer.Normalize( + state.VideoStream == null ? (int?)null : state.VideoStream.BitRate, + state.OutputVideoBitrate.Value, + state.VideoStream == null ? null : state.VideoStream.Codec, state.OutputVideoCodec, videoRequest.MaxWidth, videoRequest.MaxHeight); diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs index cf776b3f7..9cdc4a7bf 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs @@ -82,7 +82,10 @@ namespace MediaBrowser.MediaEncoding.Encoder if (state.OutputVideoBitrate.HasValue) { - var resolution = ResolutionNormalizer.Normalize(state.OutputVideoBitrate.Value, + var resolution = ResolutionNormalizer.Normalize( + state.VideoStream == null ? (int?)null : state.VideoStream.BitRate, + state.OutputVideoBitrate.Value, + state.VideoStream == null ? null : state.VideoStream.Codec, state.OutputVideoCodec, request.MaxWidth, request.MaxHeight); diff --git a/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs b/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs index b23c0b20b..8a412ac2c 100644 --- a/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs +++ b/MediaBrowser.Model/Dlna/ResolutionNormalizer.cs @@ -14,14 +14,29 @@ namespace MediaBrowser.Model.Dlna new ResolutionConfiguration(1280, 2500000) }; - public static ResolutionOptions Normalize(int maxBitrate, - string codec, + public static ResolutionOptions Normalize(int? inputBitrate, + int outputBitrate, + string inputCodec, + string outputCodec, int? maxWidth, int? maxHeight) { - foreach (var config in Configurations) + // If the bitrate isn't changing, then don't downlscale the resolution + if (inputBitrate.HasValue && outputBitrate >= inputBitrate.Value) + { + if (maxWidth.HasValue || maxHeight.HasValue) + { + return new ResolutionOptions + { + MaxWidth = maxWidth, + MaxHeight = maxHeight + }; + } + } + + foreach (var config in Configurations) { - if (maxBitrate <= config.MaxBitrate) + if (outputBitrate <= config.MaxBitrate) { var originvalValue = maxWidth; -- cgit v1.2.3 From 81fb823c024a6652d967bb818cb4fe83417132c4 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 11 Jan 2016 11:52:22 -0500 Subject: record mediastream comment --- .../MediaEncoding/IMediaEncoder.cs | 3 +- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 14 +++++----- .../Probing/ProbeResultNormalizer.cs | 1 + MediaBrowser.Model/Entities/MediaStream.cs | 6 ++++ .../MediaInfo/AudioImageProvider.cs | 29 ++++++++++++++------ .../Persistence/MediaStreamColumns.cs | 32 ++++++++++++++++++++++ .../Persistence/SqliteItemRepository.cs | 11 ++++++-- 7 files changed, 78 insertions(+), 18 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 427af6f6d..76ef054de 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -35,9 +35,10 @@ namespace MediaBrowser.Controller.MediaEncoding /// Extracts the audio image. /// /// The path. + /// Index of the image stream. /// The cancellation token. /// Task{Stream}. - Task ExtractAudioImage(string path, CancellationToken cancellationToken); + Task ExtractAudioImage(string path, int? imageStreamIndex, CancellationToken cancellationToken); /// /// Extracts the video image. diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index f436ca3a0..3c6a99c65 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -472,18 +472,18 @@ namespace MediaBrowser.MediaEncoding.Encoder /// protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); - public Task ExtractAudioImage(string path, CancellationToken cancellationToken) + public Task ExtractAudioImage(string path, int? imageStreamIndex, CancellationToken cancellationToken) { - return ExtractImage(new[] { path }, MediaProtocol.File, true, null, null, cancellationToken); + return ExtractImage(new[] { path }, imageStreamIndex, MediaProtocol.File, true, null, null, cancellationToken); } public Task ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken) { - return ExtractImage(inputFiles, protocol, false, threedFormat, offset, cancellationToken); + return ExtractImage(inputFiles, null, protocol, false, threedFormat, offset, cancellationToken); } - private async Task ExtractImage(string[] inputFiles, MediaProtocol protocol, bool isAudio, + private async Task ExtractImage(string[] inputFiles, int? imageStreamIndex, MediaProtocol protocol, bool isAudio, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken) { var resourcePool = isAudio ? _audioImageResourcePool : _videoImageResourcePool; @@ -494,7 +494,7 @@ namespace MediaBrowser.MediaEncoding.Encoder { try { - return await ExtractImageInternal(inputArgument, protocol, threedFormat, offset, true, resourcePool, cancellationToken).ConfigureAwait(false); + return await ExtractImageInternal(inputArgument, imageStreamIndex, protocol, threedFormat, offset, true, resourcePool, cancellationToken).ConfigureAwait(false); } catch (ArgumentException) { @@ -506,10 +506,10 @@ namespace MediaBrowser.MediaEncoding.Encoder } } - return await ExtractImageInternal(inputArgument, protocol, threedFormat, offset, false, resourcePool, cancellationToken).ConfigureAwait(false); + return await ExtractImageInternal(inputArgument, imageStreamIndex, protocol, threedFormat, offset, false, resourcePool, cancellationToken).ConfigureAwait(false); } - private async Task ExtractImageInternal(string inputPath, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, SemaphoreSlim resourcePool, CancellationToken cancellationToken) + private async Task ExtractImageInternal(string inputPath, int? imageStreamIndex, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, SemaphoreSlim resourcePool, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(inputPath)) { diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index d98efffe7..1df8896d5 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -141,6 +141,7 @@ namespace MediaBrowser.MediaEncoding.Probing if (streamInfo.tags != null) { stream.Language = GetDictionaryValue(streamInfo.tags, "language"); + stream.Comment = GetDictionaryValue(streamInfo.tags, "comment"); } if (string.Equals(streamInfo.codec_type, "audio", StringComparison.OrdinalIgnoreCase)) diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index d089f0aa9..7f4cc2f84 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -30,6 +30,12 @@ namespace MediaBrowser.Model.Entities /// The language. public string Language { get; set; } + /// + /// Gets or sets the comment. + /// + /// The comment. + public string Comment { get; set; } + /// /// Gets or sets a value indicating whether this instance is interlaced. /// diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs index 8884412d2..c98a67bbd 100644 --- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Extensions; +using System; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; @@ -43,20 +44,27 @@ namespace MediaBrowser.Providers.MediaInfo { var audio = (Audio)item; + var imageStreams = + audio.GetMediaSources(false) + .Take(1) + .SelectMany(i => i.MediaStreams) + .Where(i => i.Type == MediaStreamType.EmbeddedImage) + .ToList(); + // Can't extract if we didn't find a video stream in the file - if (!audio.GetMediaSources(false).Take(1).SelectMany(i => i.MediaStreams).Any(i => i.Type == MediaStreamType.EmbeddedImage)) + if (imageStreams.Count == 0) { return Task.FromResult(new DynamicImageResponse { HasImage = false }); } - return GetImage((Audio)item, cancellationToken); + return GetImage((Audio)item, imageStreams, cancellationToken); } - public async Task GetImage(Audio item, CancellationToken cancellationToken) + public async Task GetImage(Audio item, List imageStreams, CancellationToken cancellationToken) { var path = GetAudioImagePath(item); - if (!_fileSystem.FileExists(path)) + if (!_fileSystem.FileExists(path)) { var semaphore = GetLock(path); @@ -66,11 +74,16 @@ namespace MediaBrowser.Providers.MediaInfo try { // Check again in case it was saved while waiting for the lock - if (!_fileSystem.FileExists(path)) + if (!_fileSystem.FileExists(path)) { - _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); + + var imageStream = imageStreams.FirstOrDefault(i => (i.Comment ?? string.Empty).IndexOf("front", StringComparison.OrdinalIgnoreCase) != -1) ?? + imageStreams.FirstOrDefault(i => (i.Comment ?? string.Empty).IndexOf("cover", StringComparison.OrdinalIgnoreCase) != -1); + + var imageStreamIndex = imageStream == null ? (int?)null : imageStream.Index; - using (var stream = await _mediaEncoder.ExtractAudioImage(item.Path, cancellationToken).ConfigureAwait(false)) + using (var stream = await _mediaEncoder.ExtractAudioImage(item.Path, imageStreamIndex, cancellationToken).ConfigureAwait(false)) { using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true)) { diff --git a/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs b/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs index c983dd547..7e46db5a7 100644 --- a/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs +++ b/MediaBrowser.Server.Implementations/Persistence/MediaStreamColumns.cs @@ -28,6 +28,38 @@ namespace MediaBrowser.Server.Implementations.Persistence AddKeyFramesColumn(); AddRefFramesCommand(); AddCodecTagColumn(); + AddCommentColumn(); + } + + private void AddCommentColumn() + { + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = "PRAGMA table_info(mediastreams)"; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) + { + if (!reader.IsDBNull(1)) + { + var name = reader.GetString(1); + + if (string.Equals(name, "Comment", StringComparison.OrdinalIgnoreCase)) + { + return; + } + } + } + } + } + + var builder = new StringBuilder(); + + builder.AppendLine("alter table mediastreams"); + builder.AppendLine("add column Comment TEXT"); + + _connection.RunQueries(new[] { builder.ToString() }, _logger); } private void AddCodecTagColumn() diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 1d3ac293e..3d5ddcf49 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -127,7 +127,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false); var createMediaStreamsTableCommand - = "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, IsCabac BIT NULL, CodecTag TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))"; + = "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, IsCabac BIT NULL, CodecTag TEXT NULL, Comment TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))"; string[] queries = { @@ -385,7 +385,8 @@ namespace MediaBrowser.Server.Implementations.Persistence "IsAnamorphic", "RefFrames", "IsCabac", - "CodecTag" + "CodecTag", + "Comment" }; /// @@ -2683,6 +2684,7 @@ namespace MediaBrowser.Server.Implementations.Persistence _saveStreamCommand.GetParameter(index++).Value = stream.IsCabac; _saveStreamCommand.GetParameter(index++).Value = stream.CodecTag; + _saveStreamCommand.GetParameter(index++).Value = stream.Comment; _saveStreamCommand.Transaction = transaction; _saveStreamCommand.ExecuteNonQuery(); @@ -2841,6 +2843,11 @@ namespace MediaBrowser.Server.Implementations.Persistence item.CodecTag = reader.GetString(26); } + if (!reader.IsDBNull(27)) + { + item.Comment = reader.GetString(27); + } + return item; } -- cgit v1.2.3 From 9b527dcd4fd95a886b7e6cd85a7c5b171f216b61 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 13 Jan 2016 15:59:17 -0500 Subject: fix interlaced detection --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 3c6a99c65..ba0790bf3 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -307,7 +307,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } } - var args = "{0} -i {1} -map 0:v:{2} -filter:v idet -frames:v 500 -an -f null /dev/null"; + var args = "{0} -i {1} -map 0:v:{2} -an -filter:v idet -frames:v 500 -an -f null /dev/null"; var process = new Process { @@ -447,7 +447,7 @@ namespace MediaBrowser.MediaEncoding.Encoder return false; } - if (((tff + bff) / total) >= .65) + if (((tff + bff) / total) >= .4) { return true; } @@ -490,7 +490,15 @@ namespace MediaBrowser.MediaEncoding.Encoder var inputArgument = GetInputArgument(inputFiles, protocol); - if (!isAudio) + if (isAudio) + { + if (imageStreamIndex.HasValue && imageStreamIndex.Value > 0) + { + // It seems for audio files we need to subtract 1 (for the audio stream??) + imageStreamIndex = imageStreamIndex.Value - 1; + } + } + else { try { @@ -543,9 +551,11 @@ namespace MediaBrowser.MediaEncoding.Encoder } } + var mapArg = imageStreamIndex.HasValue ? (" -map 0:v:" + imageStreamIndex.Value.ToString(CultureInfo.InvariantCulture)) : string.Empty; + // Use ffmpeg to sample 100 (we can drop this if required using thumbnail=50 for 50 frames) frames and pick the best thumbnail. Have a fall back just in case. - var args = useIFrame ? string.Format("-i {0} -threads 1 -v quiet -vframes 1 -vf \"{2},thumbnail=30\" -f image2 \"{1}\"", inputPath, "-", vf) : - string.Format("-i {0} -threads 1 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, "-", vf); + var args = useIFrame ? string.Format("-i {0}{3} -threads 1 -v quiet -vframes 1 -vf \"{2},thumbnail=30\" -f image2 \"{1}\"", inputPath, "-", vf, mapArg) : + string.Format("-i {0}{3} -threads 1 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, "-", vf, mapArg); var probeSize = GetProbeSizeArgument(new[] { inputPath }, protocol); -- cgit v1.2.3 From 51df0b79f208bf11be01488aa5ffd3b171ae2198 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 1 Feb 2016 12:02:58 -0500 Subject: update interlaced detection --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 27 ++++++++++++++-------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index ba0790bf3..2a3a416ad 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -292,16 +292,25 @@ namespace MediaBrowser.MediaEncoding.Encoder return false; } - // If the video codec is not some form of mpeg, then take a shortcut and limit this to containers that are likely to have interlaced content - if ((videoStream.Codec ?? string.Empty).IndexOf("mpeg", StringComparison.OrdinalIgnoreCase) == -1) + var formats = (video.Container ?? string.Empty).Split(',').ToList(); + var enableInterlacedDection = formats.Contains("vob", StringComparer.OrdinalIgnoreCase) && + formats.Contains("m2ts", StringComparer.OrdinalIgnoreCase) && + formats.Contains("ts", StringComparer.OrdinalIgnoreCase) && + formats.Contains("mpegts", StringComparer.OrdinalIgnoreCase) && + formats.Contains("wtv", StringComparer.OrdinalIgnoreCase); + + // If it's mpeg based, assume true + if ((videoStream.Codec ?? string.Empty).IndexOf("mpeg", StringComparison.OrdinalIgnoreCase) != -1) { - var formats = (video.Container ?? string.Empty).Split(',').ToList(); - - if (!formats.Contains("vob", StringComparer.OrdinalIgnoreCase) && - !formats.Contains("m2ts", StringComparer.OrdinalIgnoreCase) && - !formats.Contains("ts", StringComparer.OrdinalIgnoreCase) && - !formats.Contains("mpegts", StringComparer.OrdinalIgnoreCase) && - !formats.Contains("wtv", StringComparer.OrdinalIgnoreCase)) + if (enableInterlacedDection) + { + return true; + } + } + else + { + // If the video codec is not some form of mpeg, then take a shortcut and limit this to containers that are likely to have interlaced content + if (!enableInterlacedDection) { return false; } -- cgit v1.2.3 From d1de9e01795d5984a52845817a63ec64e486218b Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 4 Feb 2016 14:31:04 -0500 Subject: update sync encoding to match streaming --- MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs | 24 +-- MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 211 ++++++++++++++------- .../Encoder/EncodingJobFactory.cs | 179 +++++++++-------- MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs | 47 +++-- 4 files changed, 283 insertions(+), 178 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs index b488741d1..a4d4797eb 100644 --- a/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/AudioEncoder.cs @@ -19,38 +19,40 @@ namespace MediaBrowser.MediaEncoding.Encoder { } - protected override string GetCommandLineArguments(EncodingJob job) + protected override string GetCommandLineArguments(EncodingJob state) { var audioTranscodeParams = new List(); - var bitrate = job.OutputAudioBitrate; + var bitrate = state.OutputAudioBitrate; if (bitrate.HasValue) { audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(UsCulture)); } - if (job.OutputAudioChannels.HasValue) + if (state.OutputAudioChannels.HasValue) { - audioTranscodeParams.Add("-ac " + job.OutputAudioChannels.Value.ToString(UsCulture)); + audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(UsCulture)); } - if (job.OutputAudioSampleRate.HasValue) + if (state.OutputAudioSampleRate.HasValue) { - audioTranscodeParams.Add("-ar " + job.OutputAudioSampleRate.Value.ToString(UsCulture)); + audioTranscodeParams.Add("-ar " + state.OutputAudioSampleRate.Value.ToString(UsCulture)); } - var threads = GetNumberOfThreads(job, false); + const string vn = " -vn"; - var inputModifier = GetInputModifier(job); + var threads = GetNumberOfThreads(state, false); + + var inputModifier = GetInputModifier(state); return string.Format("{0} {1} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1 -y \"{5}\"", inputModifier, - GetInputArgument(job), + GetInputArgument(state), threads, - " -vn", + vn, string.Join(" ", audioTranscodeParams.ToArray()), - job.OutputFilePath).Trim(); + state.OutputFilePath).Trim(); } protected override string GetOutputFileExtension(EncodingJob state) diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index 98e4a58a6..3a4a12b35 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -303,15 +303,15 @@ namespace MediaBrowser.MediaEncoding.Encoder return job.Options.CpuCoreLimit ?? 0; } - protected string GetInputModifier(EncodingJob job, bool genPts = true) + protected string GetInputModifier(EncodingJob state, bool genPts = true) { var inputModifier = string.Empty; - var probeSize = GetProbeSizeArgument(job); + var probeSize = GetProbeSizeArgument(state); inputModifier += " " + probeSize; inputModifier = inputModifier.Trim(); - var userAgentParam = GetUserAgentParam(job); + var userAgentParam = GetUserAgentParam(state); if (!string.IsNullOrWhiteSpace(userAgentParam)) { @@ -320,35 +320,43 @@ namespace MediaBrowser.MediaEncoding.Encoder inputModifier = inputModifier.Trim(); - inputModifier += " " + GetFastSeekCommandLineParameter(job.Options); + inputModifier += " " + GetFastSeekCommandLineParameter(state.Options); inputModifier = inputModifier.Trim(); - if (job.IsVideoRequest && genPts) + if (state.IsVideoRequest && genPts) { inputModifier += " -fflags +genpts"; } - if (!string.IsNullOrEmpty(job.InputAudioSync)) + if (!string.IsNullOrEmpty(state.InputAudioSync)) { - inputModifier += " -async " + job.InputAudioSync; + inputModifier += " -async " + state.InputAudioSync; } - if (!string.IsNullOrEmpty(job.InputVideoSync)) + if (!string.IsNullOrEmpty(state.InputVideoSync)) { - inputModifier += " -vsync " + job.InputVideoSync; + inputModifier += " -vsync " + state.InputVideoSync; } - if (job.ReadInputAtNativeFramerate) + if (state.ReadInputAtNativeFramerate) { inputModifier += " -re"; } - var videoDecoder = GetVideoDecoder(job); + var videoDecoder = GetVideoDecoder(state); if (!string.IsNullOrWhiteSpace(videoDecoder)) { inputModifier += " " + videoDecoder; } + //if (state.IsVideoRequest) + //{ + // if (string.Equals(state.OutputContainer, "mkv", StringComparison.OrdinalIgnoreCase)) + // { + // //inputModifier += " -noaccurate_seek"; + // } + //} + return inputModifier; } @@ -392,11 +400,11 @@ namespace MediaBrowser.MediaEncoding.Encoder return null; } - private string GetUserAgentParam(EncodingJob job) + private string GetUserAgentParam(EncodingJob state) { string useragent = null; - job.RemoteHttpHeaders.TryGetValue("User-Agent", out useragent); + state.RemoteHttpHeaders.TryGetValue("User-Agent", out useragent); if (!string.IsNullOrWhiteSpace(useragent)) { @@ -409,31 +417,31 @@ namespace MediaBrowser.MediaEncoding.Encoder /// /// Gets the probe size argument. /// - /// The job. + /// The state. /// System.String. - private string GetProbeSizeArgument(EncodingJob job) + private string GetProbeSizeArgument(EncodingJob state) { - if (job.PlayableStreamFileNames.Count > 0) + if (state.PlayableStreamFileNames.Count > 0) { - return MediaEncoder.GetProbeSizeArgument(job.PlayableStreamFileNames.ToArray(), job.InputProtocol); + return MediaEncoder.GetProbeSizeArgument(state.PlayableStreamFileNames.ToArray(), state.InputProtocol); } - return MediaEncoder.GetProbeSizeArgument(new[] { job.MediaPath }, job.InputProtocol); + return MediaEncoder.GetProbeSizeArgument(new[] { state.MediaPath }, state.InputProtocol); } /// /// Gets the fast seek command line parameter. /// - /// The options. + /// The request. /// System.String. /// The fast seek command line parameter. - protected string GetFastSeekCommandLineParameter(EncodingJobOptions options) + protected string GetFastSeekCommandLineParameter(EncodingJobOptions request) { - var time = options.StartTimeTicks; + var time = request.StartTimeTicks ?? 0; - if (time.HasValue && time.Value > 0) + if (time > 0) { - return string.Format("-ss {0}", MediaEncoder.GetTimeParameter(time.Value)); + return string.Format("-ss {0}", MediaEncoder.GetTimeParameter(time)); } return string.Empty; @@ -442,34 +450,35 @@ namespace MediaBrowser.MediaEncoding.Encoder /// /// Gets the input argument. /// - /// The job. + /// The state. /// System.String. - protected string GetInputArgument(EncodingJob job) + protected string GetInputArgument(EncodingJob state) { - var arg = "-i " + GetInputPathArgument(job); + var arg = string.Format("-i {0}", GetInputPathArgument(state)); - if (job.SubtitleStream != null) + if (state.SubtitleStream != null) { - if (job.SubtitleStream.IsExternal && !job.SubtitleStream.IsTextSubtitleStream) + if (state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream) { - arg += " -i \"" + job.SubtitleStream.Path + "\""; + arg += " -i \"" + state.SubtitleStream.Path + "\""; } } - return arg; + return arg.Trim(); } - private string GetInputPathArgument(EncodingJob job) + private string GetInputPathArgument(EncodingJob state) { - var protocol = job.InputProtocol; + var protocol = state.InputProtocol; + var mediaPath = state.MediaPath ?? string.Empty; - var inputPath = new[] { job.MediaPath }; + var inputPath = new[] { mediaPath }; - if (job.IsInputVideo) + if (state.IsInputVideo) { - if (!(job.VideoType == VideoType.Iso && job.IsoMount == null)) + if (!(state.VideoType == VideoType.Iso && state.IsoMount == null)) { - inputPath = MediaEncoderHelpers.GetInputArgument(FileSystem, job.MediaPath, job.InputProtocol, job.IsoMount, job.PlayableStreamFileNames); + inputPath = MediaEncoderHelpers.GetInputArgument(FileSystem, mediaPath, state.InputProtocol, state.IsoMount, state.PlayableStreamFileNames); } } @@ -491,7 +500,7 @@ namespace MediaBrowser.MediaEncoding.Encoder }, false, cancellationToken).ConfigureAwait(false); - AttachMediaStreamInfo(state, liveStreamResponse.MediaSource, state.Options); + AttachMediaSourceInfo(state, liveStreamResponse.MediaSource, state.Options); if (state.IsVideoRequest) { @@ -505,11 +514,11 @@ namespace MediaBrowser.MediaEncoding.Encoder } } - private void AttachMediaStreamInfo(EncodingJob state, + private void AttachMediaSourceInfo(EncodingJob state, MediaSourceInfo mediaSource, EncodingJobOptions videoRequest) { - EncodingJobFactory.AttachMediaStreamInfo(state, mediaSource, videoRequest); + EncodingJobFactory.AttachMediaSourceInfo(state, mediaSource, videoRequest); } /// @@ -572,7 +581,7 @@ namespace MediaBrowser.MediaEncoding.Encoder { param = "-preset superfast"; - param += " -crf 28"; + param += " -crf 23"; } else if (string.Equals(videoCodec, "libx265", StringComparison.OrdinalIgnoreCase)) @@ -582,6 +591,19 @@ namespace MediaBrowser.MediaEncoding.Encoder param += " -crf 28"; } + // h264 (h264_qsv) + else if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) + { + param = "-preset 7 -look_ahead 0"; + + } + + // h264 (libnvenc) + else if (string.Equals(videoCodec, "libnvenc", StringComparison.OrdinalIgnoreCase)) + { + param = "-preset high-performance"; + } + // webm else if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase)) { @@ -644,9 +666,53 @@ namespace MediaBrowser.MediaEncoding.Encoder param += " -profile:v " + state.Options.Profile; } - if (state.Options.Level.HasValue) + var levelString = state.Options.Level.HasValue ? state.Options.Level.Value.ToString(CultureInfo.InvariantCulture) : null; + + if (!string.IsNullOrEmpty(levelString)) { - param += " -level " + state.Options.Level.Value.ToString(UsCulture); + var h264Encoder = EncodingJobFactory.GetH264Encoder(state, GetEncodingOptions()); + + // h264_qsv and libnvenc expect levels to be expressed as a decimal. libx264 supports decimal and non-decimal format + if (String.Equals(h264Encoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) || String.Equals(h264Encoder, "libnvenc", StringComparison.OrdinalIgnoreCase)) + { + switch (levelString) + { + case "30": + param += " -level 3"; + break; + case "31": + param += " -level 3.1"; + break; + case "32": + param += " -level 3.2"; + break; + case "40": + param += " -level 4"; + break; + case "41": + param += " -level 4.1"; + break; + case "42": + param += " -level 4.2"; + break; + case "50": + param += " -level 5"; + break; + case "51": + param += " -level 5.1"; + break; + case "52": + param += " -level 5.2"; + break; + default: + param += " -level " + levelString; + break; + } + } + else + { + param += " -level " + levelString; + } } return "-pix_fmt yuv420p " + param; @@ -658,15 +724,8 @@ namespace MediaBrowser.MediaEncoding.Encoder if (bitrate.HasValue) { - var hasFixedResolution = state.Options.HasFixedResolution; - if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase)) { - if (hasFixedResolution) - { - return string.Format(" -minrate:v ({0}*.90) -maxrate:v ({0}*1.10) -bufsize:v {0} -b:v {0}", bitrate.Value.ToString(UsCulture)); - } - // With vpx when crf is used, b:v becomes a max rate // https://trac.ffmpeg.org/wiki/vpxEncodingGuide. But higher bitrate source files -b:v causes judder so limite the bitrate but dont allow it to "saturate" the bitrate. So dont contrain it down just up. return string.Format(" -maxrate:v {0} -bufsize:v ({0}*2) -b:v {0}", bitrate.Value.ToString(UsCulture)); @@ -677,20 +736,15 @@ namespace MediaBrowser.MediaEncoding.Encoder return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture)); } - // H264 - if (hasFixedResolution) + // h264 + if (isHls) { - if (isHls) - { - return string.Format(" -b:v {0} -maxrate ({0}*.80) -bufsize {0}", bitrate.Value.ToString(UsCulture)); - } - - return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture)); + return string.Format(" -b:v {0} -maxrate {0} -bufsize {1}", + bitrate.Value.ToString(UsCulture), + (bitrate.Value * 2).ToString(UsCulture)); } - return string.Format(" -maxrate {0} -bufsize {1}", - bitrate.Value.ToString(UsCulture), - (bitrate.Value * 2).ToString(UsCulture)); + return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture)); } return string.Empty; @@ -698,20 +752,23 @@ namespace MediaBrowser.MediaEncoding.Encoder protected double? GetFramerateParam(EncodingJob state) { - if (state.Options.Framerate.HasValue) + if (state.Options != null) { - return state.Options.Framerate.Value; - } - - var maxrate = state.Options.MaxFramerate; + if (state.Options.Framerate.HasValue) + { + return state.Options.Framerate.Value; + } - if (maxrate.HasValue && state.VideoStream != null) - { - var contentRate = state.VideoStream.AverageFrameRate ?? state.VideoStream.RealFrameRate; + var maxrate = state.Options.MaxFramerate; - if (contentRate.HasValue && contentRate.Value > maxrate.Value) + if (maxrate.HasValue && state.VideoStream != null) { - return maxrate; + var contentRate = state.VideoStream.AverageFrameRate ?? state.VideoStream.RealFrameRate; + + if (contentRate.HasValue && contentRate.Value > maxrate.Value) + { + return maxrate; + } } } @@ -852,7 +909,7 @@ namespace MediaBrowser.MediaEncoding.Encoder { var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture); - filters.Add(string.Format("scale=min(iw\\,{0}):trunc(ow/dar/2)*2", maxWidthParam)); + filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,{0})/2)*2:trunc(ow/dar/2)*2", maxWidthParam)); } // If a max height was requested @@ -863,6 +920,14 @@ namespace MediaBrowser.MediaEncoding.Encoder filters.Add(string.Format("scale=trunc(oh*a/2)*2:min(ih\\,{0})", maxHeightParam)); } + if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) + { + if (filters.Count > 1) + { + //filters[filters.Count - 1] += ":flags=fast_bilinear"; + } + } + var output = string.Empty; if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream) @@ -917,8 +982,10 @@ namespace MediaBrowser.MediaEncoding.Encoder seconds.ToString(UsCulture)); } + var mediaPath = state.MediaPath ?? string.Empty; + return string.Format("subtitles='{0}:si={1}',setpts=PTS -{2}/TB", - MediaEncoder.EscapeSubtitleFilterPath(state.MediaPath), + MediaEncoder.EscapeSubtitleFilterPath(mediaPath), state.InternalSubtitleStreamOffset.ToString(UsCulture), seconds.ToString(UsCulture)); } diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs index 9cdc4a7bf..27072efe1 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs @@ -10,6 +10,7 @@ using MediaBrowser.Model.MediaInfo; using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -66,38 +67,56 @@ namespace MediaBrowser.MediaEncoding.Encoder ? mediaSources.First() : mediaSources.First(i => string.Equals(i.Id, request.MediaSourceId)); - AttachMediaStreamInfo(state, mediaSource, options); + var videoRequest = state.Options; - state.OutputAudioBitrate = GetAudioBitrateParam(request, state.AudioStream); + AttachMediaSourceInfo(state, mediaSource, videoRequest); + + //var container = Path.GetExtension(state.RequestedUrl); + + //if (string.IsNullOrEmpty(container)) + //{ + // container = request.Static ? + // state.InputContainer : + // (Path.GetExtension(GetOutputFilePath(state)) ?? string.Empty).TrimStart('.'); + //} + + //state.OutputContainer = (container ?? string.Empty).TrimStart('.'); + + state.OutputAudioBitrate = GetAudioBitrateParam(state.Options, state.AudioStream); state.OutputAudioSampleRate = request.AudioSampleRate; - state.OutputAudioCodec = GetAudioCodec(request); + state.OutputAudioCodec = state.Options.AudioCodec; - state.OutputAudioChannels = GetNumAudioChannelsParam(request, state.AudioStream, state.OutputAudioCodec); + state.OutputAudioChannels = GetNumAudioChannelsParam(state.Options, state.AudioStream, state.OutputAudioCodec); - if (isVideoRequest) + if (videoRequest != null) { - state.OutputVideoCodec = GetVideoCodec(request); - state.OutputVideoBitrate = GetVideoBitrateParamValue(request, state.VideoStream); + state.OutputVideoCodec = state.Options.VideoCodec; + state.OutputVideoBitrate = GetVideoBitrateParamValue(state.Options, state.VideoStream); if (state.OutputVideoBitrate.HasValue) { var resolution = ResolutionNormalizer.Normalize( - state.VideoStream == null ? (int?)null : state.VideoStream.BitRate, - state.OutputVideoBitrate.Value, - state.VideoStream == null ? null : state.VideoStream.Codec, + state.VideoStream == null ? (int?)null : state.VideoStream.BitRate, + state.OutputVideoBitrate.Value, + state.VideoStream == null ? null : state.VideoStream.Codec, state.OutputVideoCodec, - request.MaxWidth, - request.MaxHeight); + videoRequest.MaxWidth, + videoRequest.MaxHeight); - request.MaxWidth = resolution.MaxWidth; - request.MaxHeight = resolution.MaxHeight; + videoRequest.MaxWidth = resolution.MaxWidth; + videoRequest.MaxHeight = resolution.MaxHeight; } } ApplyDeviceProfileSettings(state); - TryStreamCopy(state, request); + if (videoRequest != null) + { + TryStreamCopy(state, videoRequest); + } + + //state.OutputFilePath = GetOutputFilePath(state); return state; } @@ -119,7 +138,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } } - internal static void AttachMediaStreamInfo(EncodingJob state, + internal static void AttachMediaSourceInfo(EncodingJob state, MediaSourceInfo mediaSource, EncodingJobOptions videoRequest) { @@ -131,11 +150,6 @@ namespace MediaBrowser.MediaEncoding.Encoder state.RunTimeTicks = mediaSource.RunTimeTicks; state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders; - if (mediaSource.ReadAtNativeFramerate) - { - state.ReadInputAtNativeFramerate = true; - } - if (mediaSource.VideoType.HasValue) { state.VideoType = mediaSource.VideoType.Value; @@ -156,6 +170,7 @@ namespace MediaBrowser.MediaEncoding.Encoder state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders; state.InputBitrate = mediaSource.Bitrate; state.InputFileSize = mediaSource.Size; + state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate; if (state.ReadInputAtNativeFramerate || mediaSource.Protocol == MediaProtocol.File && string.Equals(mediaSource.Container, "wtv", StringComparison.OrdinalIgnoreCase)) @@ -165,6 +180,12 @@ namespace MediaBrowser.MediaEncoding.Encoder state.InputAudioSync = "1"; } + if (string.Equals(mediaSource.Container, "wma", StringComparison.OrdinalIgnoreCase)) + { + // Seeing some stuttering when transcoding wma to audio-only HLS + state.InputAudioSync = "1"; + } + var mediaStreams = mediaSource.MediaStreams; if (videoRequest != null) @@ -210,19 +231,21 @@ namespace MediaBrowser.MediaEncoding.Encoder /// System.Nullable{VideoCodecs}. private static string InferVideoCodec(string container) { - if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase)) + var ext = "." + (container ?? string.Empty); + + if (string.Equals(ext, ".asf", StringComparison.OrdinalIgnoreCase)) { return "wmv"; } - if (string.Equals(container, "webm", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase)) { return "vpx"; } - if (string.Equals(container, "ogg", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "ogv", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase)) { return "theora"; } - if (string.Equals(container, "m3u8", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "ts", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(ext, ".m3u8", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ts", StringComparison.OrdinalIgnoreCase)) { return "h264"; } @@ -232,35 +255,37 @@ namespace MediaBrowser.MediaEncoding.Encoder private string InferAudioCodec(string container) { - if (string.Equals(container, "mp3", StringComparison.OrdinalIgnoreCase)) + var ext = "." + (container ?? string.Empty); + + if (string.Equals(ext, ".mp3", StringComparison.OrdinalIgnoreCase)) { return "mp3"; } - if (string.Equals(container, "aac", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(ext, ".aac", StringComparison.OrdinalIgnoreCase)) { return "aac"; } - if (string.Equals(container, "wma", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(ext, ".wma", StringComparison.OrdinalIgnoreCase)) { return "wma"; } - if (string.Equals(container, "ogg", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase)) { return "vorbis"; } - if (string.Equals(container, "oga", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(ext, ".oga", StringComparison.OrdinalIgnoreCase)) { return "vorbis"; } - if (string.Equals(container, "ogv", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase)) { return "vorbis"; } - if (string.Equals(container, "webm", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase)) { return "vorbis"; } - if (string.Equals(container, "webma", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(ext, ".webma", StringComparison.OrdinalIgnoreCase)) { return "vorbis"; } @@ -398,15 +423,8 @@ namespace MediaBrowser.MediaEncoding.Encoder if (bitrate.HasValue) { - var hasFixedResolution = state.Options.HasFixedResolution; - if (string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase)) { - if (hasFixedResolution) - { - return string.Format(" -minrate:v ({0}*.90) -maxrate:v ({0}*1.10) -bufsize:v {0} -b:v {0}", bitrate.Value.ToString(UsCulture)); - } - // With vpx when crf is used, b:v becomes a max rate // https://trac.ffmpeg.org/wiki/vpxEncodingGuide. But higher bitrate source files -b:v causes judder so limite the bitrate but dont allow it to "saturate" the bitrate. So dont contrain it down just up. return string.Format(" -maxrate:v {0} -bufsize:v ({0}*2) -b:v {0}", bitrate.Value.ToString(UsCulture)); @@ -417,20 +435,15 @@ namespace MediaBrowser.MediaEncoding.Encoder return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture)); } - // H264 - if (hasFixedResolution) + // h264 + if (isHls) { - if (isHls) - { - return string.Format(" -b:v {0} -maxrate ({0}*.80) -bufsize {0}", bitrate.Value.ToString(UsCulture)); - } - - return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture)); + return string.Format(" -b:v {0} -maxrate {0} -bufsize {1}", + bitrate.Value.ToString(UsCulture), + (bitrate.Value * 2).ToString(UsCulture)); } - return string.Format(" -maxrate {0} -bufsize {1}", - bitrate.Value.ToString(UsCulture), - (bitrate.Value * 2).ToString(UsCulture)); + return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture)); } return string.Empty; @@ -466,11 +479,11 @@ namespace MediaBrowser.MediaEncoding.Encoder /// /// Gets the name of the output audio codec /// - /// The request. + /// The state. /// System.String. - private string GetAudioCodec(EncodingJobOptions request) + internal static string GetAudioEncoder(EncodingJob state) { - var codec = request.AudioCodec; + var codec = state.OutputAudioCodec; if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase)) { @@ -489,40 +502,56 @@ namespace MediaBrowser.MediaEncoding.Encoder return "wmav2"; } - return (codec ?? string.Empty).ToLower(); + return codec.ToLower(); } /// /// Gets the name of the output video codec /// - /// The request. + /// The state. + /// The options. /// System.String. - private string GetVideoCodec(EncodingJobOptions request) + internal static string GetVideoEncoder(EncodingJob state, EncodingOptions options) { - var codec = request.VideoCodec; + var codec = state.OutputVideoCodec; - if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase)) + if (!string.IsNullOrEmpty(codec)) { - return "libx264"; - } - if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase) || string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)) - { - return "libx265"; - } - if (string.Equals(codec, "vpx", StringComparison.OrdinalIgnoreCase)) - { - return "libvpx"; - } - if (string.Equals(codec, "wmv", StringComparison.OrdinalIgnoreCase)) - { - return "wmv2"; + if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase)) + { + return GetH264Encoder(state, options); + } + if (string.Equals(codec, "vpx", StringComparison.OrdinalIgnoreCase)) + { + return "libvpx"; + } + if (string.Equals(codec, "wmv", StringComparison.OrdinalIgnoreCase)) + { + return "wmv2"; + } + if (string.Equals(codec, "theora", StringComparison.OrdinalIgnoreCase)) + { + return "libtheora"; + } + + return codec.ToLower(); } - if (string.Equals(codec, "theora", StringComparison.OrdinalIgnoreCase)) + + return "copy"; + } + + internal static string GetH264Encoder(EncodingJob state, EncodingOptions options) + { + if (string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { - return "libtheora"; + // It's currently failing on live tv + if (state.RunTimeTicks.HasValue) + { + return "h264_qsv"; + } } - return (codec ?? string.Empty).ToLower(); + return "libx264"; } internal static bool CanStreamCopyVideo(EncodingJobOptions request, MediaStream videoStream) diff --git a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs index 127145aec..9d051b38b 100644 --- a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs @@ -21,14 +21,14 @@ namespace MediaBrowser.MediaEncoding.Encoder protected override string GetCommandLineArguments(EncodingJob state) { // Get the output codec name - var videoCodec = state.OutputVideoCodec; + var videoCodec = EncodingJobFactory.GetVideoEncoder(state, GetEncodingOptions()); var format = string.Empty; var keyFrame = string.Empty; - if (string.Equals(Path.GetExtension(state.OutputFilePath), ".mp4", StringComparison.OrdinalIgnoreCase) && - state.Options.Context == EncodingContext.Streaming) + if (string.Equals(Path.GetExtension(state.OutputFilePath), ".mp4", StringComparison.OrdinalIgnoreCase)) { + // Comparison: https://github.com/jansmolders86/mediacenterjs/blob/master/lib/transcoding/desktop.js format = " -f mp4 -movflags frag_keyframe+empty_moov"; } @@ -53,42 +53,49 @@ namespace MediaBrowser.MediaEncoding.Encoder /// Gets video arguments to pass to ffmpeg /// /// The state. - /// The video codec. + /// The video codec. /// System.String. - private string GetVideoArguments(EncodingJob state, string codec) + private string GetVideoArguments(EncodingJob state, string videoCodec) { - var args = "-codec:v:0 " + codec; + var args = "-codec:v:0 " + videoCodec; if (state.EnableMpegtsM2TsMode) { args += " -mpegts_m2ts_mode 1"; } - // See if we can save come cpu cycles by avoiding encoding - if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase)) + var isOutputMkv = string.Equals(state.Options.OutputContainer, "mkv", StringComparison.OrdinalIgnoreCase); + + if (state.RunTimeTicks.HasValue) { - return state.VideoStream != null && IsH264(state.VideoStream) && string.Equals(state.Options.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) ? - args + " -bsf:v h264_mp4toannexb" : - args; + //args += " -copyts -avoid_negative_ts disabled -start_at_zero"; } - if (state.Options.Context == EncodingContext.Streaming) + if (string.Equals(videoCodec, "copy", StringComparison.OrdinalIgnoreCase)) { - var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})", - 5.ToString(UsCulture)); + if (state.VideoStream != null && IsH264(state.VideoStream) && + (string.Equals(state.Options.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) || isOutputMkv)) + { + args += " -bsf:v h264_mp4toannexb"; + } - args += keyFrameArg; + return args; } + var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})", + 5.ToString(UsCulture)); + + args += keyFrameArg; + var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream; // Add resolution params, if specified if (!hasGraphicalSubs) { - args += GetOutputSizeParam(state, codec); + args += GetOutputSizeParam(state, videoCodec); } - var qualityParam = GetVideoQualityParam(state, codec, false); + var qualityParam = GetVideoQualityParam(state, videoCodec, false); if (!string.IsNullOrEmpty(qualityParam)) { @@ -98,7 +105,7 @@ namespace MediaBrowser.MediaEncoding.Encoder // This is for internal graphical subs if (hasGraphicalSubs) { - args += GetGraphicalSubtitleParam(state, codec); + args += GetGraphicalSubtitleParam(state, videoCodec); } return args; @@ -118,11 +125,11 @@ namespace MediaBrowser.MediaEncoding.Encoder } // Get the output codec name - var codec = state.OutputAudioCodec; + var codec = EncodingJobFactory.GetAudioEncoder(state); var args = "-codec:a:0 " + codec; - if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase)) { return args; } -- cgit v1.2.3 From bc6c0bd0b7ec6f57651c21726f66f9cf7a69cba3 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 6 Feb 2016 16:36:29 -0500 Subject: update sync conversion --- MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs index 9d051b38b..79f248468 100644 --- a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs @@ -26,7 +26,8 @@ namespace MediaBrowser.MediaEncoding.Encoder var format = string.Empty; var keyFrame = string.Empty; - if (string.Equals(Path.GetExtension(state.OutputFilePath), ".mp4", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(Path.GetExtension(state.OutputFilePath), ".mp4", StringComparison.OrdinalIgnoreCase) && + state.Options.Context == EncodingContext.Streaming) { // Comparison: https://github.com/jansmolders86/mediacenterjs/blob/master/lib/transcoding/desktop.js format = " -f mp4 -movflags frag_keyframe+empty_moov"; -- cgit v1.2.3 From fcd15da1e6fb6e940f55c2def0e00554feae36e0 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 7 Feb 2016 16:48:08 -0500 Subject: update progressive encoding --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 18 ++++++------------ MediaBrowser.Api/Playback/Dash/MpegDashService.cs | 2 +- MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs | 2 +- MediaBrowser.Api/Playback/Hls/VideoHlsService.cs | 2 +- MediaBrowser.Api/Playback/Progressive/VideoService.cs | 2 +- MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 18 ++++++------------ MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs | 2 +- 7 files changed, 17 insertions(+), 29 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index bb7f6bb1e..bae8074fd 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -305,9 +305,8 @@ namespace MediaBrowser.Api.Playback /// /// The state. /// The video codec. - /// if set to true [is HLS]. /// System.String. - protected string GetVideoQualityParam(StreamState state, string videoCodec, bool isHls) + protected string GetVideoQualityParam(StreamState state, string videoCodec) { var param = string.Empty; @@ -385,7 +384,7 @@ namespace MediaBrowser.Api.Playback param = "-mbd 2"; } - param += GetVideoBitrateParam(state, videoCodec, isHls); + param += GetVideoBitrateParam(state, videoCodec); var framerate = GetFramerateParam(state); if (framerate.HasValue) @@ -1190,7 +1189,7 @@ namespace MediaBrowser.Api.Playback return bitrate; } - protected string GetVideoBitrateParam(StreamState state, string videoCodec, bool isHls) + protected string GetVideoBitrateParam(StreamState state, string videoCodec) { var bitrate = state.OutputVideoBitrate; @@ -1209,14 +1208,9 @@ namespace MediaBrowser.Api.Playback } // h264 - if (isHls) - { - return string.Format(" -b:v {0} -maxrate {0} -bufsize {1}", - bitrate.Value.ToString(UsCulture), - (bitrate.Value * 2).ToString(UsCulture)); - } - - return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture)); + return string.Format(" -b:v {0} -maxrate {0} -bufsize {1}", + bitrate.Value.ToString(UsCulture), + (bitrate.Value * 2).ToString(UsCulture)); } return string.Empty; diff --git a/MediaBrowser.Api/Playback/Dash/MpegDashService.cs b/MediaBrowser.Api/Playback/Dash/MpegDashService.cs index 9ec16fcc7..defb2eef0 100644 --- a/MediaBrowser.Api/Playback/Dash/MpegDashService.cs +++ b/MediaBrowser.Api/Playback/Dash/MpegDashService.cs @@ -430,7 +430,7 @@ namespace MediaBrowser.Api.Playback.Dash var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream; - args += " " + GetVideoQualityParam(state, GetH264Encoder(state), true) + keyFrameArg; + args += " " + GetVideoQualityParam(state, GetH264Encoder(state)) + keyFrameArg; // Add resolution params, if specified if (!hasGraphicalSubs) diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index baf662c34..4a83615b4 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -822,7 +822,7 @@ namespace MediaBrowser.Api.Playback.Hls var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream; - args += " " + GetVideoQualityParam(state, GetH264Encoder(state), true) + keyFrameArg; + args += " " + GetVideoQualityParam(state, GetH264Encoder(state)) + keyFrameArg; //args += " -mixed-refs 0 -refs 3 -x264opts b_pyramid=0:weightb=0:weightp=0"; diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs index be1db1a4d..22c38009a 100644 --- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs @@ -106,7 +106,7 @@ namespace MediaBrowser.Api.Playback.Hls var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream; - args += " " + GetVideoQualityParam(state, GetH264Encoder(state), true) + keyFrameArg; + args += " " + GetVideoQualityParam(state, GetH264Encoder(state)) + keyFrameArg; // Add resolution params, if specified if (!hasGraphicalSubs) diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs index 19e568ec4..eaf65bd6b 100644 --- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs +++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs @@ -166,7 +166,7 @@ namespace MediaBrowser.Api.Playback.Progressive args += GetOutputSizeParam(state, videoCodec); } - var qualityParam = GetVideoQualityParam(state, videoCodec, false); + var qualityParam = GetVideoQualityParam(state, videoCodec); if (!string.IsNullOrEmpty(qualityParam)) { diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index 3a4a12b35..4fabed850 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -568,9 +568,8 @@ namespace MediaBrowser.MediaEncoding.Encoder /// /// The state. /// The video codec. - /// if set to true [is HLS]. /// System.String. - protected string GetVideoQualityParam(EncodingJob state, string videoCodec, bool isHls) + protected string GetVideoQualityParam(EncodingJob state, string videoCodec) { var param = string.Empty; @@ -648,7 +647,7 @@ namespace MediaBrowser.MediaEncoding.Encoder param = "-mbd 2"; } - param += GetVideoBitrateParam(state, videoCodec, isHls); + param += GetVideoBitrateParam(state, videoCodec); var framerate = GetFramerateParam(state); if (framerate.HasValue) @@ -718,7 +717,7 @@ namespace MediaBrowser.MediaEncoding.Encoder return "-pix_fmt yuv420p " + param; } - protected string GetVideoBitrateParam(EncodingJob state, string videoCodec, bool isHls) + protected string GetVideoBitrateParam(EncodingJob state, string videoCodec) { var bitrate = state.OutputVideoBitrate; @@ -737,14 +736,9 @@ namespace MediaBrowser.MediaEncoding.Encoder } // h264 - if (isHls) - { - return string.Format(" -b:v {0} -maxrate {0} -bufsize {1}", - bitrate.Value.ToString(UsCulture), - (bitrate.Value * 2).ToString(UsCulture)); - } - - return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture)); + return string.Format(" -b:v {0} -maxrate {0} -bufsize {1}", + bitrate.Value.ToString(UsCulture), + (bitrate.Value * 2).ToString(UsCulture)); } return string.Empty; diff --git a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs index 79f248468..5756566fe 100644 --- a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs @@ -96,7 +96,7 @@ namespace MediaBrowser.MediaEncoding.Encoder args += GetOutputSizeParam(state, videoCodec); } - var qualityParam = GetVideoQualityParam(state, videoCodec, false); + var qualityParam = GetVideoQualityParam(state, videoCodec); if (!string.IsNullOrEmpty(qualityParam)) { -- cgit v1.2.3 From e037fcbdafc3d93cd6daea37e93c68b69056d0c5 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 9 Feb 2016 20:36:27 -0500 Subject: update sync encoding --- .../Encoder/EncodingJobFactory.cs | 25 +++++++++------------- 1 file changed, 10 insertions(+), 15 deletions(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs index 27072efe1..252386af0 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs @@ -355,8 +355,8 @@ namespace MediaBrowser.MediaEncoding.Encoder private int? GetNumAudioChannelsParam(EncodingJobOptions request, MediaStream audioStream, string outputAudioCodec) { var inputChannels = audioStream == null - ? null - : audioStream.Channels; + ? null + : audioStream.Channels; if (inputChannels <= 0) { @@ -373,15 +373,15 @@ namespace MediaBrowser.MediaEncoding.Encoder if (request.MaxAudioChannels.HasValue) { + var channelLimit = codec.IndexOf("mp3", StringComparison.OrdinalIgnoreCase) != -1 + ? 2 + : 6; + if (inputChannels.HasValue) { - return Math.Min(request.MaxAudioChannels.Value, inputChannels.Value); + channelLimit = Math.Min(channelLimit, inputChannels.Value); } - var channelLimit = codec.IndexOf("mp3", StringComparison.OrdinalIgnoreCase) != -1 - ? 2 - : 6; - // If we don't have any media info then limit it to 5 to prevent encoding errors due to asking for too many channels return Math.Min(request.MaxAudioChannels.Value, channelLimit); } @@ -436,14 +436,9 @@ namespace MediaBrowser.MediaEncoding.Encoder } // h264 - if (isHls) - { - return string.Format(" -b:v {0} -maxrate {0} -bufsize {1}", - bitrate.Value.ToString(UsCulture), - (bitrate.Value * 2).ToString(UsCulture)); - } - - return string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture)); + return string.Format(" -b:v {0} -maxrate {0} -bufsize {1}", + bitrate.Value.ToString(UsCulture), + (bitrate.Value * 2).ToString(UsCulture)); } return string.Empty; -- cgit v1.2.3 From 1a2867ea5516989c993e0f01322142d532e6ebc4 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 11 Feb 2016 14:11:28 -0500 Subject: support tagging 3d as mvc --- MediaBrowser.Controller/Providers/BaseItemXmlParser.cs | 4 ++++ MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs | 3 +++ MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 2 ++ MediaBrowser.Model/Entities/Video3DFormat.cs | 3 ++- .../Library/Resolvers/BaseVideoResolver.cs | 4 ++++ MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs | 4 ++++ MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs | 3 +++ 7 files changed, 22 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.MediaEncoding/Encoder') diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs index 3e5353812..f9060d184 100644 --- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs @@ -889,6 +889,10 @@ namespace MediaBrowser.Controller.Providers { video.Video3DFormat = Video3DFormat.FullSideBySide; } + else if (string.Equals("MVC", val, StringComparison.OrdinalIgnoreCase)) + { + video.Video3DFormat = Video3DFormat.MVC; + } } break; } diff --git a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs index c9a4cb537..48c4fe2fd 100644 --- a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs +++ b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs @@ -736,6 +736,9 @@ namespace MediaBrowser.LocalMetadata.Savers case Video3DFormat.HalfTopAndBottom: builder.Append("HTAB"); break; + case Video3DFormat.MVC: + builder.Append("MVC"); + break; } } } diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 2a3a416ad..30e50fecd 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -557,6 +557,8 @@ namespace MediaBrowser.MediaEncoding.Encoder vf = "crop=iw:ih/2:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale=600:trunc(600/dar/2)*2"; // ftab crop heigt in half, set the display aspect,crop out any black bars we may have made the scale width to 600 break; + default: + break; } } diff --git a/MediaBrowser.Model/Entities/Video3DFormat.cs b/MediaBrowser.Model/Entities/Video3DFormat.cs index 064b02edd..722df4281 100644 --- a/MediaBrowser.Model/Entities/Video3DFormat.cs +++ b/MediaBrowser.Model/Entities/Video3DFormat.cs @@ -6,6 +6,7 @@ namespace MediaBrowser.Model.Entities HalfSideBySide, FullSideBySide, FullTopAndBottom, - HalfTopAndBottom + HalfTopAndBottom, + MVC } } diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs index 9ebf82c02..9edd3f83f 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs @@ -242,6 +242,10 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers { video.Video3DFormat = Video3DFormat.HalfTopAndBottom; } + else if (string.Equals(format3D, "mvc", StringComparison.OrdinalIgnoreCase)) + { + video.Video3DFormat = Video3DFormat.MVC; + } } } diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs index 40b974ee7..30243ff57 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs @@ -1173,6 +1173,10 @@ namespace MediaBrowser.XbmcMetadata.Parsers { video.Video3DFormat = Video3DFormat.FullSideBySide; } + else if (string.Equals("MVC", val, StringComparison.OrdinalIgnoreCase)) + { + video.Video3DFormat = Video3DFormat.MVC; + } } break; } diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs index ec12088b3..53a7926ca 100644 --- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs @@ -404,6 +404,9 @@ namespace MediaBrowser.XbmcMetadata.Savers case Video3DFormat.HalfTopAndBottom: writer.WriteElementString("format3d", "HTAB"); break; + case Video3DFormat.MVC: + writer.WriteElementString("format3d", "MVC"); + break; } } } -- cgit v1.2.3