فهرست منبع

#642 - Add server-side encoding settings

Luke Pulverenti 11 سال پیش
والد
کامیت
53f4e849fd

+ 79 - 6
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -2,12 +2,14 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.MediaInfo;
 using MediaBrowser.Controller;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaInfo;
 using MediaBrowser.Controller.Persistence;
+using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
@@ -32,7 +34,7 @@ namespace MediaBrowser.Api.Playback
         /// Gets or sets the application paths.
         /// </summary>
         /// <value>The application paths.</value>
-        protected IServerApplicationPaths ApplicationPaths { get; private set; }
+        protected IServerConfigurationManager ServerConfigurationManager { get; private set; }
 
         /// <summary>
         /// Gets or sets the user manager.
@@ -66,17 +68,20 @@ namespace MediaBrowser.Api.Playback
         /// <summary>
         /// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
         /// </summary>
-        /// <param name="appPaths">The app paths.</param>
+        /// <param name="serverConfig">The server configuration.</param>
         /// <param name="userManager">The user manager.</param>
         /// <param name="libraryManager">The library manager.</param>
         /// <param name="isoManager">The iso manager.</param>
         /// <param name="mediaEncoder">The media encoder.</param>
-        protected BaseStreamingService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository)
+        /// <param name="dtoService">The dto service.</param>
+        /// <param name="fileSystem">The file system.</param>
+        /// <param name="itemRepository">The item repository.</param>
+        protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository)
         {
             ItemRepository = itemRepository;
             FileSystem = fileSystem;
             DtoService = dtoService;
-            ApplicationPaths = appPaths;
+            ServerConfigurationManager = serverConfig;
             UserManager = userManager;
             LibraryManager = libraryManager;
             IsoManager = isoManager;
@@ -115,7 +120,7 @@ namespace MediaBrowser.Api.Playback
         /// <returns>System.String.</returns>
         protected virtual string GetOutputFilePath(StreamState state)
         {
-            var folder = ApplicationPaths.EncodedMediaCachePath;
+            var folder = ServerConfigurationManager.ApplicationPaths.EncodedMediaCachePath;
 
             var outputFileExtension = GetOutputFileExtension(state);
 
@@ -246,6 +251,74 @@ namespace MediaBrowser.Api.Playback
             return returnFirstIfNoIndex ? streams.FirstOrDefault() : null;
         }
 
+        /// <summary>
+        /// Gets the number of threads.
+        /// </summary>
+        /// <returns>System.Int32.</returns>
+        /// <exception cref="System.Exception">Unrecognized EncodingQuality value.</exception>
+        protected int GetNumberOfThreads()
+        {
+            var quality = ServerConfigurationManager.Configuration.EncodingQuality;
+
+            if (quality == EncodingQuality.Auto)
+            {
+                var cpuCount = Environment.ProcessorCount;
+
+                if (cpuCount >= 4)
+                {
+                    return 0;
+                }
+
+                return cpuCount;
+            }
+
+            switch (quality)
+            {
+                case EncodingQuality.HighSpeed:
+                    return 2;
+                case EncodingQuality.HighQuality:
+                    return 2;
+                case EncodingQuality.MaxQuality:
+                    return 0;
+                default:
+                    throw new Exception("Unrecognized EncodingQuality value.");
+            }
+        }
+
+        /// <summary>
+        /// Gets the video bitrate to specify on the command line
+        /// </summary>
+        /// <param name="state">The state.</param>
+        /// <param name="videoCodec">The video codec.</param>
+        /// <returns>System.String.</returns>
+        protected string GetVideoQualityParam(StreamState state, string videoCodec)
+        {
+            var args = string.Empty;
+
+            // webm
+            if (videoCodec.Equals("libvpx", StringComparison.OrdinalIgnoreCase))
+            {
+                args = "-speed 16 -quality good -profile:v 0 -slices 8";
+            }
+
+            // asf/wmv
+            else if (videoCodec.Equals("wmv2", StringComparison.OrdinalIgnoreCase))
+            {
+                args = "-g 100 -qmax 15";
+            }
+
+            else if (videoCodec.Equals("libx264", StringComparison.OrdinalIgnoreCase))
+            {
+                args = "-preset superfast";
+            }
+            else if (videoCodec.Equals("mpeg4", StringComparison.OrdinalIgnoreCase))
+            {
+                args = "-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -bf 2";
+            }
+
+            return args.Trim();
+        }
+        
         /// <summary>
         /// If we're going to put a fixed size on the command line, this will calculate it
         /// </summary>
@@ -656,7 +729,7 @@ namespace MediaBrowser.Api.Playback
 
             Logger.Info(process.StartInfo.FileName + " " + process.StartInfo.Arguments);
 
-            var logFilePath = Path.Combine(ApplicationPaths.LogDirectoryPath, "ffmpeg-" + Guid.NewGuid() + ".txt");
+            var logFilePath = Path.Combine(ServerConfigurationManager.ApplicationPaths.LogDirectoryPath, "ffmpeg-" + Guid.NewGuid() + ".txt");
 
             // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
             state.LogFileStream = FileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);

