Improve support of SSA (V4+) PrimaryColour style

This commit is contained in:
Arnold Szabo 2021-01-25 23:35:10 +01:00
parent 0ead2af22c
commit 1364c01e09
4 changed files with 72 additions and 21 deletions

View File

@ -308,8 +308,8 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
// Apply primary color.
if (style != null) {
if (style.primaryColor != SsaStyle.SSA_COLOR_UNKNOWN) {
spannableText.setSpan(new ForegroundColorSpan(style.primaryColor),
if (style.primaryColor.isSet) {
spannableText.setSpan(new ForegroundColorSpan(style.primaryColor.value),
0, spannableText.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}

View File

@ -89,9 +89,9 @@ import java.util.regex.Pattern;
public final String name;
@SsaAlignment public final int alignment;
@ColorInt public int primaryColor;
public SsaColor primaryColor;
private SsaStyle(String name, @SsaAlignment int alignment, @ColorInt int primaryColor) {
private SsaStyle(String name, @SsaAlignment int alignment, SsaColor primaryColor) {
this.name = name;
this.alignment = alignment;
this.primaryColor = primaryColor;
@ -152,14 +152,33 @@ import java.util.regex.Pattern;
}
}
@ColorInt
private static int parsePrimaryColor(String primaryColorStr) {
private static SsaColor parsePrimaryColor(String primaryColorStr) {
try {
return ColorParser.parseSsaColor(primaryColorStr);
return SsaColor.from(ColorParser.parseSsaColor(primaryColorStr.trim()));
} catch (IllegalArgumentException ex) {
Log.w(TAG, "Failed parsing color value: " + primaryColorStr);
}
return SSA_COLOR_UNKNOWN;
return SsaColor.UNSET;
}
/**
* Represents an SSA V4+ style color in ARGB format.
*/
/* package */ static final class SsaColor {
public static SsaColor UNSET = new SsaColor(0, false);
public final @ColorInt int value;
public final boolean isSet;
private SsaColor(@ColorInt int value, boolean isSet) {
this.value = value;
this.isSet = isSet;
}
public static SsaColor from(@ColorInt int value) {
return new SsaColor(value, true);
}
}
/**

View File

@ -75,17 +75,35 @@ public final class ColorParser {
*/
@ColorInt
public static int parseSsaColor(String colorExpression) {
// SSA V4+ color format is &HAABBGGRR.
if (colorExpression.length() != 10 || !"&H".equals(colorExpression.substring(0, 2))) {
throw new IllegalArgumentException();
// The SSA V4+ color can be represented in hex (&HAABBGGRR) or in decimal format (byte order
// AABBGGRR) and in both cases the alpha channel's value needs to be inverted as in case of SSA
// the 0xFF alpha value means transparent and 0x00 means opaque which is the opposite from the
// @ColorInt representation.
int abgr;
try {
// Parse color from hex format (&HAABBGGRR).
if (colorExpression.startsWith("&H")) {
StringBuilder rgbaStringBuilder = new StringBuilder(colorExpression);
if (colorExpression.length() < 10) {
// Add leading zeros if necessary.
while (rgbaStringBuilder.length() != 10) {
rgbaStringBuilder.insert(2, "0");
}
// Convert &HAABBGGRR to #RRGGBBAA.
String rgba = new StringBuilder()
.append(colorExpression.substring(2))
.append("#")
.reverse()
.toString();
return parseColorInternal(rgba, true);
}
abgr = (int) Long.parseLong(colorExpression.substring(2), 16);
} else {
// Parse color from decimal format (bytes order AABBGGRR).
abgr = (int) Long.parseLong(colorExpression);
}
} catch (NumberFormatException ex) {
throw new IllegalArgumentException(ex);
}
// Convert ABGR to ARGB.
int a = ((abgr >> 24) & 0xFF) ^ 0xFF; // Flip alpha.
int b = (abgr >> 16) & 0xFF;
int g = (abgr >> 8) & 0xFF;
int r = abgr & 0xff;
return Color.argb(a, r, g, b);
}
@ColorInt

View File

@ -16,6 +16,8 @@
package com.google.android.exoplayer2.util;
import static android.graphics.Color.BLACK;
import static android.graphics.Color.BLUE;
import static android.graphics.Color.GREEN;
import static android.graphics.Color.RED;
import static android.graphics.Color.WHITE;
import static android.graphics.Color.YELLOW;
@ -66,9 +68,21 @@ public final class ColorParserTest {
// Hex colors in ColorParser are RGBA, where-as {@link Color#parseColor} takes ARGB.
assertThat(parseTtmlColor("#FFFFFF00")).isEqualTo(parseColor("#00FFFFFF"));
assertThat(parseTtmlColor("#12345678")).isEqualTo(parseColor("#78123456"));
// SSA colors are in &HAABBGGRR format.
assertThat(parseSsaColor("&HFF0000FF")).isEqualTo(RED);
assertThat(parseSsaColor("&HFF00FFFF")).isEqualTo(YELLOW);
}
@Test
public void ssaColorParsing() {
// Hex format (&HAABBGGRR).
assertThat(parseSsaColor("&H000000FF")).isEqualTo(RED);
assertThat(parseSsaColor("&H0000FFFF")).isEqualTo(YELLOW);
assertThat(parseSsaColor("&H400000FF")).isEqualTo(parseColor("#BFFF0000"));
// Leading zeros.
assertThat(parseSsaColor("&HFF")).isEqualTo(RED);
assertThat(parseSsaColor("&HFF00")).isEqualTo(GREEN);
assertThat(parseSsaColor("&HFF0000")).isEqualTo(BLUE);
// Decimal format (AABBGGRR byte order).
assertThat(parseSsaColor(/*#000000FF*/"255")).isEqualTo(parseColor("#FFFF0000"));
assertThat(parseSsaColor(/*#FF0000FF*/"4278190335")).isEqualTo(parseColor("#00FF0000"));
}
@Test