From 14a0c9ebfdb3d1280c3136e6739cce12ceea98f8 Mon Sep 17 00:00:00 2001 From: ibaker Date: Fri, 20 Dec 2019 16:36:18 +0000 Subject: [PATCH] Add vertical support to WebvttCueParser PiperOrigin-RevId: 286583957 --- .../text/webvtt/WebvttCueParser.java | 20 ++++- .../core/src/test/assets/webvtt/with_vertical | 12 +++ .../text/webvtt/WebvttDecoderTest.java | 76 +++++++++++++++++-- 3 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 library/core/src/test/assets/webvtt/with_vertical diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCueParser.java b/library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCueParser.java index 565d324828..3a07a74042 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCueParser.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCueParser.java @@ -313,6 +313,8 @@ public final class WebvttCueParser { parsePositionAttribute(value, builder); } else if ("size".equals(name)) { builder.size = WebvttParserUtil.parsePercentage(value); + } else if ("vertical".equals(name)) { + builder.verticalType = parseVerticalAttribute(value); } else { Log.w(TAG, "Unknown cue setting " + name + ":" + value); } @@ -368,6 +370,19 @@ public final class WebvttCueParser { } } + @Cue.VerticalType + private static int parseVerticalAttribute(String s) { + switch (s) { + case "rl": + return Cue.VERTICAL_TYPE_RL; + case "lr": + return Cue.VERTICAL_TYPE_LR; + default: + Log.w(TAG, "Invalid 'vertical' value: " + s); + return Cue.TYPE_UNSET; + } + } + @TextAlignment private static int parseTextAlignment(String s) { switch (s) { @@ -564,6 +579,7 @@ public final class WebvttCueParser { public float position; @Cue.AnchorType public int positionAnchor; public float size; + @Cue.VerticalType public int verticalType; public WebvttCueInfoBuilder() { startTimeUs = 0; @@ -579,6 +595,7 @@ public final class WebvttCueParser { positionAnchor = Cue.TYPE_UNSET; // Default: https://www.w3.org/TR/webvtt1/#webvtt-cue-size size = 1.0f; + verticalType = Cue.TYPE_UNSET; } public WebvttCueInfo build() { @@ -600,7 +617,8 @@ public final class WebvttCueParser { .setLineAnchor(lineAnchor) .setPosition(position) .setPositionAnchor(positionAnchor) - .setSize(Math.min(size, deriveMaxSize(positionAnchor, position))); + .setSize(Math.min(size, deriveMaxSize(positionAnchor, position))) + .setVerticalType(verticalType); if (text != null) { cueBuilder.setText(text); diff --git a/library/core/src/test/assets/webvtt/with_vertical b/library/core/src/test/assets/webvtt/with_vertical new file mode 100644 index 0000000000..2bfe9b7019 --- /dev/null +++ b/library/core/src/test/assets/webvtt/with_vertical @@ -0,0 +1,12 @@ +WEBVTT + +NOTE vertical spec: https://www.w3.org/TR/webvtt1/#webvtt-alignment-cue-setting + +00:00:00.000 --> 00:00:01.234 vertical:rl +Vertical right-to-left (e.g. Japanese) + +00:02.345 --> 00:03.456 vertical:lr +Vertical left-to-right (e.g. Mongolian) + +00:04.000 --> 00:05.000 +No vertical setting (i.e. horizontal) diff --git a/library/core/src/test/java/com/google/android/exoplayer2/text/webvtt/WebvttDecoderTest.java b/library/core/src/test/java/com/google/android/exoplayer2/text/webvtt/WebvttDecoderTest.java index 06ac4d825c..f405f1c407 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/text/webvtt/WebvttDecoderTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/text/webvtt/WebvttDecoderTest.java @@ -48,6 +48,7 @@ public class WebvttDecoderTest { private static final String TYPICAL_WITH_IDS_FILE = "webvtt/typical_with_identifiers"; private static final String TYPICAL_WITH_COMMENTS_FILE = "webvtt/typical_with_comments"; private static final String WITH_POSITIONING_FILE = "webvtt/with_positioning"; + private static final String WITH_VERTICAL_FILE = "webvtt/with_vertical"; private static final String WITH_BAD_CUE_HEADER_FILE = "webvtt/with_bad_cue_header"; private static final String WITH_TAGS_FILE = "webvtt/with_tags"; private static final String WITH_CSS_STYLES = "webvtt/with_css_styles"; @@ -231,7 +232,8 @@ public class WebvttDecoderTest { /* lineAnchor= */ Cue.ANCHOR_TYPE_START, /* position= */ 0.1f, /* positionAnchor= */ Cue.ANCHOR_TYPE_START, - /* size= */ 0.35f); + /* size= */ 0.35f, + /* verticalType= */ Cue.TYPE_UNSET); assertCue( subtitle, /* eventTimeIndex= */ 2, @@ -244,7 +246,8 @@ public class WebvttDecoderTest { /* lineAnchor= */ Cue.ANCHOR_TYPE_START, /* position= */ 0.5f, /* positionAnchor= */ Cue.ANCHOR_TYPE_END, - /* size= */ 0.35f); + /* size= */ 0.35f, + /* verticalType= */ Cue.TYPE_UNSET); assertCue( subtitle, /* eventTimeIndex= */ 4, @@ -257,7 +260,8 @@ public class WebvttDecoderTest { /* lineAnchor= */ Cue.ANCHOR_TYPE_END, /* position= */ 0.5f, /* positionAnchor= */ Cue.ANCHOR_TYPE_MIDDLE, - /* size= */ 0.35f); + /* size= */ 0.35f, + /* verticalType= */ Cue.TYPE_UNSET); assertCue( subtitle, /* eventTimeIndex= */ 6, @@ -270,7 +274,8 @@ public class WebvttDecoderTest { /* lineAnchor= */ Cue.ANCHOR_TYPE_START, /* position= */ 0.5f, /* positionAnchor= */ Cue.ANCHOR_TYPE_MIDDLE, - /* size= */ 1.0f); + /* size= */ 1.0f, + /* verticalType= */ Cue.TYPE_UNSET); assertCue( subtitle, /* eventTimeIndex= */ 8, @@ -283,7 +288,8 @@ public class WebvttDecoderTest { /* lineAnchor= */ Cue.ANCHOR_TYPE_START, /* position= */ 1.0f, /* positionAnchor= */ Cue.ANCHOR_TYPE_END, - /* size= */ 1.0f); + /* size= */ 1.0f, + /* verticalType= */ Cue.TYPE_UNSET); assertCue( subtitle, /* eventTimeIndex= */ 10, @@ -296,7 +302,58 @@ public class WebvttDecoderTest { /* lineAnchor= */ Cue.ANCHOR_TYPE_END, /* position= */ 0.5f, /* positionAnchor= */ Cue.ANCHOR_TYPE_MIDDLE, - /* size= */ 0.35f); + /* size= */ 0.35f, + /* verticalType= */ Cue.TYPE_UNSET); + } + + @Test + public void testDecodeWithVertical() throws Exception { + WebvttSubtitle subtitle = getSubtitleForTestAsset(WITH_VERTICAL_FILE); + // Test event count. + assertThat(subtitle.getEventTimeCount()).isEqualTo(6); + // Test cues. + assertCue( + subtitle, + /* eventTimeIndex= */ 0, + /* startTimeUs= */ 0, + /* endTimeUs= */ 1234000, + "Vertical right-to-left (e.g. Japanese)", + Alignment.ALIGN_CENTER, + /* line= */ Cue.DIMEN_UNSET, + /* lineType= */ Cue.LINE_TYPE_NUMBER, + /* lineAnchor= */ Cue.ANCHOR_TYPE_START, + /* position= */ 0.5f, + /* positionAnchor= */ Cue.ANCHOR_TYPE_MIDDLE, + /* size= */ 1.0f, + Cue.VERTICAL_TYPE_RL); + assertCue( + subtitle, + /* eventTimeIndex= */ 2, + /* startTimeUs= */ 2345000, + /* endTimeUs= */ 3456000, + "Vertical left-to-right (e.g. Mongolian)", + Alignment.ALIGN_CENTER, + /* line= */ Cue.DIMEN_UNSET, + /* lineType= */ Cue.LINE_TYPE_NUMBER, + /* lineAnchor= */ Cue.ANCHOR_TYPE_START, + /* position= */ 0.5f, + /* positionAnchor= */ Cue.ANCHOR_TYPE_MIDDLE, + /* size= */ 1.0f, + Cue.VERTICAL_TYPE_LR); + assertCue( + subtitle, + /* eventTimeIndex= */ 4, + /* startTimeUs= */ 4000000, + /* endTimeUs= */ 5000000, + "No vertical setting (i.e. horizontal)", + Alignment.ALIGN_CENTER, + /* line= */ Cue.DIMEN_UNSET, + /* lineType= */ Cue.LINE_TYPE_NUMBER, + /* lineAnchor= */ Cue.ANCHOR_TYPE_START, + /* position= */ 0.5f, + /* positionAnchor= */ Cue.ANCHOR_TYPE_MIDDLE, + /* size= */ 1.0f, + /* verticalType= */ Cue.TYPE_UNSET); } @Test @@ -421,7 +478,8 @@ public class WebvttDecoderTest { /* lineAnchor= */ Cue.ANCHOR_TYPE_START, /* position= */ 0.5f, /* positionAnchor= */ Cue.ANCHOR_TYPE_MIDDLE, - /* size= */ 1.0f); + /* size= */ 1.0f, + /* verticalType= */ Cue.TYPE_UNSET); } private void assertCue( @@ -436,7 +494,8 @@ public class WebvttDecoderTest { @Cue.AnchorType int lineAnchor, float position, @Cue.AnchorType int positionAnchor, - float size) { + float size, + @Cue.VerticalType int verticalType) { expect .withMessage("startTimeUs") .that(subtitle.getEventTime(eventTimeIndex)) @@ -457,6 +516,7 @@ public class WebvttDecoderTest { expect.withMessage("cue.position").that(cue.position).isEqualTo(position); expect.withMessage("cue.positionAnchor").that(cue.positionAnchor).isEqualTo(positionAnchor); expect.withMessage("cue.size").that(cue.size).isEqualTo(size); + expect.withMessage("cue.verticalType").that(cue.verticalType).isEqualTo(verticalType); assertThat(expect.hasFailures()).isFalse(); }