Merge pull request #8654 from abeljim:dev-v2-8435-bolditalic

PiperOrigin-RevId: 361767801
This commit is contained in:
Ian Baker 2021-03-12 10:40:58 +00:00
commit c3e3b19ad2
5 changed files with 113 additions and 4 deletions

View File

@ -46,6 +46,9 @@
* UI * UI
* Fix `StyledPlayerView` scrubber not reappearing correctly in some cases * Fix `StyledPlayerView` scrubber not reappearing correctly in some cases
([#8646](https://github.com/google/ExoPlayer/issues/8646)). ([#8646](https://github.com/google/ExoPlayer/issues/8646)).
* Text
* Parse SSA/ASS bold & italic info in `Style:` lines
([#8435](https://github.com/google/ExoPlayer/issues/8435)).
* MediaSession extension: Remove dependency to core module and rely on common * MediaSession extension: Remove dependency to core module and rely on common
only. The `TimelineQueueEditor` uses a new `MediaDescriptionConverter` for only. The `TimelineQueueEditor` uses a new `MediaDescriptionConverter` for
this purpose and does not rely on the `ConcatenatingMediaSource` anymore. this purpose and does not rely on the `ConcatenatingMediaSource` anymore.

View File

@ -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.text.Cue.LINE_TYPE_FRACTION;
import static com.google.android.exoplayer2.util.Util.castNonNull; import static com.google.android.exoplayer2.util.Util.castNonNull;
import android.graphics.Typeface;
import android.text.Layout; import android.text.Layout;
import android.text.SpannableString; import android.text.SpannableString;
import android.text.style.ForegroundColorSpan; import android.text.style.ForegroundColorSpan;
import android.text.style.StyleSpan;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.Cue;
@ -318,6 +320,25 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
cue.setTextSize( cue.setTextSize(
style.fontSize / screenHeight, Cue.TEXT_SIZE_TYPE_FRACTIONAL_IGNORE_PADDING); style.fontSize / screenHeight, Cue.TEXT_SIZE_TYPE_FRACTIONAL_IGNORE_PADDING);
} }
if (style.bold && style.italic) {
spannableText.setSpan(
new StyleSpan(Typeface.BOLD_ITALIC),
/* start= */ 0,
/* end= */ spannableText.length(),
SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
} else if (style.bold) {
spannableText.setSpan(
new StyleSpan(Typeface.BOLD),
/* start= */ 0,
/* end= */ spannableText.length(),
SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
} else if (style.italic) {
spannableText.setSpan(
new StyleSpan(Typeface.ITALIC),
/* start= */ 0,
/* end= */ spannableText.length(),
SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
}
} }
@SsaStyle.SsaAlignment int alignment; @SsaStyle.SsaAlignment int alignment;

View File

@ -92,16 +92,22 @@ import java.util.regex.Pattern;
@SsaAlignment public final int alignment; @SsaAlignment public final int alignment;
@Nullable @ColorInt public final Integer primaryColor; @Nullable @ColorInt public final Integer primaryColor;
public final float fontSize; public final float fontSize;
public final boolean bold;
public final boolean italic;
private SsaStyle( private SsaStyle(
String name, String name,
@SsaAlignment int alignment, @SsaAlignment int alignment,
@Nullable @ColorInt Integer primaryColor, @Nullable @ColorInt Integer primaryColor,
float fontSize) { float fontSize,
boolean bold,
boolean italic) {
this.name = name; this.name = name;
this.alignment = alignment; this.alignment = alignment;
this.primaryColor = primaryColor; this.primaryColor = primaryColor;
this.fontSize = fontSize; this.fontSize = fontSize;
this.bold = bold;
this.italic = italic;
} }
@Nullable @Nullable
@ -127,7 +133,13 @@ import java.util.regex.Pattern;
: null, : null,
format.fontSizeIndex != C.INDEX_UNSET format.fontSizeIndex != C.INDEX_UNSET
? parseFontSize(styleValues[format.fontSizeIndex].trim()) ? parseFontSize(styleValues[format.fontSizeIndex].trim())
: Cue.DIMEN_UNSET); : Cue.DIMEN_UNSET,
format.boldIndex != C.INDEX_UNSET
? parseBoldOrItalic(styleValues[format.boldIndex].trim())
: false,
format.italicIndex != C.INDEX_UNSET
? parseBoldOrItalic(styleValues[format.italicIndex].trim())
: false);
} catch (RuntimeException e) { } catch (RuntimeException e) {
Log.w(TAG, "Skipping malformed 'Style:' line: '" + styleLine + "'", e); Log.w(TAG, "Skipping malformed 'Style:' line: '" + styleLine + "'", e);
return null; return null;
@ -213,6 +225,16 @@ import java.util.regex.Pattern;
} }
} }
private static boolean parseBoldOrItalic(String boldOrItalic) {
try {
int value = Integer.parseInt(boldOrItalic);
return value == 1 || value == -1;
} catch (NumberFormatException e) {
Log.w(TAG, "Failed to parse bold/italic: '" + boldOrItalic + "'", e);
return false;
}
}
/** /**
* Represents a {@code Format:} line from the {@code [V4+ Styles]} section * Represents a {@code Format:} line from the {@code [V4+ Styles]} section
* *
@ -225,14 +247,24 @@ import java.util.regex.Pattern;
public final int alignmentIndex; public final int alignmentIndex;
public final int primaryColorIndex; public final int primaryColorIndex;
public final int fontSizeIndex; public final int fontSizeIndex;
public final int boldIndex;
public final int italicIndex;
public final int length; public final int length;
private Format( private Format(
int nameIndex, int alignmentIndex, int primaryColorIndex, int fontSizeIndex, int length) { int nameIndex,
int alignmentIndex,
int primaryColorIndex,
int fontSizeIndex,
int boldIndex,
int italicIndex,
int length) {
this.nameIndex = nameIndex; this.nameIndex = nameIndex;
this.alignmentIndex = alignmentIndex; this.alignmentIndex = alignmentIndex;
this.primaryColorIndex = primaryColorIndex; this.primaryColorIndex = primaryColorIndex;
this.fontSizeIndex = fontSizeIndex; this.fontSizeIndex = fontSizeIndex;
this.boldIndex = boldIndex;
this.italicIndex = italicIndex;
this.length = length; this.length = length;
} }
@ -247,6 +279,8 @@ import java.util.regex.Pattern;
int alignmentIndex = C.INDEX_UNSET; int alignmentIndex = C.INDEX_UNSET;
int primaryColorIndex = C.INDEX_UNSET; int primaryColorIndex = C.INDEX_UNSET;
int fontSizeIndex = C.INDEX_UNSET; int fontSizeIndex = C.INDEX_UNSET;
int boldIndex = C.INDEX_UNSET;
int italicIndex = C.INDEX_UNSET;
String[] keys = String[] keys =
TextUtils.split(styleFormatLine.substring(SsaDecoder.FORMAT_LINE_PREFIX.length()), ","); TextUtils.split(styleFormatLine.substring(SsaDecoder.FORMAT_LINE_PREFIX.length()), ",");
for (int i = 0; i < keys.length; i++) { for (int i = 0; i < keys.length; i++) {
@ -263,10 +297,23 @@ import java.util.regex.Pattern;
case "fontsize": case "fontsize":
fontSizeIndex = i; fontSizeIndex = i;
break; break;
case "bold":
boldIndex = i;
break;
case "italic":
italicIndex = i;
break;
} }
} }
return nameIndex != C.INDEX_UNSET return nameIndex != C.INDEX_UNSET
? new Format(nameIndex, alignmentIndex, primaryColorIndex, fontSizeIndex, keys.length) ? new Format(
nameIndex,
alignmentIndex,
primaryColorIndex,
fontSizeIndex,
boldIndex,
italicIndex,
keys.length)
: null; : null;
} }
} }

View File

@ -49,6 +49,7 @@ public final class SsaDecoderTest {
private static final String POSITIONS_WITHOUT_PLAYRES = "media/ssa/positioning_without_playres"; 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_COLORS = "media/ssa/style_colors";
private static final String STYLE_FONT_SIZE = "media/ssa/style_font_size"; 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 @Test
public void decodeEmpty() throws IOException { public void decodeEmpty() throws IOException {
@ -336,6 +337,25 @@ public final class SsaDecoderTest {
assertThat(secondCue.textSizeType).isEqualTo(Cue.TEXT_SIZE_TYPE_FRACTIONAL_IGNORE_PADDING); 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) { private static void assertTypicalCue1(Subtitle subtitle, int eventIndex) {
assertThat(subtitle.getEventTime(eventIndex)).isEqualTo(0); assertThat(subtitle.getEventTime(eventIndex)).isEqualTo(0);
assertThat(subtitle.getCues(subtitle.getEventTime(eventIndex)).get(0).text.toString()) assertThat(subtitle.getCues(subtitle.getEventTime(eventIndex)).get(0).text.toString())

View File

@ -0,0 +1,18 @@
[Script Info]
Title: SSA/ASS Test
Original Script: Abel
Script Type: V4.00+
PlayResX: 1280
PlayResY: 720
[V4+ Styles]
Format: Name ,Bold,Italic
Style: FontBold ,-1 ,0
Style: FontItalic ,0 ,-1
Style: FontBoldItalic ,1 ,1
[Events]
Format: Start ,End ,Style ,Text
Dialogue: 0:00:01.00,0:00:03.00,FontBold ,First line with Bold.
Dialogue: 0:00:05.00,0:00:07.00,FontItalic ,Second line with Italic.
Dialogue: 0:00:09.00,0:00:11.00,FontBoldItalic,Third line with Bold Italic.