mirror of
https://github.com/samsonjs/media.git
synced 2026-03-28 09:55:48 +00:00
Add support for SSA (V4+) PrimaryColour style
This commit is contained in:
parent
c40d1c6620
commit
0ead2af22c
5 changed files with 75 additions and 5 deletions
|
|
@ -506,6 +506,13 @@
|
|||
"subtitle_mime_type": "text/x-ssa",
|
||||
"subtitle_language": "en"
|
||||
},
|
||||
{
|
||||
"name": "SubStation Alpha colors",
|
||||
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/gen-3/screens/dash-vod-single-segment/video-avc-baseline-480.mp4",
|
||||
"subtitle_uri": "https://drive.google.com/uc?export=download&id=13EdW4Qru-vQerUlwS_Ht5Cely_Tn0tQe",
|
||||
"subtitle_mime_type": "text/x-ssa",
|
||||
"subtitle_language": "en"
|
||||
},
|
||||
{
|
||||
"name": "MPEG-4 Timed Text",
|
||||
"uri": "https://storage.googleapis.com/exoplayer-test-media-1/mp4/dizzy-with-tx3g.mp4"
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ import static com.google.android.exoplayer2.text.Cue.LINE_TYPE_FRACTION;
|
|||
import static com.google.android.exoplayer2.util.Util.castNonNull;
|
||||
|
||||
import android.text.Layout;
|
||||
import android.text.SpannableString;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.text.Cue;
|
||||
|
|
@ -301,8 +303,17 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
|
|||
SsaStyle.Overrides styleOverrides,
|
||||
float screenWidth,
|
||||
float screenHeight) {
|
||||
Cue.Builder cue = new Cue.Builder().setText(text);
|
||||
SpannableString spannableText = new SpannableString(text);
|
||||
Cue.Builder cue = new Cue.Builder().setText(spannableText);
|
||||
|
||||
// Apply primary color.
|
||||
if (style != null) {
|
||||
if (style.primaryColor != SsaStyle.SSA_COLOR_UNKNOWN) {
|
||||
spannableText.setSpan(new ForegroundColorSpan(style.primaryColor),
|
||||
0, spannableText.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
// Apply alignment.
|
||||
@SsaStyle.SsaAlignment int alignment;
|
||||
if (styleOverrides.alignment != SsaStyle.SSA_ALIGNMENT_UNKNOWN) {
|
||||
alignment = styleOverrides.alignment;
|
||||
|
|
|
|||
|
|
@ -21,10 +21,12 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
|
|||
|
||||
import android.graphics.PointF;
|
||||
import android.text.TextUtils;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.ColorParser;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.lang.annotation.Documented;
|
||||
|
|
@ -83,12 +85,16 @@ import java.util.regex.Pattern;
|
|||
public static final int SSA_ALIGNMENT_TOP_CENTER = 8;
|
||||
public static final int SSA_ALIGNMENT_TOP_RIGHT = 9;
|
||||
|
||||
public static final int SSA_COLOR_UNKNOWN = -1;
|
||||
|
||||
public final String name;
|
||||
@SsaAlignment public final int alignment;
|
||||
@ColorInt public int primaryColor;
|
||||
|
||||
private SsaStyle(String name, @SsaAlignment int alignment) {
|
||||
private SsaStyle(String name, @SsaAlignment int alignment, @ColorInt int primaryColor) {
|
||||
this.name = name;
|
||||
this.alignment = alignment;
|
||||
this.primaryColor = primaryColor;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
|
@ -105,7 +111,9 @@ import java.util.regex.Pattern;
|
|||
}
|
||||
try {
|
||||
return new SsaStyle(
|
||||
styleValues[format.nameIndex].trim(), parseAlignment(styleValues[format.alignmentIndex]));
|
||||
styleValues[format.nameIndex].trim(),
|
||||
parseAlignment(styleValues[format.alignmentIndex]),
|
||||
parsePrimaryColor(styleValues[format.primaryColorIndex]));
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(TAG, "Skipping malformed 'Style:' line: '" + styleLine + "'", e);
|
||||
return null;
|
||||
|
|
@ -144,6 +152,16 @@ import java.util.regex.Pattern;
|
|||
}
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
private static int parsePrimaryColor(String primaryColorStr) {
|
||||
try {
|
||||
return ColorParser.parseSsaColor(primaryColorStr);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
Log.w(TAG, "Failed parsing color value: " + primaryColorStr);
|
||||
}
|
||||
return SSA_COLOR_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a {@code Format:} line from the {@code [V4+ Styles]} section
|
||||
*
|
||||
|
|
@ -154,11 +172,13 @@ import java.util.regex.Pattern;
|
|||
|
||||
public final int nameIndex;
|
||||
public final int alignmentIndex;
|
||||
public final int primaryColorIndex;
|
||||
public final int length;
|
||||
|
||||
private Format(int nameIndex, int alignmentIndex, int length) {
|
||||
private Format(int nameIndex, int alignmentIndex, int primaryColorIndex, int length) {
|
||||
this.nameIndex = nameIndex;
|
||||
this.alignmentIndex = alignmentIndex;
|
||||
this.primaryColorIndex = primaryColorIndex;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
|
|
@ -171,6 +191,7 @@ import java.util.regex.Pattern;
|
|||
public static Format fromFormatLine(String styleFormatLine) {
|
||||
int nameIndex = C.INDEX_UNSET;
|
||||
int alignmentIndex = C.INDEX_UNSET;
|
||||
int primaryColorIndex = C.INDEX_UNSET;
|
||||
String[] keys =
|
||||
TextUtils.split(styleFormatLine.substring(SsaDecoder.FORMAT_LINE_PREFIX.length()), ",");
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
|
|
@ -181,9 +202,14 @@ import java.util.regex.Pattern;
|
|||
case "alignment":
|
||||
alignmentIndex = i;
|
||||
break;
|
||||
case "primarycolour":
|
||||
primaryColorIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return nameIndex != C.INDEX_UNSET ? new Format(nameIndex, alignmentIndex, keys.length) : null;
|
||||
return nameIndex != C.INDEX_UNSET
|
||||
? new Format(nameIndex, alignmentIndex, primaryColorIndex, keys.length)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,27 @@ public final class ColorParser {
|
|||
return parseColorInternal(colorExpression, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a SSA V4+ color expression.
|
||||
*
|
||||
* @param colorExpression The color expression.
|
||||
* @return The parsed ARGB color.
|
||||
*/
|
||||
@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();
|
||||
}
|
||||
// Convert &HAABBGGRR to #RRGGBBAA.
|
||||
String rgba = new StringBuilder()
|
||||
.append(colorExpression.substring(2))
|
||||
.append("#")
|
||||
.reverse()
|
||||
.toString();
|
||||
return parseColorInternal(rgba, true);
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
private static int parseColorInternal(String colorExpression, boolean alphaHasFloatFormat) {
|
||||
Assertions.checkArgument(!TextUtils.isEmpty(colorExpression));
|
||||
|
|
|
|||
|
|
@ -18,8 +18,10 @@ package com.google.android.exoplayer2.util;
|
|||
import static android.graphics.Color.BLACK;
|
||||
import static android.graphics.Color.RED;
|
||||
import static android.graphics.Color.WHITE;
|
||||
import static android.graphics.Color.YELLOW;
|
||||
import static android.graphics.Color.argb;
|
||||
import static android.graphics.Color.parseColor;
|
||||
import static com.google.android.exoplayer2.util.ColorParser.parseSsaColor;
|
||||
import static com.google.android.exoplayer2.util.ColorParser.parseTtmlColor;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
|
|
@ -64,6 +66,9 @@ 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
|
||||
|
|
|
|||
Loading…
Reference in a new issue