+ 3 - 3
MediaBrowser.Api/Playback/Hls/AudioHlsService.cs

@@ -1,6 +1,6 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.MediaInfo;
-using MediaBrowser.Controller;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
@@ -26,8 +26,8 @@ namespace MediaBrowser.Api.Playback.Hls
     /// </summary>
     public class AudioHlsService : BaseHlsService
     {
-        public AudioHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository)
-            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository)
+        public AudioHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository)
+            : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository)
         {
         }
 

+ 10 - 6
MediaBrowser.Api/Playback/Hls/BaseHlsService.cs

@@ -2,7 +2,7 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.MediaInfo;
 using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
@@ -22,14 +22,14 @@ namespace MediaBrowser.Api.Playback.Hls
     /// </summary>
     public abstract class BaseHlsService : BaseStreamingService
     {
-        protected BaseHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository)
-            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository)
+        protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository)
+            : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository)
         {
         }
 
         protected override string GetOutputFilePath(StreamState state)
         {
-            var folder = ApplicationPaths.EncodedMediaCachePath;
+            var folder = ServerConfigurationManager.ApplicationPaths.EncodedMediaCachePath;
 
             var outputFileExtension = GetOutputFileExtension(state);
 
@@ -257,13 +257,16 @@ namespace MediaBrowser.Api.Playback.Hls
 
             var itsOffset = itsOffsetMs == 0 ? string.Empty : string.Format("-itsoffset {0} ", TimeSpan.FromMilliseconds(itsOffsetMs).TotalSeconds);
 
-            var args = string.Format("{0}{1} {2} {3} -i {4}{5} -threads 0 {6} {7} -sc_threshold 0 {8} -hls_time 10 -start_number 0 -hls_list_size 1440 \"{9}\"",
+            var threads = GetNumberOfThreads();
+
+            var args = string.Format("{0}{1} {2} {3} -i {4}{5} -threads {6} {7} {8} -sc_threshold 0 {9} -hls_time 10 -start_number 0 -hls_list_size 1440 \"{10}\"",
                 itsOffset,
                 probeSize,
                 GetUserAgentParam(state.Item),
                 GetFastSeekCommandLineParameter(state.Request),
                 GetInputArgument(state.Item, state.IsoMount),
                 GetSlowSeekCommandLineParameter(state.Request),
+                threads,
                 GetMapArgs(state),
                 GetVideoArguments(state, performSubtitleConversions),
                 GetAudioArguments(state),
@@ -278,7 +281,8 @@ namespace MediaBrowser.Api.Playback.Hls
 
                     var bitrate = hlsVideoRequest.BaselineStreamAudioBitRate ?? 64000;
 
-                    var lowBitrateParams = string.Format(" -threads 0 -vn -codec:a:0 libmp3lame -ac 2 -ab {1} -hls_time 10 -start_number 0 -hls_list_size 1440 \"{0}\"",
+                    var lowBitrateParams = string.Format(" -threads {0} -vn -codec:a:0 libmp3lame -ac 2 -ab {2} -hls_time 10 -start_number 0 -hls_list_size 1440 \"{1}\"",
+                        threads,
                         lowBitratePath,
                         bitrate / 2);
 

+ 4 - 4
MediaBrowser.Api/Playback/Hls/VideoHlsService.cs

@@ -1,6 +1,6 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.MediaInfo;
-using MediaBrowser.Controller;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
@@ -32,8 +32,8 @@ namespace MediaBrowser.Api.Playback.Hls
     /// </summary>
     public class VideoHlsService : BaseHlsService
     {
-        public VideoHlsService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository)
-            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository)
+        public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository)
+            : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository)
         {
         }
 
@@ -123,7 +123,7 @@ namespace MediaBrowser.Api.Playback.Hls
                                  (state.SubtitleStream.Codec.IndexOf("pgs", StringComparison.OrdinalIgnoreCase) != -1 ||
                                   state.SubtitleStream.Codec.IndexOf("dvd", StringComparison.OrdinalIgnoreCase) != -1);
 
-            var args = "-codec:v:0 " + codec + " -preset superfast" + keyFrameArg;
+            var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, "libx264") + keyFrameArg;
 
             var bitrate = GetVideoBitrateParam(state);
 

