From 852101a43f1c0addeecff8550f22f653e3d4e9ff Mon Sep 17 00:00:00 2001 From: Abel Jimenez Date: Wed, 21 Apr 2021 18:19:38 -0700 Subject: [PATCH] initial commit for underline and strikeout --- demos/main/src/main/assets/media.exolist.json | 2 +- .../exoplayer2/text/ssa/SsaDecoder.java | 16 ++++++++ .../android/exoplayer2/text/ssa/SsaStyle.java | 41 ++++++++++++++++--- .../exoplayer2/text/ssa/SsaDecoderTest.java | 34 +++++++++++++++ .../src/test/assets/media/ssa/style_strikeout | 16 ++++++++ .../src/test/assets/media/ssa/style_underline | 16 ++++++++ 6 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 testdata/src/test/assets/media/ssa/style_strikeout create mode 100644 testdata/src/test/assets/media/ssa/style_underline diff --git a/demos/main/src/main/assets/media.exolist.json b/demos/main/src/main/assets/media.exolist.json index 24d92bab57..dc9d712eb4 100644 --- a/demos/main/src/main/assets/media.exolist.json +++ b/demos/main/src/main/assets/media.exolist.json @@ -509,7 +509,7 @@ { "name": "SubStation Alpha positioning", "uri": "https://storage.googleapis.com/exoplayer-test-media-1/gen-3/screens/dash-vod-single-segment/video-avc-baseline-480.mp4", - "subtitle_uri": "https://storage.googleapis.com/exoplayer-test-media-1/ssa/test-subs-position.ass", + "subtitle_uri": "https://drive.google.com/uc?export=download&id=16IrvtynQ6-ANRpRX7hU6xEQeFU91LmXl", "subtitle_mime_type": "text/x-ssa", "subtitle_language": "en" }, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java b/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java index eea43ad232..3f764f9fb2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java @@ -22,7 +22,9 @@ import android.graphics.Typeface; import android.text.Layout; import android.text.SpannableString; import android.text.style.ForegroundColorSpan; +import android.text.style.StrikethroughSpan; import android.text.style.StyleSpan; +import android.text.style.UnderlineSpan; import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.text.Cue; @@ -340,6 +342,20 @@ public final class SsaDecoder extends SimpleSubtitleDecoder { /* end= */ spannableText.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE); } + if (style.underline) { + spannableText.setSpan( + new UnderlineSpan(), + /* start= */ 0, + /* end= */ spannableText.length(), + SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if (style.strikeout) { + spannableText.setSpan( + new StrikethroughSpan(), + /* start= */ 0, + /* end= */ spannableText.length(), + SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE); + } } @SsaStyle.SsaAlignment int alignment; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaStyle.java b/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaStyle.java index 7edddac118..a76d530c49 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaStyle.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaStyle.java @@ -22,6 +22,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import android.graphics.Color; import android.graphics.PointF; +import android.os.Binder; import android.text.TextUtils; import androidx.annotation.ColorInt; import androidx.annotation.IntDef; @@ -95,6 +96,8 @@ import java.util.regex.Pattern; public final float fontSize; public final boolean bold; public final boolean italic; + public final boolean underline; + public final boolean strikeout; private SsaStyle( String name, @@ -102,13 +105,17 @@ import java.util.regex.Pattern; @Nullable @ColorInt Integer primaryColor, float fontSize, boolean bold, - boolean italic) { + boolean italic, + boolean underline, + boolean strikeout) { this.name = name; this.alignment = alignment; this.primaryColor = primaryColor; this.fontSize = fontSize; this.bold = bold; this.italic = italic; + this.underline = underline; + this.strikeout = strikeout; } @Nullable @@ -136,10 +143,16 @@ import java.util.regex.Pattern; ? parseFontSize(styleValues[format.fontSizeIndex].trim()) : Cue.DIMEN_UNSET, format.boldIndex != C.INDEX_UNSET - ? parseBoldOrItalic(styleValues[format.boldIndex].trim()) + ? parseBooleanData(styleValues[format.boldIndex].trim()) : false, format.italicIndex != C.INDEX_UNSET - ? parseBoldOrItalic(styleValues[format.italicIndex].trim()) + ? parseBooleanData(styleValues[format.italicIndex].trim()) + : false, + format.underlineIndex != C.INDEX_UNSET + ? parseBooleanData(styleValues[format.underlineIndex].trim()) + : false, + format.strikeoutIndex != C.INDEX_UNSET + ? parseBooleanData(styleValues[format.strikeoutIndex].trim()) : false); } catch (RuntimeException e) { Log.w(TAG, "Skipping malformed 'Style:' line: '" + styleLine + "'", e); @@ -226,12 +239,12 @@ import java.util.regex.Pattern; } } - private static boolean parseBoldOrItalic(String boldOrItalic) { + private static boolean parseBooleanData(String booleanData) { try { - int value = Integer.parseInt(boldOrItalic); + int value = Integer.parseInt(booleanData); return value == 1 || value == -1; } catch (NumberFormatException e) { - Log.w(TAG, "Failed to parse bold/italic: '" + boldOrItalic + "'", e); + Log.w(TAG, "Failed to parse boolean data: '" + booleanData + "'", e); return false; } } @@ -250,6 +263,8 @@ import java.util.regex.Pattern; public final int fontSizeIndex; public final int boldIndex; public final int italicIndex; + public final int underlineIndex; + public final int strikeoutIndex; public final int length; private Format( @@ -259,6 +274,8 @@ import java.util.regex.Pattern; int fontSizeIndex, int boldIndex, int italicIndex, + int underlineIndex, + int strikeoutIndex, int length) { this.nameIndex = nameIndex; this.alignmentIndex = alignmentIndex; @@ -266,6 +283,8 @@ import java.util.regex.Pattern; this.fontSizeIndex = fontSizeIndex; this.boldIndex = boldIndex; this.italicIndex = italicIndex; + this.underlineIndex = underlineIndex; + this.strikeoutIndex = strikeoutIndex; this.length = length; } @@ -282,6 +301,8 @@ import java.util.regex.Pattern; int fontSizeIndex = C.INDEX_UNSET; int boldIndex = C.INDEX_UNSET; int italicIndex = C.INDEX_UNSET; + int underlineIndex = C.INDEX_UNSET; + int strikeoutIndex = C.INDEX_UNSET; String[] keys = TextUtils.split(styleFormatLine.substring(SsaDecoder.FORMAT_LINE_PREFIX.length()), ","); for (int i = 0; i < keys.length; i++) { @@ -304,6 +325,12 @@ import java.util.regex.Pattern; case "italic": italicIndex = i; break; + case "underline": + underlineIndex = i; + break; + case "strikeout": + strikeoutIndex = i; + break; } } return nameIndex != C.INDEX_UNSET @@ -314,6 +341,8 @@ import java.util.regex.Pattern; fontSizeIndex, boldIndex, italicIndex, + underlineIndex, + strikeoutIndex, keys.length) : null; } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/text/ssa/SsaDecoderTest.java b/library/core/src/test/java/com/google/android/exoplayer2/text/ssa/SsaDecoderTest.java index 46192e4618..33c30c0f55 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/text/ssa/SsaDecoderTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/text/ssa/SsaDecoderTest.java @@ -50,6 +50,8 @@ public final class SsaDecoderTest { private static final String STYLE_COLORS = "media/ssa/style_colors"; private static final String STYLE_FONT_SIZE = "media/ssa/style_font_size"; private static final String STYLE_BOLD_ITALIC = "media/ssa/style_bold_italic"; + private static final String STYLE_UNDERLINE = "media/ssa/style_underline"; + private static final String STYLE_STRIKEOUT = "media/ssa/style_strikeout"; @Test public void decodeEmpty() throws IOException { @@ -356,6 +358,38 @@ public final class SsaDecoderTest { SpannedSubject.assertThat(thirdCueText).hasBoldItalicSpanBetween(0, thirdCueText.length()); } + @Test + public void decodeUnderline() throws IOException { + SsaDecoder decoder = new SsaDecoder(); + byte[] bytes = + TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), STYLE_UNDERLINE); + Subtitle subtitle = decoder.decode(bytes, bytes.length, false); + assertThat(subtitle.getEventTimeCount()).isEqualTo(4); + + Spanned firstCueText = + (Spanned) Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(0))).text; + SpannedSubject.assertThat(firstCueText).hasUnderlineSpanBetween(0, firstCueText.length()); + Spanned secondCueText = + (Spanned) Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(2))).text; + SpannedSubject.assertThat(secondCueText).hasNoUnderlineSpanBetween(0, secondCueText.length()); + } + + @Test + public void decodeStrikeout() throws IOException { + SsaDecoder decoder = new SsaDecoder(); + byte[] bytes = + TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), STYLE_STRIKEOUT); + Subtitle subtitle = decoder.decode(bytes, bytes.length, false); + assertThat(subtitle.getEventTimeCount()).isEqualTo(4); + + Spanned firstCueText = + (Spanned) Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(0))).text; + SpannedSubject.assertThat(firstCueText).hasStrikethroughSpanBetween(0, firstCueText.length()); + Spanned secondCueText = + (Spanned) Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(2))).text; + SpannedSubject.assertThat(secondCueText).hasNoStrikethroughSpanBetween(0, secondCueText.length()); + } + private static void assertTypicalCue1(Subtitle subtitle, int eventIndex) { assertThat(subtitle.getEventTime(eventIndex)).isEqualTo(0); assertThat(subtitle.getCues(subtitle.getEventTime(eventIndex)).get(0).text.toString()) diff --git a/testdata/src/test/assets/media/ssa/style_strikeout b/testdata/src/test/assets/media/ssa/style_strikeout new file mode 100644 index 0000000000..9256e22402 --- /dev/null +++ b/testdata/src/test/assets/media/ssa/style_strikeout @@ -0,0 +1,16 @@ +[Script Info] +Title: SSA/ASS Test +Original Script: Abel +Script Type: V4.00+ +PlayResX: 1280 +PlayResY: 720 + +[V4+ Styles] +Format: Name ,Strikeout +Style: WithStrikeout ,-1 +Style: WithoutStrikeout ,0 + +[Events] +Format: Start ,End ,Style ,Text +Dialogue: 0:00:01.00,0:00:03.00,WithStrikeout ,First line with Strikeout. +Dialogue: 0:00:05.00,0:00:07.00,WithoutStrikeout ,Second line without Strikeout. diff --git a/testdata/src/test/assets/media/ssa/style_underline b/testdata/src/test/assets/media/ssa/style_underline new file mode 100644 index 0000000000..0bcc89e813 --- /dev/null +++ b/testdata/src/test/assets/media/ssa/style_underline @@ -0,0 +1,16 @@ +[Script Info] +Title: SSA/ASS Test +Original Script: Abel +Script Type: V4.00+ +PlayResX: 1280 +PlayResY: 720 + +[V4+ Styles] +Format: Name ,Underline +Style: WithUnderline ,-1 +Style: WithoutUnderline ,0 + +[Events] +Format: Start ,End ,Style ,Text +Dialogue: 0:00:01.00,0:00:03.00,WithUnderline ,First line with Underline. +Dialogue: 0:00:05.00,0:00:07.00,WithoutUnderline ,Second line without Underline.