diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java b/library/extractor/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java
index c02e2338ab..ba6b70499e 100644
--- a/library/extractor/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java
+++ b/library/extractor/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java
@@ -320,7 +320,7 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
/* end= */ spannableText.length(),
SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
}
- if (style.outlineColor != null) {
+ if (style.borderStyle == SsaStyle.SSA_BORDER_STYLE_BOX && style.outlineColor != null) {
spannableText.setSpan(
new BackgroundColorSpan(style.outlineColor),
/* start= */ 0,
diff --git a/library/extractor/src/main/java/com/google/android/exoplayer2/text/ssa/SsaStyle.java b/library/extractor/src/main/java/com/google/android/exoplayer2/text/ssa/SsaStyle.java
index 92821c02d9..4766306961 100644
--- a/library/extractor/src/main/java/com/google/android/exoplayer2/text/ssa/SsaStyle.java
+++ b/library/extractor/src/main/java/com/google/android/exoplayer2/text/ssa/SsaStyle.java
@@ -92,6 +92,31 @@ import java.util.regex.Pattern;
public static final int SSA_ALIGNMENT_TOP_CENTER = 8;
public static final int SSA_ALIGNMENT_TOP_RIGHT = 9;
+ /**
+ * The SSA/ASS BorderStyle.
+ *
+ *
Allowed values:
+ *
+ *
+ * - {@link #SSA_BORDER_STYLE_UNKNOWN}
+ *
- {@link #SSA_BORDER_STYLE_OUTLINE}
+ *
- {@link #SSA_BORDER_STYLE_BOX}
+ *
+ */
+ @Target(TYPE_USE)
+ @IntDef({
+ SSA_BORDER_STYLE_UNKNOWN,
+ SSA_BORDER_STYLE_OUTLINE,
+ SSA_BORDER_STYLE_BOX,
+ })
+ @Documented
+ @Retention(SOURCE)
+ public @interface SsaBorderStyle {}
+
+ public static final int SSA_BORDER_STYLE_UNKNOWN = -1;
+ public static final int SSA_BORDER_STYLE_OUTLINE = 1;
+ public static final int SSA_BORDER_STYLE_BOX = 3;
+
public final String name;
public final @SsaAlignment int alignment;
@Nullable @ColorInt public final Integer primaryColor;
@@ -101,6 +126,7 @@ import java.util.regex.Pattern;
public final boolean italic;
public final boolean underline;
public final boolean strikeout;
+ public final @SsaBorderStyle int borderStyle;
private SsaStyle(
String name,
@@ -111,7 +137,8 @@ import java.util.regex.Pattern;
boolean bold,
boolean italic,
boolean underline,
- boolean strikeout) {
+ boolean strikeout,
+ int borderStyle) {
this.name = name;
this.alignment = alignment;
this.primaryColor = primaryColor;
@@ -121,6 +148,7 @@ import java.util.regex.Pattern;
this.italic = italic;
this.underline = underline;
this.strikeout = strikeout;
+ this.borderStyle = borderStyle;
}
@Nullable
@@ -157,7 +185,10 @@ import java.util.regex.Pattern;
format.underlineIndex != C.INDEX_UNSET
&& parseBooleanValue(styleValues[format.underlineIndex].trim()),
format.strikeoutIndex != C.INDEX_UNSET
- && parseBooleanValue(styleValues[format.strikeoutIndex].trim()));
+ && parseBooleanValue(styleValues[format.strikeoutIndex].trim()),
+ format.borderStyleIndex != C.INDEX_UNSET
+ ? parseBorderStyle(styleValues[format.borderStyleIndex].trim())
+ : SSA_BORDER_STYLE_UNKNOWN);
} catch (RuntimeException e) {
Log.w(TAG, "Skipping malformed 'Style:' line: '" + styleLine + "'", e);
return null;
@@ -195,6 +226,30 @@ import java.util.regex.Pattern;
}
}
+ private static @SsaBorderStyle int parseBorderStyle(String borderStyleStr) {
+ try {
+ @SsaBorderStyle int borderStyle = Integer.parseInt(borderStyleStr.trim());
+ if (isValidBorderStyle(borderStyle)) {
+ return borderStyle;
+ }
+ } catch (NumberFormatException e) {
+ // Swallow the exception and return UNKNOWN below.
+ }
+ Log.w(TAG, "Ignoring unknown BorderStyle: " + borderStyleStr);
+ return SSA_BORDER_STYLE_UNKNOWN;
+ }
+
+ private static boolean isValidBorderStyle(@SsaBorderStyle int alignment) {
+ switch (alignment) {
+ case SSA_BORDER_STYLE_OUTLINE:
+ case SSA_BORDER_STYLE_BOX:
+ return true;
+ case SSA_BORDER_STYLE_UNKNOWN:
+ default:
+ return false;
+ }
+ }
+
/**
* Parses a SSA V4+ color expression.
*
@@ -269,6 +324,7 @@ import java.util.regex.Pattern;
public final int italicIndex;
public final int underlineIndex;
public final int strikeoutIndex;
+ public final int borderStyleIndex;
public final int length;
private Format(
@@ -281,6 +337,7 @@ import java.util.regex.Pattern;
int italicIndex,
int underlineIndex,
int strikeoutIndex,
+ int borderStyleIndex,
int length) {
this.nameIndex = nameIndex;
this.alignmentIndex = alignmentIndex;
@@ -291,6 +348,7 @@ import java.util.regex.Pattern;
this.italicIndex = italicIndex;
this.underlineIndex = underlineIndex;
this.strikeoutIndex = strikeoutIndex;
+ this.borderStyleIndex = borderStyleIndex;
this.length = length;
}
@@ -310,6 +368,7 @@ import java.util.regex.Pattern;
int italicIndex = C.INDEX_UNSET;
int underlineIndex = C.INDEX_UNSET;
int strikeoutIndex = C.INDEX_UNSET;
+ int borderStyleIndex = C.INDEX_UNSET;
String[] keys =
TextUtils.split(styleFormatLine.substring(SsaDecoder.FORMAT_LINE_PREFIX.length()), ",");
for (int i = 0; i < keys.length; i++) {
@@ -341,6 +400,9 @@ import java.util.regex.Pattern;
case "strikeout":
strikeoutIndex = i;
break;
+ case "borderstyle":
+ borderStyleIndex = i;
+ break;
}
}
return nameIndex != C.INDEX_UNSET
@@ -354,6 +416,7 @@ import java.util.regex.Pattern;
italicIndex,
underlineIndex,
strikeoutIndex,
+ borderStyleIndex,
keys.length)
: null;
}
diff --git a/library/extractor/src/test/java/com/google/android/exoplayer2/text/ssa/SsaDecoderTest.java b/library/extractor/src/test/java/com/google/android/exoplayer2/text/ssa/SsaDecoderTest.java
index a4001a2d4b..60eb6008c9 100644
--- a/library/extractor/src/test/java/com/google/android/exoplayer2/text/ssa/SsaDecoderTest.java
+++ b/library/extractor/src/test/java/com/google/android/exoplayer2/text/ssa/SsaDecoderTest.java
@@ -301,7 +301,7 @@ public final class SsaDecoderTest {
SsaDecoder decoder = new SsaDecoder();
byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), STYLE_COLORS);
Subtitle subtitle = decoder.decode(bytes, bytes.length, false);
- assertThat(subtitle.getEventTimeCount()).isEqualTo(16);
+ assertThat(subtitle.getEventTimeCount()).isEqualTo(18);
// &H000000FF (AABBGGRR) -> #FFFF0000 (AARRGGBB)
Spanned firstCueText =
(Spanned) Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(0))).text;
@@ -342,11 +342,15 @@ public final class SsaDecoderTest {
(Spanned) Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(12))).text;
SpannedSubject.assertThat(seventhCueText)
.hasNoForegroundColorSpanBetween(0, seventhCueText.length());
+ // OutlineColour should be treated as background only when BorderStyle=3
Spanned eighthCueText =
(Spanned) Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(14))).text;
SpannedSubject.assertThat(eighthCueText)
.hasBackgroundColorSpanBetween(0, eighthCueText.length())
.withColor(Color.BLUE);
+ Spanned ninthCueText =
+ (Spanned) Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(16))).text;
+ SpannedSubject.assertThat(ninthCueText).hasNoBackgroundColorSpanBetween(0, ninthCueText.length());
}
@Test
diff --git a/testdata/src/test/assets/media/ssa/style_colors b/testdata/src/test/assets/media/ssa/style_colors
index fe31e66380..a0ec2240c0 100644
--- a/testdata/src/test/assets/media/ssa/style_colors
+++ b/testdata/src/test/assets/media/ssa/style_colors
@@ -5,15 +5,16 @@ PlayResX: 1280
PlayResY: 720
[V4+ Styles]
-Format: Name ,PrimaryColour,OutlineColour
-Style: PrimaryColourStyleHexRed ,&H000000FF ,&H00000000
-Style: PrimaryColourStyleHexYellow ,&H0000FFFF ,&H00000000
-Style: PrimaryColourStyleHexGreen ,&HFF00 ,&H00000000
-Style: PrimaryColourStyleHexAlpha ,&HA00000FF ,&H00000000
-Style: PrimaryColourStyleDecimal ,16711680 ,&H00000000
-Style: PrimaryColourStyleDecimalAlpha,2164195328 ,&H00000000
-Style: PrimaryColourStyleInvalid ,blue ,&H00000000
-Style: OutlineColourStyleBlue ,&H00000000 ,&H00FF0000
+Format: Name ,PrimaryColour,OutlineColour,BorderStyle
+Style: PrimaryColourStyleHexRed ,&H000000FF ,&H00000000 ,3
+Style: PrimaryColourStyleHexYellow ,&H0000FFFF ,&H00000000 ,3
+Style: PrimaryColourStyleHexGreen ,&HFF00 ,&H00000000 ,3
+Style: PrimaryColourStyleHexAlpha ,&HA00000FF ,&H00000000 ,3
+Style: PrimaryColourStyleDecimal ,16711680 ,&H00000000 ,3
+Style: PrimaryColourStyleDecimalAlpha,2164195328 ,&H00000000 ,3
+Style: PrimaryColourStyleInvalid ,blue ,&H00000000 ,3
+Style: OutlineColourStyleBlue ,&H00000000 ,&H00FF0000 ,3
+Style: OutlineColourStyleIgnored ,&H00000000 ,&H00FF0000 ,1
[Events]
@@ -26,3 +27,4 @@ Dialogue: 0:00:09.00,0:00:10.00,PrimaryColourStyleDecimal ,Fifth line in BLU
Dialogue: 0:00:11.00,0:00:12.00,PrimaryColourStyleDecimalAlpha,Sixth line in BLUE with alpha (2164195328).
Dialogue: 0:00:13.00,0:00:14.00,PrimaryColourInvalid ,Seventh line with invalid color.
Dialogue: 0:00:15.00,0:00:16.00,OutlineColourStyleBlue ,Eighth line with BLUE (&H00FF0000) outline.
+Dialogue: 0:00:17.00,0:00:18.00,OutlineColourStyleIgnored ,Ninth line with ignored outline because BorderStyle is not 3.