From 71409c440a05bef54758102e4155b0b85ce41562 Mon Sep 17 00:00:00 2001 From: Abel Jimenez Date: Mon, 1 Mar 2021 15:52:24 -0800 Subject: [PATCH 1/3] ssa bold and italic --- .../test/assets/media/ssa/style_bold_italic | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 testdata/src/test/assets/media/ssa/style_bold_italic diff --git a/testdata/src/test/assets/media/ssa/style_bold_italic b/testdata/src/test/assets/media/ssa/style_bold_italic new file mode 100644 index 0000000000..e0f0f1c28a --- /dev/null +++ b/testdata/src/test/assets/media/ssa/style_bold_italic @@ -0,0 +1,19 @@ +[Script Info] +Title: SSA/ASS Test +Original Script: Abel +Script Type: V4.00+ +PlayResX: 1280 +PlayResY: 720 + +[V4+ Styles] +Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding +Style: FontBold ,Roboto,50,&H000000FF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,3,0,2,50,50,70,1 +Style: FontItalic ,Roboto,50,&H000000FF,&H000000FF,&H00000000,&H00000000,0,-1,0,0,100,100,0,0,1,3,0,2,50,50,70,1 +Style: FontItalic ,Roboto,50,&H000000FF,&H000000FF,&H00000000,&H00000000,-1,-1,0,0,100,100,0,0,1,3,0,2,50,50,70,1 + + + +[Events] +Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text +Dialogue: 0,0:00:00.95,0:00:03.11,FontSizeSmall ,Arnold,0,0,0,,First line with font size 30. +Dialogue: 0,0:00:08.50,0:00:11.50,FontSizeBig ,Arnold,0,0,0,,Second line with font size 72.2. \ No newline at end of file From ec69977a1c127448312b428b53b7a9ce238edadf Mon Sep 17 00:00:00 2001 From: Abel Jimenez Date: Mon, 1 Mar 2021 15:55:34 -0800 Subject: [PATCH 2/3] ssa bold and italic --- demos/main/src/main/assets/media.exolist.json | 7 +++ .../exoplayer2/text/ssa/SsaDecoder.java | 23 ++++++++ .../android/exoplayer2/text/ssa/SsaStyle.java | 58 ++++++++++++++++++- .../exoplayer2/text/ssa/SsaDecoderTest.java | 20 +++++++ .../test/assets/media/ssa/style_bold_italic | 7 ++- 5 files changed, 109 insertions(+), 6 deletions(-) diff --git a/demos/main/src/main/assets/media.exolist.json b/demos/main/src/main/assets/media.exolist.json index b515eca98a..5a58af4231 100644 --- a/demos/main/src/main/assets/media.exolist.json +++ b/demos/main/src/main/assets/media.exolist.json @@ -506,6 +506,13 @@ "subtitle_mime_type": "text/x-ssa", "subtitle_language": "en" }, + { + "name": "SubStation Alpha Style", + "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=16IrvtynQ6-ANRpRX7hU6xEQeFU91LmXl", + "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" 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 d8d1523b29..4e34287e14 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 @@ -18,9 +18,11 @@ package com.google.android.exoplayer2.text.ssa; import static com.google.android.exoplayer2.text.Cue.LINE_TYPE_FRACTION; import static com.google.android.exoplayer2.util.Util.castNonNull; +import android.graphics.Typeface; import android.text.Layout; import android.text.SpannableString; import android.text.style.ForegroundColorSpan; +import android.text.style.StyleSpan; import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.text.Cue; @@ -319,6 +321,27 @@ public final class SsaDecoder extends SimpleSubtitleDecoder { style.fontSize / screenHeight, Cue.TEXT_SIZE_TYPE_FRACTIONAL_IGNORE_PADDING); } + if (style.bold && style.italic) { + spannableText.setSpan( + new StyleSpan(Typeface.BOLD_ITALIC), + 0, + spannableText.length(), + SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE); + } + else if(style.bold){ + spannableText.setSpan( + new StyleSpan(Typeface.BOLD), + 0, + spannableText.length(), + SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE); + } + else if(style.italic){ + spannableText.setSpan( + new StyleSpan(Typeface.ITALIC), + 0, + 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 554e576710..a7d1f52990 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 @@ -92,16 +92,22 @@ import java.util.regex.Pattern; @SsaAlignment public final int alignment; @Nullable @ColorInt public final Integer primaryColor; public final float fontSize; + public final boolean bold; + public final boolean italic; private SsaStyle( String name, @SsaAlignment int alignment, @Nullable @ColorInt Integer primaryColor, - float fontSize) { + float fontSize, + boolean bold, + boolean italic) { this.name = name; this.alignment = alignment; this.primaryColor = primaryColor; this.fontSize = fontSize; + this.bold = bold; + this.italic = italic; } @Nullable @@ -121,7 +127,9 @@ import java.util.regex.Pattern; styleValues[format.nameIndex].trim(), parseAlignment(styleValues[format.alignmentIndex].trim()), parseColor(styleValues[format.primaryColorIndex].trim()), - parseFontSize(styleValues[format.fontSizeIndex].trim())); + parseFontSize(styleValues[format.fontSizeIndex].trim()), + parseBold(styleValues[format.boldIndex].trim()), + parseItalic(styleValues[format.italicIndex].trim())); } catch (RuntimeException e) { Log.w(TAG, "Skipping malformed 'Style:' line: '" + styleLine + "'", e); return null; @@ -207,6 +215,36 @@ import java.util.regex.Pattern; } } + private static boolean parseBold(String bold) { + try { + int boldFlag = Integer.parseInt(bold); + if(boldFlag == 1 || boldFlag == -1){ + return true; + } + else{ + return false; + } + } catch (NumberFormatException e) { + Log.w(TAG, "Failed to parse bold: '" + bold + "'", e); + return false; + } + } + + private static boolean parseItalic(String italic) { + try { + int italicFlag = Integer.parseInt(italic); + if(italicFlag == 1 || italicFlag == -1){ + return true; + } + else{ + return false; + } + } catch (NumberFormatException e) { + Log.w(TAG, "Failed to parse italic: '" + italic + "'", e); + return false; + } + } + /** * Represents a {@code Format:} line from the {@code [V4+ Styles]} section * @@ -219,6 +257,8 @@ import java.util.regex.Pattern; public final int alignmentIndex; public final int primaryColorIndex; public final int fontSizeIndex; + public final int boldIndex; + public final int italicIndex; public final int length; private Format( @@ -226,11 +266,15 @@ import java.util.regex.Pattern; int alignmentIndex, int primaryColorIndex, int fontSizeIndex, + int boldIndex, + int italicIndex, int length) { this.nameIndex = nameIndex; this.alignmentIndex = alignmentIndex; this.primaryColorIndex = primaryColorIndex; this.fontSizeIndex = fontSizeIndex; + this.boldIndex = boldIndex; + this.italicIndex = italicIndex; this.length = length; } @@ -245,6 +289,8 @@ import java.util.regex.Pattern; int alignmentIndex = C.INDEX_UNSET; int primaryColorIndex = C.INDEX_UNSET; int fontSizeIndex = C.INDEX_UNSET; + int boldIndex = C.INDEX_UNSET; + int italicIndex = C.INDEX_UNSET; String[] keys = TextUtils.split(styleFormatLine.substring(SsaDecoder.FORMAT_LINE_PREFIX.length()), ","); for (int i = 0; i < keys.length; i++) { @@ -261,10 +307,16 @@ import java.util.regex.Pattern; case "fontsize": fontSizeIndex = i; break; + case "bold": + boldIndex = i; + break; + case "italic": + italicIndex = i; + break; } } return nameIndex != C.INDEX_UNSET - ? new Format(nameIndex, alignmentIndex, primaryColorIndex, fontSizeIndex, keys.length) + ? new Format(nameIndex, alignmentIndex, primaryColorIndex, fontSizeIndex, boldIndex, italicIndex, 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 5ab8f8ed1d..542b11b980 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 @@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import android.graphics.Color; +import android.graphics.Typeface; import android.text.Layout; import android.text.Spanned; import androidx.test.core.app.ApplicationProvider; @@ -49,6 +50,7 @@ public final class SsaDecoderTest { private static final String POSITIONS_WITHOUT_PLAYRES = "media/ssa/positioning_without_playres"; 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"; @Test public void decodeEmpty() throws IOException { @@ -335,6 +337,24 @@ public final class SsaDecoderTest { assertThat(secondCue.textSizeType).isEqualTo(Cue.TEXT_SIZE_TYPE_FRACTIONAL_IGNORE_PADDING); } + @Test + public void decodeBoldItalic() throws IOException{ + SsaDecoder decoder = new SsaDecoder(); + byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), STYLE_BOLD_ITALIC); + Subtitle subtitle = decoder.decode(bytes, bytes.length, false); + assertThat(subtitle.getEventTimeCount()).isEqualTo(6); + + Spanned firstCueText = + (Spanned) Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(0))).text; + SpannedSubject.assertThat(firstCueText).hasBoldSpanBetween(0, firstCueText.length()); + Spanned secondCueText = + (Spanned) Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(2))).text; + SpannedSubject.assertThat(secondCueText).hasItalicSpanBetween(0, secondCueText.length()); + Spanned thirdCueText = + (Spanned) Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(4))).text; + SpannedSubject.assertThat(thirdCueText).hasBoldItalicSpanBetween(0, thirdCueText.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_bold_italic b/testdata/src/test/assets/media/ssa/style_bold_italic index e0f0f1c28a..4a3f244307 100644 --- a/testdata/src/test/assets/media/ssa/style_bold_italic +++ b/testdata/src/test/assets/media/ssa/style_bold_italic @@ -9,11 +9,12 @@ PlayResY: 720 Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: FontBold ,Roboto,50,&H000000FF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,3,0,2,50,50,70,1 Style: FontItalic ,Roboto,50,&H000000FF,&H000000FF,&H00000000,&H00000000,0,-1,0,0,100,100,0,0,1,3,0,2,50,50,70,1 -Style: FontItalic ,Roboto,50,&H000000FF,&H000000FF,&H00000000,&H00000000,-1,-1,0,0,100,100,0,0,1,3,0,2,50,50,70,1 +Style: FontBoldItalic ,Roboto,50,&H000000FF,&H000000FF,&H00000000,&H00000000,-1,-1,0,0,100,100,0,0,1,3,0,2,50,50,70,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text -Dialogue: 0,0:00:00.95,0:00:03.11,FontSizeSmall ,Arnold,0,0,0,,First line with font size 30. -Dialogue: 0,0:00:08.50,0:00:11.50,FontSizeBig ,Arnold,0,0,0,,Second line with font size 72.2. \ No newline at end of file +Dialogue: 0,0:00:01.00,0:00:03.00,FontBold ,Abel,0,0,0,,First line with Bold. +Dialogue: 0,0:00:05.00,0:00:07.00,FontItalic ,Abel,0,0,0,,Second line with Italic. +Dialogue: 0,0:00:09.00,0:00:11.00,FontBoldItalic ,Abel,0,0,0,,Third line with Bold Italic. \ No newline at end of file From 8ac74a009ea0eb26f8eea1ef2ed723a85ab20eff Mon Sep 17 00:00:00 2001 From: Abel Jimenez Date: Wed, 3 Mar 2021 02:51:26 -0800 Subject: [PATCH 3/3] formatting --- .../exoplayer2/text/ssa/SsaDecoder.java | 18 ++++++++---------- .../android/exoplayer2/text/ssa/SsaStyle.java | 10 ++++------ .../exoplayer2/text/ssa/SsaDecoderTest.java | 2 +- 3 files changed, 13 insertions(+), 17 deletions(-) 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 4e34287e14..777290e0fc 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 @@ -324,22 +324,20 @@ public final class SsaDecoder extends SimpleSubtitleDecoder { if (style.bold && style.italic) { spannableText.setSpan( new StyleSpan(Typeface.BOLD_ITALIC), - 0, - spannableText.length(), + /* start= */0, + /* end= */ spannableText.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE); - } - else if(style.bold){ + } else if (style.bold) { spannableText.setSpan( new StyleSpan(Typeface.BOLD), - 0, - spannableText.length(), + /* start= */0, + /* end= */ spannableText.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE); - } - else if(style.italic){ + } else if (style.italic) { spannableText.setSpan( new StyleSpan(Typeface.ITALIC), - 0, - spannableText.length(), + /* start= */0, + /* end= */ spannableText.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE); } } 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 a7d1f52990..3e0279fca0 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 @@ -218,10 +218,9 @@ import java.util.regex.Pattern; private static boolean parseBold(String bold) { try { int boldFlag = Integer.parseInt(bold); - if(boldFlag == 1 || boldFlag == -1){ + if (boldFlag == 1 || boldFlag == -1) { return true; - } - else{ + } else { return false; } } catch (NumberFormatException e) { @@ -233,10 +232,9 @@ import java.util.regex.Pattern; private static boolean parseItalic(String italic) { try { int italicFlag = Integer.parseInt(italic); - if(italicFlag == 1 || italicFlag == -1){ + if (italicFlag == 1 || italicFlag == -1) { return true; - } - else{ + } else { return false; } } catch (NumberFormatException e) { 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 542b11b980..3bdebdf82b 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 @@ -338,7 +338,7 @@ public final class SsaDecoderTest { } @Test - public void decodeBoldItalic() throws IOException{ + public void decodeBoldItalic() throws IOException { SsaDecoder decoder = new SsaDecoder(); byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), STYLE_BOLD_ITALIC); Subtitle subtitle = decoder.decode(bytes, bytes.length, false);