+ 9 - 6
MediaBrowser.Api/Playback/Progressive/AudioService.cs

@@ -1,6 +1,6 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.MediaInfo;
-using MediaBrowser.Controller;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Library;
@@ -41,8 +41,8 @@ namespace MediaBrowser.Api.Playback.Progressive
     /// </summary>
     public class AudioService : BaseProgressiveStreamingService
     {
-        public AudioService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor, IFileSystem fileSystem)
-            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo, dtoService, imageProcessor, fileSystem)
+        public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, IImageProcessor imageProcessor)
+            : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, imageProcessor)
         {
         }
 
@@ -101,13 +101,16 @@ namespace MediaBrowser.Api.Playback.Progressive
 
             const string vn = " -vn";
 
-            return string.Format("{0} -i {1}{2} -threads 0{5} {3} -id3v2_version 3 -write_id3v1 1 \"{4}\"",
+            var threads = GetNumberOfThreads();
+
+            return string.Format("{0} -i {1}{2} -threads {3}{4} {5} -id3v2_version 3 -write_id3v1 1 \"{6}\"",
                 GetFastSeekCommandLineParameter(request),
                 GetInputArgument(state.Item, state.IsoMount),
                 GetSlowSeekCommandLineParameter(request),
+                threads,
+                vn,
                 string.Join(" ", audioTranscodeParams.ToArray()),
-                outputPath,
-                vn).Trim();
+                outputPath).Trim();
         }
     }
 }

+ 4 - 4
MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs

@@ -2,7 +2,7 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.MediaInfo;
 using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
@@ -26,8 +26,8 @@ namespace MediaBrowser.Api.Playback.Progressive
     {
         protected readonly IImageProcessor ImageProcessor;
 
-        protected BaseProgressiveStreamingService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepository, IDtoService dtoService, IImageProcessor imageProcessor, IFileSystem fileSystem) :
-            base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository)
+        protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, IImageProcessor imageProcessor)
+            : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository)
         {
             ImageProcessor = imageProcessor;
         }
@@ -304,7 +304,7 @@ namespace MediaBrowser.Api.Playback.Progressive
                 }
             }
 
-            return new ImageService(UserManager, LibraryManager, ApplicationPaths, null, ItemRepository, DtoService, ImageProcessor, null)
+            return new ImageService(UserManager, LibraryManager, ServerConfigurationManager.ApplicationPaths, null, ItemRepository, DtoService, ImageProcessor, null)
             {
                 Logger = Logger,
                 Request = Request,

+ 23 - 57
MediaBrowser.Api/Playback/Progressive/VideoService.cs

@@ -1,6 +1,6 @@
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.MediaInfo;
-using MediaBrowser.Controller;
+using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities;
@@ -55,8 +55,8 @@ namespace MediaBrowser.Api.Playback.Progressive
     /// </summary>
     public class VideoService : BaseProgressiveStreamingService
     {
-        public VideoService(IServerApplicationPaths appPaths, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IDtoService dtoService, IImageProcessor imageProcessor, IFileSystem fileSystem)
-            : base(appPaths, userManager, libraryManager, isoManager, mediaEncoder, itemRepo, dtoService, imageProcessor, fileSystem)
+        public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IDtoService dtoService, IFileSystem fileSystem, IItemRepository itemRepository, IImageProcessor imageProcessor)
+            : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, dtoService, fileSystem, itemRepository, imageProcessor)
         {
         }
 
@@ -104,7 +104,7 @@ namespace MediaBrowser.Api.Playback.Progressive
                 format = " -f mp4 -movflags frag_keyframe+empty_moov";
             }
 
