mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-04-24 22:17:25 -04:00
Make probesize and analyzeduration configurable and simplify circular
dependencies Makes the probesize and analyzeduration configurable with env args. (`JELLYFIN_FFmpeg_probesize` and `FFmpeg_analyzeduration`)
This commit is contained in:
parent
e7098f1997
commit
cc5acf37f7
28 changed files with 395 additions and 319 deletions
|
@ -886,16 +886,14 @@ namespace Emby.Server.Implementations
|
||||||
serviceCollection.AddSingleton(ChapterManager);
|
serviceCollection.AddSingleton(ChapterManager);
|
||||||
|
|
||||||
MediaEncoder = new MediaBrowser.MediaEncoding.Encoder.MediaEncoder(
|
MediaEncoder = new MediaBrowser.MediaEncoding.Encoder.MediaEncoder(
|
||||||
LoggerFactory,
|
LoggerFactory.CreateLogger<MediaBrowser.MediaEncoding.Encoder.MediaEncoder>(),
|
||||||
JsonSerializer,
|
|
||||||
StartupOptions.FFmpegPath,
|
|
||||||
ServerConfigurationManager,
|
ServerConfigurationManager,
|
||||||
FileSystemManager,
|
FileSystemManager,
|
||||||
() => SubtitleEncoder,
|
|
||||||
() => MediaSourceManager,
|
|
||||||
ProcessFactory,
|
ProcessFactory,
|
||||||
5000,
|
LocalizationManager,
|
||||||
LocalizationManager);
|
() => SubtitleEncoder,
|
||||||
|
_configuration,
|
||||||
|
StartupOptions.FFmpegPath);
|
||||||
serviceCollection.AddSingleton(MediaEncoder);
|
serviceCollection.AddSingleton(MediaEncoder);
|
||||||
|
|
||||||
EncodingManager = new MediaEncoder.EncodingManager(FileSystemManager, LoggerFactory, MediaEncoder, ChapterManager, LibraryManager);
|
EncodingManager = new MediaEncoder.EncodingManager(FileSystemManager, LoggerFactory, MediaEncoder, ChapterManager, LibraryManager);
|
||||||
|
@ -912,10 +910,19 @@ namespace Emby.Server.Implementations
|
||||||
AuthService = new AuthService(authContext, ServerConfigurationManager, SessionManager, NetworkManager);
|
AuthService = new AuthService(authContext, ServerConfigurationManager, SessionManager, NetworkManager);
|
||||||
serviceCollection.AddSingleton(AuthService);
|
serviceCollection.AddSingleton(AuthService);
|
||||||
|
|
||||||
SubtitleEncoder = new MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder(LibraryManager, LoggerFactory, ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager, ProcessFactory);
|
SubtitleEncoder = new MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder(
|
||||||
|
LibraryManager,
|
||||||
|
LoggerFactory.CreateLogger<MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder>(),
|
||||||
|
ApplicationPaths,
|
||||||
|
FileSystemManager,
|
||||||
|
MediaEncoder,
|
||||||
|
HttpClient,
|
||||||
|
MediaSourceManager,
|
||||||
|
ProcessFactory);
|
||||||
serviceCollection.AddSingleton(SubtitleEncoder);
|
serviceCollection.AddSingleton(SubtitleEncoder);
|
||||||
|
|
||||||
serviceCollection.AddSingleton(typeof(IResourceFileManager), typeof(ResourceFileManager));
|
serviceCollection.AddSingleton(typeof(IResourceFileManager), typeof(ResourceFileManager));
|
||||||
|
serviceCollection.AddSingleton<EncodingHelper>();
|
||||||
|
|
||||||
_displayPreferencesRepository.Initialize();
|
_displayPreferencesRepository.Initialize();
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using static MediaBrowser.Controller.Extensions.ConfigurationExtensions;
|
||||||
|
|
||||||
namespace Emby.Server.Implementations
|
namespace Emby.Server.Implementations
|
||||||
{
|
{
|
||||||
public static class ConfigurationOptions
|
public static class ConfigurationOptions
|
||||||
{
|
{
|
||||||
public static readonly Dictionary<string, string> Configuration = new Dictionary<string, string>
|
public static Dictionary<string, string> Configuration => new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
{ "HttpListenerHost:DefaultRedirectPath", "web/index.html" },
|
{ "HttpListenerHost_DefaultRedirectPath", "web/index.html" },
|
||||||
{ "MusicBrainz:BaseUrl", "https://www.musicbrainz.org" }
|
{ "MusicBrainz_BaseUrl", "https://www.musicbrainz.org" },
|
||||||
|
{ FfmpegProbeSizeKey, "1G" },
|
||||||
|
{ FfmpegAnalyzeDuration, "200M" }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
<PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
|
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="3.0.1" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.0.1" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.0.1" />
|
||||||
|
|
|
@ -56,7 +56,7 @@ namespace Emby.Server.Implementations.HttpServer
|
||||||
_appHost = applicationHost;
|
_appHost = applicationHost;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_config = config;
|
_config = config;
|
||||||
_defaultRedirectPath = configuration["HttpListenerHost:DefaultRedirectPath"];
|
_defaultRedirectPath = configuration["HttpListenerHost_DefaultRedirectPath"];
|
||||||
_baseUrlPrefix = _config.Configuration.BaseUrl;
|
_baseUrlPrefix = _config.Configuration.BaseUrl;
|
||||||
_networkManager = networkManager;
|
_networkManager = networkManager;
|
||||||
_jsonSerializer = jsonSerializer;
|
_jsonSerializer = jsonSerializer;
|
||||||
|
|
|
@ -6,6 +6,7 @@ using System.Net;
|
||||||
using System.Net.Security;
|
using System.Net.Security;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -133,6 +134,10 @@ namespace Jellyfin.Server
|
||||||
|
|
||||||
ApplicationHost.LogEnvironmentInfo(_logger, appPaths);
|
ApplicationHost.LogEnvironmentInfo(_logger, appPaths);
|
||||||
|
|
||||||
|
// Make sure we have all the code pages we can get
|
||||||
|
// Ref: https://docs.microsoft.com/en-us/dotnet/api/system.text.codepagesencodingprovider.instance?view=netcore-3.0#remarks
|
||||||
|
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||||
|
|
||||||
// Increase the max http request limit
|
// Increase the max http request limit
|
||||||
// The default connection limit is 10 for ASP.NET hosted applications and 2 for all others.
|
// The default connection limit is 10 for ASP.NET hosted applications and 2 for all others.
|
||||||
ServicePointManager.DefaultConnectionLimit = Math.Max(96, ServicePointManager.DefaultConnectionLimit);
|
ServicePointManager.DefaultConnectionLimit = Math.Max(96, ServicePointManager.DefaultConnectionLimit);
|
||||||
|
@ -369,9 +374,9 @@ namespace Jellyfin.Server
|
||||||
|
|
||||||
return new ConfigurationBuilder()
|
return new ConfigurationBuilder()
|
||||||
.SetBasePath(appPaths.ConfigurationDirectoryPath)
|
.SetBasePath(appPaths.ConfigurationDirectoryPath)
|
||||||
|
.AddInMemoryCollection(ConfigurationOptions.Configuration)
|
||||||
.AddJsonFile("logging.json", false, true)
|
.AddJsonFile("logging.json", false, true)
|
||||||
.AddEnvironmentVariables("JELLYFIN_")
|
.AddEnvironmentVariables("JELLYFIN_")
|
||||||
.AddInMemoryCollection(ConfigurationOptions.Configuration)
|
|
||||||
.Build();
|
.Build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,8 +69,6 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
protected IDeviceManager DeviceManager { get; private set; }
|
protected IDeviceManager DeviceManager { get; private set; }
|
||||||
|
|
||||||
protected ISubtitleEncoder SubtitleEncoder { get; private set; }
|
|
||||||
|
|
||||||
protected IMediaSourceManager MediaSourceManager { get; private set; }
|
protected IMediaSourceManager MediaSourceManager { get; private set; }
|
||||||
|
|
||||||
protected IJsonSerializer JsonSerializer { get; private set; }
|
protected IJsonSerializer JsonSerializer { get; private set; }
|
||||||
|
@ -96,11 +94,11 @@ namespace MediaBrowser.Api.Playback
|
||||||
IMediaEncoder mediaEncoder,
|
IMediaEncoder mediaEncoder,
|
||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
IDlnaManager dlnaManager,
|
IDlnaManager dlnaManager,
|
||||||
ISubtitleEncoder subtitleEncoder,
|
|
||||||
IDeviceManager deviceManager,
|
IDeviceManager deviceManager,
|
||||||
IMediaSourceManager mediaSourceManager,
|
IMediaSourceManager mediaSourceManager,
|
||||||
IJsonSerializer jsonSerializer,
|
IJsonSerializer jsonSerializer,
|
||||||
IAuthorizationContext authorizationContext)
|
IAuthorizationContext authorizationContext,
|
||||||
|
EncodingHelper encodingHelper)
|
||||||
{
|
{
|
||||||
ServerConfigurationManager = serverConfig;
|
ServerConfigurationManager = serverConfig;
|
||||||
UserManager = userManager;
|
UserManager = userManager;
|
||||||
|
@ -109,13 +107,12 @@ namespace MediaBrowser.Api.Playback
|
||||||
MediaEncoder = mediaEncoder;
|
MediaEncoder = mediaEncoder;
|
||||||
FileSystem = fileSystem;
|
FileSystem = fileSystem;
|
||||||
DlnaManager = dlnaManager;
|
DlnaManager = dlnaManager;
|
||||||
SubtitleEncoder = subtitleEncoder;
|
|
||||||
DeviceManager = deviceManager;
|
DeviceManager = deviceManager;
|
||||||
MediaSourceManager = mediaSourceManager;
|
MediaSourceManager = mediaSourceManager;
|
||||||
JsonSerializer = jsonSerializer;
|
JsonSerializer = jsonSerializer;
|
||||||
AuthorizationContext = authorizationContext;
|
AuthorizationContext = authorizationContext;
|
||||||
|
|
||||||
EncodingHelper = new EncodingHelper(MediaEncoder, FileSystem, SubtitleEncoder);
|
EncodingHelper = encodingHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -152,8 +149,6 @@ namespace MediaBrowser.Api.Playback
|
||||||
return Path.Combine(folder, filename + ext);
|
return Path.Combine(folder, filename + ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
|
|
||||||
|
|
||||||
protected virtual string GetDefaultEncoderPreset()
|
protected virtual string GetDefaultEncoderPreset()
|
||||||
{
|
{
|
||||||
return "superfast";
|
return "superfast";
|
||||||
|
|
|
@ -25,6 +25,34 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class BaseHlsService : BaseStreamingService
|
public abstract class BaseHlsService : BaseStreamingService
|
||||||
{
|
{
|
||||||
|
public BaseHlsService(
|
||||||
|
IServerConfigurationManager serverConfig,
|
||||||
|
IUserManager userManager,
|
||||||
|
ILibraryManager libraryManager,
|
||||||
|
IIsoManager isoManager,
|
||||||
|
IMediaEncoder mediaEncoder,
|
||||||
|
IFileSystem fileSystem,
|
||||||
|
IDlnaManager dlnaManager,
|
||||||
|
IDeviceManager deviceManager,
|
||||||
|
IMediaSourceManager mediaSourceManager,
|
||||||
|
IJsonSerializer jsonSerializer,
|
||||||
|
IAuthorizationContext authorizationContext,
|
||||||
|
EncodingHelper encodingHelper)
|
||||||
|
: base(serverConfig,
|
||||||
|
userManager,
|
||||||
|
libraryManager,
|
||||||
|
isoManager,
|
||||||
|
mediaEncoder,
|
||||||
|
fileSystem,
|
||||||
|
dlnaManager,
|
||||||
|
deviceManager,
|
||||||
|
mediaSourceManager,
|
||||||
|
jsonSerializer,
|
||||||
|
authorizationContext,
|
||||||
|
encodingHelper)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the audio arguments.
|
/// Gets the audio arguments.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -313,33 +341,5 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BaseHlsService(
|
|
||||||
IServerConfigurationManager serverConfig,
|
|
||||||
IUserManager userManager,
|
|
||||||
ILibraryManager libraryManager,
|
|
||||||
IIsoManager isoManager,
|
|
||||||
IMediaEncoder mediaEncoder,
|
|
||||||
IFileSystem fileSystem,
|
|
||||||
IDlnaManager dlnaManager,
|
|
||||||
ISubtitleEncoder subtitleEncoder,
|
|
||||||
IDeviceManager deviceManager,
|
|
||||||
IMediaSourceManager mediaSourceManager,
|
|
||||||
IJsonSerializer jsonSerializer,
|
|
||||||
IAuthorizationContext authorizationContext)
|
|
||||||
: base(serverConfig,
|
|
||||||
userManager,
|
|
||||||
libraryManager,
|
|
||||||
isoManager,
|
|
||||||
mediaEncoder,
|
|
||||||
fileSystem,
|
|
||||||
dlnaManager,
|
|
||||||
subtitleEncoder,
|
|
||||||
deviceManager,
|
|
||||||
mediaSourceManager,
|
|
||||||
jsonSerializer,
|
|
||||||
authorizationContext)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,6 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
[Authenticated]
|
[Authenticated]
|
||||||
public class DynamicHlsService : BaseHlsService
|
public class DynamicHlsService : BaseHlsService
|
||||||
{
|
{
|
||||||
|
|
||||||
public DynamicHlsService(
|
public DynamicHlsService(
|
||||||
IServerConfigurationManager serverConfig,
|
IServerConfigurationManager serverConfig,
|
||||||
IUserManager userManager,
|
IUserManager userManager,
|
||||||
|
@ -103,12 +102,12 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
IMediaEncoder mediaEncoder,
|
IMediaEncoder mediaEncoder,
|
||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
IDlnaManager dlnaManager,
|
IDlnaManager dlnaManager,
|
||||||
ISubtitleEncoder subtitleEncoder,
|
|
||||||
IDeviceManager deviceManager,
|
IDeviceManager deviceManager,
|
||||||
IMediaSourceManager mediaSourceManager,
|
IMediaSourceManager mediaSourceManager,
|
||||||
IJsonSerializer jsonSerializer,
|
IJsonSerializer jsonSerializer,
|
||||||
IAuthorizationContext authorizationContext,
|
IAuthorizationContext authorizationContext,
|
||||||
INetworkManager networkManager)
|
INetworkManager networkManager,
|
||||||
|
EncodingHelper encodingHelper)
|
||||||
: base(serverConfig,
|
: base(serverConfig,
|
||||||
userManager,
|
userManager,
|
||||||
libraryManager,
|
libraryManager,
|
||||||
|
@ -116,11 +115,11 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
mediaEncoder,
|
mediaEncoder,
|
||||||
fileSystem,
|
fileSystem,
|
||||||
dlnaManager,
|
dlnaManager,
|
||||||
subtitleEncoder,
|
|
||||||
deviceManager,
|
deviceManager,
|
||||||
mediaSourceManager,
|
mediaSourceManager,
|
||||||
jsonSerializer,
|
jsonSerializer,
|
||||||
authorizationContext)
|
authorizationContext,
|
||||||
|
encodingHelper)
|
||||||
{
|
{
|
||||||
NetworkManager = networkManager;
|
NetworkManager = networkManager;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,34 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
[Authenticated]
|
[Authenticated]
|
||||||
public class VideoHlsService : BaseHlsService
|
public class VideoHlsService : BaseHlsService
|
||||||
{
|
{
|
||||||
|
public VideoHlsService(
|
||||||
|
IServerConfigurationManager serverConfig,
|
||||||
|
IUserManager userManager,
|
||||||
|
ILibraryManager libraryManager,
|
||||||
|
IIsoManager isoManager,
|
||||||
|
IMediaEncoder mediaEncoder,
|
||||||
|
IFileSystem fileSystem,
|
||||||
|
IDlnaManager dlnaManager,
|
||||||
|
IDeviceManager deviceManager,
|
||||||
|
IMediaSourceManager mediaSourceManager,
|
||||||
|
IJsonSerializer jsonSerializer,
|
||||||
|
IAuthorizationContext authorizationContext,
|
||||||
|
EncodingHelper encodingHelper)
|
||||||
|
: base(serverConfig,
|
||||||
|
userManager,
|
||||||
|
libraryManager,
|
||||||
|
isoManager,
|
||||||
|
mediaEncoder,
|
||||||
|
fileSystem,
|
||||||
|
dlnaManager,
|
||||||
|
deviceManager,
|
||||||
|
mediaSourceManager,
|
||||||
|
jsonSerializer,
|
||||||
|
authorizationContext,
|
||||||
|
encodingHelper)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public Task<object> Get(GetLiveHlsStream request)
|
public Task<object> Get(GetLiveHlsStream request)
|
||||||
{
|
{
|
||||||
return ProcessRequestAsync(request, true);
|
return ProcessRequestAsync(request, true);
|
||||||
|
@ -135,33 +163,5 @@ namespace MediaBrowser.Api.Playback.Hls
|
||||||
|
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
public VideoHlsService(
|
|
||||||
IServerConfigurationManager serverConfig,
|
|
||||||
IUserManager userManager,
|
|
||||||
ILibraryManager libraryManager,
|
|
||||||
IIsoManager isoManager,
|
|
||||||
IMediaEncoder mediaEncoder,
|
|
||||||
IFileSystem fileSystem,
|
|
||||||
IDlnaManager dlnaManager,
|
|
||||||
ISubtitleEncoder subtitleEncoder,
|
|
||||||
IDeviceManager deviceManager,
|
|
||||||
IMediaSourceManager mediaSourceManager,
|
|
||||||
IJsonSerializer jsonSerializer,
|
|
||||||
IAuthorizationContext authorizationContext)
|
|
||||||
: base(serverConfig,
|
|
||||||
userManager,
|
|
||||||
libraryManager,
|
|
||||||
isoManager,
|
|
||||||
mediaEncoder,
|
|
||||||
fileSystem,
|
|
||||||
dlnaManager,
|
|
||||||
subtitleEncoder,
|
|
||||||
deviceManager,
|
|
||||||
mediaSourceManager,
|
|
||||||
jsonSerializer,
|
|
||||||
authorizationContext)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,11 +40,11 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
IMediaEncoder mediaEncoder,
|
IMediaEncoder mediaEncoder,
|
||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
IDlnaManager dlnaManager,
|
IDlnaManager dlnaManager,
|
||||||
ISubtitleEncoder subtitleEncoder,
|
|
||||||
IDeviceManager deviceManager,
|
IDeviceManager deviceManager,
|
||||||
IMediaSourceManager mediaSourceManager,
|
IMediaSourceManager mediaSourceManager,
|
||||||
IJsonSerializer jsonSerializer,
|
IJsonSerializer jsonSerializer,
|
||||||
IAuthorizationContext authorizationContext)
|
IAuthorizationContext authorizationContext,
|
||||||
|
EncodingHelper encodingHelper)
|
||||||
: base(httpClient,
|
: base(httpClient,
|
||||||
serverConfig,
|
serverConfig,
|
||||||
userManager,
|
userManager,
|
||||||
|
@ -53,11 +53,11 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
mediaEncoder,
|
mediaEncoder,
|
||||||
fileSystem,
|
fileSystem,
|
||||||
dlnaManager,
|
dlnaManager,
|
||||||
subtitleEncoder,
|
|
||||||
deviceManager,
|
deviceManager,
|
||||||
mediaSourceManager,
|
mediaSourceManager,
|
||||||
jsonSerializer,
|
jsonSerializer,
|
||||||
authorizationContext)
|
authorizationContext,
|
||||||
|
encodingHelper)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,23 +35,24 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
IMediaEncoder mediaEncoder,
|
IMediaEncoder mediaEncoder,
|
||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
IDlnaManager dlnaManager,
|
IDlnaManager dlnaManager,
|
||||||
ISubtitleEncoder subtitleEncoder,
|
|
||||||
IDeviceManager deviceManager,
|
IDeviceManager deviceManager,
|
||||||
IMediaSourceManager mediaSourceManager,
|
IMediaSourceManager mediaSourceManager,
|
||||||
IJsonSerializer jsonSerializer,
|
IJsonSerializer jsonSerializer,
|
||||||
IAuthorizationContext authorizationContext)
|
IAuthorizationContext authorizationContext,
|
||||||
: base(serverConfig,
|
EncodingHelper encodingHelper)
|
||||||
|
: base(
|
||||||
|
serverConfig,
|
||||||
userManager,
|
userManager,
|
||||||
libraryManager,
|
libraryManager,
|
||||||
isoManager,
|
isoManager,
|
||||||
mediaEncoder,
|
mediaEncoder,
|
||||||
fileSystem,
|
fileSystem,
|
||||||
dlnaManager,
|
dlnaManager,
|
||||||
subtitleEncoder,
|
|
||||||
deviceManager,
|
deviceManager,
|
||||||
mediaSourceManager,
|
mediaSourceManager,
|
||||||
jsonSerializer,
|
jsonSerializer,
|
||||||
authorizationContext)
|
authorizationContext,
|
||||||
|
encodingHelper)
|
||||||
{
|
{
|
||||||
HttpClient = httpClient;
|
HttpClient = httpClient;
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,11 +77,11 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
IMediaEncoder mediaEncoder,
|
IMediaEncoder mediaEncoder,
|
||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
IDlnaManager dlnaManager,
|
IDlnaManager dlnaManager,
|
||||||
ISubtitleEncoder subtitleEncoder,
|
|
||||||
IDeviceManager deviceManager,
|
IDeviceManager deviceManager,
|
||||||
IMediaSourceManager mediaSourceManager,
|
IMediaSourceManager mediaSourceManager,
|
||||||
IJsonSerializer jsonSerializer,
|
IJsonSerializer jsonSerializer,
|
||||||
IAuthorizationContext authorizationContext)
|
IAuthorizationContext authorizationContext,
|
||||||
|
EncodingHelper encodingHelper)
|
||||||
: base(httpClient,
|
: base(httpClient,
|
||||||
serverConfig,
|
serverConfig,
|
||||||
userManager,
|
userManager,
|
||||||
|
@ -90,11 +90,11 @@ namespace MediaBrowser.Api.Playback.Progressive
|
||||||
mediaEncoder,
|
mediaEncoder,
|
||||||
fileSystem,
|
fileSystem,
|
||||||
dlnaManager,
|
dlnaManager,
|
||||||
subtitleEncoder,
|
|
||||||
deviceManager,
|
deviceManager,
|
||||||
mediaSourceManager,
|
mediaSourceManager,
|
||||||
jsonSerializer,
|
jsonSerializer,
|
||||||
authorizationContext)
|
authorizationContext,
|
||||||
|
encodingHelper)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ using MediaBrowser.Common.Net;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Devices;
|
using MediaBrowser.Controller.Devices;
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Drawing;
|
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.Controller.Net;
|
using MediaBrowser.Controller.Net;
|
||||||
|
@ -75,6 +74,9 @@ namespace MediaBrowser.Api.Playback
|
||||||
[Authenticated]
|
[Authenticated]
|
||||||
public class UniversalAudioService : BaseApiService
|
public class UniversalAudioService : BaseApiService
|
||||||
{
|
{
|
||||||
|
private readonly ILoggerFactory _loggerFactory;
|
||||||
|
private readonly EncodingHelper _encodingHelper;
|
||||||
|
|
||||||
public UniversalAudioService(
|
public UniversalAudioService(
|
||||||
IHttpClient httpClient,
|
IHttpClient httpClient,
|
||||||
IServerConfigurationManager serverConfigurationManager,
|
IServerConfigurationManager serverConfigurationManager,
|
||||||
|
@ -85,14 +87,12 @@ namespace MediaBrowser.Api.Playback
|
||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
IDlnaManager dlnaManager,
|
IDlnaManager dlnaManager,
|
||||||
IDeviceManager deviceManager,
|
IDeviceManager deviceManager,
|
||||||
ISubtitleEncoder subtitleEncoder,
|
|
||||||
IMediaSourceManager mediaSourceManager,
|
IMediaSourceManager mediaSourceManager,
|
||||||
IZipClient zipClient,
|
|
||||||
IJsonSerializer jsonSerializer,
|
IJsonSerializer jsonSerializer,
|
||||||
IAuthorizationContext authorizationContext,
|
IAuthorizationContext authorizationContext,
|
||||||
IImageProcessor imageProcessor,
|
|
||||||
INetworkManager networkManager,
|
INetworkManager networkManager,
|
||||||
ILoggerFactory loggerFactory)
|
ILoggerFactory loggerFactory,
|
||||||
|
EncodingHelper encodingHelper)
|
||||||
{
|
{
|
||||||
HttpClient = httpClient;
|
HttpClient = httpClient;
|
||||||
ServerConfigurationManager = serverConfigurationManager;
|
ServerConfigurationManager = serverConfigurationManager;
|
||||||
|
@ -103,15 +103,12 @@ namespace MediaBrowser.Api.Playback
|
||||||
FileSystem = fileSystem;
|
FileSystem = fileSystem;
|
||||||
DlnaManager = dlnaManager;
|
DlnaManager = dlnaManager;
|
||||||
DeviceManager = deviceManager;
|
DeviceManager = deviceManager;
|
||||||
SubtitleEncoder = subtitleEncoder;
|
|
||||||
MediaSourceManager = mediaSourceManager;
|
MediaSourceManager = mediaSourceManager;
|
||||||
ZipClient = zipClient;
|
|
||||||
JsonSerializer = jsonSerializer;
|
JsonSerializer = jsonSerializer;
|
||||||
AuthorizationContext = authorizationContext;
|
AuthorizationContext = authorizationContext;
|
||||||
ImageProcessor = imageProcessor;
|
|
||||||
NetworkManager = networkManager;
|
NetworkManager = networkManager;
|
||||||
_loggerFactory = loggerFactory;
|
_loggerFactory = loggerFactory;
|
||||||
_logger = loggerFactory.CreateLogger(nameof(UniversalAudioService));
|
_encodingHelper = encodingHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IHttpClient HttpClient { get; private set; }
|
protected IHttpClient HttpClient { get; private set; }
|
||||||
|
@ -123,15 +120,10 @@ namespace MediaBrowser.Api.Playback
|
||||||
protected IFileSystem FileSystem { get; private set; }
|
protected IFileSystem FileSystem { get; private set; }
|
||||||
protected IDlnaManager DlnaManager { get; private set; }
|
protected IDlnaManager DlnaManager { get; private set; }
|
||||||
protected IDeviceManager DeviceManager { get; private set; }
|
protected IDeviceManager DeviceManager { get; private set; }
|
||||||
protected ISubtitleEncoder SubtitleEncoder { get; private set; }
|
|
||||||
protected IMediaSourceManager MediaSourceManager { get; private set; }
|
protected IMediaSourceManager MediaSourceManager { get; private set; }
|
||||||
protected IZipClient ZipClient { get; private set; }
|
|
||||||
protected IJsonSerializer JsonSerializer { get; private set; }
|
protected IJsonSerializer JsonSerializer { get; private set; }
|
||||||
protected IAuthorizationContext AuthorizationContext { get; private set; }
|
protected IAuthorizationContext AuthorizationContext { get; private set; }
|
||||||
protected IImageProcessor ImageProcessor { get; private set; }
|
|
||||||
protected INetworkManager NetworkManager { get; private set; }
|
protected INetworkManager NetworkManager { get; private set; }
|
||||||
private ILoggerFactory _loggerFactory;
|
|
||||||
private ILogger _logger;
|
|
||||||
|
|
||||||
public Task<object> Get(GetUniversalAudioStream request)
|
public Task<object> Get(GetUniversalAudioStream request)
|
||||||
{
|
{
|
||||||
|
@ -242,7 +234,17 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
AuthorizationContext.GetAuthorizationInfo(Request).DeviceId = request.DeviceId;
|
AuthorizationContext.GetAuthorizationInfo(Request).DeviceId = request.DeviceId;
|
||||||
|
|
||||||
var mediaInfoService = new MediaInfoService(MediaSourceManager, DeviceManager, LibraryManager, ServerConfigurationManager, NetworkManager, MediaEncoder, UserManager, JsonSerializer, AuthorizationContext, _loggerFactory)
|
var mediaInfoService = new MediaInfoService(
|
||||||
|
MediaSourceManager,
|
||||||
|
DeviceManager,
|
||||||
|
LibraryManager,
|
||||||
|
ServerConfigurationManager,
|
||||||
|
NetworkManager,
|
||||||
|
MediaEncoder,
|
||||||
|
UserManager,
|
||||||
|
JsonSerializer,
|
||||||
|
AuthorizationContext,
|
||||||
|
_loggerFactory)
|
||||||
{
|
{
|
||||||
Request = Request
|
Request = Request
|
||||||
};
|
};
|
||||||
|
@ -276,19 +278,20 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
if (!isStatic && string.Equals(mediaSource.TranscodingSubProtocol, "hls", StringComparison.OrdinalIgnoreCase))
|
if (!isStatic && string.Equals(mediaSource.TranscodingSubProtocol, "hls", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var service = new DynamicHlsService(ServerConfigurationManager,
|
var service = new DynamicHlsService(
|
||||||
|
ServerConfigurationManager,
|
||||||
UserManager,
|
UserManager,
|
||||||
LibraryManager,
|
LibraryManager,
|
||||||
IsoManager,
|
IsoManager,
|
||||||
MediaEncoder,
|
MediaEncoder,
|
||||||
FileSystem,
|
FileSystem,
|
||||||
DlnaManager,
|
DlnaManager,
|
||||||
SubtitleEncoder,
|
|
||||||
DeviceManager,
|
DeviceManager,
|
||||||
MediaSourceManager,
|
MediaSourceManager,
|
||||||
JsonSerializer,
|
JsonSerializer,
|
||||||
AuthorizationContext,
|
AuthorizationContext,
|
||||||
NetworkManager)
|
NetworkManager,
|
||||||
|
_encodingHelper)
|
||||||
{
|
{
|
||||||
Request = Request
|
Request = Request
|
||||||
};
|
};
|
||||||
|
@ -330,11 +333,11 @@ namespace MediaBrowser.Api.Playback
|
||||||
MediaEncoder,
|
MediaEncoder,
|
||||||
FileSystem,
|
FileSystem,
|
||||||
DlnaManager,
|
DlnaManager,
|
||||||
SubtitleEncoder,
|
|
||||||
DeviceManager,
|
DeviceManager,
|
||||||
MediaSourceManager,
|
MediaSourceManager,
|
||||||
JsonSerializer,
|
JsonSerializer,
|
||||||
AuthorizationContext)
|
AuthorizationContext,
|
||||||
|
_encodingHelper)
|
||||||
{
|
{
|
||||||
Request = Request
|
Request = Request
|
||||||
};
|
};
|
||||||
|
|
|
@ -137,7 +137,7 @@ namespace MediaBrowser.Controller.Entities
|
||||||
/// <value>The video3 D format.</value>
|
/// <value>The video3 D format.</value>
|
||||||
public Video3DFormat? Video3DFormat { get; set; }
|
public Video3DFormat? Video3DFormat { get; set; }
|
||||||
|
|
||||||
public string[] GetPlayableStreamFileNames(IMediaEncoder mediaEncoder)
|
public string[] GetPlayableStreamFileNames()
|
||||||
{
|
{
|
||||||
var videoType = VideoType;
|
var videoType = VideoType;
|
||||||
|
|
||||||
|
@ -153,7 +153,8 @@ namespace MediaBrowser.Controller.Entities
|
||||||
{
|
{
|
||||||
return Array.Empty<string>();
|
return Array.Empty<string>();
|
||||||
}
|
}
|
||||||
return mediaEncoder.GetPlayableStreamFileNames(Path, videoType);
|
|
||||||
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace MediaBrowser.Controller.Extensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Configuration extensions for <c>MediaBrowser.Controller</c>.
|
||||||
|
/// </summary>
|
||||||
|
public static class ConfigurationExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The key for the FFmpeg probe size option.
|
||||||
|
/// </summary>
|
||||||
|
public const string FfmpegProbeSizeKey = "FFmpeg_probesize";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The key for the FFmpeg analyse duration option.
|
||||||
|
/// </summary>
|
||||||
|
public const string FfmpegAnalyzeDuration = "FFmpeg_analyzeduration";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the FFmpeg probe size from the <see cref="IConfiguration" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configuration">This configuration.</param>
|
||||||
|
/// <returns>The FFmpeg probe size option.</returns>
|
||||||
|
public static string GetProbeSize(this IConfiguration configuration)
|
||||||
|
=> configuration[FfmpegProbeSizeKey];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the FFmpeg analyse duration from the <see cref="IConfiguration" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configuration">This configuration.</param>
|
||||||
|
/// <returns>The FFmpeg analyse duration option.</returns>
|
||||||
|
public static string GetAnalyzeDuration(this IConfiguration configuration)
|
||||||
|
=> configuration[FfmpegAnalyzeDuration];
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,10 @@
|
||||||
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
<RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
||||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" />
|
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" />
|
||||||
|
|
|
@ -12,6 +12,7 @@ using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.MediaInfo;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.MediaEncoding
|
namespace MediaBrowser.Controller.MediaEncoding
|
||||||
{
|
{
|
||||||
|
@ -22,6 +23,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
private readonly IMediaEncoder _mediaEncoder;
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly ISubtitleEncoder _subtitleEncoder;
|
private readonly ISubtitleEncoder _subtitleEncoder;
|
||||||
|
private readonly IConfiguration _configuration;
|
||||||
|
|
||||||
private static readonly string[] _videoProfiles = new[]
|
private static readonly string[] _videoProfiles = new[]
|
||||||
{
|
{
|
||||||
|
@ -34,11 +36,16 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
"ConstrainedHigh"
|
"ConstrainedHigh"
|
||||||
};
|
};
|
||||||
|
|
||||||
public EncodingHelper(IMediaEncoder mediaEncoder, IFileSystem fileSystem, ISubtitleEncoder subtitleEncoder)
|
public EncodingHelper(
|
||||||
|
IMediaEncoder mediaEncoder,
|
||||||
|
IFileSystem fileSystem,
|
||||||
|
ISubtitleEncoder subtitleEncoder,
|
||||||
|
IConfiguration configuration)
|
||||||
{
|
{
|
||||||
_mediaEncoder = mediaEncoder;
|
_mediaEncoder = mediaEncoder;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
_subtitleEncoder = subtitleEncoder;
|
_subtitleEncoder = subtitleEncoder;
|
||||||
|
_configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetH264Encoder(EncodingJobInfo state, EncodingOptions encodingOptions)
|
public string GetH264Encoder(EncodingJobInfo state, EncodingOptions encodingOptions)
|
||||||
|
@ -172,7 +179,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetInputFormat(string container)
|
public static string GetInputFormat(string container)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(container))
|
if (string.IsNullOrEmpty(container))
|
||||||
{
|
{
|
||||||
|
@ -641,7 +648,11 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(state.SubtitleStream.Language))
|
if (!string.IsNullOrEmpty(state.SubtitleStream.Language))
|
||||||
{
|
{
|
||||||
var charenc = _subtitleEncoder.GetSubtitleFileCharacterSet(subtitlePath, state.SubtitleStream.Language, state.MediaSource.Protocol, CancellationToken.None).Result;
|
var charenc = _subtitleEncoder.GetSubtitleFileCharacterSet(
|
||||||
|
subtitlePath,
|
||||||
|
state.SubtitleStream.Language,
|
||||||
|
state.MediaSource.Protocol,
|
||||||
|
CancellationToken.None).GetAwaiter().GetResult();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(charenc))
|
if (!string.IsNullOrEmpty(charenc))
|
||||||
{
|
{
|
||||||
|
@ -1946,7 +1957,9 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
|
|
||||||
var output = string.Empty;
|
var output = string.Empty;
|
||||||
|
|
||||||
if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode)
|
if (state.SubtitleStream != null
|
||||||
|
&& state.SubtitleStream.IsTextSubtitleStream
|
||||||
|
&& state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode)
|
||||||
{
|
{
|
||||||
var subParam = GetTextSubtitleParam(state);
|
var subParam = GetTextSubtitleParam(state);
|
||||||
|
|
||||||
|
@ -2035,11 +2048,11 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetProbeSizeArgument(int numInputFiles)
|
public string GetProbeSizeArgument(int numInputFiles)
|
||||||
=> numInputFiles > 1 ? "-probesize 1G" : "";
|
=> numInputFiles > 1 ? "-probesize " + _configuration["FFmpeg:probesize"] : string.Empty;
|
||||||
|
|
||||||
public static string GetAnalyzeDurationArgument(int numInputFiles)
|
public string GetAnalyzeDurationArgument(int numInputFiles)
|
||||||
=> numInputFiles > 1 ? "-analyzeduration 200M" : "";
|
=> numInputFiles > 1 ? "-analyzeduration " + _configuration["FFmpeg:analyzeduration"] : string.Empty;
|
||||||
|
|
||||||
public string GetInputModifier(EncodingJobInfo state, EncodingOptions encodingOptions)
|
public string GetInputModifier(EncodingJobInfo state, EncodingOptions encodingOptions)
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,6 +15,9 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IMediaEncoder : ITranscoderSupport
|
public interface IMediaEncoder : ITranscoderSupport
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The location of the discovered FFmpeg tool.
|
||||||
|
/// </summary>
|
||||||
FFmpegLocation EncoderLocation { get; }
|
FFmpegLocation EncoderLocation { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -97,7 +100,6 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||||
void UpdateEncoderPath(string path, string pathType);
|
void UpdateEncoderPath(string path, string pathType);
|
||||||
bool SupportsEncoder(string encoder);
|
bool SupportsEncoder(string encoder);
|
||||||
|
|
||||||
string[] GetPlayableStreamFileNames(string path, VideoType videoType);
|
|
||||||
IEnumerable<string> GetPrimaryPlaylistVobFiles(string path, IIsoMount isoMount, uint? titleNumber);
|
IEnumerable<string> GetPrimaryPlaylistVobFiles(string path, IIsoMount isoMount, uint? titleNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,13 @@ using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
using MediaBrowser.Controller.Library;
|
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
using MediaBrowser.MediaEncoding.Probing;
|
using MediaBrowser.MediaEncoding.Probing;
|
||||||
using MediaBrowser.Model.Configuration;
|
using MediaBrowser.Model.Configuration;
|
||||||
|
@ -19,9 +19,9 @@ using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Globalization;
|
using MediaBrowser.Model.Globalization;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.MediaInfo;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
using MediaBrowser.Model.Serialization;
|
|
||||||
using MediaBrowser.Model.System;
|
using MediaBrowser.Model.System;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
namespace MediaBrowser.MediaEncoding.Encoder
|
namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
{
|
{
|
||||||
|
@ -31,55 +31,60 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
public class MediaEncoder : IMediaEncoder, IDisposable
|
public class MediaEncoder : IMediaEncoder, IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the encoder path.
|
/// The default image extraction timeout in milliseconds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The encoder path.</value>
|
internal const int DefaultImageExtractionTimeout = 5000;
|
||||||
public string EncoderPath => FFmpegPath;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The location of the discovered FFmpeg tool.
|
|
||||||
/// </summary>
|
|
||||||
public FFmpegLocation EncoderLocation { get; private set; }
|
|
||||||
|
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IJsonSerializer _jsonSerializer;
|
private readonly IServerConfigurationManager _configurationManager;
|
||||||
private string FFmpegPath;
|
private readonly IFileSystem _fileSystem;
|
||||||
private string FFprobePath;
|
|
||||||
protected readonly IServerConfigurationManager ConfigurationManager;
|
|
||||||
protected readonly IFileSystem FileSystem;
|
|
||||||
protected readonly Func<ISubtitleEncoder> SubtitleEncoder;
|
|
||||||
protected readonly Func<IMediaSourceManager> MediaSourceManager;
|
|
||||||
private readonly IProcessFactory _processFactory;
|
private readonly IProcessFactory _processFactory;
|
||||||
private readonly int DefaultImageExtractionTimeoutMs;
|
private readonly ILocalizationManager _localization;
|
||||||
private readonly string StartupOptionFFmpegPath;
|
private readonly Func<ISubtitleEncoder> _subtitleEncoder;
|
||||||
|
private readonly IConfiguration _configuration;
|
||||||
|
private readonly string _startupOptionFFmpegPath;
|
||||||
|
|
||||||
private readonly SemaphoreSlim _thumbnailResourcePool = new SemaphoreSlim(2, 2);
|
private readonly SemaphoreSlim _thumbnailResourcePool = new SemaphoreSlim(2, 2);
|
||||||
|
|
||||||
|
private readonly object _runningProcessesLock = new object();
|
||||||
private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>();
|
private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>();
|
||||||
private readonly ILocalizationManager _localization;
|
|
||||||
|
private EncodingHelper _encodingHelper;
|
||||||
|
|
||||||
|
private string _ffmpegPath;
|
||||||
|
private string _ffprobePath;
|
||||||
|
|
||||||
public MediaEncoder(
|
public MediaEncoder(
|
||||||
ILoggerFactory loggerFactory,
|
ILogger<MediaEncoder> logger,
|
||||||
IJsonSerializer jsonSerializer,
|
|
||||||
string startupOptionsFFmpegPath,
|
|
||||||
IServerConfigurationManager configurationManager,
|
IServerConfigurationManager configurationManager,
|
||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
Func<ISubtitleEncoder> subtitleEncoder,
|
|
||||||
Func<IMediaSourceManager> mediaSourceManager,
|
|
||||||
IProcessFactory processFactory,
|
IProcessFactory processFactory,
|
||||||
int defaultImageExtractionTimeoutMs,
|
ILocalizationManager localization,
|
||||||
ILocalizationManager localization)
|
Func<ISubtitleEncoder> subtitleEncoder,
|
||||||
|
IConfiguration configuration,
|
||||||
|
string startupOptionsFFmpegPath)
|
||||||
{
|
{
|
||||||
_logger = loggerFactory.CreateLogger(nameof(MediaEncoder));
|
_logger = logger;
|
||||||
_jsonSerializer = jsonSerializer;
|
_configurationManager = configurationManager;
|
||||||
StartupOptionFFmpegPath = startupOptionsFFmpegPath;
|
_fileSystem = fileSystem;
|
||||||
ConfigurationManager = configurationManager;
|
|
||||||
FileSystem = fileSystem;
|
|
||||||
SubtitleEncoder = subtitleEncoder;
|
|
||||||
_processFactory = processFactory;
|
_processFactory = processFactory;
|
||||||
DefaultImageExtractionTimeoutMs = defaultImageExtractionTimeoutMs;
|
|
||||||
_localization = localization;
|
_localization = localization;
|
||||||
|
_startupOptionFFmpegPath = startupOptionsFFmpegPath;
|
||||||
|
_subtitleEncoder = subtitleEncoder;
|
||||||
|
_configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private EncodingHelper EncodingHelper
|
||||||
|
=> LazyInitializer.EnsureInitialized(
|
||||||
|
ref _encodingHelper,
|
||||||
|
() => new EncodingHelper(this, _fileSystem, _subtitleEncoder(), _configuration));
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string EncoderPath => _ffmpegPath;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public FFmpegLocation EncoderLocation { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Run at startup or if the user removes a Custom path from transcode page.
|
/// Run at startup or if the user removes a Custom path from transcode page.
|
||||||
/// Sets global variables FFmpegPath.
|
/// Sets global variables FFmpegPath.
|
||||||
|
@ -88,39 +93,39 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
public void SetFFmpegPath()
|
public void SetFFmpegPath()
|
||||||
{
|
{
|
||||||
// 1) Custom path stored in config/encoding xml file under tag <EncoderAppPath> takes precedence
|
// 1) Custom path stored in config/encoding xml file under tag <EncoderAppPath> takes precedence
|
||||||
if (!ValidatePath(ConfigurationManager.GetConfiguration<EncodingOptions>("encoding").EncoderAppPath, FFmpegLocation.Custom))
|
if (!ValidatePath(_configurationManager.GetConfiguration<EncodingOptions>("encoding").EncoderAppPath, FFmpegLocation.Custom))
|
||||||
{
|
{
|
||||||
// 2) Check if the --ffmpeg CLI switch has been given
|
// 2) Check if the --ffmpeg CLI switch has been given
|
||||||
if (!ValidatePath(StartupOptionFFmpegPath, FFmpegLocation.SetByArgument))
|
if (!ValidatePath(_startupOptionFFmpegPath, FFmpegLocation.SetByArgument))
|
||||||
{
|
{
|
||||||
// 3) Search system $PATH environment variable for valid FFmpeg
|
// 3) Search system $PATH environment variable for valid FFmpeg
|
||||||
if (!ValidatePath(ExistsOnSystemPath("ffmpeg"), FFmpegLocation.System))
|
if (!ValidatePath(ExistsOnSystemPath("ffmpeg"), FFmpegLocation.System))
|
||||||
{
|
{
|
||||||
EncoderLocation = FFmpegLocation.NotFound;
|
EncoderLocation = FFmpegLocation.NotFound;
|
||||||
FFmpegPath = null;
|
_ffmpegPath = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the FFmpeg path to the config/encoding.xml file as <EncoderAppPathDisplay> so it appears in UI
|
// Write the FFmpeg path to the config/encoding.xml file as <EncoderAppPathDisplay> so it appears in UI
|
||||||
var config = ConfigurationManager.GetConfiguration<EncodingOptions>("encoding");
|
var config = _configurationManager.GetConfiguration<EncodingOptions>("encoding");
|
||||||
config.EncoderAppPathDisplay = FFmpegPath ?? string.Empty;
|
config.EncoderAppPathDisplay = _ffmpegPath ?? string.Empty;
|
||||||
ConfigurationManager.SaveConfiguration("encoding", config);
|
_configurationManager.SaveConfiguration("encoding", config);
|
||||||
|
|
||||||
// Only if mpeg path is set, try and set path to probe
|
// Only if mpeg path is set, try and set path to probe
|
||||||
if (FFmpegPath != null)
|
if (_ffmpegPath != null)
|
||||||
{
|
{
|
||||||
// Determine a probe path from the mpeg path
|
// Determine a probe path from the mpeg path
|
||||||
FFprobePath = Regex.Replace(FFmpegPath, @"[^\/\\]+?(\.[^\/\\\n.]+)?$", @"ffprobe$1");
|
_ffprobePath = Regex.Replace(_ffmpegPath, @"[^\/\\]+?(\.[^\/\\\n.]+)?$", @"ffprobe$1");
|
||||||
|
|
||||||
// Interrogate to understand what coders are supported
|
// Interrogate to understand what coders are supported
|
||||||
var validator = new EncoderValidator(_logger, FFmpegPath);
|
var validator = new EncoderValidator(_logger, _ffmpegPath);
|
||||||
|
|
||||||
SetAvailableDecoders(validator.GetDecoders());
|
SetAvailableDecoders(validator.GetDecoders());
|
||||||
SetAvailableEncoders(validator.GetEncoders());
|
SetAvailableEncoders(validator.GetEncoders());
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("FFmpeg: {0}: {1}", EncoderLocation, FFmpegPath ?? string.Empty);
|
_logger.LogInformation("FFmpeg: {0}: {1}", EncoderLocation, _ffmpegPath ?? string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -160,9 +165,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
// Write the new ffmpeg path to the xml as <EncoderAppPath>
|
// Write the new ffmpeg path to the xml as <EncoderAppPath>
|
||||||
// This ensures its not lost on next startup
|
// This ensures its not lost on next startup
|
||||||
var config = ConfigurationManager.GetConfiguration<EncodingOptions>("encoding");
|
var config = _configurationManager.GetConfiguration<EncodingOptions>("encoding");
|
||||||
config.EncoderAppPath = newPath;
|
config.EncoderAppPath = newPath;
|
||||||
ConfigurationManager.SaveConfiguration("encoding", config);
|
_configurationManager.SaveConfiguration("encoding", config);
|
||||||
|
|
||||||
// Trigger SetFFmpegPath so we validate the new path and setup probe path
|
// Trigger SetFFmpegPath so we validate the new path and setup probe path
|
||||||
SetFFmpegPath();
|
SetFFmpegPath();
|
||||||
|
@ -193,7 +198,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
// ToDo - Enable the ffmpeg validator. At the moment any version can be used.
|
// ToDo - Enable the ffmpeg validator. At the moment any version can be used.
|
||||||
rc = true;
|
rc = true;
|
||||||
|
|
||||||
FFmpegPath = path;
|
_ffmpegPath = path;
|
||||||
EncoderLocation = location;
|
EncoderLocation = location;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -209,7 +214,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var files = FileSystem.GetFilePaths(path);
|
var files = _fileSystem.GetFilePaths(path);
|
||||||
|
|
||||||
var excludeExtensions = new[] { ".c" };
|
var excludeExtensions = new[] { ".c" };
|
||||||
|
|
||||||
|
@ -304,7 +309,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
{
|
{
|
||||||
var extractChapters = request.MediaType == DlnaProfileType.Video && request.ExtractChapters;
|
var extractChapters = request.MediaType == DlnaProfileType.Video && request.ExtractChapters;
|
||||||
|
|
||||||
var inputFiles = MediaEncoderHelpers.GetInputArgument(FileSystem, request.MediaSource.Path, request.MountedIso, request.PlayableStreamFileNames);
|
var inputFiles = MediaEncoderHelpers.GetInputArgument(_fileSystem, request.MediaSource.Path, request.MountedIso, request.PlayableStreamFileNames);
|
||||||
|
|
||||||
var probeSize = EncodingHelper.GetProbeSizeArgument(inputFiles.Length);
|
var probeSize = EncodingHelper.GetProbeSizeArgument(inputFiles.Length);
|
||||||
string analyzeDuration;
|
string analyzeDuration;
|
||||||
|
@ -365,7 +370,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
// Must consume both or ffmpeg may hang due to deadlocks. See comments below.
|
// Must consume both or ffmpeg may hang due to deadlocks. See comments below.
|
||||||
RedirectStandardOutput = true,
|
RedirectStandardOutput = true,
|
||||||
|
|
||||||
FileName = FFprobePath,
|
FileName = _ffprobePath,
|
||||||
Arguments = args,
|
Arguments = args,
|
||||||
|
|
||||||
|
|
||||||
|
@ -383,7 +388,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
_logger.LogDebug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
|
_logger.LogDebug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var processWrapper = new ProcessWrapper(process, this, _logger))
|
using (var processWrapper = new ProcessWrapper(process, this))
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Starting ffprobe with args {Args}", args);
|
_logger.LogDebug("Starting ffprobe with args {Args}", args);
|
||||||
StartProcess(processWrapper);
|
StartProcess(processWrapper);
|
||||||
|
@ -391,7 +396,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
InternalMediaInfoResult result;
|
InternalMediaInfoResult result;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result = await _jsonSerializer.DeserializeFromStreamAsync<InternalMediaInfoResult>(
|
result = await JsonSerializer.DeserializeAsync<InternalMediaInfoResult>(
|
||||||
process.StandardOutput.BaseStream).ConfigureAwait(false);
|
process.StandardOutput.BaseStream).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
@ -423,7 +428,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ProbeResultNormalizer(_logger, FileSystem, _localization).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
|
return new ProbeResultNormalizer(_logger, _fileSystem, _localization).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,7 +491,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
throw new ArgumentNullException(nameof(inputPath));
|
throw new ArgumentNullException(nameof(inputPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
var tempExtractPath = Path.Combine(ConfigurationManager.ApplicationPaths.TempDirectory, Guid.NewGuid() + ".jpg");
|
var tempExtractPath = Path.Combine(_configurationManager.ApplicationPaths.TempDirectory, Guid.NewGuid() + ".jpg");
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(tempExtractPath));
|
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.
|
// 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.
|
||||||
|
@ -545,7 +550,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
args = string.Format("-ss {0} ", GetTimeParameter(offset.Value)) + args;
|
args = string.Format("-ss {0} ", GetTimeParameter(offset.Value)) + args;
|
||||||
}
|
}
|
||||||
|
|
||||||
var encodinghelper = new EncodingHelper(this, FileSystem, SubtitleEncoder());
|
|
||||||
if (videoStream != null)
|
if (videoStream != null)
|
||||||
{
|
{
|
||||||
/* fix
|
/* fix
|
||||||
|
@ -559,7 +563,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(container))
|
if (!string.IsNullOrWhiteSpace(container))
|
||||||
{
|
{
|
||||||
var inputFormat = encodinghelper.GetInputFormat(container);
|
var inputFormat = EncodingHelper.GetInputFormat(container);
|
||||||
if (!string.IsNullOrWhiteSpace(inputFormat))
|
if (!string.IsNullOrWhiteSpace(inputFormat))
|
||||||
{
|
{
|
||||||
args = "-f " + inputFormat + " " + args;
|
args = "-f " + inputFormat + " " + args;
|
||||||
|
@ -570,7 +574,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
{
|
{
|
||||||
CreateNoWindow = true,
|
CreateNoWindow = true,
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
FileName = FFmpegPath,
|
FileName = _ffmpegPath,
|
||||||
Arguments = args,
|
Arguments = args,
|
||||||
IsHidden = true,
|
IsHidden = true,
|
||||||
ErrorDialog = false,
|
ErrorDialog = false,
|
||||||
|
@ -579,7 +583,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
_logger.LogDebug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
|
_logger.LogDebug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
|
||||||
|
|
||||||
using (var processWrapper = new ProcessWrapper(process, this, _logger))
|
using (var processWrapper = new ProcessWrapper(process, this))
|
||||||
{
|
{
|
||||||
bool ranToCompletion;
|
bool ranToCompletion;
|
||||||
|
|
||||||
|
@ -588,10 +592,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
{
|
{
|
||||||
StartProcess(processWrapper);
|
StartProcess(processWrapper);
|
||||||
|
|
||||||
var timeoutMs = ConfigurationManager.Configuration.ImageExtractionTimeoutMs;
|
var timeoutMs = _configurationManager.Configuration.ImageExtractionTimeoutMs;
|
||||||
if (timeoutMs <= 0)
|
if (timeoutMs <= 0)
|
||||||
{
|
{
|
||||||
timeoutMs = DefaultImageExtractionTimeoutMs;
|
timeoutMs = DefaultImageExtractionTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
ranToCompletion = await process.WaitForExitAsync(timeoutMs).ConfigureAwait(false);
|
ranToCompletion = await process.WaitForExitAsync(timeoutMs).ConfigureAwait(false);
|
||||||
|
@ -607,7 +611,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
}
|
}
|
||||||
|
|
||||||
var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
|
var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
|
||||||
var file = FileSystem.GetFileInfo(tempExtractPath);
|
var file = _fileSystem.GetFileInfo(tempExtractPath);
|
||||||
|
|
||||||
if (exitCode == -1 || !file.Exists || file.Length == 0)
|
if (exitCode == -1 || !file.Exists || file.Length == 0)
|
||||||
{
|
{
|
||||||
|
@ -675,7 +679,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
args = analyzeDurationArgument + " " + args;
|
args = analyzeDurationArgument + " " + args;
|
||||||
}
|
}
|
||||||
|
|
||||||
var encodinghelper = new EncodingHelper(this, FileSystem, SubtitleEncoder());
|
|
||||||
if (videoStream != null)
|
if (videoStream != null)
|
||||||
{
|
{
|
||||||
/* fix
|
/* fix
|
||||||
|
@ -689,7 +692,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(container))
|
if (!string.IsNullOrWhiteSpace(container))
|
||||||
{
|
{
|
||||||
var inputFormat = encodinghelper.GetInputFormat(container);
|
var inputFormat = EncodingHelper.GetInputFormat(container);
|
||||||
if (!string.IsNullOrWhiteSpace(inputFormat))
|
if (!string.IsNullOrWhiteSpace(inputFormat))
|
||||||
{
|
{
|
||||||
args = "-f " + inputFormat + " " + args;
|
args = "-f " + inputFormat + " " + args;
|
||||||
|
@ -700,7 +703,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
{
|
{
|
||||||
CreateNoWindow = true,
|
CreateNoWindow = true,
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
FileName = FFmpegPath,
|
FileName = _ffmpegPath,
|
||||||
Arguments = args,
|
Arguments = args,
|
||||||
IsHidden = true,
|
IsHidden = true,
|
||||||
ErrorDialog = false,
|
ErrorDialog = false,
|
||||||
|
@ -713,7 +716,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
bool ranToCompletion = false;
|
bool ranToCompletion = false;
|
||||||
|
|
||||||
using (var processWrapper = new ProcessWrapper(process, this, _logger))
|
using (var processWrapper = new ProcessWrapper(process, this))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -736,10 +739,10 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
var jpegCount = FileSystem.GetFilePaths(targetDirectory)
|
var jpegCount = _fileSystem.GetFilePaths(targetDirectory)
|
||||||
.Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase));
|
.Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
isResponsive = (jpegCount > lastCount);
|
isResponsive = jpegCount > lastCount;
|
||||||
lastCount = jpegCount;
|
lastCount = jpegCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -770,7 +773,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
{
|
{
|
||||||
process.Process.Start();
|
process.Process.Start();
|
||||||
|
|
||||||
lock (_runningProcesses)
|
lock (_runningProcessesLock)
|
||||||
{
|
{
|
||||||
_runningProcesses.Add(process);
|
_runningProcesses.Add(process);
|
||||||
}
|
}
|
||||||
|
@ -804,7 +807,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
private void StopProcesses()
|
private void StopProcesses()
|
||||||
{
|
{
|
||||||
List<ProcessWrapper> proceses;
|
List<ProcessWrapper> proceses;
|
||||||
lock (_runningProcesses)
|
lock (_runningProcessesLock)
|
||||||
{
|
{
|
||||||
proceses = _runningProcesses.ToList();
|
proceses = _runningProcesses.ToList();
|
||||||
_runningProcesses.Clear();
|
_runningProcesses.Clear();
|
||||||
|
@ -827,12 +830,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
return path.Replace('\\', '/').Replace(":", "\\:").Replace("'", "'\\\\\\''");
|
return path.Replace('\\', '/').Replace(":", "\\:").Replace("'", "'\\\\\\''");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
|
||||||
/// </summary>
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -852,11 +854,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string[] GetPlayableStreamFileNames(string path, VideoType videoType)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<string> GetPrimaryPlaylistVobFiles(string path, IIsoMount isoMount, uint? titleNumber)
|
public IEnumerable<string> GetPrimaryPlaylistVobFiles(string path, IIsoMount isoMount, uint? titleNumber)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
@ -870,21 +867,24 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
private class ProcessWrapper : IDisposable
|
private class ProcessWrapper : IDisposable
|
||||||
{
|
{
|
||||||
public readonly IProcess Process;
|
|
||||||
public bool HasExited;
|
|
||||||
public int? ExitCode;
|
|
||||||
private readonly MediaEncoder _mediaEncoder;
|
private readonly MediaEncoder _mediaEncoder;
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
public ProcessWrapper(IProcess process, MediaEncoder mediaEncoder, ILogger logger)
|
private bool _disposed = false;
|
||||||
|
|
||||||
|
public ProcessWrapper(IProcess process, MediaEncoder mediaEncoder)
|
||||||
{
|
{
|
||||||
Process = process;
|
Process = process;
|
||||||
_mediaEncoder = mediaEncoder;
|
_mediaEncoder = mediaEncoder;
|
||||||
_logger = logger;
|
Process.Exited += OnProcessExited;
|
||||||
Process.Exited += Process_Exited;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Process_Exited(object sender, EventArgs e)
|
public IProcess Process { get; }
|
||||||
|
|
||||||
|
public bool HasExited { get; private set; }
|
||||||
|
|
||||||
|
public int? ExitCode { get; private set; }
|
||||||
|
|
||||||
|
void OnProcessExited(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
var process = (IProcess)sender;
|
var process = (IProcess)sender;
|
||||||
|
|
||||||
|
@ -903,7 +903,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
|
|
||||||
private void DisposeProcess(IProcess process)
|
private void DisposeProcess(IProcess process)
|
||||||
{
|
{
|
||||||
lock (_mediaEncoder._runningProcesses)
|
lock (_mediaEncoder._runningProcessesLock)
|
||||||
{
|
{
|
||||||
_mediaEncoder._runningProcesses.Remove(this);
|
_mediaEncoder._runningProcesses.Remove(this);
|
||||||
}
|
}
|
||||||
|
@ -917,17 +917,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool _disposed;
|
|
||||||
private readonly object _syncLock = new object();
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
|
||||||
lock (_syncLock)
|
|
||||||
{
|
{
|
||||||
if (!_disposed)
|
if (!_disposed)
|
||||||
{
|
{
|
||||||
if (Process != null)
|
if (Process != null)
|
||||||
{
|
{
|
||||||
Process.Exited -= Process_Exited;
|
Process.Exited -= OnProcessExited;
|
||||||
DisposeProcess(Process);
|
DisposeProcess(Process);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -937,4 +933,3 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ using MediaBrowser.Model.MediaInfo;
|
||||||
namespace MediaBrowser.MediaEncoding.Subtitles
|
namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interface ISubtitleWriter
|
/// Interface ISubtitleWriter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ISubtitleWriter
|
public interface ISubtitleWriter
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,27 +1,39 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using MediaBrowser.Model.MediaInfo;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
using MediaBrowser.Model.Serialization;
|
|
||||||
|
|
||||||
namespace MediaBrowser.MediaEncoding.Subtitles
|
namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// JSON subtitle writer.
|
||||||
|
/// </summary>
|
||||||
public class JsonWriter : ISubtitleWriter
|
public class JsonWriter : ISubtitleWriter
|
||||||
{
|
{
|
||||||
private readonly IJsonSerializer _json;
|
/// <inheritdoc />
|
||||||
|
|
||||||
public JsonWriter(IJsonSerializer json)
|
|
||||||
{
|
|
||||||
_json = json;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken)
|
public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
using (var writer = new Utf8JsonWriter(stream))
|
||||||
{
|
{
|
||||||
var json = _json.SerializeToString(info);
|
var trackevents = info.TrackEvents;
|
||||||
|
writer.WriteStartArray("TrackEvents");
|
||||||
|
|
||||||
writer.Write(json);
|
for (int i = 0; i < trackevents.Count; i++)
|
||||||
|
{
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
var current = trackevents[i];
|
||||||
|
writer.WriteStartObject();
|
||||||
|
|
||||||
|
writer.WriteString("Id", current.Id);
|
||||||
|
writer.WriteString("Text", current.Text);
|
||||||
|
writer.WriteNumber("StartPositionTicks", current.StartPositionTicks);
|
||||||
|
writer.WriteNumber("EndPositionTicks", current.EndPositionTicks);
|
||||||
|
|
||||||
|
writer.WriteEndObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteEndObject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,14 +14,19 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
{
|
{
|
||||||
using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
||||||
{
|
{
|
||||||
var index = 1;
|
var trackEvents = info.TrackEvents;
|
||||||
|
|
||||||
foreach (var trackEvent in info.TrackEvents)
|
for (int i = 0; i < trackEvents.Count; i++)
|
||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
writer.WriteLine(index.ToString(CultureInfo.InvariantCulture));
|
var trackEvent = trackEvents[i];
|
||||||
writer.WriteLine(@"{0:hh\:mm\:ss\,fff} --> {1:hh\:mm\:ss\,fff}", TimeSpan.FromTicks(trackEvent.StartPositionTicks), TimeSpan.FromTicks(trackEvent.EndPositionTicks));
|
|
||||||
|
writer.WriteLine((i + 1).ToString(CultureInfo.InvariantCulture));
|
||||||
|
writer.WriteLine(
|
||||||
|
@"{0:hh\:mm\:ss\,fff} --> {1:hh\:mm\:ss\,fff}",
|
||||||
|
TimeSpan.FromTicks(trackEvent.StartPositionTicks),
|
||||||
|
TimeSpan.FromTicks(trackEvent.EndPositionTicks));
|
||||||
|
|
||||||
var text = trackEvent.Text;
|
var text = trackEvent.Text;
|
||||||
|
|
||||||
|
@ -29,9 +34,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
text = Regex.Replace(text, @"\\n", " ", RegexOptions.IgnoreCase);
|
text = Regex.Replace(text, @"\\n", " ", RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
writer.WriteLine(text);
|
writer.WriteLine(text);
|
||||||
writer.WriteLine(string.Empty);
|
writer.WriteLine();
|
||||||
|
|
||||||
index++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.MediaInfo;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
using MediaBrowser.Model.Serialization;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using UtfUnknown;
|
using UtfUnknown;
|
||||||
|
|
||||||
|
@ -30,28 +29,25 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
private readonly IApplicationPaths _appPaths;
|
private readonly IApplicationPaths _appPaths;
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly IMediaEncoder _mediaEncoder;
|
private readonly IMediaEncoder _mediaEncoder;
|
||||||
private readonly IJsonSerializer _json;
|
|
||||||
private readonly IHttpClient _httpClient;
|
private readonly IHttpClient _httpClient;
|
||||||
private readonly IMediaSourceManager _mediaSourceManager;
|
private readonly IMediaSourceManager _mediaSourceManager;
|
||||||
private readonly IProcessFactory _processFactory;
|
private readonly IProcessFactory _processFactory;
|
||||||
|
|
||||||
public SubtitleEncoder(
|
public SubtitleEncoder(
|
||||||
ILibraryManager libraryManager,
|
ILibraryManager libraryManager,
|
||||||
ILoggerFactory loggerFactory,
|
ILogger<SubtitleEncoder> logger,
|
||||||
IApplicationPaths appPaths,
|
IApplicationPaths appPaths,
|
||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
IMediaEncoder mediaEncoder,
|
IMediaEncoder mediaEncoder,
|
||||||
IJsonSerializer json,
|
|
||||||
IHttpClient httpClient,
|
IHttpClient httpClient,
|
||||||
IMediaSourceManager mediaSourceManager,
|
IMediaSourceManager mediaSourceManager,
|
||||||
IProcessFactory processFactory)
|
IProcessFactory processFactory)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_logger = loggerFactory.CreateLogger(nameof(SubtitleEncoder));
|
_logger = logger;
|
||||||
_appPaths = appPaths;
|
_appPaths = appPaths;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
_mediaEncoder = mediaEncoder;
|
_mediaEncoder = mediaEncoder;
|
||||||
_json = json;
|
|
||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
_mediaSourceManager = mediaSourceManager;
|
_mediaSourceManager = mediaSourceManager;
|
||||||
_processFactory = processFactory;
|
_processFactory = processFactory;
|
||||||
|
@ -59,7 +55,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
|
|
||||||
private string SubtitleCachePath => Path.Combine(_appPaths.DataPath, "subtitles");
|
private string SubtitleCachePath => Path.Combine(_appPaths.DataPath, "subtitles");
|
||||||
|
|
||||||
private Stream ConvertSubtitles(Stream stream,
|
private Stream ConvertSubtitles(
|
||||||
|
Stream stream,
|
||||||
string inputFormat,
|
string inputFormat,
|
||||||
string outputFormat,
|
string outputFormat,
|
||||||
long startTimeTicks,
|
long startTimeTicks,
|
||||||
|
@ -170,7 +167,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
&& (mediaSource.VideoType.Value == VideoType.BluRay || mediaSource.VideoType.Value == VideoType.Dvd))
|
&& (mediaSource.VideoType.Value == VideoType.BluRay || mediaSource.VideoType.Value == VideoType.Dvd))
|
||||||
{
|
{
|
||||||
var mediaSourceItem = (Video)_libraryManager.GetItemById(new Guid(mediaSource.Id));
|
var mediaSourceItem = (Video)_libraryManager.GetItemById(new Guid(mediaSource.Id));
|
||||||
inputFiles = mediaSourceItem.GetPlayableStreamFileNames(_mediaEncoder);
|
inputFiles = mediaSourceItem.GetPlayableStreamFileNames();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -179,32 +176,27 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
|
|
||||||
var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource.Protocol, subtitleStream, cancellationToken).ConfigureAwait(false);
|
var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource.Protocol, subtitleStream, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
var stream = await GetSubtitleStream(fileInfo.Path, subtitleStream.Language, fileInfo.Protocol, fileInfo.IsExternal, cancellationToken).ConfigureAwait(false);
|
var stream = await GetSubtitleStream(fileInfo.Path, fileInfo.Protocol, fileInfo.IsExternal, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
return (stream, fileInfo.Format);
|
return (stream, fileInfo.Format);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Stream> GetSubtitleStream(string path, string language, MediaProtocol protocol, bool requiresCharset, CancellationToken cancellationToken)
|
private async Task<Stream> GetSubtitleStream(string path, MediaProtocol protocol, bool requiresCharset, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (requiresCharset)
|
if (requiresCharset)
|
||||||
{
|
{
|
||||||
var bytes = await GetBytes(path, protocol, cancellationToken).ConfigureAwait(false);
|
using (var stream = await GetStream(path, protocol, cancellationToken).ConfigureAwait(false))
|
||||||
|
|
||||||
var charset = CharsetDetector.DetectFromBytes(bytes).Detected?.EncodingName;
|
|
||||||
_logger.LogDebug("charset {CharSet} detected for {Path}", charset ?? "null", path);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(charset))
|
|
||||||
{
|
{
|
||||||
// Make sure we have all the code pages we can get
|
var result = CharsetDetector.DetectFromStream(stream).Detected;
|
||||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
|
||||||
using (var inputStream = new MemoryStream(bytes))
|
if (result != null)
|
||||||
using (var reader = new StreamReader(inputStream, Encoding.GetEncoding(charset)))
|
|
||||||
{
|
{
|
||||||
|
_logger.LogDebug("charset {CharSet} detected for {Path}", result.EncodingName, path);
|
||||||
|
|
||||||
|
using var reader = new StreamReader(stream, result.Encoding);
|
||||||
var text = await reader.ReadToEndAsync().ConfigureAwait(false);
|
var text = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
bytes = Encoding.UTF8.GetBytes(text);
|
return new MemoryStream(Encoding.UTF8.GetBytes(text));
|
||||||
|
|
||||||
return new MemoryStream(bytes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -323,7 +315,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
|
|
||||||
if (string.Equals(format, "json", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(format, "json", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return new JsonWriter(_json);
|
return new JsonWriter();
|
||||||
}
|
}
|
||||||
if (string.Equals(format, SubtitleFormat.SRT, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(format, SubtitleFormat.SRT, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
@ -544,7 +536,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
{
|
{
|
||||||
if (!File.Exists(outputPath))
|
if (!File.Exists(outputPath))
|
||||||
{
|
{
|
||||||
await ExtractTextSubtitleInternal(_mediaEncoder.GetInputArgument(inputFiles, protocol), subtitleStreamIndex, outputCodec, outputPath, cancellationToken).ConfigureAwait(false);
|
await ExtractTextSubtitleInternal(
|
||||||
|
_mediaEncoder.GetInputArgument(inputFiles, protocol),
|
||||||
|
subtitleStreamIndex,
|
||||||
|
outputCodec,
|
||||||
|
outputPath,
|
||||||
|
cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
@ -572,8 +569,13 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
|
Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
|
||||||
|
|
||||||
var processArgs = string.Format("-i {0} -map 0:{1} -an -vn -c:s {2} \"{3}\"", inputPath,
|
var processArgs = string.Format(
|
||||||
subtitleStreamIndex, outputCodec, outputPath);
|
CultureInfo.InvariantCulture,
|
||||||
|
"-i {0} -map 0:{1} -an -vn -c:s {2} \"{3}\"",
|
||||||
|
inputPath,
|
||||||
|
subtitleStreamIndex,
|
||||||
|
outputCodec,
|
||||||
|
outputPath);
|
||||||
|
|
||||||
var process = _processFactory.Create(new ProcessOptions
|
var process = _processFactory.Create(new ProcessOptions
|
||||||
{
|
{
|
||||||
|
@ -721,41 +723,38 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public async Task<string> GetSubtitleFileCharacterSet(string path, string language, MediaProtocol protocol, CancellationToken cancellationToken)
|
public async Task<string> GetSubtitleFileCharacterSet(string path, string language, MediaProtocol protocol, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var bytes = await GetBytes(path, protocol, cancellationToken).ConfigureAwait(false);
|
using (var stream = await GetStream(path, protocol, cancellationToken).ConfigureAwait(false))
|
||||||
|
{
|
||||||
var charset = CharsetDetector.DetectFromBytes(bytes).Detected?.EncodingName;
|
var charset = CharsetDetector.DetectFromStream(stream).Detected?.EncodingName;
|
||||||
|
|
||||||
_logger.LogDebug("charset {0} detected for {Path}", charset ?? "null", path);
|
_logger.LogDebug("charset {0} detected for {Path}", charset ?? "null", path);
|
||||||
|
|
||||||
return charset;
|
return charset;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<byte[]> GetBytes(string path, MediaProtocol protocol, CancellationToken cancellationToken)
|
private Task<Stream> GetStream(string path, MediaProtocol protocol, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (protocol == MediaProtocol.Http)
|
switch (protocol)
|
||||||
{
|
{
|
||||||
|
case MediaProtocol.Http:
|
||||||
var opts = new HttpRequestOptions()
|
var opts = new HttpRequestOptions()
|
||||||
{
|
{
|
||||||
Url = path,
|
Url = path,
|
||||||
CancellationToken = cancellationToken
|
CancellationToken = cancellationToken,
|
||||||
|
BufferContent = true
|
||||||
};
|
};
|
||||||
using (var file = await _httpClient.Get(opts).ConfigureAwait(false))
|
|
||||||
using (var memoryStream = new MemoryStream())
|
|
||||||
{
|
|
||||||
await file.CopyToAsync(memoryStream).ConfigureAwait(false);
|
|
||||||
memoryStream.Position = 0;
|
|
||||||
|
|
||||||
return memoryStream.ToArray();
|
return _httpClient.Get(opts);
|
||||||
}
|
|
||||||
}
|
|
||||||
if (protocol == MediaProtocol.File)
|
|
||||||
{
|
|
||||||
return File.ReadAllBytes(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
case MediaProtocol.File:
|
||||||
|
return Task.FromResult<Stream>(File.OpenRead(path));
|
||||||
|
default:
|
||||||
throw new ArgumentOutOfRangeException(nameof(protocol));
|
throw new ArgumentOutOfRangeException(nameof(protocol));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -49,12 +49,5 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
writer.WriteLine("</tt>");
|
writer.WriteLine("</tt>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string FormatTime(long ticks)
|
|
||||||
{
|
|
||||||
var time = TimeSpan.FromTicks(ticks);
|
|
||||||
|
|
||||||
return string.Format(@"{0:hh\:mm\:ss\,fff}", time);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,7 +231,6 @@ namespace MediaBrowser.Model.Configuration
|
||||||
LocalNetworkSubnets = Array.Empty<string>();
|
LocalNetworkSubnets = Array.Empty<string>();
|
||||||
LocalNetworkAddresses = Array.Empty<string>();
|
LocalNetworkAddresses = Array.Empty<string>();
|
||||||
CodecsUsed = Array.Empty<string>();
|
CodecsUsed = Array.Empty<string>();
|
||||||
ImageExtractionTimeoutMs = 0;
|
|
||||||
PathSubstitutions = Array.Empty<PathSubstitution>();
|
PathSubstitutions = Array.Empty<PathSubstitution>();
|
||||||
IgnoreVirtualInterfaces = false;
|
IgnoreVirtualInterfaces = false;
|
||||||
EnableSimpleArtistDetection = true;
|
EnableSimpleArtistDetection = true;
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.MediaInfo
|
namespace MediaBrowser.Model.MediaInfo
|
||||||
{
|
{
|
||||||
public class SubtitleTrackInfo
|
public class SubtitleTrackInfo
|
||||||
{
|
{
|
||||||
public SubtitleTrackEvent[] TrackEvents { get; set; }
|
public IReadOnlyList<SubtitleTrackEvent> TrackEvents { get; set; }
|
||||||
|
|
||||||
public SubtitleTrackInfo()
|
public SubtitleTrackInfo()
|
||||||
{
|
{
|
||||||
TrackEvents = new SubtitleTrackEvent[] { };
|
TrackEvents = Array.Empty<SubtitleTrackEvent>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,11 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||||
{
|
{
|
||||||
var protocol = item.PathProtocol ?? MediaProtocol.File;
|
var protocol = item.PathProtocol ?? MediaProtocol.File;
|
||||||
|
|
||||||
var inputPath = MediaEncoderHelpers.GetInputArgument(_fileSystem, item.Path, null, item.GetPlayableStreamFileNames(_mediaEncoder));
|
var inputPath = MediaEncoderHelpers.GetInputArgument(
|
||||||
|
_fileSystem,
|
||||||
|
item.Path,
|
||||||
|
null,
|
||||||
|
item.GetPlayableStreamFileNames());
|
||||||
|
|
||||||
var mediaStreams =
|
var mediaStreams =
|
||||||
item.GetMediaStreams();
|
item.GetMediaStreams();
|
||||||
|
|
|
@ -57,7 +57,7 @@ namespace MediaBrowser.Providers.Music
|
||||||
_appHost = appHost;
|
_appHost = appHost;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
_musicBrainzBaseUrl = configuration["MusicBrainz:BaseUrl"];
|
_musicBrainzBaseUrl = configuration["MusicBrainz_BaseUrl"];
|
||||||
|
|
||||||
// Use a stopwatch to ensure we don't exceed the MusicBrainz rate limit
|
// Use a stopwatch to ensure we don't exceed the MusicBrainz rate limit
|
||||||
_stopWatchMusicBrainz.Start();
|
_stopWatchMusicBrainz.Start();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue