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