diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index ed5fa5bfd7..ef5191df18 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -334,6 +334,12 @@ namespace MediaBrowser.Api 1000 : 1800000; + // We can really reduce the timeout for apps that are using the newer api + if (!string.IsNullOrWhiteSpace(job.PlaySessionId) && job.Type == TranscodingJobType.Hls) + { + timerDuration = 40000; + } + if (job.KillTimer == null) { if (startTimerIfNeeded) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs index fe0fb32955..bb8841222a 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs @@ -41,6 +41,8 @@ namespace MediaBrowser.Controller.MediaEncoding public int? SubtitleStreamIndex { get; set; } public int? MaxRefFrames { get; set; } public int? MaxVideoBitDepth { get; set; } + public int? CpuCoreLimit { get; set; } + public bool ReadInputAtNativeFramerate { get; set; } public SubtitleDeliveryMethod SubtitleMethod { get; set; } /// diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index 78ac92f25b..c30ceb62db 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -70,10 +70,7 @@ namespace MediaBrowser.MediaEncoding.Encoder encodingJob.OutputFilePath = GetOutputFilePath(encodingJob); Directory.CreateDirectory(Path.GetDirectoryName(encodingJob.OutputFilePath)); - if (options.Context == EncodingContext.Static && encodingJob.IsInputVideo) - { - encodingJob.ReadInputAtNativeFramerate = true; - } + encodingJob.ReadInputAtNativeFramerate = options.ReadInputAtNativeFramerate; await AcquireResources(encodingJob, cancellationToken).ConfigureAwait(false); @@ -305,19 +302,7 @@ namespace MediaBrowser.MediaEncoding.Encoder /// System.Int32. protected int GetNumberOfThreads(EncodingJob job, bool isWebm) { - // Only need one thread for sync - if (job.Options.Context == EncodingContext.Static) - { - return 1; - } - - if (isWebm) - { - // Recommended per docs - return Math.Max(Environment.ProcessorCount - 1, 2); - } - - return 0; + return job.Options.CpuCoreLimit ?? 0; } protected EncodingQuality GetQualitySetting() diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs index a0f5d928dd..ea3cc6d898 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs @@ -124,10 +124,14 @@ namespace MediaBrowser.MediaEncoding.Encoder state.InputContainer = mediaSource.Container; state.InputFileSize = mediaSource.Size; state.InputBitrate = mediaSource.Bitrate; - state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate; state.RunTimeTicks = mediaSource.RunTimeTicks; state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders; + if (mediaSource.ReadAtNativeFramerate) + { + state.ReadInputAtNativeFramerate = true; + } + if (mediaSource.VideoType.HasValue) { state.VideoType = mediaSource.VideoType.Value; @@ -148,7 +152,6 @@ namespace MediaBrowser.MediaEncoding.Encoder state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders; state.InputBitrate = mediaSource.Bitrate; state.InputFileSize = mediaSource.Size; - state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate; if (state.ReadInputAtNativeFramerate || mediaSource.Protocol == MediaProtocol.File && string.Equals(mediaSource.Container, "wtv", StringComparison.OrdinalIgnoreCase)) diff --git a/MediaBrowser.Model/Sync/SyncOptions.cs b/MediaBrowser.Model/Sync/SyncOptions.cs index 765dea86b9..7f0c17b373 100644 --- a/MediaBrowser.Model/Sync/SyncOptions.cs +++ b/MediaBrowser.Model/Sync/SyncOptions.cs @@ -5,5 +5,12 @@ namespace MediaBrowser.Model.Sync { public string TemporaryPath { get; set; } public long UploadSpeedLimitBytes { get; set; } + public int TranscodingCpuCoreLimit { get; set; } + public bool EnableFullSpeedTranscoding { get; set; } + + public SyncOptions() + { + TranscodingCpuCoreLimit = 1; + } } } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs index 3e816802e9..d78f1b48e6 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeAudioInfo.cs @@ -147,6 +147,7 @@ namespace MediaBrowser.Providers.MediaInfo audio.Artists = data.Artists; audio.AlbumArtists = data.AlbumArtists; audio.IndexNumber = data.IndexNumber; + audio.ParentIndexNumber = data.ParentIndexNumber; audio.ProductionYear = data.ProductionYear; audio.PremiereDate = data.PremiereDate; diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index b651b72dae..ea64b2780a 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1415,5 +1415,9 @@ "OptionAllowMediaPlaybackTranscodingHelp": "Users will receive friendly messages when content is unplayable based on policy.", "TabStreaming": "Streaming", "LabelRemoteClientBitrateLimit": "Remote client bitrate limit (mbps):", - "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle." + "LabelRemoteClientBitrateLimitHelp": "An optional streaming bitrate limit for all remote clients. This is useful to prevent clients from requesting a higher bitrate than your connection can handle.", + "LabelConversionCpuCoreLimit": "CPU core limit:", + "LabelConversionCpuCoreLimitHelp": "Limit the number of CPU cores that will be used during sync conversion.", + "OptionEnableFullSpeedConversion": "Enable full speed conversion", + "OptionEnableFullSpeedConversionHelp": "By default sync conversion is performed at a low speed to reduce resource consumption." } diff --git a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs index d8fc425d1a..fd4092974e 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs @@ -456,17 +456,18 @@ namespace MediaBrowser.Server.Implementations.Sync jobItem.Progress = 0; + var syncOptions = _config.GetSyncOptions(); var user = _userManager.GetUserById(job.UserId); var video = item as Video; if (video != null) { - await Sync(jobItem, job, video, user, enableConversion, progress, cancellationToken).ConfigureAwait(false); + await Sync(jobItem, job, video, user, enableConversion, syncOptions, progress, cancellationToken).ConfigureAwait(false); } else if (item is Audio) { - await Sync(jobItem, job, (Audio)item, user, enableConversion, progress, cancellationToken).ConfigureAwait(false); + await Sync(jobItem, job, (Audio)item, user, enableConversion, syncOptions, progress, cancellationToken).ConfigureAwait(false); } else if (item is Photo) @@ -480,7 +481,7 @@ namespace MediaBrowser.Server.Implementations.Sync } } - private async Task Sync(SyncJobItem jobItem, SyncJob job, Video item, User user, bool enableConversion, IProgress progress, CancellationToken cancellationToken) + private async Task Sync(SyncJobItem jobItem, SyncJob job, Video item, User user, bool enableConversion, SyncOptions syncOptions, IProgress progress, CancellationToken cancellationToken) { var jobOptions = _syncManager.GetVideoOptions(jobItem, job); var conversionOptions = new VideoOptions @@ -542,7 +543,9 @@ namespace MediaBrowser.Server.Implementations.Sync jobItem.OutputPath = await _mediaEncoder.EncodeVideo(new EncodingJobOptions(streamInfo, conversionOptions.Profile) { - OutputDirectory = jobItem.TemporaryPath + OutputDirectory = jobItem.TemporaryPath, + CpuCoreLimit = syncOptions.TranscodingCpuCoreLimit, + ReadInputAtNativeFramerate = !syncOptions.EnableFullSpeedTranscoding }, innerProgress, cancellationToken); } @@ -677,7 +680,7 @@ namespace MediaBrowser.Server.Implementations.Sync private const int DatabaseProgressUpdateIntervalSeconds = 2; - private async Task Sync(SyncJobItem jobItem, SyncJob job, Audio item, User user, bool enableConversion, IProgress progress, CancellationToken cancellationToken) + private async Task Sync(SyncJobItem jobItem, SyncJob job, Audio item, User user, bool enableConversion, SyncOptions syncOptions, IProgress progress, CancellationToken cancellationToken) { var jobOptions = _syncManager.GetAudioOptions(jobItem, job); var conversionOptions = new AudioOptions @@ -725,7 +728,8 @@ namespace MediaBrowser.Server.Implementations.Sync jobItem.OutputPath = await _mediaEncoder.EncodeAudio(new EncodingJobOptions(streamInfo, conversionOptions.Profile) { - OutputDirectory = jobItem.TemporaryPath + OutputDirectory = jobItem.TemporaryPath, + CpuCoreLimit = syncOptions.TranscodingCpuCoreLimit }, innerProgress, cancellationToken); }