From b0379ec7f8fb4804f76d64264a4b35b65debedc6 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 13 Apr 2016 16:49:16 -0400 Subject: improve embedded image extraction --- MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs') diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 76ef054de..d2feb4116 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -51,6 +51,8 @@ namespace MediaBrowser.Controller.MediaEncoding /// Task{Stream}. Task ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken); + Task ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, int? imageStreamIndex, CancellationToken cancellationToken); + /// /// Extracts the video images on interval. /// -- cgit v1.2.3 From a15a762ba114683ffcc4c6aab5974d24f8f32c02 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 30 Apr 2016 15:16:43 -0400 Subject: fixes #1484 - (Feature request) Make emby choose output stream based on ffmpeg config --- MediaBrowser.Api/Playback/MediaInfoService.cs | 7 ++++-- .../MediaEncoding/IMediaEncoder.cs | 3 ++- .../ContentDirectory/ContentDirectory.cs | 8 +++++-- .../ContentDirectory/ControlHandler.cs | 7 ++++-- MediaBrowser.Dlna/Didl/DidlBuilder.cs | 9 +++++--- MediaBrowser.Dlna/Main/DlnaEntryPoint.cs | 8 +++++-- MediaBrowser.Dlna/PlayTo/PlayToController.cs | 11 +++++---- MediaBrowser.Dlna/PlayTo/PlayToManager.cs | 8 +++++-- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 26 ++++++++++++++++++++-- MediaBrowser.Model/Dlna/ILocalPlayer.cs | 13 +++++++++++ MediaBrowser.Model/Dlna/StreamBuilder.cs | 23 +++++++++++++++---- .../Sync/SyncJobProcessor.cs | 4 ++-- .../ApplicationHost.cs | 2 +- .../FFMpeg/FFmpegValidator.cs | 4 +++- 14 files changed, 105 insertions(+), 28 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs') diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs index ffe7c50c8..2d9cc40c0 100644 --- a/MediaBrowser.Api/Playback/MediaInfoService.cs +++ b/MediaBrowser.Api/Playback/MediaInfoService.cs @@ -15,6 +15,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Controller.MediaEncoding; namespace MediaBrowser.Api.Playback { @@ -66,14 +67,16 @@ namespace MediaBrowser.Api.Playback private readonly ILibraryManager _libraryManager; private readonly IServerConfigurationManager _config; private readonly INetworkManager _networkManager; + private readonly IMediaEncoder _mediaEncoder; - public MediaInfoService(IMediaSourceManager mediaSourceManager, IDeviceManager deviceManager, ILibraryManager libraryManager, IServerConfigurationManager config, INetworkManager networkManager) + public MediaInfoService(IMediaSourceManager mediaSourceManager, IDeviceManager deviceManager, ILibraryManager libraryManager, IServerConfigurationManager config, INetworkManager networkManager, IMediaEncoder mediaEncoder) { _mediaSourceManager = mediaSourceManager; _deviceManager = deviceManager; _libraryManager = libraryManager; _config = config; _networkManager = networkManager; + _mediaEncoder = mediaEncoder; } public object Get(GetBitrateTestBytes request) @@ -241,7 +244,7 @@ namespace MediaBrowser.Api.Playback int? subtitleStreamIndex, string playSessionId) { - var streamBuilder = new StreamBuilder(Logger); + var streamBuilder = new StreamBuilder(_mediaEncoder, Logger); var options = new VideoOptions { diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index d2feb4116..7c3959f6e 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -4,13 +4,14 @@ using System; using System.IO; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Dlna; namespace MediaBrowser.Controller.MediaEncoding { /// /// Interface IMediaEncoder /// - public interface IMediaEncoder + public interface IMediaEncoder : ITranscoderSupport { /// /// Gets the encoder path. diff --git a/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs b/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs index 21289970e..093b37df3 100644 --- a/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs +++ b/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs @@ -12,6 +12,7 @@ using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; using System.Linq; +using MediaBrowser.Controller.MediaEncoding; namespace MediaBrowser.Dlna.ContentDirectory { @@ -27,6 +28,7 @@ namespace MediaBrowser.Dlna.ContentDirectory private readonly IChannelManager _channelManager; private readonly IMediaSourceManager _mediaSourceManager; private readonly IUserViewManager _userViewManager; + private readonly Func _mediaEncoder; public ContentDirectory(IDlnaManager dlna, IUserDataManager userDataManager, @@ -35,7 +37,7 @@ namespace MediaBrowser.Dlna.ContentDirectory IServerConfigurationManager config, IUserManager userManager, ILogger logger, - IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager) + IHttpClient httpClient, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, Func mediaEncoder) : base(logger, httpClient) { _dlna = dlna; @@ -48,6 +50,7 @@ namespace MediaBrowser.Dlna.ContentDirectory _channelManager = channelManager; _mediaSourceManager = mediaSourceManager; _userViewManager = userViewManager; + _mediaEncoder = mediaEncoder; } private int SystemUpdateId @@ -89,7 +92,8 @@ namespace MediaBrowser.Dlna.ContentDirectory _localization, _channelManager, _mediaSourceManager, - _userViewManager) + _userViewManager, + _mediaEncoder()) .ProcessControlRequest(request); } diff --git a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs index 01c7c33b6..34fb2a6df 100644 --- a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs +++ b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs @@ -23,6 +23,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; +using MediaBrowser.Controller.MediaEncoding; namespace MediaBrowser.Dlna.ContentDirectory { @@ -34,6 +35,7 @@ namespace MediaBrowser.Dlna.ContentDirectory private readonly IServerConfigurationManager _config; private readonly User _user; private readonly IUserViewManager _userViewManager; + private readonly IMediaEncoder _mediaEncoder; private const string NS_DC = "http://purl.org/dc/elements/1.1/"; private const string NS_DIDL = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"; @@ -47,7 +49,7 @@ namespace MediaBrowser.Dlna.ContentDirectory private readonly DeviceProfile _profile; - public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager) + public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IChannelManager channelManager, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, IMediaEncoder mediaEncoder) : base(config, logger) { _libraryManager = libraryManager; @@ -56,10 +58,11 @@ namespace MediaBrowser.Dlna.ContentDirectory _systemUpdateId = systemUpdateId; _channelManager = channelManager; _userViewManager = userViewManager; + _mediaEncoder = mediaEncoder; _profile = profile; _config = config; - _didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, Logger, libraryManager); + _didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, Logger, libraryManager, _mediaEncoder); } protected override IEnumerable> GetResult(string methodName, Headers methodParams) diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs index 89d00eb32..af833a85c 100644 --- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs +++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs @@ -19,6 +19,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Xml; +using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Configuration; namespace MediaBrowser.Dlna.Didl @@ -42,8 +43,9 @@ namespace MediaBrowser.Dlna.Didl private readonly IMediaSourceManager _mediaSourceManager; private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; + private readonly IMediaEncoder _mediaEncoder; - public DidlBuilder(DeviceProfile profile, User user, IImageProcessor imageProcessor, string serverAddress, string accessToken, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, ILogger logger, ILibraryManager libraryManager) + public DidlBuilder(DeviceProfile profile, User user, IImageProcessor imageProcessor, string serverAddress, string accessToken, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, ILogger logger, ILibraryManager libraryManager, IMediaEncoder mediaEncoder) { _profile = profile; _imageProcessor = imageProcessor; @@ -53,6 +55,7 @@ namespace MediaBrowser.Dlna.Didl _mediaSourceManager = mediaSourceManager; _logger = logger; _libraryManager = libraryManager; + _mediaEncoder = mediaEncoder; _accessToken = accessToken; _user = user; } @@ -142,7 +145,7 @@ namespace MediaBrowser.Dlna.Didl { var sources = _mediaSourceManager.GetStaticMediaSources(video, true, _user).ToList(); - streamInfo = new StreamBuilder(GetStreamBuilderLogger(options)).BuildVideoItem(new VideoOptions + streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildVideoItem(new VideoOptions { ItemId = GetClientId(video), MediaSources = sources, @@ -385,7 +388,7 @@ namespace MediaBrowser.Dlna.Didl { var sources = _mediaSourceManager.GetStaticMediaSources(audio, true, _user).ToList(); - streamInfo = new StreamBuilder(GetStreamBuilderLogger(options)).BuildAudioItem(new AudioOptions + streamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger(options)).BuildAudioItem(new AudioOptions { ItemId = GetClientId(audio), MediaSources = sources, diff --git a/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs b/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs index 37584f006..733bda9ae 100644 --- a/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs +++ b/MediaBrowser.Dlna/Main/DlnaEntryPoint.cs @@ -14,6 +14,7 @@ using MediaBrowser.Dlna.Ssdp; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; +using MediaBrowser.Controller.MediaEncoding; namespace MediaBrowser.Dlna.Main { @@ -34,6 +35,7 @@ namespace MediaBrowser.Dlna.Main private readonly IUserDataManager _userDataManager; private readonly ILocalizationManager _localization; private readonly IMediaSourceManager _mediaSourceManager; + private readonly IMediaEncoder _mediaEncoder; private readonly SsdpHandler _ssdpHandler; private readonly IDeviceDiscovery _deviceDiscovery; @@ -54,7 +56,7 @@ namespace MediaBrowser.Dlna.Main IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, - ISsdpHandler ssdpHandler, IDeviceDiscovery deviceDiscovery) + ISsdpHandler ssdpHandler, IDeviceDiscovery deviceDiscovery, IMediaEncoder mediaEncoder) { _config = config; _appHost = appHost; @@ -69,6 +71,7 @@ namespace MediaBrowser.Dlna.Main _localization = localization; _mediaSourceManager = mediaSourceManager; _deviceDiscovery = deviceDiscovery; + _mediaEncoder = mediaEncoder; _ssdpHandler = (SsdpHandler)ssdpHandler; _logger = logManager.GetLogger("Dlna"); } @@ -196,7 +199,8 @@ namespace MediaBrowser.Dlna.Main _config, _userDataManager, _localization, - _mediaSourceManager); + _mediaSourceManager, + _mediaEncoder); _manager.Start(); } diff --git a/MediaBrowser.Dlna/PlayTo/PlayToController.cs b/MediaBrowser.Dlna/PlayTo/PlayToController.cs index db5e0ee29..80bb756ef 100644 --- a/MediaBrowser.Dlna/PlayTo/PlayToController.cs +++ b/MediaBrowser.Dlna/PlayTo/PlayToController.cs @@ -18,6 +18,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.MediaEncoding; namespace MediaBrowser.Dlna.PlayTo { @@ -35,6 +36,7 @@ namespace MediaBrowser.Dlna.PlayTo private readonly ILocalizationManager _localization; private readonly IMediaSourceManager _mediaSourceManager; private readonly IConfigurationManager _config; + private readonly IMediaEncoder _mediaEncoder; private readonly IDeviceDiscovery _deviceDiscovery; private readonly string _serverAddress; @@ -74,7 +76,7 @@ namespace MediaBrowser.Dlna.PlayTo get { return IsSessionActive; } } - public PlayToController(SessionInfo session, ISessionManager sessionManager, ILibraryManager libraryManager, ILogger logger, IDlnaManager dlnaManager, IUserManager userManager, IImageProcessor imageProcessor, string serverAddress, string accessToken, IDeviceDiscovery deviceDiscovery, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IConfigurationManager config) + public PlayToController(SessionInfo session, ISessionManager sessionManager, ILibraryManager libraryManager, ILogger logger, IDlnaManager dlnaManager, IUserManager userManager, IImageProcessor imageProcessor, string serverAddress, string accessToken, IDeviceDiscovery deviceDiscovery, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IConfigurationManager config, IMediaEncoder mediaEncoder) { _session = session; _sessionManager = sessionManager; @@ -88,6 +90,7 @@ namespace MediaBrowser.Dlna.PlayTo _localization = localization; _mediaSourceManager = mediaSourceManager; _config = config; + _mediaEncoder = mediaEncoder; _accessToken = accessToken; _logger = logger; _creationTime = DateTime.UtcNow; @@ -478,7 +481,7 @@ namespace MediaBrowser.Dlna.PlayTo playlistItem.StreamUrl = playlistItem.StreamInfo.ToDlnaUrl(_serverAddress, _accessToken); - var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager, _logger, _libraryManager) + var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager, _logger, _libraryManager, _mediaEncoder) .GetItemDidl(_config.GetDlnaConfiguration(), item, null, _session.DeviceId, new Filter(), playlistItem.StreamInfo); playlistItem.Didl = itemXml; @@ -550,7 +553,7 @@ namespace MediaBrowser.Dlna.PlayTo { return new PlaylistItem { - StreamInfo = new StreamBuilder(GetStreamBuilderLogger()).BuildVideoItem(new VideoOptions + StreamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger()).BuildVideoItem(new VideoOptions { ItemId = item.Id.ToString("N"), MediaSources = mediaSources, @@ -570,7 +573,7 @@ namespace MediaBrowser.Dlna.PlayTo { return new PlaylistItem { - StreamInfo = new StreamBuilder(GetStreamBuilderLogger()).BuildAudioItem(new AudioOptions + StreamInfo = new StreamBuilder(_mediaEncoder, GetStreamBuilderLogger()).BuildAudioItem(new AudioOptions { ItemId = item.Id.ToString("N"), MediaSources = mediaSources, diff --git a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs index 18daef331..bbb9bf6de 100644 --- a/MediaBrowser.Dlna/PlayTo/PlayToManager.cs +++ b/MediaBrowser.Dlna/PlayTo/PlayToManager.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Net; +using MediaBrowser.Controller.MediaEncoding; namespace MediaBrowser.Dlna.PlayTo { @@ -32,11 +33,12 @@ namespace MediaBrowser.Dlna.PlayTo private readonly IDeviceDiscovery _deviceDiscovery; private readonly IMediaSourceManager _mediaSourceManager; + private readonly IMediaEncoder _mediaEncoder; private readonly List _nonRendererUrls = new List(); private DateTime _lastRendererClear; - public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager) + public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder) { _logger = logger; _sessionManager = sessionManager; @@ -51,6 +53,7 @@ namespace MediaBrowser.Dlna.PlayTo _userDataManager = userDataManager; _localization = localization; _mediaSourceManager = mediaSourceManager; + _mediaEncoder = mediaEncoder; } public void Start() @@ -132,7 +135,8 @@ namespace MediaBrowser.Dlna.PlayTo _userDataManager, _localization, _mediaSourceManager, - _config); + _config, + _mediaEncoder); controller.Init(device); diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 01fb31d0c..399fdead9 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -96,15 +96,23 @@ namespace MediaBrowser.MediaEncoding.Encoder FFMpegPath = ffMpegPath; } + private List _encoders = new List(); public void SetAvailableEncoders(List list) { - + _encoders = list.ToList(); + //_logger.Info("Supported encoders: {0}", string.Join(",", list.ToArray())); } private List _decoders = new List(); public void SetAvailableDecoders(List list) { _decoders = list.ToList(); + //_logger.Info("Supported decoders: {0}", string.Join(",", list.ToArray())); + } + + public bool SupportsEncoder(string decoder) + { + return _encoders.Contains(decoder, StringComparer.OrdinalIgnoreCase); } public bool SupportsDecoder(string decoder) @@ -112,6 +120,20 @@ namespace MediaBrowser.MediaEncoding.Encoder return _decoders.Contains(decoder, StringComparer.OrdinalIgnoreCase); } + public bool CanEncodeToAudioCodec(string codec) + { + if (string.Equals(codec, "opus", StringComparison.OrdinalIgnoreCase)) + { + codec = "libopus"; + } + else if (string.Equals(codec, "mp3", StringComparison.OrdinalIgnoreCase)) + { + codec = "libmp3lame"; + } + + return SupportsEncoder(codec); + } + /// /// Gets the encoder path. /// @@ -296,7 +318,7 @@ namespace MediaBrowser.MediaEncoding.Encoder 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) { diff --git a/MediaBrowser.Model/Dlna/ILocalPlayer.cs b/MediaBrowser.Model/Dlna/ILocalPlayer.cs index 55e11ec4b..9de360023 100644 --- a/MediaBrowser.Model/Dlna/ILocalPlayer.cs +++ b/MediaBrowser.Model/Dlna/ILocalPlayer.cs @@ -23,4 +23,17 @@ namespace MediaBrowser.Model.Dlna /// true if this instance [can access URL] the specified URL; otherwise, false. bool CanAccessUrl(string url, bool requiresCustomRequestHeaders); } + + public interface ITranscoderSupport + { + bool CanEncodeToAudioCodec(string codec); + } + + public class FullTranscoderSupport : ITranscoderSupport + { + public bool CanEncodeToAudioCodec(string codec) + { + return true; + } + } } diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 98d246980..07a4b8995 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -13,15 +13,27 @@ namespace MediaBrowser.Model.Dlna { private readonly ILocalPlayer _localPlayer; private readonly ILogger _logger; + private readonly ITranscoderSupport _transcoderSupport; - public StreamBuilder(ILocalPlayer localPlayer, ILogger logger) + public StreamBuilder(ILocalPlayer localPlayer, ITranscoderSupport transcoderSupport, ILogger logger) { + _transcoderSupport = transcoderSupport; _localPlayer = localPlayer; _logger = logger; } + public StreamBuilder(ITranscoderSupport transcoderSupport, ILogger logger) + : this(new NullLocalPlayer(), transcoderSupport, logger) + { + } + + public StreamBuilder(ILocalPlayer localPlayer, ILogger logger) + : this(localPlayer, new FullTranscoderSupport(), logger) + { + } + public StreamBuilder(ILogger logger) - : this(new NullLocalPlayer(), logger) + : this(new NullLocalPlayer(), new FullTranscoderSupport(), logger) { } @@ -185,8 +197,11 @@ namespace MediaBrowser.Model.Dlna { if (i.Type == playlistItem.MediaType && i.Context == options.Context) { - transcodingProfile = i; - break; + if (_transcoderSupport.CanEncodeToAudioCodec(i.AudioCodec ?? i.Container)) + { + transcodingProfile = i; + break; + } } } diff --git a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs index 10b872753..d95a4fefb 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs @@ -582,7 +582,7 @@ namespace MediaBrowser.Server.Implementations.Sync conversionOptions.ItemId = item.Id.ToString("N"); conversionOptions.MediaSources = _mediaSourceManager.GetStaticMediaSources(item, false, user).ToList(); - var streamInfo = new StreamBuilder(_logger).BuildVideoItem(conversionOptions); + var streamInfo = new StreamBuilder(_mediaEncoder, _logger).BuildVideoItem(conversionOptions); var mediaSource = streamInfo.MediaSource; // No sense creating external subs if we're already burning one into the video @@ -786,7 +786,7 @@ namespace MediaBrowser.Server.Implementations.Sync conversionOptions.ItemId = item.Id.ToString("N"); conversionOptions.MediaSources = _mediaSourceManager.GetStaticMediaSources(item, false, user).ToList(); - var streamInfo = new StreamBuilder(_logger).BuildAudioItem(conversionOptions); + var streamInfo = new StreamBuilder(_mediaEncoder, _logger).BuildAudioItem(conversionOptions); var mediaSource = streamInfo.MediaSource; jobItem.MediaSourceId = streamInfo.MediaSourceId; diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 01575e71f..fd6dee0f6 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -515,7 +515,7 @@ namespace MediaBrowser.Server.Startup.Common UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager); RegisterSingleInstance(UserViewManager); - var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager, MediaSourceManager, UserViewManager); + var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager, MediaSourceManager, UserViewManager, () => MediaEncoder); RegisterSingleInstance(contentDirectory); var mediaRegistrar = new MediaReceiverRegistrar(LogManager.GetLogger("MediaReceiverRegistrar"), HttpClient, ServerConfigurationManager); diff --git a/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs b/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs index 5ba5fb44a..0ae021407 100644 --- a/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs +++ b/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs @@ -42,6 +42,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg catch { } + //_logger.Debug("ffmpeg decoder query result: {0}", output ?? string.Empty); var found = new List(); var required = new[] @@ -78,6 +79,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg catch { } + //_logger.Debug("ffmpeg encoder query result: {0}", output ?? string.Empty); var found = new List(); var required = new[] @@ -89,8 +91,8 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg //"libvpx", //"libvpx-vp9", "aac", - "ac3", "libmp3lame", + "libopus", //"libvorbis", "srt" }; -- cgit v1.2.3 From 6e9f8fb2d1a878369ee36b2e9ebfe7a54954183f Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 20 Jun 2016 02:19:28 -0400 Subject: allow customization of ffmpeg path --- .../MediaEncoding/IMediaEncoder.cs | 2 + MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 71 ++++++++++++++++++++++ .../Configuration/EncodingOptions.cs | 1 + MediaBrowser.Model/System/SystemInfo.cs | 2 + .../ApplicationHost.cs | 30 ++++++--- .../FFMpeg/FFmpegValidator.cs | 9 +-- 6 files changed, 100 insertions(+), 15 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs') diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 7c3959f6e..023af7d1a 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -134,5 +134,7 @@ namespace MediaBrowser.Controller.MediaEncoding /// The path. /// System.String. string EscapeSubtitleFilterPath(string path); + + void Init(); } } diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 399fdead9..dafc63cfb 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -21,6 +21,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Model.Configuration; +using MediaBrowser.Common.Configuration; namespace MediaBrowser.MediaEncoding.Encoder { @@ -77,6 +79,7 @@ namespace MediaBrowser.MediaEncoding.Encoder protected readonly Func MediaSourceManager; private readonly List _runningProcesses = new List(); + private readonly bool _hasExternalEncoder; public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, string version, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func subtitleEncoder, Func mediaSourceManager) { @@ -94,6 +97,74 @@ namespace MediaBrowser.MediaEncoding.Encoder MediaSourceManager = mediaSourceManager; FFProbePath = ffProbePath; FFMpegPath = ffMpegPath; + + _hasExternalEncoder = !string.IsNullOrWhiteSpace(ffMpegPath); + } + + public void Init() + { + ConfigureEncoderPaths(); + } + + private void ConfigureEncoderPaths() + { + if (_hasExternalEncoder) + { + LogPaths(); + return; + } + + var appPath = GetEncodingOptions().EncoderAppPath; + appPath = "C:\\dev\\Emby.dev\\ProgramData-Server\\ffmpeg"; + + if (Directory.Exists(appPath)) + { + SetPathsFromDirectory(appPath); + } + + else if (File.Exists(appPath)) + { + FFMpegPath = appPath; + + SetProbePathFromEncoderPath(appPath); + } + + LogPaths(); + } + + private void SetPathsFromDirectory(string path) + { + // Since we can't predict the file extension, first try directly within the folder + // If that doesn't pan out, then do a recursive search + var files = Directory.GetFiles(path); + + FFMpegPath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffmpeg", StringComparison.OrdinalIgnoreCase)); + FFProbePath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffprobe", StringComparison.OrdinalIgnoreCase)); + + if (string.IsNullOrWhiteSpace(FFMpegPath) || !File.Exists(FFMpegPath)) + { + files = Directory.GetFiles(path, "*", SearchOption.AllDirectories); + + FFMpegPath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffmpeg", StringComparison.OrdinalIgnoreCase)); + SetProbePathFromEncoderPath(FFMpegPath); + } + } + + private void SetProbePathFromEncoderPath(string appPath) + { + FFProbePath = Directory.GetFiles(Path.GetDirectoryName(appPath)) + .FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffprobe", StringComparison.OrdinalIgnoreCase)); + } + + private void LogPaths() + { + _logger.Info("FFMpeg: {0}", FFMpegPath ?? "not found"); + _logger.Info("FFProbe: {0}", FFProbePath ?? "not found"); + } + + private EncodingOptions GetEncodingOptions() + { + return ConfigurationManager.GetConfiguration("encoding"); } private List _encoders = new List(); diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs index d33cf5577..91d28a296 100644 --- a/MediaBrowser.Model/Configuration/EncodingOptions.cs +++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs @@ -9,6 +9,7 @@ namespace MediaBrowser.Model.Configuration public bool EnableThrottling { get; set; } public int ThrottleDelaySeconds { get; set; } public string HardwareAccelerationType { get; set; } + public string EncoderAppPath { get; set; } public EncodingOptions() { diff --git a/MediaBrowser.Model/System/SystemInfo.cs b/MediaBrowser.Model/System/SystemInfo.cs index 6b54a90d4..73d5961f6 100644 --- a/MediaBrowser.Model/System/SystemInfo.cs +++ b/MediaBrowser.Model/System/SystemInfo.cs @@ -152,6 +152,8 @@ namespace MediaBrowser.Model.System /// true if [supports automatic run at startup]; otherwise, false. public bool SupportsAutoRunAtStartup { get; set; } + public bool HasExternalEncoder { get; set; } + /// /// Initializes a new instance of the class. /// diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 7341f56cb..c6a180db1 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -323,6 +323,8 @@ namespace MediaBrowser.Server.Startup.Common await base.RunStartupTasks().ConfigureAwait(false); + InitMediaEncoder(); + Logger.Info("ServerId: {0}", SystemId); Logger.Info("Core startup complete"); HttpServer.GlobalResponse = null; @@ -344,6 +346,20 @@ namespace MediaBrowser.Server.Startup.Common LogManager.RemoveConsoleOutput(); } + private void InitMediaEncoder() + { + MediaEncoder.Init(); + + Task.Run(() => + { + var result = new FFmpegValidator(Logger, ApplicationPaths, FileSystemManager).Validate(MediaEncoder.EncoderPath); + + var mediaEncoder = (MediaEncoder) MediaEncoder; + mediaEncoder.SetAvailableDecoders(result.Item1); + mediaEncoder.SetAvailableEncoders(result.Item2); + }); + } + public override Task Init(IProgress progress) { HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber; @@ -634,6 +650,8 @@ namespace MediaBrowser.Server.Startup.Common var info = await new FFMpegLoader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager, NativeApp.Environment, NativeApp.GetType().Assembly, NativeApp.GetFfmpegInstallInfo()) .GetFFMpegInfo(NativeApp.Environment, _startupOptions, progress).ConfigureAwait(false); + _hasExternalEncoder = !string.IsNullOrWhiteSpace(info.EncoderPath); + var mediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"), JsonSerializer, info.EncoderPath, @@ -651,14 +669,6 @@ namespace MediaBrowser.Server.Startup.Common MediaEncoder = mediaEncoder; RegisterSingleInstance(MediaEncoder); - - Task.Run(() => - { - var result = new FFmpegValidator(Logger, ApplicationPaths, FileSystemManager).Validate(info); - - mediaEncoder.SetAvailableDecoders(result.Item1); - mediaEncoder.SetAvailableEncoders(result.Item2); - }); } /// @@ -1094,6 +1104,7 @@ namespace MediaBrowser.Server.Startup.Common } } + private bool _hasExternalEncoder; /// /// Gets the system status. /// @@ -1133,7 +1144,8 @@ namespace MediaBrowser.Server.Startup.Common SupportsRunningAsService = SupportsRunningAsService, ServerName = FriendlyName, LocalAddress = localAddress, - SupportsLibraryMonitor = SupportsLibraryMonitor + SupportsLibraryMonitor = SupportsLibraryMonitor, + HasExternalEncoder = _hasExternalEncoder }; } diff --git a/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs b/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs index 0ae021407..d92dc1b96 100644 --- a/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs +++ b/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs @@ -21,13 +21,10 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg _fileSystem = fileSystem; } - public Tuple,List> Validate(FFMpegInfo info) + public Tuple,List> Validate(string encoderPath) { - _logger.Info("FFMpeg: {0}", info.EncoderPath); - _logger.Info("FFProbe: {0}", info.ProbePath); - - var decoders = GetDecoders(info.EncoderPath); - var encoders = GetEncoders(info.EncoderPath); + var decoders = GetDecoders(encoderPath); + var encoders = GetEncoders(encoderPath); return new Tuple, List>(decoders, encoders); } -- cgit v1.2.3 From fb07b4640c60d5135097d25d71cad4d2e4b6131f Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 20 Jun 2016 02:45:35 -0400 Subject: update ffmpeg path customization --- .../MediaEncoding/IMediaEncoder.cs | 6 ---- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 40 +++++++++++++++------- .../ApplicationHost.cs | 4 +-- 3 files changed, 29 insertions(+), 21 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs') diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 023af7d1a..c00f76f22 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -19,12 +19,6 @@ namespace MediaBrowser.Controller.MediaEncoding /// The encoder path. string EncoderPath { get; } - /// - /// Gets the version. - /// - /// The version. - string Version { get; } - /// /// Supportses the decoder. /// diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 61986e3bc..fc627c232 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -66,8 +66,6 @@ namespace MediaBrowser.MediaEncoding.Encoder public string FFProbePath { get; private set; } - public string Version { get; private set; } - protected readonly IServerConfigurationManager ConfigurationManager; protected readonly IFileSystem FileSystem; protected readonly ILiveTvManager LiveTvManager; @@ -81,11 +79,10 @@ namespace MediaBrowser.MediaEncoding.Encoder private readonly List _runningProcesses = new List(); private readonly bool _hasExternalEncoder; - public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, string version, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func subtitleEncoder, Func mediaSourceManager) + public MediaEncoder(ILogger logger, IJsonSerializer jsonSerializer, string ffMpegPath, string ffProbePath, bool hasExternalEncoder, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILiveTvManager liveTvManager, IIsoManager isoManager, ILibraryManager libraryManager, IChannelManager channelManager, ISessionManager sessionManager, Func subtitleEncoder, Func mediaSourceManager) { _logger = logger; _jsonSerializer = jsonSerializer; - Version = version; ConfigurationManager = configurationManager; FileSystem = fileSystem; LiveTvManager = liveTvManager; @@ -98,34 +95,51 @@ namespace MediaBrowser.MediaEncoding.Encoder FFProbePath = ffProbePath; FFMpegPath = ffMpegPath; - _hasExternalEncoder = !string.IsNullOrWhiteSpace(ffMpegPath); + _hasExternalEncoder = hasExternalEncoder; } public void Init() { ConfigureEncoderPaths(); + + if (_hasExternalEncoder) + { + LogPaths(); + return; + } + + // If the path was passed in, save it into config now. + var encodingOptions = GetEncodingOptions(); + var appPath = encodingOptions.EncoderAppPath; + if (!string.IsNullOrWhiteSpace(FFMpegPath) && !string.Equals(FFMpegPath, appPath, StringComparison.Ordinal)) + { + encodingOptions.EncoderAppPath = FFMpegPath; + ConfigurationManager.SaveConfiguration("encoding", encodingOptions); + } } private void ConfigureEncoderPaths() { if (_hasExternalEncoder) { - LogPaths(); return; } var appPath = GetEncodingOptions().EncoderAppPath; - if (Directory.Exists(appPath)) + if (!string.IsNullOrWhiteSpace(appPath)) { - SetPathsFromDirectory(appPath); - } + if (Directory.Exists(appPath)) + { + SetPathsFromDirectory(appPath); + } - else if (File.Exists(appPath)) - { - FFMpegPath = appPath; + else if (File.Exists(appPath)) + { + FFMpegPath = appPath; - SetProbePathFromEncoderPath(appPath); + SetProbePathFromEncoderPath(appPath); + } } LogPaths(); diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index c6a180db1..1130d3a11 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -650,13 +650,13 @@ namespace MediaBrowser.Server.Startup.Common var info = await new FFMpegLoader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager, NativeApp.Environment, NativeApp.GetType().Assembly, NativeApp.GetFfmpegInstallInfo()) .GetFFMpegInfo(NativeApp.Environment, _startupOptions, progress).ConfigureAwait(false); - _hasExternalEncoder = !string.IsNullOrWhiteSpace(info.EncoderPath); + _hasExternalEncoder = string.Equals(info.Version, "custom", StringComparison.OrdinalIgnoreCase); var mediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"), JsonSerializer, info.EncoderPath, info.ProbePath, - info.Version, + _hasExternalEncoder, ServerConfigurationManager, FileSystemManager, LiveTvManager, -- cgit v1.2.3 From cffc9417c7a25263a194615096685bd8ef1e37b2 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 23 Jun 2016 13:04:18 -0400 Subject: update startup wizard --- MediaBrowser.Api/ConfigurationService.cs | 20 +++++- MediaBrowser.Api/ItemLookupService.cs | 13 ++++ MediaBrowser.Api/StartupWizardService.cs | 9 ++- MediaBrowser.Api/System/SystemService.cs | 6 +- MediaBrowser.Api/UserLibrary/ItemsService.cs | 16 +++-- .../MediaEncoding/IMediaEncoder.cs | 2 + MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 72 +++++++++++++++++----- .../MediaBrowser.Model.Portable.csproj | 3 + .../MediaBrowser.Model.net35.csproj | 3 + MediaBrowser.Model/MediaBrowser.Model.csproj | 1 + MediaBrowser.Model/System/Architecture.cs | 9 +++ MediaBrowser.Model/System/SystemInfo.cs | 2 + MediaBrowser.Providers/Movies/MovieDbSearch.cs | 24 ++++++-- .../Persistence/SqliteItemRepository.cs | 3 +- MediaBrowser.Server.Mono/Native/BaseMonoApp.cs | 9 +-- .../ApplicationHost.cs | 14 +++-- .../FFMpeg/FFMpegLoader.cs | 18 ++---- .../NativeEnvironment.cs | 10 +-- .../Native/WindowsApp.cs | 27 +------- .../MediaBrowser.WebDashboard.csproj | 9 +++ 20 files changed, 186 insertions(+), 84 deletions(-) create mode 100644 MediaBrowser.Model/System/Architecture.cs (limited to 'MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs') diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs index 446415fbb..9c8120de7 100644 --- a/MediaBrowser.Api/ConfigurationService.cs +++ b/MediaBrowser.Api/ConfigurationService.cs @@ -9,7 +9,9 @@ using ServiceStack.Web; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading.Tasks; using CommonIO; +using MediaBrowser.Controller.MediaEncoding; namespace MediaBrowser.Api { @@ -71,6 +73,14 @@ namespace MediaBrowser.Api } + [Route("/System/MediaEncoder/Path", "POST", Summary = "Updates the path to the media encoder")] + [Authenticated(Roles = "Admin", AllowBeforeStartupWizard = true)] + public class UpdateMediaEncoderPath : IReturnVoid + { + [ApiMember(Name = "Path", Description = "Path", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Path { get; set; } + } + public class ConfigurationService : BaseApiService { /// @@ -86,14 +96,22 @@ namespace MediaBrowser.Api private readonly IFileSystem _fileSystem; private readonly IProviderManager _providerManager; private readonly ILibraryManager _libraryManager; + private readonly IMediaEncoder _mediaEncoder; - public ConfigurationService(IJsonSerializer jsonSerializer, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IProviderManager providerManager, ILibraryManager libraryManager) + public ConfigurationService(IJsonSerializer jsonSerializer, IServerConfigurationManager configurationManager, IFileSystem fileSystem, IProviderManager providerManager, ILibraryManager libraryManager, IMediaEncoder mediaEncoder) { _jsonSerializer = jsonSerializer; _configurationManager = configurationManager; _fileSystem = fileSystem; _providerManager = providerManager; _libraryManager = libraryManager; + _mediaEncoder = mediaEncoder; + } + + public void Post(UpdateMediaEncoderPath request) + { + var task = _mediaEncoder.UpdateEncoderPath(request.Path); + Task.WaitAll(task); } /// diff --git a/MediaBrowser.Api/ItemLookupService.cs b/MediaBrowser.Api/ItemLookupService.cs index ad0ca68af..357ff4394 100644 --- a/MediaBrowser.Api/ItemLookupService.cs +++ b/MediaBrowser.Api/ItemLookupService.cs @@ -38,6 +38,12 @@ namespace MediaBrowser.Api { } + [Route("/Items/RemoteSearch/Trailer", "POST")] + [Authenticated] + public class GetTrailerRemoteSearchResults : RemoteSearchQuery, IReturn> + { + } + [Route("/Items/RemoteSearch/AdultVideo", "POST")] [Authenticated] public class GetAdultVideoRemoteSearchResults : RemoteSearchQuery, IReturn> @@ -132,6 +138,13 @@ namespace MediaBrowser.Api return ToOptimizedResult(infos); } + public async Task Post(GetTrailerRemoteSearchResults request) + { + var result = await _providerManager.GetRemoteSearchResults(request, CancellationToken.None).ConfigureAwait(false); + + return ToOptimizedResult(result); + } + public async Task Post(GetMovieRemoteSearchResults request) { var result = await _providerManager.GetRemoteSearchResults(request, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs index 93c9f8b9f..6c58228ea 100644 --- a/MediaBrowser.Api/StartupWizardService.cs +++ b/MediaBrowser.Api/StartupWizardService.cs @@ -11,6 +11,7 @@ using ServiceStack; using System; using System.Linq; using System.Threading.Tasks; +using MediaBrowser.Controller.MediaEncoding; namespace MediaBrowser.Api { @@ -52,14 +53,16 @@ namespace MediaBrowser.Api private readonly IUserManager _userManager; private readonly IConnectManager _connectManager; private readonly ILiveTvManager _liveTvManager; + private readonly IMediaEncoder _mediaEncoder; - public StartupWizardService(IServerConfigurationManager config, IServerApplicationHost appHost, IUserManager userManager, IConnectManager connectManager, ILiveTvManager liveTvManager) + public StartupWizardService(IServerConfigurationManager config, IServerApplicationHost appHost, IUserManager userManager, IConnectManager connectManager, ILiveTvManager liveTvManager, IMediaEncoder mediaEncoder) { _config = config; _appHost = appHost; _userManager = userManager; _connectManager = connectManager; _liveTvManager = liveTvManager; + _mediaEncoder = mediaEncoder; } public void Post(ReportStartupWizardComplete request) @@ -75,7 +78,8 @@ namespace MediaBrowser.Api return new StartupInfo { - SupportsRunningAsService = info.SupportsRunningAsService + SupportsRunningAsService = info.SupportsRunningAsService, + HasMediaEncoder = !string.IsNullOrWhiteSpace(_mediaEncoder.EncoderPath) }; } @@ -231,6 +235,7 @@ namespace MediaBrowser.Api public class StartupInfo { public bool SupportsRunningAsService { get; set; } + public bool HasMediaEncoder { get; set; } } public class StartupUser diff --git a/MediaBrowser.Api/System/SystemService.cs b/MediaBrowser.Api/System/SystemService.cs index 346f6b32a..c2318dccb 100644 --- a/MediaBrowser.Api/System/SystemService.cs +++ b/MediaBrowser.Api/System/SystemService.cs @@ -19,7 +19,7 @@ namespace MediaBrowser.Api.System /// Class GetSystemInfo /// [Route("/System/Info", "GET", Summary = "Gets information about the server")] - [Authenticated(EscapeParentalControl = true)] + [Authenticated(EscapeParentalControl = true, AllowBeforeStartupWizard = true)] public class GetSystemInfo : IReturn { @@ -120,7 +120,7 @@ namespace MediaBrowser.Api.System try { - files = _fileSystem.GetFiles(_appPaths.LogDirectoryPath) + files = _fileSystem.GetFiles(_appPaths.LogDirectoryPath) .Where(i => string.Equals(i.Extension, ".txt", StringComparison.OrdinalIgnoreCase)) .ToList(); } @@ -146,7 +146,7 @@ namespace MediaBrowser.Api.System public Task Get(GetLogFile request) { - var file = _fileSystem.GetFiles(_appPaths.LogDirectoryPath) + var file = _fileSystem.GetFiles(_appPaths.LogDirectoryPath) .First(i => string.Equals(i.Name, request.Name, StringComparison.OrdinalIgnoreCase)); return ResultFactory.GetStaticFileResult(Request, file.FullName, FileShare.ReadWrite); diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index f89cd0ef6..51ca2d5ca 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -119,11 +119,17 @@ namespace MediaBrowser.Api.UserLibrary // Default list type = children + var folder = item as Folder; + if (folder == null) + { + folder = user == null ? _libraryManager.RootFolder : _libraryManager.GetUserRootFolder(); + } + if (!string.IsNullOrEmpty(request.Ids)) { request.Recursive = true; var query = GetItemsQuery(request, user); - var result = await ((Folder)item).GetItems(query).ConfigureAwait(false); + var result = await folder.GetItems(query).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(request.SortBy)) { @@ -138,22 +144,22 @@ namespace MediaBrowser.Api.UserLibrary if (request.Recursive) { - return await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false); + return await folder.GetItems(GetItemsQuery(request, user)).ConfigureAwait(false); } if (user == null) { - return await ((Folder)item).GetItems(GetItemsQuery(request, null)).ConfigureAwait(false); + return await folder.GetItems(GetItemsQuery(request, null)).ConfigureAwait(false); } var userRoot = item as UserRootFolder; if (userRoot == null) { - return await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false); + return await folder.GetItems(GetItemsQuery(request, user)).ConfigureAwait(false); } - IEnumerable items = ((Folder)item).GetChildren(user, true); + IEnumerable items = folder.GetChildren(user, true); var itemsArray = items.ToArray(); diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index c00f76f22..77ba1685f 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -130,5 +130,7 @@ namespace MediaBrowser.Controller.MediaEncoding string EscapeSubtitleFilterPath(string path); void Init(); + + Task UpdateEncoderPath(string path); } } diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 39a233856..f8321f6cd 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -23,6 +23,7 @@ using System.Threading.Tasks; using CommonIO; using MediaBrowser.Model.Configuration; using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; namespace MediaBrowser.MediaEncoding.Encoder { @@ -118,6 +119,35 @@ namespace MediaBrowser.MediaEncoding.Encoder } } + public async Task UpdateEncoderPath(string path) + { + if (string.IsNullOrWhiteSpace(path)) + { + throw new ArgumentNullException("path"); + } + + if (!File.Exists(path) && !Directory.Exists(path)) + { + throw new ResourceNotFoundException(); + } + + var newPaths = GetEncoderPaths(path); + if (string.IsNullOrWhiteSpace(newPaths.Item1)) + { + throw new ResourceNotFoundException("ffmpeg not found"); + } + if (string.IsNullOrWhiteSpace(newPaths.Item2)) + { + throw new ResourceNotFoundException("ffprobe not found"); + } + + var config = GetEncodingOptions(); + config.EncoderAppPath = path; + ConfigurationManager.SaveConfiguration("encoding", config); + + Init(); + } + private void ConfigureEncoderPaths() { if (_hasExternalEncoder) @@ -131,46 +161,60 @@ namespace MediaBrowser.MediaEncoding.Encoder { appPath = Path.Combine(ConfigurationManager.ApplicationPaths.ProgramDataPath, "ffmpeg"); } + var newPaths = GetEncoderPaths(appPath); + + if (!string.IsNullOrWhiteSpace(newPaths.Item1) && !string.IsNullOrWhiteSpace(newPaths.Item2)) + { + FFMpegPath = newPaths.Item1; + FFProbePath = newPaths.Item2; + } + + LogPaths(); + } + + private Tuple GetEncoderPaths(string configuredPath) + { + var appPath = configuredPath; if (!string.IsNullOrWhiteSpace(appPath)) { if (Directory.Exists(appPath)) { - SetPathsFromDirectory(appPath); + return GetPathsFromDirectory(appPath); } - else if (File.Exists(appPath)) + if (File.Exists(appPath)) { - FFMpegPath = appPath; - - SetProbePathFromEncoderPath(appPath); + return new Tuple(appPath, GetProbePathFromEncoderPath(appPath)); } } - LogPaths(); + return new Tuple(null, null); } - private void SetPathsFromDirectory(string path) + private Tuple GetPathsFromDirectory(string path) { // Since we can't predict the file extension, first try directly within the folder // If that doesn't pan out, then do a recursive search var files = Directory.GetFiles(path); - FFMpegPath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffmpeg", StringComparison.OrdinalIgnoreCase)); - FFProbePath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffprobe", StringComparison.OrdinalIgnoreCase)); + var ffmpegPath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffmpeg", StringComparison.OrdinalIgnoreCase)); + var ffprobePath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffprobe", StringComparison.OrdinalIgnoreCase)); - if (string.IsNullOrWhiteSpace(FFMpegPath) || !File.Exists(FFMpegPath)) + if (string.IsNullOrWhiteSpace(ffmpegPath) || !File.Exists(ffmpegPath)) { files = Directory.GetFiles(path, "*", SearchOption.AllDirectories); - FFMpegPath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffmpeg", StringComparison.OrdinalIgnoreCase)); - SetProbePathFromEncoderPath(FFMpegPath); + ffmpegPath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffmpeg", StringComparison.OrdinalIgnoreCase)); + ffprobePath = GetProbePathFromEncoderPath(ffmpegPath); } + + return new Tuple(ffmpegPath, ffprobePath); } - private void SetProbePathFromEncoderPath(string appPath) + private string GetProbePathFromEncoderPath(string appPath) { - FFProbePath = Directory.GetFiles(Path.GetDirectoryName(appPath)) + return Directory.GetFiles(Path.GetDirectoryName(appPath)) .FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffprobe", StringComparison.OrdinalIgnoreCase)); } diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index f9d28605e..0de9fb519 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -1136,6 +1136,9 @@ Sync\SyncTarget.cs + + System\Architecture.cs + System\LogFile.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index edaa0e027..fe0b3bcae 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -1101,6 +1101,9 @@ Sync\SyncTarget.cs + + System\Architecture.cs + System\LogFile.cs diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 7c9f132db..e54273b84 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -395,6 +395,7 @@ + diff --git a/MediaBrowser.Model/System/Architecture.cs b/MediaBrowser.Model/System/Architecture.cs new file mode 100644 index 000000000..09eedddc1 --- /dev/null +++ b/MediaBrowser.Model/System/Architecture.cs @@ -0,0 +1,9 @@ +namespace MediaBrowser.Model.System +{ + public enum Architecture + { + X86 = 0, + X64 = 1, + Arm = 2 + } +} diff --git a/MediaBrowser.Model/System/SystemInfo.cs b/MediaBrowser.Model/System/SystemInfo.cs index 73d5961f6..868d9dc28 100644 --- a/MediaBrowser.Model/System/SystemInfo.cs +++ b/MediaBrowser.Model/System/SystemInfo.cs @@ -154,6 +154,8 @@ namespace MediaBrowser.Model.System public bool HasExternalEncoder { get; set; } + public Architecture SystemArchitecture { get; set; } + /// /// Initializes a new instance of the class. /// diff --git a/MediaBrowser.Providers/Movies/MovieDbSearch.cs b/MediaBrowser.Providers/Movies/MovieDbSearch.cs index ceb41178e..ab2cd3bed 100644 --- a/MediaBrowser.Providers/Movies/MovieDbSearch.cs +++ b/MediaBrowser.Providers/Movies/MovieDbSearch.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Movies internal static string ApiKey = "f6bd687ffa63cd282b6ff2c6877f2669"; internal static string AcceptHeader = "application/json,image/*"; - + private readonly ILogger _logger; private readonly IJsonSerializer _json; private readonly ILibraryManager _libraryManager; @@ -54,6 +54,11 @@ namespace MediaBrowser.Providers.Movies var name = idInfo.Name; var year = idInfo.Year; + if (string.IsNullOrWhiteSpace(name)) + { + return new List(); + } + var tmdbSettings = await MovieDbProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false); var tmdbImageUrl = tmdbSettings.images.secure_base_url + "original"; @@ -73,7 +78,7 @@ namespace MediaBrowser.Providers.Movies //var searchType = item is BoxSet ? "collection" : "movie"; var results = await GetSearchResults(name, searchType, year, language, tmdbImageUrl, cancellationToken).ConfigureAwait(false); - + if (results.Count == 0) { //try in english if wasn't before @@ -123,19 +128,23 @@ namespace MediaBrowser.Providers.Movies }); } - private async Task> GetSearchResults(string name, string type, int? year, string language, string baseImageUrl, CancellationToken cancellationToken) + private Task> GetSearchResults(string name, string type, int? year, string language, string baseImageUrl, CancellationToken cancellationToken) { switch (type) { case "tv": - return await GetSearchResultsTv(name, year, language, baseImageUrl, cancellationToken); + return GetSearchResultsTv(name, year, language, baseImageUrl, cancellationToken); default: - return await GetSearchResultsGeneric(name, type, year, language, baseImageUrl, cancellationToken); + return GetSearchResultsGeneric(name, type, year, language, baseImageUrl, cancellationToken); } } private async Task> GetSearchResultsGeneric(string name, string type, int? year, string language, string baseImageUrl, CancellationToken cancellationToken) { + if (string.IsNullOrWhiteSpace(name)) + { + throw new ArgumentException("name"); + } var url3 = string.Format(Search3, WebUtility.UrlEncode(name), ApiKey, language, type); @@ -189,6 +198,11 @@ namespace MediaBrowser.Providers.Movies private async Task> GetSearchResultsTv(string name, int? year, string language, string baseImageUrl, CancellationToken cancellationToken) { + if (string.IsNullOrWhiteSpace(name)) + { + throw new ArgumentException("name"); + } + var url3 = string.Format(Search3, WebUtility.UrlEncode(name), ApiKey, language, "tv"); using (var json = await MovieDbProvider.Current.GetMovieDbResponse(new HttpRequestOptions diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 992a0a2cf..784766071 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -127,7 +127,8 @@ namespace MediaBrowser.Server.Implementations.Persistence connection.RunQueries(new[] { - "pragma temp_store = memory" + "pragma temp_store = memory", + "PRAGMA main.locking_mode=EXCLUSIVE" }, Logger); diff --git a/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs b/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs index a012a19a3..5d7274356 100644 --- a/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs +++ b/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.Reflection; using System.Text.RegularExpressions; using MediaBrowser.Controller.Power; +using MediaBrowser.Model.System; using MediaBrowser.Server.Implementations.Persistence; using MediaBrowser.Server.Startup.Common.FFMpeg; using OperatingSystem = MediaBrowser.Server.Startup.Common.OperatingSystem; @@ -176,7 +177,7 @@ namespace MediaBrowser.Server.Mono.Native } else if (string.Equals(uname.machine, "x86_64", StringComparison.OrdinalIgnoreCase)) { - info.SystemArchitecture = Architecture.X86_X64; + info.SystemArchitecture = Architecture.X64; } else if (uname.machine.StartsWith("arm", StringComparison.OrdinalIgnoreCase)) { @@ -260,7 +261,7 @@ namespace MediaBrowser.Server.Mono.Native switch (environment.SystemArchitecture) { - case Architecture.X86_X64: + case Architecture.X64: info.Version = "20160124"; break; case Architecture.X86: @@ -283,7 +284,7 @@ namespace MediaBrowser.Server.Mono.Native switch (environment.SystemArchitecture) { - case Architecture.X86_X64: + case Architecture.X64: return new[] { "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/osx/ffmpeg-x64-2.8.5.7z" @@ -300,7 +301,7 @@ namespace MediaBrowser.Server.Mono.Native switch (environment.SystemArchitecture) { - case Architecture.X86_X64: + case Architecture.X64: return new[] { "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/linux/ffmpeg-git-20160215-64bit-static.7z" diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index e7e6a9dc3..7390fbbbc 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -647,15 +647,20 @@ namespace MediaBrowser.Server.Startup.Common /// Task. private async Task RegisterMediaEncoder(IProgress progress) { + string encoderPath = null; + string probePath = null; + var info = await new FFMpegLoader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager, NativeApp.Environment, NativeApp.GetFfmpegInstallInfo()) .GetFFMpegInfo(NativeApp.Environment, _startupOptions, progress).ConfigureAwait(false); - _hasExternalEncoder = string.Equals(info.Version, "custom", StringComparison.OrdinalIgnoreCase); + encoderPath = info.EncoderPath; + probePath = info.ProbePath; + _hasExternalEncoder = string.Equals(info.Version, "external", StringComparison.OrdinalIgnoreCase); var mediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"), JsonSerializer, - info.EncoderPath, - info.ProbePath, + encoderPath, + probePath, _hasExternalEncoder, ServerConfigurationManager, FileSystemManager, @@ -1145,7 +1150,8 @@ namespace MediaBrowser.Server.Startup.Common ServerName = FriendlyName, LocalAddress = localAddress, SupportsLibraryMonitor = SupportsLibraryMonitor, - HasExternalEncoder = _hasExternalEncoder + HasExternalEncoder = _hasExternalEncoder, + SystemArchitecture = NativeApp.Environment.SystemArchitecture }; } diff --git a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegLoader.cs b/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegLoader.cs index 2c393ff29..a4c50d0d8 100644 --- a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegLoader.cs +++ b/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegLoader.cs @@ -53,13 +53,17 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg { ProbePath = customffProbePath, EncoderPath = customffMpegPath, - Version = "custom" + Version = "external" }; } var downloadInfo = _ffmpegInstallInfo; var version = downloadInfo.Version; + if (string.Equals(version, "0", StringComparison.OrdinalIgnoreCase)) + { + return new FFMpegInfo(); + } if (string.Equals(version, "path", StringComparison.OrdinalIgnoreCase)) { @@ -175,18 +179,6 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg return null; } - private async void DownloadFFMpegInBackground(FFMpegInstallInfo downloadinfo, string directory) - { - try - { - await DownloadFFMpeg(downloadinfo, directory, new Progress()).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.ErrorException("Error downloading ffmpeg", ex); - } - } - private async Task DownloadFFMpeg(FFMpegInstallInfo downloadinfo, string directory, IProgress progress) { foreach (var url in downloadinfo.DownloadUrls) diff --git a/MediaBrowser.Server.Startup.Common/NativeEnvironment.cs b/MediaBrowser.Server.Startup.Common/NativeEnvironment.cs index 5b45afe73..b30509982 100644 --- a/MediaBrowser.Server.Startup.Common/NativeEnvironment.cs +++ b/MediaBrowser.Server.Startup.Common/NativeEnvironment.cs @@ -1,4 +1,5 @@ - +using MediaBrowser.Model.System; + namespace MediaBrowser.Server.Startup.Common { public class NativeEnvironment @@ -15,11 +16,4 @@ namespace MediaBrowser.Server.Startup.Common Bsd = 2, Linux = 3 } - - public enum Architecture - { - X86 = 0, - X86_X64 = 1, - Arm = 2 - } } diff --git a/MediaBrowser.ServerApplication/Native/WindowsApp.cs b/MediaBrowser.ServerApplication/Native/WindowsApp.cs index 2ea5064a4..d8b2720c2 100644 --- a/MediaBrowser.ServerApplication/Native/WindowsApp.cs +++ b/MediaBrowser.ServerApplication/Native/WindowsApp.cs @@ -10,6 +10,7 @@ using System.Reflection; using System.Windows.Forms; using CommonIO; using MediaBrowser.Controller.Power; +using MediaBrowser.Model.System; using MediaBrowser.Server.Implementations.Persistence; using MediaBrowser.Server.Startup.Common.FFMpeg; using OperatingSystem = MediaBrowser.Server.Startup.Common.OperatingSystem; @@ -53,7 +54,7 @@ namespace MediaBrowser.ServerApplication.Native return new NativeEnvironment { OperatingSystem = OperatingSystem.Windows, - SystemArchitecture = System.Environment.Is64BitOperatingSystem ? Architecture.X86_X64 : Architecture.X86, + SystemArchitecture = System.Environment.Is64BitOperatingSystem ? Architecture.X64 : Architecture.X86, OperatingSystemVersionString = System.Environment.OSVersion.VersionString }; } @@ -158,9 +159,7 @@ namespace MediaBrowser.ServerApplication.Native info.FFMpegFilename = "ffmpeg.exe"; info.FFProbeFilename = "ffprobe.exe"; - info.Version = "20160410"; - info.ArchiveType = "7z"; - info.DownloadUrls = GetDownloadUrls(); + info.Version = "0"; return info; } @@ -205,25 +204,5 @@ namespace MediaBrowser.ServerApplication.Native { ((Process)sender).Dispose(); } - - private string[] GetDownloadUrls() - { - switch (Environment.SystemArchitecture) - { - case Architecture.X86_X64: - return new[] - { - "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/windows/ffmpeg-20160410-win64.7z", - "https://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-20160409-git-0c90b2e-win64-static.7z" - }; - case Architecture.X86: - return new[] - { - "https://github.com/MediaBrowser/Emby.Resources/raw/master/ffmpeg/windows/ffmpeg-20160410-win32.7z", - "https://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20160409-git-0c90b2e-win32-static.7z" - }; - } - return new string[] { }; - } } } \ No newline at end of file diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index bc5db0224..4eae9975a 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -374,6 +374,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + PreserveNewest @@ -1094,6 +1100,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest -- cgit v1.2.3 From 775fc940201df06af46772ec612d2a525daf572d Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 29 Jun 2016 01:49:31 -0400 Subject: update path configs --- MediaBrowser.Api/ConfigurationService.cs | 4 +- .../MediaEncoding/IMediaEncoder.cs | 16 +++-- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 76 +++++++++++++++++++--- MediaBrowser.Model/System/SystemInfo.cs | 2 +- .../ApplicationHost.cs | 7 +- 5 files changed, 82 insertions(+), 23 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs') diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs index 9c8120de7..2e5c252d6 100644 --- a/MediaBrowser.Api/ConfigurationService.cs +++ b/MediaBrowser.Api/ConfigurationService.cs @@ -79,6 +79,8 @@ namespace MediaBrowser.Api { [ApiMember(Name = "Path", Description = "Path", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public string Path { get; set; } + [ApiMember(Name = "PathType", Description = "PathType", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string PathType { get; set; } } public class ConfigurationService : BaseApiService @@ -110,7 +112,7 @@ namespace MediaBrowser.Api public void Post(UpdateMediaEncoderPath request) { - var task = _mediaEncoder.UpdateEncoderPath(request.Path); + var task = _mediaEncoder.UpdateEncoderPath(request.Path, request.PathType); Task.WaitAll(task); } diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 77ba1685f..12c893b0f 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -13,6 +13,8 @@ namespace MediaBrowser.Controller.MediaEncoding /// public interface IMediaEncoder : ITranscoderSupport { + string EncoderLocationType { get; } + /// /// Gets the encoder path. /// @@ -60,12 +62,12 @@ namespace MediaBrowser.Controller.MediaEncoding /// The maximum width. /// The cancellation token. /// Task. - Task ExtractVideoImagesOnInterval(string[] inputFiles, - MediaProtocol protocol, - Video3DFormat? threedFormat, - TimeSpan interval, - string targetDirectory, - string filenamePrefix, + Task ExtractVideoImagesOnInterval(string[] inputFiles, + MediaProtocol protocol, + Video3DFormat? threedFormat, + TimeSpan interval, + string targetDirectory, + string filenamePrefix, int? maxWidth, CancellationToken cancellationToken); @@ -131,6 +133,6 @@ namespace MediaBrowser.Controller.MediaEncoding void Init(); - Task UpdateEncoderPath(string path); + Task UpdateEncoderPath(string path, string pathType); } } diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 11291a05a..5b9a2a682 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -99,6 +99,39 @@ namespace MediaBrowser.MediaEncoding.Encoder _hasExternalEncoder = hasExternalEncoder; } + public string EncoderLocationType + { + get + { + if (_hasExternalEncoder) + { + return "External"; + } + + if (string.IsNullOrWhiteSpace(FFMpegPath)) + { + return null; + } + + if (IsSystemInstalledPath(FFMpegPath)) + { + return "System"; + } + + return "Custom"; + } + } + + private bool IsSystemInstalledPath(string path) + { + if (path.IndexOf("/", StringComparison.Ordinal) == -1 && path.IndexOf("\\", StringComparison.Ordinal) == -1) + { + return true; + } + + return false; + } + public void Init() { ConfigureEncoderPaths(); @@ -115,10 +148,13 @@ namespace MediaBrowser.MediaEncoding.Encoder var valueToSave = FFMpegPath; - // if using system variable, don't save this. - if (string.Equals(valueToSave, "ffmpeg", StringComparison.OrdinalIgnoreCase)) + if (!string.IsNullOrWhiteSpace(valueToSave)) { - valueToSave = null; + // if using system variable, don't save this. + if (IsSystemInstalledPath(valueToSave)) + { + valueToSave = null; + } } if (!string.Equals(valueToSave, appPath, StringComparison.Ordinal)) @@ -128,19 +164,39 @@ namespace MediaBrowser.MediaEncoding.Encoder } } - public async Task UpdateEncoderPath(string path) + public async Task UpdateEncoderPath(string path, string pathType) { - if (string.IsNullOrWhiteSpace(path)) + if (_hasExternalEncoder) { - throw new ArgumentNullException("path"); + return; } - if (!File.Exists(path) && !Directory.Exists(path)) + Tuple newPaths; + + if (string.Equals(pathType, "system", StringComparison.OrdinalIgnoreCase)) + { + path = "ffmpeg"; + + newPaths = TestForInstalledVersions(); + } + else if (string.Equals(pathType, "custom", StringComparison.OrdinalIgnoreCase)) + { + if (string.IsNullOrWhiteSpace(path)) + { + throw new ArgumentNullException("path"); + } + + if (!File.Exists(path) && !Directory.Exists(path)) + { + throw new ResourceNotFoundException(); + } + newPaths = GetEncoderPaths(path); + } + else { - throw new ResourceNotFoundException(); + throw new ArgumentException("Unexpected pathType value"); } - var newPaths = GetEncoderPaths(path); if (string.IsNullOrWhiteSpace(newPaths.Item1)) { throw new ResourceNotFoundException("ffmpeg not found"); @@ -252,7 +308,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } } - private Tuple GetPathsFromDirectory(string path) + private Tuple GetPathsFromDirectory(string path) { // Since we can't predict the file extension, first try directly within the folder // If that doesn't pan out, then do a recursive search diff --git a/MediaBrowser.Model/System/SystemInfo.cs b/MediaBrowser.Model/System/SystemInfo.cs index 868d9dc28..3d1de5b37 100644 --- a/MediaBrowser.Model/System/SystemInfo.cs +++ b/MediaBrowser.Model/System/SystemInfo.cs @@ -152,7 +152,7 @@ namespace MediaBrowser.Model.System /// true if [supports automatic run at startup]; otherwise, false. public bool SupportsAutoRunAtStartup { get; set; } - public bool HasExternalEncoder { get; set; } + public string EncoderLocationType { get; set; } public Architecture SystemArchitecture { get; set; } diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index ec1ccbff5..1d7b65e5f 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -658,13 +658,13 @@ namespace MediaBrowser.Server.Startup.Common encoderPath = info.EncoderPath; probePath = info.ProbePath; - _hasExternalEncoder = string.Equals(info.Version, "external", StringComparison.OrdinalIgnoreCase); + var hasExternalEncoder = string.Equals(info.Version, "external", StringComparison.OrdinalIgnoreCase); var mediaEncoder = new MediaEncoder(LogManager.GetLogger("MediaEncoder"), JsonSerializer, encoderPath, probePath, - _hasExternalEncoder, + hasExternalEncoder, ServerConfigurationManager, FileSystemManager, LiveTvManager, @@ -1100,7 +1100,6 @@ namespace MediaBrowser.Server.Startup.Common } } - private bool _hasExternalEncoder; /// /// Gets the system status. /// @@ -1141,7 +1140,7 @@ namespace MediaBrowser.Server.Startup.Common ServerName = FriendlyName, LocalAddress = localAddress, SupportsLibraryMonitor = SupportsLibraryMonitor, - HasExternalEncoder = _hasExternalEncoder, + EncoderLocationType = MediaEncoder.EncoderLocationType, SystemArchitecture = NativeApp.Environment.SystemArchitecture }; } -- cgit v1.2.3 From 525f7804532bb0d5a1dc38668fbcf511acc2877c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 30 Jun 2016 00:23:52 -0400 Subject: add startup error handling --- .../MediaEncoding/IMediaEncoder.cs | 2 +- .../Encoder/EncoderValidator.cs | 159 ++++++++++++++++++++ MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 15 +- .../MediaBrowser.MediaEncoding.csproj | 1 + .../Connect/ConnectEntryPoint.cs | 10 +- .../Connect/ConnectManager.cs | 7 +- .../ApplicationHost.cs | 16 +- .../FFMpeg/FFmpegValidator.cs | 161 --------------------- .../MediaBrowser.Server.Startup.Common.csproj | 1 - 9 files changed, 187 insertions(+), 185 deletions(-) create mode 100644 MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs delete mode 100644 MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs (limited to 'MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs') diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 12c893b0f..62377b19e 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -131,7 +131,7 @@ namespace MediaBrowser.Controller.MediaEncoding /// System.String. string EscapeSubtitleFilterPath(string path); - void Init(); + Task Init(); Task UpdateEncoderPath(string path, string pathType); } diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs new file mode 100644 index 000000000..99581332d --- /dev/null +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using MediaBrowser.Model.Logging; + +namespace MediaBrowser.MediaEncoding.Encoder +{ + public class EncoderValidator + { + private readonly ILogger _logger; + + public EncoderValidator(ILogger logger) + { + _logger = logger; + } + + public Tuple, List> Validate(string encoderPath) + { + _logger.Info("Validating media encoder at {0}", encoderPath); + + var decoders = GetDecoders(encoderPath); + var encoders = GetEncoders(encoderPath); + + _logger.Info("Encoder validation complete"); + + return new Tuple, List>(decoders, encoders); + } + + private List GetDecoders(string ffmpegPath) + { + string output = string.Empty; + try + { + output = GetFFMpegOutput(ffmpegPath, "-decoders"); + } + catch + { + } + //_logger.Debug("ffmpeg decoder query result: {0}", output ?? string.Empty); + + var found = new List(); + var required = new[] + { + "h264_qsv", + "mpeg2_qsv", + "vc1_qsv" + }; + + foreach (var codec in required) + { + var srch = " " + codec + " "; + + if (output.IndexOf(srch, StringComparison.OrdinalIgnoreCase) == -1) + { + _logger.Warn("ffmpeg is missing decoder " + codec); + } + else + { + found.Add(codec); + } + } + + return found; + } + + private List GetEncoders(string ffmpegPath) + { + string output = null; + try + { + output = GetFFMpegOutput(ffmpegPath, "-encoders"); + } + catch + { + } + //_logger.Debug("ffmpeg encoder query result: {0}", output ?? string.Empty); + + var found = new List(); + var required = new[] + { + "libx264", + "libx265", + "mpeg4", + "msmpeg4", + //"libvpx", + //"libvpx-vp9", + "aac", + "libmp3lame", + "libopus", + //"libvorbis", + "srt" + }; + + foreach (var codec in required) + { + var srch = " " + codec + " "; + + if (output.IndexOf(srch, StringComparison.OrdinalIgnoreCase) == -1) + { + _logger.Warn("ffmpeg is missing encoder " + codec); + } + else + { + found.Add(codec); + } + } + + return found; + } + + private string GetFFMpegOutput(string path, string arguments) + { + var process = new Process + { + StartInfo = new ProcessStartInfo + { + CreateNoWindow = true, + UseShellExecute = false, + FileName = path, + Arguments = arguments, + WindowStyle = ProcessWindowStyle.Hidden, + ErrorDialog = false, + RedirectStandardOutput = true, + RedirectStandardError = true + } + }; + + using (process) + { + process.Start(); + + try + { + process.BeginErrorReadLine(); + + using (var reader = new StreamReader(process.StandardOutput.BaseStream)) + { + return reader.ReadToEnd(); + } + } + catch + { + // Hate having to do this + try + { + process.Kill(); + } + catch (Exception ex1) + { + _logger.ErrorException("Error killing ffmpeg", ex1); + } + + throw; + } + } + } + } +} diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index b5be4eb87..7264ad2d1 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -132,7 +132,20 @@ namespace MediaBrowser.MediaEncoding.Encoder return false; } - public void Init() + public async Task Init() + { + InitPaths(); + + if (!string.IsNullOrWhiteSpace(FFMpegPath)) + { + var result = new EncoderValidator(_logger).Validate(FFMpegPath); + + SetAvailableDecoders(result.Item1); + SetAvailableEncoders(result.Item2); + } + } + + private void InitPaths() { ConfigureEncoderPaths(); diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index 5576a49bd..794353451 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -71,6 +71,7 @@ + diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs b/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs index 79872b100..28a62c012 100644 --- a/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs +++ b/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs @@ -44,11 +44,12 @@ namespace MediaBrowser.Server.Implementations.Connect LoadCachedAddress(); _timer = new PeriodicTimer(TimerCallback, null, TimeSpan.FromSeconds(5), TimeSpan.FromHours(3)); + ((ConnectManager)_connectManager).Start(); } private readonly string[] _ipLookups = { - "http://bot.whatismyipaddress.com", + "http://bot.whatismyipaddress.com", "https://connect.emby.media/service/ip" }; @@ -78,17 +79,18 @@ namespace MediaBrowser.Server.Implementations.Connect } // If this produced an ipv6 address, try again - if (validIpAddress == null || validIpAddress.AddressFamily == AddressFamily.InterNetworkV6) + if (validIpAddress != null && validIpAddress.AddressFamily == AddressFamily.InterNetworkV6) { foreach (var ipLookupUrl in _ipLookups) { try { - validIpAddress = await GetIpAddress(ipLookupUrl, true).ConfigureAwait(false); + var newAddress = await GetIpAddress(ipLookupUrl, true).ConfigureAwait(false); // Try to find the ipv4 address, if present - if (validIpAddress.AddressFamily == AddressFamily.InterNetwork) + if (newAddress.AddressFamily == AddressFamily.InterNetwork) { + validIpAddress = newAddress; break; } } diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs index 8dbea707d..24750de94 100644 --- a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs +++ b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs @@ -139,11 +139,14 @@ namespace MediaBrowser.Server.Implementations.Connect _securityManager = securityManager; _fileSystem = fileSystem; - _config.ConfigurationUpdated += _config_ConfigurationUpdated; - LoadCachedData(); } + internal void Start() + { + _config.ConfigurationUpdated += _config_ConfigurationUpdated; + } + internal void OnWanAddressResolved(IPAddress address) { DiscoveredWanIpAddress = address; diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 8978cec5f..1e5c54d93 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -322,7 +322,7 @@ namespace MediaBrowser.Server.Startup.Common await base.RunStartupTasks().ConfigureAwait(false); - InitMediaEncoder(); + await MediaEncoder.Init().ConfigureAwait(false); Logger.Info("ServerId: {0}", SystemId); Logger.Info("Core startup complete"); @@ -350,20 +350,6 @@ namespace MediaBrowser.Server.Startup.Common LogManager.RemoveConsoleOutput(); } - private void InitMediaEncoder() - { - MediaEncoder.Init(); - - Task.Run(() => - { - var result = new FFmpegValidator(Logger, ApplicationPaths, FileSystemManager).Validate(MediaEncoder.EncoderPath); - - var mediaEncoder = (MediaEncoder) MediaEncoder; - mediaEncoder.SetAvailableDecoders(result.Item1); - mediaEncoder.SetAvailableEncoders(result.Item2); - }); - } - public override Task Init(IProgress progress) { HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber; diff --git a/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs b/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs deleted file mode 100644 index d92dc1b96..000000000 --- a/MediaBrowser.Server.Startup.Common/FFMpeg/FFmpegValidator.cs +++ /dev/null @@ -1,161 +0,0 @@ -using MediaBrowser.Common.Configuration; -using MediaBrowser.Model.Logging; -using System; -using System.Diagnostics; -using System.IO; -using System.Collections.Generic; -using CommonIO; - -namespace MediaBrowser.Server.Startup.Common.FFMpeg -{ - public class FFmpegValidator - { - private readonly ILogger _logger; - private readonly IApplicationPaths _appPaths; - private readonly IFileSystem _fileSystem; - - public FFmpegValidator(ILogger logger, IApplicationPaths appPaths, IFileSystem fileSystem) - { - _logger = logger; - _appPaths = appPaths; - _fileSystem = fileSystem; - } - - public Tuple,List> Validate(string encoderPath) - { - var decoders = GetDecoders(encoderPath); - var encoders = GetEncoders(encoderPath); - - return new Tuple, List>(decoders, encoders); - } - - private List GetDecoders(string ffmpegPath) - { - string output = string.Empty; - try - { - output = GetFFMpegOutput(ffmpegPath, "-decoders"); - } - catch - { - } - //_logger.Debug("ffmpeg decoder query result: {0}", output ?? string.Empty); - - var found = new List(); - var required = new[] - { - "h264_qsv", - "mpeg2_qsv", - "vc1_qsv" - }; - - foreach (var codec in required) - { - var srch = " " + codec + " "; - - if (output.IndexOf(srch, StringComparison.OrdinalIgnoreCase) == -1) - { - _logger.Warn("ffmpeg is missing decoder " + codec); - } - else - { - found.Add(codec); - } - } - - return found; - } - - private List GetEncoders(string ffmpegPath) - { - string output = null; - try - { - output = GetFFMpegOutput(ffmpegPath, "-encoders"); - } - catch - { - } - //_logger.Debug("ffmpeg encoder query result: {0}", output ?? string.Empty); - - var found = new List(); - var required = new[] - { - "libx264", - "libx265", - "mpeg4", - "msmpeg4", - //"libvpx", - //"libvpx-vp9", - "aac", - "libmp3lame", - "libopus", - //"libvorbis", - "srt" - }; - - foreach (var codec in required) - { - var srch = " " + codec + " "; - - if (output.IndexOf(srch, StringComparison.OrdinalIgnoreCase) == -1) - { - _logger.Warn("ffmpeg is missing encoder " + codec); - } - else - { - found.Add(codec); - } - } - - return found; - } - - private string GetFFMpegOutput(string path, string arguments) - { - var process = new Process - { - StartInfo = new ProcessStartInfo - { - CreateNoWindow = true, - UseShellExecute = false, - FileName = path, - Arguments = arguments, - WindowStyle = ProcessWindowStyle.Hidden, - ErrorDialog = false, - RedirectStandardOutput = true, - RedirectStandardError = true - } - }; - - using (process) - { - process.Start(); - - try - { - process.BeginErrorReadLine(); - - using (var reader = new StreamReader(process.StandardOutput.BaseStream)) - { - return reader.ReadToEnd(); - } - } - catch - { - // Hate having to do this - try - { - process.Kill(); - } - catch (Exception ex1) - { - _logger.ErrorException("Error killing ffmpeg", ex1); - } - - throw; - } - } - } - } -} diff --git a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj index 5b88a6bd9..808d25fc9 100644 --- a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj +++ b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj @@ -68,7 +68,6 @@ - -- cgit v1.2.3 From 00634b62c53d145e3dc6ad707dfbe98cb21bfa5a Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 30 Jun 2016 22:35:18 -0400 Subject: remove standard output redirect on image extractions --- .../MediaEncoding/IMediaEncoder.cs | 6 ++-- .../Encoder/EncoderValidator.cs | 5 +-- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 37 ++++++++-------------- .../MediaInfo/AudioImageProvider.cs | 15 ++++++--- .../MediaInfo/VideoImageProvider.cs | 9 +++--- .../MediaEncoder/EncodingManager.cs | 14 +++++--- 6 files changed, 41 insertions(+), 45 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs') diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 62377b19e..c8a8caa91 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.Controller.MediaEncoding /// Index of the image stream. /// The cancellation token. /// Task{Stream}. - Task ExtractAudioImage(string path, int? imageStreamIndex, CancellationToken cancellationToken); + Task ExtractAudioImage(string path, int? imageStreamIndex, CancellationToken cancellationToken); /// /// Extracts the video image. @@ -46,9 +46,9 @@ namespace MediaBrowser.Controller.MediaEncoding /// The offset. /// The cancellation token. /// Task{Stream}. - Task ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken); + Task ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken); - Task ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, int? imageStreamIndex, CancellationToken cancellationToken); + Task ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, int? imageStreamIndex, CancellationToken cancellationToken); /// /// Extracts the video images on interval. diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 23e3d0fa6..859452362 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -117,8 +117,7 @@ namespace MediaBrowser.MediaEncoding.Encoder Arguments = arguments, WindowStyle = ProcessWindowStyle.Hidden, ErrorDialog = false, - RedirectStandardOutput = true, - //RedirectStandardError = true + RedirectStandardOutput = true } }; @@ -128,8 +127,6 @@ namespace MediaBrowser.MediaEncoding.Encoder try { - //process.BeginErrorReadLine(); - return process.StandardOutput.ReadToEnd(); } catch diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 7264ad2d1..68113c0d1 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -767,22 +767,22 @@ namespace MediaBrowser.MediaEncoding.Encoder /// protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); - public Task ExtractAudioImage(string path, int? imageStreamIndex, CancellationToken cancellationToken) + public Task ExtractAudioImage(string path, int? imageStreamIndex, CancellationToken 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) + public Task ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken) { return ExtractImage(inputFiles, null, protocol, false, threedFormat, offset, cancellationToken); } - public Task ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, int? imageStreamIndex, CancellationToken cancellationToken) + public Task ExtractVideoImage(string[] inputFiles, MediaProtocol protocol, int? imageStreamIndex, CancellationToken cancellationToken) { return ExtractImage(inputFiles, imageStreamIndex, protocol, false, null, null, cancellationToken); } - private async Task ExtractImage(string[] inputFiles, int? imageStreamIndex, 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; @@ -816,13 +816,16 @@ namespace MediaBrowser.MediaEncoding.Encoder return await ExtractImageInternal(inputArgument, imageStreamIndex, protocol, threedFormat, offset, false, resourcePool, cancellationToken).ConfigureAwait(false); } - private async Task ExtractImageInternal(string inputPath, int? imageStreamIndex, 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)) { throw new ArgumentNullException("inputPath"); } + var tempExtractPath = Path.Combine(ConfigurationManager.ApplicationPaths.TempDirectory, Guid.NewGuid() + ".jpg"); + Directory.CreateDirectory(Path.GetDirectoryName(tempExtractPath)); + // apply some filters to thumbnail extracted below (below) crop any black lines that we made and get the correct ar then scale to width 600. // This filter chain may have adverse effects on recorded tv thumbnails if ar changes during presentation ex. commercials @ diff ar var vf = "scale=600:trunc(600/dar/2)*2"; @@ -855,8 +858,8 @@ 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}{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 args = useIFrame ? string.Format("-i {0}{3} -threads 1 -v quiet -vframes 1 -vf \"{2},thumbnail=30\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg) : + string.Format("-i {0}{3} -threads 1 -v quiet -vframes 1 -vf \"{2}\" -f image2 \"{1}\"", inputPath, tempExtractPath, vf, mapArg); var probeSize = GetProbeSizeArgument(new[] { inputPath }, protocol); @@ -880,8 +883,6 @@ namespace MediaBrowser.MediaEncoding.Encoder Arguments = args, WindowStyle = ProcessWindowStyle.Hidden, ErrorDialog = false, - RedirectStandardOutput = true, - RedirectStandardError = true, RedirectStandardInput = true } }; @@ -894,20 +895,10 @@ namespace MediaBrowser.MediaEncoding.Encoder bool ranToCompletion; - var memoryStream = new MemoryStream(); - try { StartProcess(processWrapper); -#pragma warning disable 4014 - // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback - process.StandardOutput.BaseStream.CopyToAsync(memoryStream); -#pragma warning restore 4014 - - // MUST read both stdout and stderr asynchronously or a deadlock may occurr - process.BeginErrorReadLine(); - ranToCompletion = process.WaitForExit(10000); if (!ranToCompletion) @@ -922,11 +913,10 @@ namespace MediaBrowser.MediaEncoding.Encoder } var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1; + var file = new FileInfo(tempExtractPath); - if (exitCode == -1 || memoryStream.Length == 0) + if (exitCode == -1 || !file.Exists || file.Length == 0) { - memoryStream.Dispose(); - var msg = string.Format("ffmpeg image extraction failed for {0}", inputPath); _logger.Error(msg); @@ -934,8 +924,7 @@ namespace MediaBrowser.MediaEncoding.Encoder throw new ApplicationException(msg); } - memoryStream.Position = 0; - return memoryStream; + return tempExtractPath; } } diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs index 4b795a474..bec9280b3 100644 --- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs @@ -83,12 +83,17 @@ namespace MediaBrowser.Providers.MediaInfo var imageStreamIndex = imageStream == null ? (int?)null : imageStream.Index; - using (var stream = await _mediaEncoder.ExtractAudioImage(item.Path, imageStreamIndex, cancellationToken).ConfigureAwait(false)) + var tempFile = await _mediaEncoder.ExtractAudioImage(item.Path, imageStreamIndex, cancellationToken).ConfigureAwait(false); + + File.Copy(tempFile, path, true); + + try { - using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true)) - { - await stream.CopyToAsync(fileStream).ConfigureAwait(false); - } + File.Delete(tempFile); + } + catch + { + } } } diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs index ff6eef167..9a1f072cd 100644 --- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs @@ -116,7 +116,7 @@ namespace MediaBrowser.Providers.MediaInfo imageStreams.FirstOrDefault(i => (i.Comment ?? string.Empty).IndexOf("cover", StringComparison.OrdinalIgnoreCase) != -1) ?? imageStreams.FirstOrDefault(); - Stream stream; + string extractedImagePath; if (imageStream != null) { @@ -135,7 +135,7 @@ namespace MediaBrowser.Providers.MediaInfo } } - stream = await _mediaEncoder.ExtractVideoImage(inputPath, protocol, videoIndex, cancellationToken).ConfigureAwait(false); + extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, protocol, videoIndex, cancellationToken).ConfigureAwait(false); } else { @@ -146,14 +146,15 @@ namespace MediaBrowser.Providers.MediaInfo ? TimeSpan.FromTicks(Convert.ToInt64(item.RunTimeTicks.Value * .1)) : TimeSpan.FromSeconds(10); - stream = await _mediaEncoder.ExtractVideoImage(inputPath, protocol, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false); + extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, protocol, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false); } return new DynamicImageResponse { Format = ImageFormat.Jpg, HasImage = true, - Stream = stream + Path = extractedImagePath, + Protocol = MediaProtocol.File }; } finally diff --git a/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs b/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs index a7b0d61c7..b1b2072c4 100644 --- a/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs +++ b/MediaBrowser.Server.Implementations/MediaEncoder/EncodingManager.cs @@ -139,12 +139,16 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder { _fileSystem.CreateDirectory(Path.GetDirectoryName(path)); - using (var stream = await _encoder.ExtractVideoImage(inputPath, protocol, video.Video3DFormat, time, cancellationToken).ConfigureAwait(false)) + var tempFile = await _encoder.ExtractVideoImage(inputPath, protocol, video.Video3DFormat, time, cancellationToken).ConfigureAwait(false); + File.Copy(tempFile, path, true); + + try + { + File.Delete(tempFile); + } + catch { - using (var fileStream = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true)) - { - await stream.CopyToAsync(fileStream).ConfigureAwait(false); - } + } chapter.ImagePath = path; -- cgit v1.2.3