diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index a4abb129b..ac7dab080 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1435,6 +1435,9 @@ namespace MediaBrowser.Api.Playback state.PlayableStreamFileNames = video.PlayableStreamFileNames == null ? new List() : video.PlayableStreamFileNames.ToList(); + + state.DeInterlace = string.Equals(video.Container, "wtv", StringComparison.OrdinalIgnoreCase); + state.InputTimestamp = video.Timestamp; } state.RunTimeTicks = item.RunTimeTicks; diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index fe9199244..051413259 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -10,6 +10,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Threading; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Api.Playback { @@ -26,7 +27,7 @@ namespace MediaBrowser.Api.Playback { get { return Request as VideoStreamRequest; } } - + /// /// Gets or sets the log file stream. /// @@ -77,19 +78,21 @@ namespace MediaBrowser.Api.Playback public string InputAudioSync { get; set; } public string InputVideoSync { get; set; } - + public bool DeInterlace { get; set; } public bool ReadInputAtNativeFramerate { get; set; } public string InputFormat { get; set; } public string InputVideoCodec { get; set; } public string InputAudioCodec { get; set; } + public TransportStreamTimestamp InputTimestamp { get; set; } + public string MimeType { get; set; } public bool EstimateContentLength { get; set; } public bool EnableMpegtsM2TsMode { get; set; } public TranscodeSeekInfo TranscodeSeekInfo { get; set; } - + public string GetMimeType(string outputPath) { if (!string.IsNullOrEmpty(MimeType)) @@ -269,11 +272,13 @@ namespace MediaBrowser.Api.Playback { get { - var stream = VideoStream; + var defaultValue = string.Equals(OutputContainer, "m2ts", StringComparison.OrdinalIgnoreCase) ? + TransportStreamTimestamp.VALID : + TransportStreamTimestamp.NONE; return !Request.Static - ? TransportStreamTimestamp.VALID - : stream == null ? TransportStreamTimestamp.VALID : stream.Timestamp; + ? defaultValue + : InputTimestamp; } } diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 2d926e236..bfb306b31 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Resolvers; +using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Entities; using System; using System.Collections; @@ -11,6 +12,7 @@ using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Controller.Entities { @@ -31,6 +33,12 @@ namespace MediaBrowser.Controller.Entities public string Container { get; set; } public int? TotalBitrate { get; set; } + /// + /// Gets or sets the timestamp. + /// + /// The timestamp. + public TransportStreamTimestamp Timestamp { get; set; } + public Video() { PlayableStreamFileNames = new List(); diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index 56baaec0a..2ccd364d5 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -86,9 +86,6 @@ Configuration\DlnaOptions.cs - - Configuration\ManualLoginCategory.cs - Configuration\MetadataOptions.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index 37fb68ad6..c3eb6b11d 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -73,9 +73,6 @@ Configuration\DlnaOptions.cs - - Configuration\ManualLoginCategory.cs - Configuration\MetadataOptions.cs diff --git a/MediaBrowser.Model/Configuration/ManualLoginCategory.cs b/MediaBrowser.Model/Configuration/ManualLoginCategory.cs deleted file mode 100644 index 37b6d6c82..000000000 --- a/MediaBrowser.Model/Configuration/ManualLoginCategory.cs +++ /dev/null @@ -1,9 +0,0 @@ - -namespace MediaBrowser.Model.Configuration -{ - public enum ManualLoginCategory - { - Mobile, - MediaBrowserTheater - } -} diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index ca5f569ed..325db34ed 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -168,8 +168,6 @@ namespace MediaBrowser.Model.Configuration /// The dashboard source path. public string DashboardSourcePath { get; set; } - public ManualLoginCategory[] ManualLoginClients { get; set; } - /// /// Gets or sets a value indicating whether [enable tv db updates]. /// @@ -178,6 +176,9 @@ namespace MediaBrowser.Model.Configuration public bool EnableTmdbUpdates { get; set; } public bool EnableFanArtUpdates { get; set; } + public bool RequireManualLoginForMobileApps { get; set; } + public bool RequireManualLoginForOtherApps { get; set; } + /// /// Gets or sets the image saving convention. /// @@ -256,7 +257,6 @@ namespace MediaBrowser.Model.Configuration EnableInternetProviders = true; //initial installs will need these - ManualLoginClients = new ManualLoginCategory[] { }; PathSubstitutions = new PathSubstitution[] { }; MetadataRefreshDays = 30; diff --git a/MediaBrowser.Model/Dlna/ConditionProcessor.cs b/MediaBrowser.Model/Dlna/ConditionProcessor.cs index 292ca2148..2e337982f 100644 --- a/MediaBrowser.Model/Dlna/ConditionProcessor.cs +++ b/MediaBrowser.Model/Dlna/ConditionProcessor.cs @@ -1,5 +1,7 @@ using System; using System.Globalization; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Model.Dlna { diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs index b2bbe3b14..f3357dc5b 100644 --- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs +++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Model.Dlna { diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs index f6ca6b48f..70285078a 100644 --- a/MediaBrowser.Model/Dlna/DeviceProfile.cs +++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.Linq; using System.Xml.Serialization; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Model.Dlna { diff --git a/MediaBrowser.Model/Dlna/MediaFormatProfile.cs b/MediaBrowser.Model/Dlna/MediaFormatProfile.cs index 596985bdc..f3d04335f 100644 --- a/MediaBrowser.Model/Dlna/MediaFormatProfile.cs +++ b/MediaBrowser.Model/Dlna/MediaFormatProfile.cs @@ -110,11 +110,4 @@ namespace MediaBrowser.Model.Dlna MPEG4_H263_3GPP_P0_L10_AMR, MPEG4_H263_MP4_P0_L10_AAC } - - public enum TransportStreamTimestamp - { - NONE, - ZERO, - VALID - } } diff --git a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs index 9337a6c95..589dc3376 100644 --- a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs +++ b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Model.Dlna { @@ -147,14 +149,14 @@ namespace MediaBrowser.Model.Dlna } else if (string.Equals(videoCodec, "mpeg4", StringComparison.OrdinalIgnoreCase) || string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase)) { - // if (audioCodec == AudioCodec.AAC) - // return Collections.singletonList(MediaFormatProfile.valueOf(String.format("MPEG4_P2_TS_ASP_AAC%s", cast(Object[])[ suffix ]))); - // if (audioCodec == AudioCodec.MP3) - // return Collections.singletonList(MediaFormatProfile.valueOf(String.format("MPEG4_P2_TS_ASP_MPEG1_L3%s", cast(Object[])[ suffix ]))); - // if (audioCodec == AudioCodec.MP2) - // return Collections.singletonList(MediaFormatProfile.valueOf(String.format("MPEG4_P2_TS_ASP_MPEG2_L2%s", cast(Object[])[ suffix ]))); - // if ((audioCodec is null) || (audioCodec == AudioCodec.AC3)) { - // return Collections.singletonList(MediaFormatProfile.valueOf(String.format("MPEG4_P2_TS_ASP_AC3%s", cast(Object[])[ suffix ]))); + if (string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase)) + return new[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_AAC{0}", suffix)) }; + if (string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase)) + return new[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_MPEG1_L3{0}", suffix)) }; + if (string.Equals(audioCodec, "mp2", StringComparison.OrdinalIgnoreCase)) + return new[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_MPEG2_L2{0}", suffix)) }; + if (string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase)) + return new[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_AC3{0}", suffix)) }; } return new List(); diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index f3425d202..13c698ded 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Model.Dlna { @@ -285,7 +286,7 @@ namespace MediaBrowser.Model.Dlna var audioBitrate = audioStream == null ? null : audioStream.BitRate; var audioChannels = audioStream == null ? null : audioStream.Channels; - var timestamp = videoStream == null ? TransportStreamTimestamp.NONE : videoStream.Timestamp; + var timestamp = videoStream == null ? TransportStreamTimestamp.NONE : mediaSource.Timestamp; var packetLength = videoStream == null ? null : videoStream.PacketLength; // Check container conditions diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index 0ab6805e3..e49c31947 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Model.Dlna { @@ -339,11 +340,13 @@ namespace MediaBrowser.Model.Dlna { get { - var stream = TargetVideoStream; - - return !IsDirectStream + var defaultValue = string.Equals(Container, "m2ts", StringComparison.OrdinalIgnoreCase) ? TransportStreamTimestamp.VALID - : stream == null ? TransportStreamTimestamp.VALID : stream.Timestamp; + : TransportStreamTimestamp.NONE; + + return !IsDirectStream + ? defaultValue + : MediaSource == null ? defaultValue : MediaSource.Timestamp; } } diff --git a/MediaBrowser.Model/Dto/MediaVersionInfo.cs b/MediaBrowser.Model/Dto/MediaVersionInfo.cs index cfef83d2c..e2b197213 100644 --- a/MediaBrowser.Model/Dto/MediaVersionInfo.cs +++ b/MediaBrowser.Model/Dto/MediaVersionInfo.cs @@ -1,5 +1,6 @@ using MediaBrowser.Model.Entities; using System.Collections.Generic; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Model.Dto { @@ -30,6 +31,8 @@ namespace MediaBrowser.Model.Dto public int? Bitrate { get; set; } + public TransportStreamTimestamp Timestamp { get; set; } + public MediaSourceInfo() { Formats = new List(); diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index 920112d02..d54e3c0ef 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Diagnostics; -using MediaBrowser.Model.Dlna; namespace MediaBrowser.Model.Entities { @@ -52,12 +51,6 @@ namespace MediaBrowser.Model.Entities /// The length of the packet. public int? PacketLength { get; set; } - /// - /// Gets or sets the timestamp. - /// - /// The timestamp. - public TransportStreamTimestamp Timestamp { get; set; } - /// /// Gets or sets the channels. /// diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 1ae0833fb..c22688b33 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -62,7 +62,6 @@ - diff --git a/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs b/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs index 963e8dd95..35000ca39 100644 --- a/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs +++ b/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs @@ -34,4 +34,11 @@ namespace MediaBrowser.Model.MediaInfo /// The chapters. public List Chapters { get; set; } } + + public enum TransportStreamTimestamp + { + NONE, + ZERO, + VALID + } } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index 2d29286d3..4f47edee0 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -1,11 +1,13 @@ using DvdLib.Ifo; using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.IO; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; @@ -33,6 +35,7 @@ namespace MediaBrowser.Providers.MediaInfo private readonly IApplicationPaths _appPaths; private readonly IJsonSerializer _json; private readonly IEncodingManager _encodingManager; + private readonly IFileSystem _fileSystem; private readonly CultureInfo _usCulture = new CultureInfo("en-US"); @@ -215,6 +218,8 @@ namespace MediaBrowser.Providers.MediaInfo video.HasSubtitles = mediaStreams.Any(i => i.Type == MediaStreamType.Subtitle); + ExtractTimestamp(video); + await _encodingManager.RefreshChapterImages(new ChapterImageRefreshOptions { Chapters = chapters, @@ -568,6 +573,53 @@ namespace MediaBrowser.Providers.MediaInfo } } + private void ExtractTimestamp(Video video) + { + if (video.VideoType == VideoType.VideoFile) + { + if (string.Equals(video.Container, "mpeg2ts", StringComparison.OrdinalIgnoreCase) || + string.Equals(video.Container, "m2ts", StringComparison.OrdinalIgnoreCase) || + string.Equals(video.Container, "ts", StringComparison.OrdinalIgnoreCase)) + { + try + { + video.Timestamp = GetMpegTimestamp(video.Path); + } + catch (Exception ex) + { + _logger.ErrorException("Error extracting timestamp info from {0}", ex, video.Path); + } + } + } + } + + private TransportStreamTimestamp GetMpegTimestamp(string path) + { + var packetBuffer = new byte['Å']; + + using (var fs = _fileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + fs.Read(packetBuffer, 0, packetBuffer.Length); + } + + if (packetBuffer[0] == 71) + { + return TransportStreamTimestamp.NONE; + } + + if ((packetBuffer[4] == 71) && (packetBuffer['Ä'] == 71)) + { + if ((packetBuffer[0] == 0) && (packetBuffer[1] == 0) && (packetBuffer[2] == 0) && (packetBuffer[3] == 0)) + { + return TransportStreamTimestamp.ZERO; + } + + return TransportStreamTimestamp.VALID; + } + + return TransportStreamTimestamp.NONE; + } + private void FetchFromDvdLib(Video item, IIsoMount mount) { var path = mount == null ? item.Path : mount.MountedPath; diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index d32e6ad0e..ee6bbb04f 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -1237,7 +1237,8 @@ namespace MediaBrowser.Server.Implementations.Dto VideoType = i.VideoType, Container = i.Container, Size = i.Size, - Formats = (i.FormatName ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList() + Formats = (i.FormatName ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(), + Timestamp = i.Timestamp }; if (string.IsNullOrEmpty(info.Container)) diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 9eb289fe8..01a997cca 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -276,7 +276,7 @@ "HeaderPleaseSignIn": "Please sign in", "LabelUser": "User:", "LabelPassword": "Password:", - "ButtonManualLogin": "Manual Login:", + "ButtonManualLogin": "Manual Login", "PasswordLocalhostMessage": "Passwords are not required when logging in from localhost.", "TabGuide": "Guide", "TabChannels": "Channels", @@ -545,5 +545,14 @@ "LabelDefaultUser": "Default user:", "LabelDefaultUserHelp": "Determines which user library should be displayed on connected devices. This can be overridden for each device using profiles.", "TitleDlna": "DLNA", - "HeaderServerSettings": "Server Settings" + "HeaderServerSettings": "Server Settings", + "LabelWeatherDisplayLocation": "Weather display location:", + "LabelWeatherDisplayLocationHelp": "US zip code / City, State, Country / City, Country", + "LabelWeatherDisplayUnit": "Weather display unit:", + "OptionCelsius": "Celsius", + "OptionFahrenheit": "Fahrenheit", + "HeaderRequireManualLogin": "Require manual username entry for:", + "HeaderRequireManualLoginHelp": "When disabled clients may present a login screen with a visual selection of users.", + "OptionOtherApps": "Other apps", + "OptionMobileApps": "Mobile apps" } \ No newline at end of file