-            var threads = string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase) ? 2 : 0;
+            var threads = string.Equals(videoCodec, "libvpx", StringComparison.OrdinalIgnoreCase) ? 2 : GetNumberOfThreads();
 
             return string.Format("{0} {1} {2} -i {3}{4}{5} {6} {7} -threads {8} {9}{10} \"{11}\"",
                 probeSize,
@@ -165,9 +165,16 @@ namespace MediaBrowser.Api.Playback.Progressive
 
             var qualityParam = GetVideoQualityParam(state, codec);
 
+            var bitrate = GetVideoBitrateParam(state);
+
+            if (bitrate.HasValue)
+            {
+                qualityParam += string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
+            }
+
             if (!string.IsNullOrEmpty(qualityParam))
             {
-                args += " " + qualityParam;
+                args += " " + qualityParam.Trim();
             }
 
             args += " -vsync vfr";
@@ -213,9 +220,9 @@ namespace MediaBrowser.Api.Playback.Progressive
             {
                 return "-acodec copy";
             }
-            
+
             var args = "-acodec " + codec;
-            
+
             // Add the number of audio channels
             var channels = GetNumAudioChannelsParam(request, state.AudioStream);
 
@@ -231,64 +238,23 @@ namespace MediaBrowser.Api.Playback.Progressive
                 args += " -ab " + bitrate.Value.ToString(UsCulture);
             }
 
-                var volParam = string.Empty;
-                var AudioSampleRate = string.Empty;
+            var volParam = string.Empty;
+            var AudioSampleRate = string.Empty;
 
-                // Boost volume to 200% when downsampling from 6ch to 2ch
-                if (channels.HasValue && channels.Value <= 2 && state.AudioStream.Channels.HasValue && state.AudioStream.Channels.Value > 5)
-                {
-                    volParam = ",volume=2.000000";
-                }
-                
-                if (state.Request.AudioSampleRate.HasValue)
-                {
-                    AudioSampleRate= state.Request.AudioSampleRate.Value + ":";
-                }
-
-                args += string.Format(" -af \"aresample={0}async=1000{1}\"",AudioSampleRate, volParam);
-
-                return args;
-            }
-
-        /// <summary>
-        /// Gets the video bitrate to specify on the command line
-        /// </summary>
-        /// <param name="state">The state.</param>
-        /// <param name="videoCodec">The video codec.</param>
-        /// <returns>System.String.</returns>
-        private string GetVideoQualityParam(StreamState state, string videoCodec)
-        {
-            var args = string.Empty;
-
-            // webm
-            if (videoCodec.Equals("libvpx", StringComparison.OrdinalIgnoreCase))
-            {
-                args = "-speed 16 -quality good -profile:v 0 -slices 8";
-            }
-
-            // asf/wmv
-            else if (videoCodec.Equals("wmv2", StringComparison.OrdinalIgnoreCase))
+            // Boost volume to 200% when downsampling from 6ch to 2ch
+            if (channels.HasValue && channels.Value <= 2 && state.AudioStream.Channels.HasValue && state.AudioStream.Channels.Value > 5)
             {
-                args = "-g 100 -qmax 15";
+                volParam = ",volume=2.000000";
             }
 
-            else if (videoCodec.Equals("libx264", StringComparison.OrdinalIgnoreCase))
+            if (state.Request.AudioSampleRate.HasValue)
             {
-                args = "-preset superfast";
+                AudioSampleRate = state.Request.AudioSampleRate.Value + ":";
             }
-            else if (videoCodec.Equals("mpeg4", StringComparison.OrdinalIgnoreCase))
-            {
-                args = "-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -bf 2";
-            }
-
-            var bitrate = GetVideoBitrateParam(state);
 
-            if (bitrate.HasValue)
-            {
-                args += string.Format(" -b:v {0}", bitrate.Value.ToString(UsCulture));
-            }
+            args += string.Format(" -af \"aresample={0}async=1000{1}\"", AudioSampleRate, volParam);
 
-            return args.Trim();
+            return args;
         }
     }
 }

+ 14 - 0
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -234,6 +234,12 @@ namespace MediaBrowser.Model.Configuration
         /// <value><c>true</c> if [enable people prefix sub folders]; otherwise, <c>false</c>.</value>
         public bool EnablePeoplePrefixSubFolders { get; set; }
 
+        /// <summary>
+        /// Gets or sets the encoding quality.
+        /// </summary>
+        /// <value>The encoding quality.</value>
+        public EncodingQuality EncodingQuality { get; set; }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ServerConfiguration" /> class.
         /// </summary>
@@ -293,4 +299,12 @@ namespace MediaBrowser.Model.Configuration
         Legacy,
         Compatible
     }
+
+    public enum EncodingQuality
+    {
+        Auto,
+        HighSpeed,
+        HighQuality,
+        MaxQuality
+    }
 }