Add vertical support to WebvttCueParser

PiperOrigin-RevId: 286583957
This commit is contained in:
ibaker 2019-12-20 16:36:18 +00:00 committed by Oliver Woodman
parent f88fbaf655
commit 14a0c9ebfd
3 changed files with 99 additions and 9 deletions

View File

@ -313,6 +313,8 @@ public final class WebvttCueParser {
parsePositionAttribute(value, builder); parsePositionAttribute(value, builder);
} else if ("size".equals(name)) { } else if ("size".equals(name)) {
builder.size = WebvttParserUtil.parsePercentage(value); builder.size = WebvttParserUtil.parsePercentage(value);
} else if ("vertical".equals(name)) {
builder.verticalType = parseVerticalAttribute(value);
} else { } else {
Log.w(TAG, "Unknown cue setting " + name + ":" + value); 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 @TextAlignment
private static int parseTextAlignment(String s) { private static int parseTextAlignment(String s) {
switch (s) { switch (s) {
@ -564,6 +579,7 @@ public final class WebvttCueParser {
public float position; public float position;
@Cue.AnchorType public int positionAnchor; @Cue.AnchorType public int positionAnchor;
public float size; public float size;
@Cue.VerticalType public int verticalType;
public WebvttCueInfoBuilder() { public WebvttCueInfoBuilder() {
startTimeUs = 0; startTimeUs = 0;
@ -579,6 +595,7 @@ public final class WebvttCueParser {
positionAnchor = Cue.TYPE_UNSET; positionAnchor = Cue.TYPE_UNSET;
// Default: https://www.w3.org/TR/webvtt1/#webvtt-cue-size // Default: https://www.w3.org/TR/webvtt1/#webvtt-cue-size
size = 1.0f; size = 1.0f;
verticalType = Cue.TYPE_UNSET;
} }
public WebvttCueInfo build() { public WebvttCueInfo build() {
@ -600,7 +617,8 @@ public final class WebvttCueParser {
.setLineAnchor(lineAnchor) .setLineAnchor(lineAnchor)
.setPosition(position) .setPosition(position)
.setPositionAnchor(positionAnchor) .setPositionAnchor(positionAnchor)
.setSize(Math.min(size, deriveMaxSize(positionAnchor, position))); .setSize(Math.min(size, deriveMaxSize(positionAnchor, position)))
.setVerticalType(verticalType);
if (text != null) { if (text != null) {
cueBuilder.setText(text); cueBuilder.setText(text);

View File

@ -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)

View File

@ -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_IDS_FILE = "webvtt/typical_with_identifiers";
private static final String TYPICAL_WITH_COMMENTS_FILE = "webvtt/typical_with_comments"; 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_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_BAD_CUE_HEADER_FILE = "webvtt/with_bad_cue_header";
private static final String WITH_TAGS_FILE = "webvtt/with_tags"; private static final String WITH_TAGS_FILE = "webvtt/with_tags";
private static final String WITH_CSS_STYLES = "webvtt/with_css_styles"; private static final String WITH_CSS_STYLES = "webvtt/with_css_styles";
@ -231,7 +232,8 @@ public class WebvttDecoderTest {
/* lineAnchor= */ Cue.ANCHOR_TYPE_START, /* lineAnchor= */ Cue.ANCHOR_TYPE_START,
/* position= */ 0.1f, /* position= */ 0.1f,
/* positionAnchor= */ Cue.ANCHOR_TYPE_START, /* positionAnchor= */ Cue.ANCHOR_TYPE_START,
/* size= */ 0.35f); /* size= */ 0.35f,
/* verticalType= */ Cue.TYPE_UNSET);
assertCue( assertCue(
subtitle, subtitle,
/* eventTimeIndex= */ 2, /* eventTimeIndex= */ 2,
@ -244,7 +246,8 @@ public class WebvttDecoderTest {
/* lineAnchor= */ Cue.ANCHOR_TYPE_START, /* lineAnchor= */ Cue.ANCHOR_TYPE_START,
/* position= */ 0.5f, /* position= */ 0.5f,
/* positionAnchor= */ Cue.ANCHOR_TYPE_END, /* positionAnchor= */ Cue.ANCHOR_TYPE_END,
/* size= */ 0.35f); /* size= */ 0.35f,
/* verticalType= */ Cue.TYPE_UNSET);
assertCue( assertCue(
subtitle, subtitle,
/* eventTimeIndex= */ 4, /* eventTimeIndex= */ 4,
@ -257,7 +260,8 @@ public class WebvttDecoderTest {
/* lineAnchor= */ Cue.ANCHOR_TYPE_END, /* lineAnchor= */ Cue.ANCHOR_TYPE_END,
/* position= */ 0.5f, /* position= */ 0.5f,
/* positionAnchor= */ Cue.ANCHOR_TYPE_MIDDLE, /* positionAnchor= */ Cue.ANCHOR_TYPE_MIDDLE,
/* size= */ 0.35f); /* size= */ 0.35f,
/* verticalType= */ Cue.TYPE_UNSET);
assertCue( assertCue(
subtitle, subtitle,
/* eventTimeIndex= */ 6, /* eventTimeIndex= */ 6,
@ -270,7 +274,8 @@ public class WebvttDecoderTest {
/* lineAnchor= */ Cue.ANCHOR_TYPE_START, /* lineAnchor= */ Cue.ANCHOR_TYPE_START,
/* position= */ 0.5f, /* position= */ 0.5f,
/* positionAnchor= */ Cue.ANCHOR_TYPE_MIDDLE, /* positionAnchor= */ Cue.ANCHOR_TYPE_MIDDLE,
/* size= */ 1.0f); /* size= */ 1.0f,
/* verticalType= */ Cue.TYPE_UNSET);
assertCue( assertCue(
subtitle, subtitle,
/* eventTimeIndex= */ 8, /* eventTimeIndex= */ 8,
@ -283,7 +288,8 @@ public class WebvttDecoderTest {
/* lineAnchor= */ Cue.ANCHOR_TYPE_START, /* lineAnchor= */ Cue.ANCHOR_TYPE_START,
/* position= */ 1.0f, /* position= */ 1.0f,
/* positionAnchor= */ Cue.ANCHOR_TYPE_END, /* positionAnchor= */ Cue.ANCHOR_TYPE_END,
/* size= */ 1.0f); /* size= */ 1.0f,
/* verticalType= */ Cue.TYPE_UNSET);
assertCue( assertCue(
subtitle, subtitle,
/* eventTimeIndex= */ 10, /* eventTimeIndex= */ 10,
@ -296,7 +302,58 @@ public class WebvttDecoderTest {
/* lineAnchor= */ Cue.ANCHOR_TYPE_END, /* lineAnchor= */ Cue.ANCHOR_TYPE_END,
/* position= */ 0.5f, /* position= */ 0.5f,
/* positionAnchor= */ Cue.ANCHOR_TYPE_MIDDLE, /* 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 @Test
@ -421,7 +478,8 @@ public class WebvttDecoderTest {
/* lineAnchor= */ Cue.ANCHOR_TYPE_START, /* lineAnchor= */ Cue.ANCHOR_TYPE_START,
/* position= */ 0.5f, /* position= */ 0.5f,
/* positionAnchor= */ Cue.ANCHOR_TYPE_MIDDLE, /* positionAnchor= */ Cue.ANCHOR_TYPE_MIDDLE,
/* size= */ 1.0f); /* size= */ 1.0f,
/* verticalType= */ Cue.TYPE_UNSET);
} }
private void assertCue( private void assertCue(
@ -436,7 +494,8 @@ public class WebvttDecoderTest {
@Cue.AnchorType int lineAnchor, @Cue.AnchorType int lineAnchor,
float position, float position,
@Cue.AnchorType int positionAnchor, @Cue.AnchorType int positionAnchor,
float size) { float size,
@Cue.VerticalType int verticalType) {
expect expect
.withMessage("startTimeUs") .withMessage("startTimeUs")
.that(subtitle.getEventTime(eventTimeIndex)) .that(subtitle.getEventTime(eventTimeIndex))
@ -457,6 +516,7 @@ public class WebvttDecoderTest {
expect.withMessage("cue.position").that(cue.position).isEqualTo(position); expect.withMessage("cue.position").that(cue.position).isEqualTo(position);
expect.withMessage("cue.positionAnchor").that(cue.positionAnchor).isEqualTo(positionAnchor); expect.withMessage("cue.positionAnchor").that(cue.positionAnchor).isEqualTo(positionAnchor);
expect.withMessage("cue.size").that(cue.size).isEqualTo(size); expect.withMessage("cue.size").that(cue.size).isEqualTo(size);
expect.withMessage("cue.verticalType").that(cue.verticalType).isEqualTo(verticalType);
assertThat(expect.hasFailures()).isFalse(); assertThat(expect.hasFailures()).isFalse();
} }