Merge pull request #8654 from abeljim:dev-v2-8435-bolditalic
PiperOrigin-RevId: 361767801
This commit is contained in:
commit
c3e3b19ad2
@ -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.
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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())
|
||||||
|
18
testdata/src/test/assets/media/ssa/style_bold_italic
vendored
Normal file
18
testdata/src/test/assets/media/ssa/style_bold_italic
vendored
Normal 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.
|
Loading…
x
Reference in New Issue
Block a user