From d1b72b7e9a42bf011e4d5e84c2aec84ed9dffe89 Mon Sep 17 00:00:00 2001 From: Ravisha Date: Wed, 20 Dec 2023 00:40:36 +0530 Subject: [PATCH 1/6] Update Variant.java https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis Enabled REQ-VIDEO-LAYOUT --- src/main/java/io/lindstrom/m3u8/model/Variant.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/lindstrom/m3u8/model/Variant.java b/src/main/java/io/lindstrom/m3u8/model/Variant.java index 8af11d7..3b05a15 100644 --- a/src/main/java/io/lindstrom/m3u8/model/Variant.java +++ b/src/main/java/io/lindstrom/m3u8/model/Variant.java @@ -109,6 +109,11 @@ public interface Variant { */ Optional pathwayId(); + /** + * @return variant attribute REQ-VIDEO-LAYOUT + */ + Optional reqVideoLayout(); + static Builder builder() { return new Builder(); } @@ -122,4 +127,4 @@ public Builder videoRange(String value) { return videoRange(VideoRange.valueOf(value)); } } -} \ No newline at end of file +} From 7bcaa0f8a662d2eb4e82cc97d14e5516315181a5 Mon Sep 17 00:00:00 2001 From: Ravisha Date: Wed, 20 Dec 2023 00:43:23 +0530 Subject: [PATCH 2/6] Update VariantAttribute.java --- .../lindstrom/m3u8/parser/VariantAttribute.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java b/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java index cfb7d19..5d82141 100644 --- a/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java +++ b/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java @@ -213,7 +213,18 @@ public void read(Variant.Builder builder, String value) throws PlaylistParserExc public void write(Variant value, TextBuilder textBuilder) { value.pathwayId().ifPresent(v -> textBuilder.addQuoted(key(), v)); } - }; + }, + + REQ_VIDEO_LAYOUT { + @Override + public void read(Variant.Builder builder, String value) { + builder.reqVideoLayout(value); + } + + @Override + public void write(Variant value, TextBuilder textBuilder) { + value.reqVideoLayout().ifPresent(v -> textBuilder.addQuoted(name(), v)); + }; final static Map attributeMap = ParserUtils.toMap(values(), Attribute::key); @@ -223,4 +234,4 @@ static Variant parse(String attributes, String uri, ParsingMode parsingMode) thr builder.uri(uri); return builder.build(); } -} \ No newline at end of file +} From 68dd579d7acf6503237fe00a6a1a800509559008 Mon Sep 17 00:00:00 2001 From: Ravisha Date: Thu, 21 Dec 2023 13:32:04 +0530 Subject: [PATCH 3/6] Using key instead of name from enum --- src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java b/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java index 5d82141..2646773 100644 --- a/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java +++ b/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java @@ -223,7 +223,7 @@ public void read(Variant.Builder builder, String value) { @Override public void write(Variant value, TextBuilder textBuilder) { - value.reqVideoLayout().ifPresent(v -> textBuilder.addQuoted(name(), v)); + value.reqVideoLayout().ifPresent(v -> textBuilder.addQuoted(key(), v)); }; final static Map attributeMap = ParserUtils.toMap(values(), Attribute::key); From 0a776aab1b2d1ab0553a42f9fdd7347800f4b66c Mon Sep 17 00:00:00 2001 From: Ravisha Date: Wed, 25 Jun 2025 18:33:28 +0530 Subject: [PATCH 4/6] Addressed review comments and updated gitignore --- .gitignore | 1 + src/main/java/io/lindstrom/m3u8/model/Variant.java | 2 +- .../java/io/lindstrom/m3u8/parser/VariantAttribute.java | 8 +++++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 501c140..6017c92 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ build out .gradle +.idea diff --git a/src/main/java/io/lindstrom/m3u8/model/Variant.java b/src/main/java/io/lindstrom/m3u8/model/Variant.java index 3b05a15..99f5671 100644 --- a/src/main/java/io/lindstrom/m3u8/model/Variant.java +++ b/src/main/java/io/lindstrom/m3u8/model/Variant.java @@ -112,7 +112,7 @@ public interface Variant { /** * @return variant attribute REQ-VIDEO-LAYOUT */ - Optional reqVideoLayout(); + List reqVideoLayout(); static Builder builder() { return new Builder(); diff --git a/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java b/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java index 2646773..b4beb8f 100644 --- a/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java +++ b/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java @@ -218,13 +218,15 @@ public void write(Variant value, TextBuilder textBuilder) { REQ_VIDEO_LAYOUT { @Override public void read(Variant.Builder builder, String value) { - builder.reqVideoLayout(value); + builder.codecs(ParserUtils.split(value, ",")); } @Override public void write(Variant value, TextBuilder textBuilder) { - value.reqVideoLayout().ifPresent(v -> textBuilder.addQuoted(key(), v)); - }; + if (!value.codecs().isEmpty()) { + textBuilder.addQuoted(name(), String.join(",", value.codecs())); + } + } final static Map attributeMap = ParserUtils.toMap(values(), Attribute::key); From aba26f4ee856514808c8e399b50c505ed9d85adf Mon Sep 17 00:00:00 2001 From: Ravisha Date: Wed, 25 Jun 2025 18:51:43 +0530 Subject: [PATCH 5/6] Adding test cases --- .../io/lindstrom/m3u8/parser/VariantAttribute.java | 1 + .../m3u8/parser/MediaPlaylistParserTest.java | 12 ++++++++++++ .../resources/media/spatial-video-1-variant.m3u8 | 13 +++++++++++++ .../resources/media/spatial-video-5-variant.m3u8 | 5 +++++ 4 files changed, 31 insertions(+) create mode 100644 src/test/resources/media/spatial-video-1-variant.m3u8 create mode 100644 src/test/resources/media/spatial-video-5-variant.m3u8 diff --git a/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java b/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java index b4beb8f..50fae20 100644 --- a/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java +++ b/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java @@ -227,6 +227,7 @@ public void write(Variant value, TextBuilder textBuilder) { textBuilder.addQuoted(name(), String.join(",", value.codecs())); } } + }; final static Map attributeMap = ParserUtils.toMap(values(), Attribute::key); diff --git a/src/test/java/io/lindstrom/m3u8/parser/MediaPlaylistParserTest.java b/src/test/java/io/lindstrom/m3u8/parser/MediaPlaylistParserTest.java index e2efec2..86c7afc 100644 --- a/src/test/java/io/lindstrom/m3u8/parser/MediaPlaylistParserTest.java +++ b/src/test/java/io/lindstrom/m3u8/parser/MediaPlaylistParserTest.java @@ -42,6 +42,18 @@ public void parse5() throws Exception { parser.readPlaylist(Paths.get("src/test/resources/media/variant.m3u8")); } + + @Test + public void parseSpatialVideo1Variant() throws Exception { + parser.readPlaylist(Paths.get("src/test/resources/media/spatial-video-1-variant.m3u8")); + } + + + @Test + public void parseSpatialVideo5Variant() throws Exception { + parser.readPlaylist(Paths.get("src/test/resources/media/spatial-video-5-variant.m3u8")); + } + @Test public void extInfDurationFormat() throws Exception { String actual = parser.writePlaylistAsString(parser.readPlaylist(Paths.get("src/test/resources/media/issue-17.m3u8"))); diff --git a/src/test/resources/media/spatial-video-1-variant.m3u8 b/src/test/resources/media/spatial-video-1-variant.m3u8 new file mode 100644 index 0000000..fd72c3f --- /dev/null +++ b/src/test/resources/media/spatial-video-1-variant.m3u8 @@ -0,0 +1,13 @@ +#EXTM3U +#EXT-X-VERSION:12 +#EXT-X-MEDIA:TYPE=SUBTITLES,URI="en-US/en-US.m3u8",GROUP-ID="subs",LANGUAGE="en-US",NAME="English",DEFAULT=NO,AUTOSELECT=NO,FORCED=NO +#EXT-X-STREAM-INF:BANDWIDTH=263248,AVERAGE-BANDWIDTH=271179,CODECS="hvc1.2.20000000.L123.B0",RESOLUTION=1920x1080,FRAME-RATE=60.0,SUBTITLES="subs",CLOSED-CAPTIONS=NONE,VIDEO-RANGE=SDR,REQ-VIDEO-LAYOUT="CH-STEREO" +1080p/1080p.m3u8 +#EXT-X-STREAM-INF:BANDWIDTH=146501,AVERAGE-BANDWIDTH=154432,CODECS="hvc1.2.20000000.L123.B0",RESOLUTION=1280x720,FRAME-RATE=60.0,SUBTITLES="subs",CLOSED-CAPTIONS=NONE,VIDEO-RANGE=SDR,REQ-VIDEO-LAYOUT="CH-STEREO" +720p/720p.m3u8 +#EXT-X-STREAM-INF:BANDWIDTH=109068,AVERAGE-BANDWIDTH=117006,CODECS="hvc1.2.20000000.L123.B0",RESOLUTION=960x540,FRAME-RATE=60.0,SUBTITLES="subs",CLOSED-CAPTIONS=NONE,VIDEO-RANGE=SDR,REQ-VIDEO-LAYOUT="CH-STEREO" +540p/540p.m3u8 +#EXT-X-STREAM-INF:BANDWIDTH=83879,AVERAGE-BANDWIDTH=91809,CODECS="hvc1.2.20000000.L123.B0",RESOLUTION=640x360,FRAME-RATE=60.0,SUBTITLES="subs",CLOSED-CAPTIONS=NONE,VIDEO-RANGE=SDR,REQ-VIDEO-LAYOUT="CH-STEREO" +360p/360p.m3u8 +#EXT-X-STREAM-INF:BANDWIDTH=72223,AVERAGE-BANDWIDTH=80153,CODECS="hvc1.2.20000000.L123.B0",RESOLUTION=480x270,FRAME-RATE=60.0,SUBTITLES="subs",CLOSED-CAPTIONS=NONE,VIDEO-RANGE=SDR,REQ-VIDEO-LAYOUT="CH-STEREO" +270p/270p.m3u8 diff --git a/src/test/resources/media/spatial-video-5-variant.m3u8 b/src/test/resources/media/spatial-video-5-variant.m3u8 new file mode 100644 index 0000000..117e1e1 --- /dev/null +++ b/src/test/resources/media/spatial-video-5-variant.m3u8 @@ -0,0 +1,5 @@ +#EXTM3U +#EXT-X-VERSION:12 +#EXT-X-MEDIA:TYPE=SUBTITLES,URI="subs_en-US/en-US.m3u8",GROUP-ID="subs",LANGUAGE="en-US",NAME="English",DEFAULT=NO,AUTOSELECT=NO,FORCED=NO +#EXT-X-STREAM-INF:BANDWIDTH=263248,AVERAGE-BANDWIDTH=271179,CODECS="hvc1.2.20000000.L123.B0",RESOLUTION=1920x1080,FRAME-RATE=60.0,SUBTITLES="subs",CLOSED-CAPTIONS=NONE,VIDEO-RANGE=SDR,REQ-VIDEO-LAYOUT="CH-STEREO" +1080p/1080p.m3u8 \ No newline at end of file From cd5e1efff49958a6508187c73045971c8ef1f6ae Mon Sep 17 00:00:00 2001 From: Ravisha Date: Thu, 26 Jun 2025 12:04:15 +0530 Subject: [PATCH 6/6] Fixed test cases --- src/main/java/io/lindstrom/m3u8/model/Variant.java | 2 +- .../io/lindstrom/m3u8/parser/VariantAttribute.java | 6 +++--- .../io/lindstrom/m3u8/model/IFrameVariantTest.java | 3 ++- .../m3u8/parser/MediaPlaylistParserTest.java | 12 ------------ .../parser/MultivariantPlaylistReadAndWrite.java | 2 ++ .../with-1-variant.m3u8} | 0 .../with-5-variant.m3u8} | 0 7 files changed, 8 insertions(+), 17 deletions(-) rename src/test/resources/{media/spatial-video-1-variant.m3u8 => spatial/with-1-variant.m3u8} (100%) rename src/test/resources/{media/spatial-video-5-variant.m3u8 => spatial/with-5-variant.m3u8} (100%) diff --git a/src/main/java/io/lindstrom/m3u8/model/Variant.java b/src/main/java/io/lindstrom/m3u8/model/Variant.java index 99f5671..962a2b3 100644 --- a/src/main/java/io/lindstrom/m3u8/model/Variant.java +++ b/src/main/java/io/lindstrom/m3u8/model/Variant.java @@ -112,7 +112,7 @@ public interface Variant { /** * @return variant attribute REQ-VIDEO-LAYOUT */ - List reqVideoLayout(); + Optional> reqVideoLayout(); static Builder builder() { return new Builder(); diff --git a/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java b/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java index 50fae20..d720993 100644 --- a/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java +++ b/src/main/java/io/lindstrom/m3u8/parser/VariantAttribute.java @@ -218,13 +218,13 @@ public void write(Variant value, TextBuilder textBuilder) { REQ_VIDEO_LAYOUT { @Override public void read(Variant.Builder builder, String value) { - builder.codecs(ParserUtils.split(value, ",")); + builder.reqVideoLayout(ParserUtils.split(value, ",")); } @Override public void write(Variant value, TextBuilder textBuilder) { - if (!value.codecs().isEmpty()) { - textBuilder.addQuoted(name(), String.join(",", value.codecs())); + if (value.reqVideoLayout().isPresent()) { + textBuilder.addQuoted(key(), String.join(",", value.reqVideoLayout().get())); } } }; diff --git a/src/test/java/io/lindstrom/m3u8/model/IFrameVariantTest.java b/src/test/java/io/lindstrom/m3u8/model/IFrameVariantTest.java index edd5daa..95a5cd6 100644 --- a/src/test/java/io/lindstrom/m3u8/model/IFrameVariantTest.java +++ b/src/test/java/io/lindstrom/m3u8/model/IFrameVariantTest.java @@ -16,7 +16,7 @@ public class IFrameVariantTest { public void allMethodsFromVariantExists() { // All attributes defined for the EXT-X-STREAM-INF tag (Section 4.4.6.2) // are also defined for the EXT-X-I-FRAME-STREAM-INF tag, except for the - // FRAME-RATE, AUDIO, SUBTITLES, and CLOSED-CAPTIONS attributes. + // FRAME-RATE, AUDIO, SUBTITLES, CLOSED-CAPTIONS and REQ-VIDEO-LAYOUTattributes. List ignoreMethods = new ArrayList<>(); ignoreMethods.add("frameRate"); ignoreMethods.add("audio"); @@ -24,6 +24,7 @@ public void allMethodsFromVariantExists() { ignoreMethods.add("frameRate"); ignoreMethods.add("closedCaptions"); ignoreMethods.add("closedCaptionsNone"); + ignoreMethods.add("reqVideoLayout"); for (Method m : Variant.class.getMethods()) { if (ignoreMethods.contains(m.getName())) { diff --git a/src/test/java/io/lindstrom/m3u8/parser/MediaPlaylistParserTest.java b/src/test/java/io/lindstrom/m3u8/parser/MediaPlaylistParserTest.java index 86c7afc..e2efec2 100644 --- a/src/test/java/io/lindstrom/m3u8/parser/MediaPlaylistParserTest.java +++ b/src/test/java/io/lindstrom/m3u8/parser/MediaPlaylistParserTest.java @@ -42,18 +42,6 @@ public void parse5() throws Exception { parser.readPlaylist(Paths.get("src/test/resources/media/variant.m3u8")); } - - @Test - public void parseSpatialVideo1Variant() throws Exception { - parser.readPlaylist(Paths.get("src/test/resources/media/spatial-video-1-variant.m3u8")); - } - - - @Test - public void parseSpatialVideo5Variant() throws Exception { - parser.readPlaylist(Paths.get("src/test/resources/media/spatial-video-5-variant.m3u8")); - } - @Test public void extInfDurationFormat() throws Exception { String actual = parser.writePlaylistAsString(parser.readPlaylist(Paths.get("src/test/resources/media/issue-17.m3u8"))); diff --git a/src/test/java/io/lindstrom/m3u8/parser/MultivariantPlaylistReadAndWrite.java b/src/test/java/io/lindstrom/m3u8/parser/MultivariantPlaylistReadAndWrite.java index f68d018..539152d 100644 --- a/src/test/java/io/lindstrom/m3u8/parser/MultivariantPlaylistReadAndWrite.java +++ b/src/test/java/io/lindstrom/m3u8/parser/MultivariantPlaylistReadAndWrite.java @@ -34,6 +34,8 @@ public static List data() { "open-m3u8/multivariantPlaylistWithAlternativeAudio.m3u8", "open-m3u8/multivariantPlaylistWithAlternativeVideo.m3u8", "open-m3u8/multivariantPlaylistWithIFrames.m3u8", + "spatial/with-1-variant.m3u8", + "spatial/with-5-variant.m3u8", "multivariant/content-steering.m3u8") .map(p -> Paths.get("src/test/resources/", p)) .collect(Collectors.toList()); diff --git a/src/test/resources/media/spatial-video-1-variant.m3u8 b/src/test/resources/spatial/with-1-variant.m3u8 similarity index 100% rename from src/test/resources/media/spatial-video-1-variant.m3u8 rename to src/test/resources/spatial/with-1-variant.m3u8 diff --git a/src/test/resources/media/spatial-video-5-variant.m3u8 b/src/test/resources/spatial/with-5-variant.m3u8 similarity index 100% rename from src/test/resources/media/spatial-video-5-variant.m3u8 rename to src/test/resources/spatial/with-5-variant.m3u8