diff options
Diffstat (limited to 'MediaBrowser.MediaEncoding')
8 files changed, 225 insertions, 2 deletions
diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 20d372d7a..d378c6e13 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -100,6 +100,7 @@ namespace MediaBrowser.MediaEncoding.Encoder "scale_vaapi", "deinterlace_vaapi", "tonemap_vaapi", + "procamp_vaapi", "overlay_vaapi", "hwupload_vaapi" }; diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index 92c9fc1a0..afe4ff4e7 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -30,7 +30,7 @@ <PackageReference Include="libse" Version="3.6.5" /> <PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" /> <PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" /> - <PackageReference Include="UTF.Unknown" Version="2.5.0" /> + <PackageReference Include="UTF.Unknown" Version="2.5.1" /> </ItemGroup> <!-- Code Analyzers--> diff --git a/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs b/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs index c9c8c34c2..eab8f79bb 100644 --- a/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs +++ b/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs @@ -310,5 +310,12 @@ namespace MediaBrowser.MediaEncoding.Probing /// <value>The color primaries.</value> [JsonPropertyName("color_primaries")] public string ColorPrimaries { get; set; } + + /// <summary> + /// Gets or sets the side_data_list. + /// </summary> + /// <value>The side_data_list.</value> + [JsonPropertyName("side_data_list")] + public IReadOnlyList<MediaStreamInfoSideData> SideDataList { get; set; } } } diff --git a/MediaBrowser.MediaEncoding/Probing/MediaStreamInfoSideData.cs b/MediaBrowser.MediaEncoding/Probing/MediaStreamInfoSideData.cs new file mode 100644 index 000000000..095757bef --- /dev/null +++ b/MediaBrowser.MediaEncoding/Probing/MediaStreamInfoSideData.cs @@ -0,0 +1,74 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace MediaBrowser.MediaEncoding.Probing +{ + /// <summary> + /// Class MediaStreamInfoSideData. + /// </summary> + public class MediaStreamInfoSideData + { + /// <summary> + /// Gets or sets the SideDataType. + /// </summary> + /// <value>The SideDataType.</value> + [JsonPropertyName("side_data_type")] + public string? SideDataType { get; set; } + + /// <summary> + /// Gets or sets the DvVersionMajor. + /// </summary> + /// <value>The DvVersionMajor.</value> + [JsonPropertyName("dv_version_major")] + public int? DvVersionMajor { get; set; } + + /// <summary> + /// Gets or sets the DvVersionMinor. + /// </summary> + /// <value>The DvVersionMinor.</value> + [JsonPropertyName("dv_version_minor")] + public int? DvVersionMinor { get; set; } + + /// <summary> + /// Gets or sets the DvProfile. + /// </summary> + /// <value>The DvProfile.</value> + [JsonPropertyName("dv_profile")] + public int? DvProfile { get; set; } + + /// <summary> + /// Gets or sets the DvLevel. + /// </summary> + /// <value>The DvLevel.</value> + [JsonPropertyName("dv_level")] + public int? DvLevel { get; set; } + + /// <summary> + /// Gets or sets the RpuPresentFlag. + /// </summary> + /// <value>The RpuPresentFlag.</value> + [JsonPropertyName("rpu_present_flag")] + public int? RpuPresentFlag { get; set; } + + /// <summary> + /// Gets or sets the ElPresentFlag. + /// </summary> + /// <value>The ElPresentFlag.</value> + [JsonPropertyName("el_present_flag")] + public int? ElPresentFlag { get; set; } + + /// <summary> + /// Gets or sets the BlPresentFlag. + /// </summary> + /// <value>The BlPresentFlag.</value> + [JsonPropertyName("bl_present_flag")] + public int? BlPresentFlag { get; set; } + + /// <summary> + /// Gets or sets the DvBlSignalCompatibilityId. + /// </summary> + /// <value>The DvBlSignalCompatibilityId.</value> + [JsonPropertyName("dv_bl_signal_compatibility_id")] + public int? DvBlSignalCompatibilityId { get; set; } + } +} diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 3f78d0d42..74d7341e9 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -841,6 +841,27 @@ namespace MediaBrowser.MediaEncoding.Probing { stream.ColorPrimaries = streamInfo.ColorPrimaries; } + + if (streamInfo.SideDataList != null) + { + foreach (var data in streamInfo.SideDataList) + { + // Parse Dolby Vision metadata from side_data + if (string.Equals(data.SideDataType, "DOVI configuration record", StringComparison.OrdinalIgnoreCase)) + { + stream.DvVersionMajor = data.DvVersionMajor; + stream.DvVersionMinor = data.DvVersionMinor; + stream.DvProfile = data.DvProfile; + stream.DvLevel = data.DvLevel; + stream.RpuPresentFlag = data.RpuPresentFlag; + stream.ElPresentFlag = data.ElPresentFlag; + stream.BlPresentFlag = data.BlPresentFlag; + stream.DvBlSignalCompatibilityId = data.DvBlSignalCompatibilityId; + + break; + } + } + } } else { diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/AssWriter.cs new file mode 100644 index 000000000..0d1cf6e25 --- /dev/null +++ b/MediaBrowser.MediaEncoding/Subtitles/AssWriter.cs @@ -0,0 +1,54 @@ +using System; +using System.Globalization; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using MediaBrowser.Model.MediaInfo; + +namespace MediaBrowser.MediaEncoding.Subtitles +{ + /// <summary> + /// ASS subtitle writer. + /// </summary> + public class AssWriter : ISubtitleWriter + { + /// <inheritdoc /> + public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken) + { + using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true)) + { + var trackEvents = info.TrackEvents; + var timeFormat = @"hh\:mm\:ss\.ff"; + + // Write ASS header + writer.WriteLine("[Script Info]"); + writer.WriteLine("Title: Jellyfin transcoded ASS subtitle"); + writer.WriteLine("ScriptType: v4.00+"); + writer.WriteLine(); + writer.WriteLine("[V4+ Styles]"); + writer.WriteLine("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding"); + writer.WriteLine("Style: Default,Arial,20,&H00FFFFFF,&H00FFFFFF,&H19333333,&H910E0807,0,0,0,0,100,100,0,0,0,1,0,2,10,10,10,1"); + writer.WriteLine(); + writer.WriteLine("[Events]"); + writer.WriteLine("Format: Layer, Start, End, Style, Text"); + + for (int i = 0; i < trackEvents.Count; i++) + { + cancellationToken.ThrowIfCancellationRequested(); + + var trackEvent = trackEvents[i]; + var startTime = TimeSpan.FromTicks(trackEvent.StartPositionTicks).ToString(timeFormat, CultureInfo.InvariantCulture); + var endTime = TimeSpan.FromTicks(trackEvent.EndPositionTicks).ToString(timeFormat, CultureInfo.InvariantCulture); + var text = Regex.Replace(trackEvent.Text, @"\n", "\\n", RegexOptions.IgnoreCase); + + writer.WriteLine( + "Dialogue: 0,{0},{1},Default,{2}", + startTime, + endTime, + text); + } + } + } + } +} diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaWriter.cs new file mode 100644 index 000000000..6761cd309 --- /dev/null +++ b/MediaBrowser.MediaEncoding/Subtitles/SsaWriter.cs @@ -0,0 +1,54 @@ +using System; +using System.Globalization; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using MediaBrowser.Model.MediaInfo; + +namespace MediaBrowser.MediaEncoding.Subtitles +{ + /// <summary> + /// SSA subtitle writer. + /// </summary> + public class SsaWriter : ISubtitleWriter + { + /// <inheritdoc /> + public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken) + { + using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true)) + { + var trackEvents = info.TrackEvents; + var timeFormat = @"hh\:mm\:ss\.ff"; + + // Write SSA header + writer.WriteLine("[Script Info]"); + writer.WriteLine("Title: Jellyfin transcoded SSA subtitle"); + writer.WriteLine("ScriptType: v4.00"); + writer.WriteLine(); + writer.WriteLine("[V4 Styles]"); + writer.WriteLine("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding"); + writer.WriteLine("Style: Default,Arial,20,&H00FFFFFF,&H00FFFFFF,&H19333333,&H19333333,0,0,0,1,0,2,10,10,10,0,1"); + writer.WriteLine(); + writer.WriteLine("[Events]"); + writer.WriteLine("Format: Layer, Start, End, Style, Text"); + + for (int i = 0; i < trackEvents.Count; i++) + { + cancellationToken.ThrowIfCancellationRequested(); + + var trackEvent = trackEvents[i]; + var startTime = TimeSpan.FromTicks(trackEvent.StartPositionTicks).ToString(timeFormat, CultureInfo.InvariantCulture); + var endTime = TimeSpan.FromTicks(trackEvent.EndPositionTicks).ToString(timeFormat, CultureInfo.InvariantCulture); + var text = Regex.Replace(trackEvent.Text, @"\n", "\\n", RegexOptions.IgnoreCase); + + writer.WriteLine( + "Dialogue: 0,{0},{1},Default,{2}", + startTime, + endTime, + text); + } + } + } + } +} diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 49bc2d775..7091af734 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -283,6 +283,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles private bool TryGetWriter(string format, [NotNullWhen(true)] out ISubtitleWriter? value) { + if (string.Equals(format, SubtitleFormat.ASS, StringComparison.OrdinalIgnoreCase)) + { + value = new AssWriter(); + return true; + } + if (string.IsNullOrEmpty(format)) { throw new ArgumentNullException(nameof(format)); @@ -294,12 +300,18 @@ namespace MediaBrowser.MediaEncoding.Subtitles return true; } - if (string.Equals(format, SubtitleFormat.SRT, StringComparison.OrdinalIgnoreCase)) + if (string.Equals(format, SubtitleFormat.SRT, StringComparison.OrdinalIgnoreCase) || string.Equals(format, SubtitleFormat.SUBRIP, StringComparison.OrdinalIgnoreCase)) { value = new SrtWriter(); return true; } + if (string.Equals(format, SubtitleFormat.SSA, StringComparison.OrdinalIgnoreCase)) + { + value = new SsaWriter(); + return true; + } + if (string.Equals(format, SubtitleFormat.VTT, StringComparison.OrdinalIgnoreCase)) { value = new VttWriter(); |
