From e7217c5bc7a755234924c2297fe40b4e1617c674 Mon Sep 17 00:00:00 2001 From: Arthur Yousif Date: Sat, 8 Mar 2025 15:45:04 -0600 Subject: [PATCH] Added support for multiple windows in a WDS based on the spec def at https://blog.thescorpius.com/index.php/2017/07/15/presentation-graphic-stream-sup-files-bluray-subtitle-format/ --- libsup/WindowDefinition.cs | 85 +++++++++++++++++++++++++++++++ libsup/WindowDefinitionSegment.cs | 67 +++++++----------------- 2 files changed, 104 insertions(+), 48 deletions(-) create mode 100644 libsup/WindowDefinition.cs diff --git a/libsup/WindowDefinition.cs b/libsup/WindowDefinition.cs new file mode 100644 index 0000000..5718b7d --- /dev/null +++ b/libsup/WindowDefinition.cs @@ -0,0 +1,85 @@ +using JetBrains.Annotations; +using System; +using System.IO; + +namespace libsup +{ + /// + /// A window + /// + [PublicAPI] + public sealed class WindowDefinition + { + /// + /// Gets the window identifier. + /// + /// + /// The window identifier. + /// + public byte WindowId { get; } + /// + /// Gets the window horizontal position. + /// + /// + /// The window horizontal position. + /// + public ushort WindowHorizontalPosition { get; } + /// + /// Gets the window vertical position. + /// + /// + /// The window vertical position. + /// + public ushort WindowVerticalPosition { get; } + /// + /// Gets the width of the window. + /// + /// + /// The width of the window. + /// + public ushort WindowWidth { get; } + /// + /// Gets the height of the window. + /// + /// + /// The height of the window. + /// + public ushort WindowHeight { get; } + /// + /// Initializes a new instance of the class. + /// + internal WindowDefinition() + { + // do nothing + } + internal WindowDefinition(byte[] bytes) + { + // Check for invalid amount of bytes in the given byte collection. + if (bytes.Length != 9) + { + throw new InvalidDataException( + "The given byte array has an invalid amount of data and cannot be parsed as a window item!"); + } + + // Map the byte values in the given collection to their corresponding properties. + WindowId = bytes[0]; + + var horizpos = bytes.Slice(1, 2); + var vertipos = bytes.Slice(3, 2); + var width = bytes.Slice(5, 2); + var height = bytes.Slice(7, 2); + + if (!BitConverter.IsLittleEndian) + { + Array.Reverse(horizpos); + Array.Reverse(vertipos); + Array.Reverse(width); + Array.Reverse(height); + } + WindowHorizontalPosition = BitConverter.ToUInt16(horizpos, 0); + WindowVerticalPosition = BitConverter.ToUInt16(vertipos, 0); + WindowWidth = BitConverter.ToUInt16(width, 0); + WindowHeight = BitConverter.ToUInt16(height, 0); + } + } +} diff --git a/libsup/WindowDefinitionSegment.cs b/libsup/WindowDefinitionSegment.cs index a849fa8..bbb71d1 100644 --- a/libsup/WindowDefinitionSegment.cs +++ b/libsup/WindowDefinitionSegment.cs @@ -1,6 +1,6 @@ -using System; +using JetBrains.Annotations; +using System.Collections.Immutable; using System.IO; -using JetBrains.Annotations; namespace libsup { @@ -19,30 +19,19 @@ public sealed class WindowDefinitionSegment : SegmentDetail public override SegmentType SegmentType => SegmentType.WDS; /// - /// ID of this window. + /// Number of windows defined in this segment. Added support for multiple + /// windows based on the PGS spec. available here: + /// https://blog.thescorpius.com/index.php/2017/07/15/presentation-graphic-stream-sup-files-bluray-subtitle-format/ /// - public byte WindowId { get; } + public byte NumberOfWindows { get; internal set; } = 1; /// - /// X offset from the top left pixel of the window in the screen. + /// Gets the windows. /// - public ushort WindowHorizontalPosition { get; } - - /// - /// Y offset from the top left pixel of the window in the screen. - /// - public ushort WindowVerticalPosition { get; } - - /// - /// Width of the window. - /// - public ushort WindowWidth { get; } - - /// - /// Height of the window. - /// - public ushort WindowHeight { get; } - + /// + /// The windows. + /// + public ImmutableList Windows { get; } /// public override object Clone() { @@ -50,16 +39,13 @@ public override object Clone() } /// - /// Create a clone of an existing . + /// Initializes a new instance of the class. /// - /// The original . + /// The old. private WindowDefinitionSegment(WindowDefinitionSegment old) { - WindowId = old.WindowId; - WindowHorizontalPosition = old.WindowHorizontalPosition; - WindowVerticalPosition = old.WindowVerticalPosition; - WindowWidth = old.WindowWidth; - WindowHeight = old.WindowHeight; + NumberOfWindows = old.NumberOfWindows; + Windows = ImmutableList.Empty.AddRange(old.Windows); } /// @@ -78,27 +64,12 @@ internal WindowDefinitionSegment(byte[] bytes) } // Read values into temporary byte arrays. - var winid = bytes.Slice(0, 1); - var horizpos = bytes.Slice(1, 2); - var vertipos = bytes.Slice(3, 2); - var width = bytes.Slice(5, 2); - var height = bytes.Slice(7, 2); - - // Reverse the big-endian encoded arrays if our system is not a big-endian system. - if (!BitConverter.IsLittleEndian) + var numWindows = bytes.Slice(0, 1); + Windows = ImmutableList.Empty; + for (var i = 1; i < bytes.Length; i += MinimumLength) { - Array.Reverse(horizpos); - Array.Reverse(vertipos); - Array.Reverse(width); - Array.Reverse(height); + Windows = Windows.Add(new WindowDefinition(bytes.Slice(i, 9))); } - - // Map the byte arrays into their corresponding property. - WindowId = winid[0]; - WindowHorizontalPosition = BitConverter.ToUInt16(horizpos, 0); - WindowVerticalPosition = BitConverter.ToUInt16(vertipos, 0); - WindowWidth = BitConverter.ToUInt16(width, 0); - WindowHeight = BitConverter.ToUInt16(height, 0); } } }