mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-04-20 09:04:42 +01:00
Merge branch 'master' into update-plugin
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#pragma warning disable CS1591
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -63,6 +64,7 @@ namespace MediaBrowser.Controller.Drawing
|
||||
/// Create an image collage.
|
||||
/// </summary>
|
||||
/// <param name="options">The options to use when creating the collage.</param>
|
||||
void CreateImageCollage(ImageCollageOptions options);
|
||||
/// <param name="libraryName">Optional. </param>
|
||||
void CreateImageCollage(ImageCollageOptions options, string? libraryName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma warning disable CS1591
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -75,7 +76,7 @@ namespace MediaBrowser.Controller.Drawing
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task<(string path, string mimeType, DateTime dateModified)> ProcessImage(ImageProcessingOptions options);
|
||||
Task<(string path, string? mimeType, DateTime dateModified)> ProcessImage(ImageProcessingOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the supported image output formats.
|
||||
@@ -87,7 +88,8 @@ namespace MediaBrowser.Controller.Drawing
|
||||
/// Creates the image collage.
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
void CreateImageCollage(ImageCollageOptions options);
|
||||
/// <param name="libraryName">The library name to draw onto the collage.</param>
|
||||
void CreateImageCollage(ImageCollageOptions options, string? libraryName);
|
||||
|
||||
bool SupportsTransparency(string path);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
if (file.StartsWith("http", System.StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
item.SetImage(new ItemImageInfo
|
||||
item.SetImage(
|
||||
new ItemImageInfo
|
||||
{
|
||||
Path = file,
|
||||
Type = imageType
|
||||
|
||||
@@ -255,7 +255,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
var id = child.Id;
|
||||
if (dictionary.ContainsKey(id))
|
||||
{
|
||||
Logger.LogError("Found folder containing items with duplicate id. Path: {path}, Child Name: {ChildName}",
|
||||
Logger.LogError(
|
||||
"Found folder containing items with duplicate id. Path: {path}, Child Name: {ChildName}",
|
||||
Path ?? Name,
|
||||
child.Path ?? child.Name);
|
||||
}
|
||||
@@ -984,7 +985,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
return items;
|
||||
}
|
||||
|
||||
private static bool CollapseBoxSetItems(InternalItemsQuery query,
|
||||
private static bool CollapseBoxSetItems(
|
||||
InternalItemsQuery query,
|
||||
BaseItem queryParent,
|
||||
User user,
|
||||
IServerConfigurationManager configurationManager)
|
||||
@@ -1593,7 +1595,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <param name="datePlayed">The date played.</param>
|
||||
/// <param name="resetPosition">if set to <c>true</c> [reset position].</param>
|
||||
/// <returns>Task.</returns>
|
||||
public override void MarkPlayed(User user,
|
||||
public override void MarkPlayed(
|
||||
User user,
|
||||
DateTime? datePlayed,
|
||||
bool resetPosition)
|
||||
{
|
||||
|
||||
@@ -343,7 +343,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
var parentFolders = GetMediaFolders(parent, query.User, new[] { CollectionType.TvShows, string.Empty });
|
||||
|
||||
var result = _tvSeriesManager.GetNextUp(new NextUpQuery
|
||||
var result = _tvSeriesManager.GetNextUp(
|
||||
new NextUpQuery
|
||||
{
|
||||
Limit = query.Limit,
|
||||
StartIndex = query.StartIndex,
|
||||
@@ -443,7 +444,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
return Filter(item, query.User, query, BaseItem.UserDataManager, BaseItem.LibraryManager);
|
||||
}
|
||||
|
||||
public static QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items,
|
||||
public static QueryResult<BaseItem> PostFilterAndSort(
|
||||
IEnumerable<BaseItem> items,
|
||||
BaseItem queryParent,
|
||||
int? totalRecordLimit,
|
||||
InternalItemsQuery query,
|
||||
|
||||
@@ -566,7 +566,8 @@ namespace MediaBrowser.Controller.Library
|
||||
|
||||
int GetCount(InternalItemsQuery query);
|
||||
|
||||
void AddExternalSubtitleStreams(List<MediaStream> streams,
|
||||
void AddExternalSubtitleStreams(
|
||||
List<MediaStream> streams,
|
||||
string videoPath,
|
||||
string[] files);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -70,15 +70,15 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
var codecMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{"qsv", hwEncoder + "_qsv"},
|
||||
{hwEncoder + "_qsv", hwEncoder + "_qsv"},
|
||||
{"nvenc", hwEncoder + "_nvenc"},
|
||||
{"amf", hwEncoder + "_amf"},
|
||||
{"omx", hwEncoder + "_omx"},
|
||||
{hwEncoder + "_v4l2m2m", hwEncoder + "_v4l2m2m"},
|
||||
{"mediacodec", hwEncoder + "_mediacodec"},
|
||||
{"vaapi", hwEncoder + "_vaapi"},
|
||||
{"videotoolbox", hwEncoder + "_videotoolbox"}
|
||||
{ "qsv", hwEncoder + "_qsv" },
|
||||
{ hwEncoder + "_qsv", hwEncoder + "_qsv" },
|
||||
{ "nvenc", hwEncoder + "_nvenc" },
|
||||
{ "amf", hwEncoder + "_amf" },
|
||||
{ "omx", hwEncoder + "_omx" },
|
||||
{ hwEncoder + "_v4l2m2m", hwEncoder + "_v4l2m2m" },
|
||||
{ "mediacodec", hwEncoder + "_mediacodec" },
|
||||
{ "vaapi", hwEncoder + "_vaapi" },
|
||||
{ "videotoolbox", hwEncoder + "_videotoolbox" }
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(hwType)
|
||||
@@ -451,11 +451,13 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
var arg = new StringBuilder();
|
||||
var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions) ?? string.Empty;
|
||||
var outputVideoCodec = GetVideoEncoder(state, encodingOptions) ?? string.Empty;
|
||||
var isSwDecoder = string.IsNullOrEmpty(videoDecoder);
|
||||
var isD3d11vaDecoder = videoDecoder.IndexOf("d3d11va", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
var isVaapiEncoder = outputVideoCodec.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
var isQsvDecoder = videoDecoder.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
var isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
var isNvencHevcDecoder = videoDecoder.IndexOf("hevc_cuvid", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
var isNvdecHevcDecoder = videoDecoder.IndexOf("hevc_cuvid", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
|
||||
var isMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||
@@ -517,11 +519,12 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
|
||||
if (state.IsVideoRequest
|
||||
&& string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase))
|
||||
&& (string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && isNvdecHevcDecoder || isSwDecoder)
|
||||
|| (string.Equals(encodingOptions.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && isD3d11vaDecoder || isSwDecoder))
|
||||
{
|
||||
var isColorDepth10 = IsColorDepth10(state);
|
||||
|
||||
if (isNvencHevcDecoder && isColorDepth10
|
||||
if (isColorDepth10
|
||||
&& _mediaEncoder.SupportsHwaccel("opencl")
|
||||
&& encodingOptions.EnableTonemapping
|
||||
&& !string.IsNullOrEmpty(state.VideoStream.VideoRange)
|
||||
@@ -880,6 +883,19 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
param += "-quality speed";
|
||||
break;
|
||||
}
|
||||
|
||||
var videoStream = state.VideoStream;
|
||||
var isColorDepth10 = IsColorDepth10(state);
|
||||
|
||||
if (isColorDepth10
|
||||
&& _mediaEncoder.SupportsHwaccel("opencl")
|
||||
&& encodingOptions.EnableTonemapping
|
||||
&& !string.IsNullOrEmpty(videoStream.VideoRange)
|
||||
&& videoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Enhance workload when tone mapping with AMF on some APUs
|
||||
param += " -preanalysis true";
|
||||
}
|
||||
}
|
||||
else if (string.Equals(videoEncoder, "libvpx", StringComparison.OrdinalIgnoreCase)) // webm
|
||||
{
|
||||
@@ -1023,19 +1039,19 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
&& !string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(videoEncoder, "h264_amf", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param = "-pix_fmt yuv420p " + param;
|
||||
}
|
||||
|
||||
if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
|
||||
if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(videoEncoder, "h264_amf", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions) ?? string.Empty;
|
||||
var videoStream = state.VideoStream;
|
||||
var isColorDepth10 = IsColorDepth10(state);
|
||||
|
||||
if (videoDecoder.IndexOf("hevc_cuvid", StringComparison.OrdinalIgnoreCase) != -1
|
||||
&& isColorDepth10
|
||||
if (isColorDepth10
|
||||
&& _mediaEncoder.SupportsHwaccel("opencl")
|
||||
&& encodingOptions.EnableTonemapping
|
||||
&& !string.IsNullOrEmpty(videoStream.VideoRange)
|
||||
@@ -1651,47 +1667,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
var outputSizeParam = ReadOnlySpan<char>.Empty;
|
||||
var request = state.BaseRequest;
|
||||
|
||||
outputSizeParam = GetOutputSizeParam(state, options, outputVideoCodec).TrimEnd('"');
|
||||
|
||||
// All possible beginning of video filters
|
||||
// Don't break the order
|
||||
string[] beginOfOutputSizeParam = new[]
|
||||
{
|
||||
// for tonemap_opencl
|
||||
"hwupload,tonemap_opencl",
|
||||
|
||||
// hwupload=extra_hw_frames=64,vpp_qsv (for overlay_qsv on linux)
|
||||
"hwupload=extra_hw_frames",
|
||||
|
||||
// vpp_qsv
|
||||
"vpp",
|
||||
|
||||
// hwdownload,format=p010le (hardware decode + software encode for vaapi)
|
||||
"hwdownload",
|
||||
|
||||
// format=nv12|vaapi,hwupload,scale_vaapi
|
||||
"format",
|
||||
|
||||
// bwdif,scale=expr
|
||||
"bwdif",
|
||||
|
||||
// yadif,scale=expr
|
||||
"yadif",
|
||||
|
||||
// scale=expr
|
||||
"scale"
|
||||
};
|
||||
|
||||
var index = -1;
|
||||
foreach (var param in beginOfOutputSizeParam)
|
||||
{
|
||||
index = outputSizeParam.IndexOf(param, StringComparison.OrdinalIgnoreCase);
|
||||
if (index != -1)
|
||||
{
|
||||
outputSizeParam = outputSizeParam.Slice(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
outputSizeParam = GetOutputSizeParamInternal(state, options, outputVideoCodec);
|
||||
|
||||
var videoSizeParam = string.Empty;
|
||||
var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options) ?? string.Empty;
|
||||
@@ -1822,7 +1798,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
return (Convert.ToInt32(outputWidth), Convert.ToInt32(outputHeight));
|
||||
}
|
||||
|
||||
public List<string> GetScalingFilters(EncodingJobInfo state,
|
||||
public List<string> GetScalingFilters(
|
||||
EncodingJobInfo state,
|
||||
int? videoWidth,
|
||||
int? videoHeight,
|
||||
Video3DFormat? threedFormat,
|
||||
@@ -2082,10 +2059,19 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
return string.Format(CultureInfo.InvariantCulture, filter, widthParam, heightParam);
|
||||
}
|
||||
|
||||
public string GetOutputSizeParam(
|
||||
EncodingJobInfo state,
|
||||
EncodingOptions options,
|
||||
string outputVideoCodec)
|
||||
{
|
||||
string filters = GetOutputSizeParamInternal(state, options, outputVideoCodec);
|
||||
return string.IsNullOrEmpty(filters) ? string.Empty : " -vf \"" + filters + "\"";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If we're going to put a fixed size on the command line, this will calculate it.
|
||||
/// </summary>
|
||||
public string GetOutputSizeParam(
|
||||
public string GetOutputSizeParamInternal(
|
||||
EncodingJobInfo state,
|
||||
EncodingOptions options,
|
||||
string outputVideoCodec)
|
||||
@@ -2101,6 +2087,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
var inputHeight = videoStream?.Height;
|
||||
var threeDFormat = state.MediaSource.Video3DFormat;
|
||||
|
||||
var isSwDecoder = string.IsNullOrEmpty(videoDecoder);
|
||||
var isD3d11vaDecoder = videoDecoder.IndexOf("d3d11va", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
var isVaapiH264Encoder = outputVideoCodec.IndexOf("h264_vaapi", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
var isQsvH264Encoder = outputVideoCodec.IndexOf("h264_qsv", StringComparison.OrdinalIgnoreCase) != -1;
|
||||
@@ -2116,47 +2104,77 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
// If double rate deinterlacing is enabled and the input framerate is 30fps or below, otherwise the output framerate will be too high for many devices
|
||||
var doubleRateDeinterlace = options.DeinterlaceDoubleRate && (videoStream?.RealFrameRate ?? 60) <= 30;
|
||||
|
||||
// Currently only with the use of NVENC decoder can we get a decent performance.
|
||||
// Currently only the HEVC/H265 format is supported.
|
||||
// NVIDIA Pascal and Turing or higher are recommended.
|
||||
if (isNvdecHevcDecoder && isColorDepth10
|
||||
&& _mediaEncoder.SupportsHwaccel("opencl")
|
||||
&& options.EnableTonemapping
|
||||
&& !string.IsNullOrEmpty(videoStream.VideoRange)
|
||||
&& videoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase))
|
||||
var isScalingInAdvance = false;
|
||||
var isDeinterlaceH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true);
|
||||
var isDeinterlaceHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true);
|
||||
|
||||
if ((string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && isNvdecHevcDecoder || isSwDecoder)
|
||||
|| (string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && isD3d11vaDecoder || isSwDecoder))
|
||||
{
|
||||
var parameters = "tonemap_opencl=format=nv12:primaries=bt709:transfer=bt709:matrix=bt709:tonemap={0}:desat={1}:threshold={2}:peak={3}";
|
||||
|
||||
if (options.TonemappingParam != 0)
|
||||
// Currently only with the use of NVENC decoder can we get a decent performance.
|
||||
// Currently only the HEVC/H265 format is supported with NVDEC decoder.
|
||||
// NVIDIA Pascal and Turing or higher are recommended.
|
||||
// AMD Polaris and Vega or higher are recommended.
|
||||
if (isColorDepth10
|
||||
&& _mediaEncoder.SupportsHwaccel("opencl")
|
||||
&& options.EnableTonemapping
|
||||
&& !string.IsNullOrEmpty(videoStream.VideoRange)
|
||||
&& videoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
parameters += ":param={4}";
|
||||
}
|
||||
var parameters = "tonemap_opencl=format=nv12:primaries=bt709:transfer=bt709:matrix=bt709:tonemap={0}:desat={1}:threshold={2}:peak={3}";
|
||||
|
||||
if (!string.Equals(options.TonemappingRange, "auto", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
parameters += ":range={5}";
|
||||
}
|
||||
if (options.TonemappingParam != 0)
|
||||
{
|
||||
parameters += ":param={4}";
|
||||
}
|
||||
|
||||
// Upload the HDR10 or HLG data to the OpenCL device,
|
||||
// use tonemap_opencl filter for tone mapping,
|
||||
// and then download the SDR data to memory.
|
||||
filters.Add("hwupload");
|
||||
filters.Add(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
parameters,
|
||||
options.TonemappingAlgorithm,
|
||||
options.TonemappingDesat,
|
||||
options.TonemappingThreshold,
|
||||
options.TonemappingPeak,
|
||||
options.TonemappingParam,
|
||||
options.TonemappingRange));
|
||||
filters.Add("hwdownload");
|
||||
if (!string.Equals(options.TonemappingRange, "auto", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
parameters += ":range={5}";
|
||||
}
|
||||
|
||||
if (hasGraphicalSubs || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true)
|
||||
|| string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
filters.Add("format=nv12");
|
||||
if (isSwDecoder || isD3d11vaDecoder)
|
||||
{
|
||||
isScalingInAdvance = true;
|
||||
// Add zscale filter before tone mapping filter for performance.
|
||||
var (width, height) = GetFixedOutputSize(inputWidth, inputHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight);
|
||||
if (width.HasValue && height.HasValue)
|
||||
{
|
||||
filters.Add(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"zscale=s={0}x{1}",
|
||||
width.Value,
|
||||
height.Value));
|
||||
}
|
||||
|
||||
// Convert to hardware pixel format p010 when using SW decoder.
|
||||
filters.Add("format=p010");
|
||||
}
|
||||
|
||||
// Upload the HDR10 or HLG data to the OpenCL device,
|
||||
// use tonemap_opencl filter for tone mapping,
|
||||
// and then download the SDR data to memory.
|
||||
filters.Add("hwupload");
|
||||
filters.Add(
|
||||
string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
parameters,
|
||||
options.TonemappingAlgorithm,
|
||||
options.TonemappingDesat,
|
||||
options.TonemappingThreshold,
|
||||
options.TonemappingPeak,
|
||||
options.TonemappingParam,
|
||||
options.TonemappingRange));
|
||||
filters.Add("hwdownload");
|
||||
|
||||
if (isLibX264Encoder
|
||||
|| hasGraphicalSubs
|
||||
|| (isNvdecHevcDecoder && isDeinterlaceHevc)
|
||||
|| (!isNvdecHevcDecoder && isDeinterlaceH264 || isDeinterlaceHevc))
|
||||
{
|
||||
filters.Add("format=nv12");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2201,7 +2219,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
|
||||
// Add hardware deinterlace filter before scaling filter
|
||||
if (state.DeInterlace("h264", true) || state.DeInterlace("avc", true))
|
||||
if (isDeinterlaceH264)
|
||||
{
|
||||
if (isVaapiH264Encoder)
|
||||
{
|
||||
@@ -2214,10 +2232,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
|
||||
// Add software deinterlace filter before scaling filter
|
||||
if ((state.DeInterlace("h264", true)
|
||||
|| state.DeInterlace("avc", true)
|
||||
|| state.DeInterlace("h265", true)
|
||||
|| state.DeInterlace("hevc", true))
|
||||
if ((isDeinterlaceH264 || isDeinterlaceHevc)
|
||||
&& !isVaapiH264Encoder
|
||||
&& !isQsvH264Encoder
|
||||
&& !isNvdecH264Decoder)
|
||||
@@ -2241,7 +2256,21 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
|
||||
// Add scaling filter: scale_*=format=nv12 or scale_*=w=*:h=*:format=nv12 or scale=expr
|
||||
filters.AddRange(GetScalingFilters(state, inputWidth, inputHeight, threeDFormat, videoDecoder, outputVideoCodec, request.Width, request.Height, request.MaxWidth, request.MaxHeight));
|
||||
if (!isScalingInAdvance)
|
||||
{
|
||||
filters.AddRange(
|
||||
GetScalingFilters(
|
||||
state,
|
||||
inputWidth,
|
||||
inputHeight,
|
||||
threeDFormat,
|
||||
videoDecoder,
|
||||
outputVideoCodec,
|
||||
request.Width,
|
||||
request.Height,
|
||||
request.MaxWidth,
|
||||
request.MaxHeight));
|
||||
}
|
||||
|
||||
// Add parameters to use VAAPI with burn-in text subtitles (GH issue #642)
|
||||
if (isVaapiH264Encoder)
|
||||
@@ -2274,7 +2303,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
output += string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
" -vf \"{0}\"",
|
||||
"{0}",
|
||||
string.Join(",", filters));
|
||||
}
|
||||
|
||||
@@ -3067,21 +3096,31 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
var isWindows8orLater = Environment.OSVersion.Version.Major > 6 || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor > 1);
|
||||
var isDxvaSupported = _mediaEncoder.SupportsHwaccel("dxva2") || _mediaEncoder.SupportsHwaccel("d3d11va");
|
||||
|
||||
if ((isDxvaSupported || IsVaapiSupported(state)) && options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase))
|
||||
if (string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (isLinux)
|
||||
// Currently there is no AMF decoder on Linux, only have h264 encoder.
|
||||
if (isDxvaSupported && options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return "-hwaccel vaapi";
|
||||
}
|
||||
if (isWindows && isWindows8orLater)
|
||||
{
|
||||
return "-hwaccel d3d11va";
|
||||
}
|
||||
|
||||
if (isWindows && isWindows8orLater)
|
||||
{
|
||||
return "-hwaccel d3d11va";
|
||||
if (isWindows && !isWindows8orLater)
|
||||
{
|
||||
return "-hwaccel dxva2";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isWindows && !isWindows8orLater)
|
||||
if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (IsVaapiSupported(state) && options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
return "-hwaccel dxva2";
|
||||
if (isLinux)
|
||||
{
|
||||
return "-hwaccel vaapi";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -342,7 +342,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
var size = new ImageDimensions(VideoStream.Width.Value, VideoStream.Height.Value);
|
||||
|
||||
var newSize = DrawingUtils.Resize(size,
|
||||
var newSize = DrawingUtils.Resize(
|
||||
size,
|
||||
BaseRequest.Width ?? 0,
|
||||
BaseRequest.Height ?? 0,
|
||||
BaseRequest.MaxWidth ?? 0,
|
||||
@@ -368,7 +369,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
var size = new ImageDimensions(VideoStream.Width.Value, VideoStream.Height.Value);
|
||||
|
||||
var newSize = DrawingUtils.Resize(size,
|
||||
var newSize = DrawingUtils.Resize(
|
||||
size,
|
||||
BaseRequest.Width ?? 0,
|
||||
BaseRequest.Height ?? 0,
|
||||
BaseRequest.MaxWidth ?? 0,
|
||||
|
||||
@@ -68,7 +68,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
/// <summary>
|
||||
/// Extracts the video images on interval.
|
||||
/// </summary>
|
||||
Task ExtractVideoImagesOnInterval(string[] inputFiles,
|
||||
Task ExtractVideoImagesOnInterval(
|
||||
string[] inputFiles,
|
||||
string container,
|
||||
MediaStream videoStream,
|
||||
MediaProtocol protocol,
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.Net.WebSockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.Session;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Controller.Net
|
||||
@@ -28,10 +29,22 @@ namespace MediaBrowser.Controller.Net
|
||||
new List<Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// Gets the type used for the messages sent to the client.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
protected abstract string Name { get; }
|
||||
/// <value>The type.</value>
|
||||
protected abstract SessionMessageType Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the message type received from the client to start sending messages.
|
||||
/// </summary>
|
||||
/// <value>The type.</value>
|
||||
protected abstract SessionMessageType StartType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the message type received from the client to stop sending messages.
|
||||
/// </summary>
|
||||
/// <value>The type.</value>
|
||||
protected abstract SessionMessageType StopType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the data to send.
|
||||
@@ -66,12 +79,12 @@ namespace MediaBrowser.Controller.Net
|
||||
throw new ArgumentNullException(nameof(message));
|
||||
}
|
||||
|
||||
if (string.Equals(message.MessageType, Name + "Start", StringComparison.OrdinalIgnoreCase))
|
||||
if (message.MessageType == StartType)
|
||||
{
|
||||
Start(message);
|
||||
}
|
||||
|
||||
if (string.Equals(message.MessageType, Name + "Stop", StringComparison.OrdinalIgnoreCase))
|
||||
if (message.MessageType == StopType)
|
||||
{
|
||||
Stop(message);
|
||||
}
|
||||
@@ -159,7 +172,7 @@ namespace MediaBrowser.Controller.Net
|
||||
new WebSocketMessage<TReturnDataType>
|
||||
{
|
||||
MessageId = Guid.NewGuid(),
|
||||
MessageType = Name,
|
||||
MessageType = Type,
|
||||
Data = data
|
||||
},
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
@@ -176,7 +189,7 @@ namespace MediaBrowser.Controller.Net
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "Error sending web socket message {Name}", Name);
|
||||
Logger.LogError(ex, "Error sending web socket message {Name}", Type);
|
||||
DisposeConnection(tuple);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,12 +16,6 @@ namespace MediaBrowser.Controller.Net
|
||||
/// </summary>
|
||||
event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected;
|
||||
|
||||
/// <summary>
|
||||
/// Inits this instance.
|
||||
/// </summary>
|
||||
/// <param name="listeners">The websocket listeners.</param>
|
||||
void Init(IEnumerable<IWebSocketListener> listeners);
|
||||
|
||||
/// <summary>
|
||||
/// The HTTP request handler.
|
||||
/// </summary>
|
||||
|
||||
@@ -29,7 +29,8 @@ namespace MediaBrowser.Controller.Resolvers
|
||||
|
||||
public interface IMultiItemResolver
|
||||
{
|
||||
MultiItemResolverResult ResolveMultiple(Folder parent,
|
||||
MultiItemResolverResult ResolveMultiple(
|
||||
Folder parent,
|
||||
List<FileSystemMetadata> files,
|
||||
string collectionType,
|
||||
IDirectoryService directoryService);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Session;
|
||||
|
||||
namespace MediaBrowser.Controller.Session
|
||||
{
|
||||
@@ -23,6 +24,6 @@ namespace MediaBrowser.Controller.Session
|
||||
/// <summary>
|
||||
/// Sends the message.
|
||||
/// </summary>
|
||||
Task SendMessage<T>(string name, Guid messageId, T data, CancellationToken cancellationToken);
|
||||
Task SendMessage<T>(SessionMessageType name, Guid messageId, T data, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,16 +188,16 @@ namespace MediaBrowser.Controller.Session
|
||||
/// <param name="data">The data.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task SendMessageToAdminSessions<T>(string name, T data, CancellationToken cancellationToken);
|
||||
Task SendMessageToAdminSessions<T>(SessionMessageType name, T data, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Sends the message to user sessions.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <returns>Task.</returns>
|
||||
Task SendMessageToUserSessions<T>(List<Guid> userIds, string name, T data, CancellationToken cancellationToken);
|
||||
Task SendMessageToUserSessions<T>(List<Guid> userIds, SessionMessageType name, T data, CancellationToken cancellationToken);
|
||||
|
||||
Task SendMessageToUserSessions<T>(List<Guid> userIds, string name, Func<T> dataFn, CancellationToken cancellationToken);
|
||||
Task SendMessageToUserSessions<T>(List<Guid> userIds, SessionMessageType name, Func<T> dataFn, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Sends the message to user device sessions.
|
||||
@@ -208,7 +208,7 @@ namespace MediaBrowser.Controller.Session
|
||||
/// <param name="data">The data.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task SendMessageToUserDeviceSessions<T>(string deviceId, string name, T data, CancellationToken cancellationToken);
|
||||
Task SendMessageToUserDeviceSessions<T>(string deviceId, SessionMessageType name, T data, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Sends the restart required message.
|
||||
|
||||
@@ -230,8 +230,8 @@ namespace MediaBrowser.Controller.Session
|
||||
/// Gets or sets the supported commands.
|
||||
/// </summary>
|
||||
/// <value>The supported commands.</value>
|
||||
public string[] SupportedCommands
|
||||
=> Capabilities == null ? Array.Empty<string>() : Capabilities.SupportedCommands;
|
||||
public GeneralCommandType[] SupportedCommands
|
||||
=> Capabilities == null ? Array.Empty<GeneralCommandType>() : Capabilities.SupportedCommands;
|
||||
|
||||
public Tuple<ISessionController, bool> EnsureController<T>(Func<SessionInfo, ISessionController> factory)
|
||||
{
|
||||
|
||||
@@ -14,12 +14,12 @@ namespace MediaBrowser.Controller.SyncPlay
|
||||
public class GroupInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the default ping value used for sessions.
|
||||
/// The default ping value used for sessions.
|
||||
/// </summary>
|
||||
public long DefaultPing { get; } = 500;
|
||||
public const long DefaultPing = 500;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the group identifier.
|
||||
/// Gets the group identifier.
|
||||
/// </summary>
|
||||
/// <value>The group identifier.</value>
|
||||
public Guid GroupId { get; } = Guid.NewGuid();
|
||||
@@ -58,7 +58,8 @@ namespace MediaBrowser.Controller.SyncPlay
|
||||
/// <summary>
|
||||
/// Checks if a session is in this group.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if the session is in this group; <c>false</c> otherwise.</value>
|
||||
/// <param name="sessionId">The session id to check.</param>
|
||||
/// <returns><c>true</c> if the session is in this group; <c>false</c> otherwise.</returns>
|
||||
public bool ContainsSession(string sessionId)
|
||||
{
|
||||
return Participants.ContainsKey(sessionId);
|
||||
@@ -70,16 +71,14 @@ namespace MediaBrowser.Controller.SyncPlay
|
||||
/// <param name="session">The session.</param>
|
||||
public void AddSession(SessionInfo session)
|
||||
{
|
||||
if (ContainsSession(session.Id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var member = new GroupMember();
|
||||
member.Session = session;
|
||||
member.Ping = DefaultPing;
|
||||
member.IsBuffering = false;
|
||||
Participants[session.Id] = member;
|
||||
Participants.TryAdd(
|
||||
session.Id,
|
||||
new GroupMember
|
||||
{
|
||||
Session = session,
|
||||
Ping = DefaultPing,
|
||||
IsBuffering = false
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -88,12 +87,7 @@ namespace MediaBrowser.Controller.SyncPlay
|
||||
/// <param name="session">The session.</param>
|
||||
public void RemoveSession(SessionInfo session)
|
||||
{
|
||||
if (!ContainsSession(session.Id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Participants.Remove(session.Id, out _);
|
||||
Participants.Remove(session.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -103,18 +97,16 @@ namespace MediaBrowser.Controller.SyncPlay
|
||||
/// <param name="ping">The ping.</param>
|
||||
public void UpdatePing(SessionInfo session, long ping)
|
||||
{
|
||||
if (!ContainsSession(session.Id))
|
||||
if (Participants.TryGetValue(session.Id, out GroupMember value))
|
||||
{
|
||||
return;
|
||||
value.Ping = ping;
|
||||
}
|
||||
|
||||
Participants[session.Id].Ping = ping;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the highest ping in the group.
|
||||
/// </summary>
|
||||
/// <value name="session">The highest ping in the group.</value>
|
||||
/// <returns>The highest ping in the group.</returns>
|
||||
public long GetHighestPing()
|
||||
{
|
||||
long max = long.MinValue;
|
||||
@@ -133,18 +125,16 @@ namespace MediaBrowser.Controller.SyncPlay
|
||||
/// <param name="isBuffering">The state.</param>
|
||||
public void SetBuffering(SessionInfo session, bool isBuffering)
|
||||
{
|
||||
if (!ContainsSession(session.Id))
|
||||
if (Participants.TryGetValue(session.Id, out GroupMember value))
|
||||
{
|
||||
return;
|
||||
value.IsBuffering = isBuffering;
|
||||
}
|
||||
|
||||
Participants[session.Id].IsBuffering = isBuffering;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the group buffering state.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if there is a session buffering in the group; <c>false</c> otherwise.</value>
|
||||
/// <returns><c>true</c> if there is a session buffering in the group; <c>false</c> otherwise.</returns>
|
||||
public bool IsBuffering()
|
||||
{
|
||||
foreach (var session in Participants.Values)
|
||||
@@ -161,7 +151,7 @@ namespace MediaBrowser.Controller.SyncPlay
|
||||
/// <summary>
|
||||
/// Checks if the group is empty.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if the group is empty; <c>false</c> otherwise.</value>
|
||||
/// <returns><c>true</c> if the group is empty; <c>false</c> otherwise.</returns>
|
||||
public bool IsEmpty()
|
||||
{
|
||||
return Participants.Count == 0;
|
||||
|
||||
Reference in New Issue
Block a user