mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
initial commit for underline and strikeout
This commit is contained in:
parent
c01d26f86b
commit
852101a43f
@ -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"
|
||||
},
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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())
|
||||
|
16
testdata/src/test/assets/media/ssa/style_strikeout
vendored
Normal file
16
testdata/src/test/assets/media/ssa/style_strikeout
vendored
Normal file
@ -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.
|
16
testdata/src/test/assets/media/ssa/style_underline
vendored
Normal file
16
testdata/src/test/assets/media/ssa/style_underline
vendored
Normal file
@ -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.
|
Loading…
x
Reference in New Issue
Block a user