Merge pull request #8615 from szaboa:dev-v2-8435-ssa-font-size

PiperOrigin-RevId: 359244236
This commit is contained in:
marcbaechinger 2021-02-24 15:46:44 +00:00
parent 3f8f7ba97f
commit e21b99a671
6 changed files with 71 additions and 6 deletions

View File

@ -21,6 +21,9 @@
* Fix a bug with playback of ads in playlists, where the incorrect period * Fix a bug with playback of ads in playlists, where the incorrect period
index was used when deciding whether to trigger playback of an ad after index was used when deciding whether to trigger playback of an ad after
a seek. a seek.
* Text:
* Parse SSA/ASS font size in `Style:` lines
([#8435](https://github.com/google/ExoPlayer/issues/8435)).
* VP9 extension: Update to use NDK r22 * VP9 extension: Update to use NDK r22
([#8581](https://github.com/google/ExoPlayer/issues/8581)). ([#8581](https://github.com/google/ExoPlayer/issues/8581)).
* FLAC extension: Update to use NDK r22 * FLAC extension: Update to use NDK r22

View File

@ -314,6 +314,10 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
/* end= */ spannableText.length(), /* end= */ spannableText.length(),
SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE); SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
} }
if (style.fontSize != Cue.DIMEN_UNSET && screenHeight != Cue.DIMEN_UNSET) {
cue.setTextSize(
style.fontSize / screenHeight, Cue.TEXT_SIZE_TYPE_FRACTIONAL_IGNORE_PADDING);
}
} }
@SsaStyle.SsaAlignment int alignment; @SsaStyle.SsaAlignment int alignment;

View File

@ -27,6 +27,7 @@ import androidx.annotation.ColorInt;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
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.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
@ -90,12 +91,17 @@ import java.util.regex.Pattern;
public final String name; public final String name;
@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;
private SsaStyle( private SsaStyle(
String name, @SsaAlignment int alignment, @Nullable @ColorInt Integer primaryColor) { String name,
@SsaAlignment int alignment,
@Nullable @ColorInt Integer primaryColor,
float fontSize) {
this.name = name; this.name = name;
this.alignment = alignment; this.alignment = alignment;
this.primaryColor = primaryColor; this.primaryColor = primaryColor;
this.fontSize = fontSize;
} }
@Nullable @Nullable
@ -114,7 +120,8 @@ import java.util.regex.Pattern;
return new SsaStyle( return new SsaStyle(
styleValues[format.nameIndex].trim(), styleValues[format.nameIndex].trim(),
parseAlignment(styleValues[format.alignmentIndex].trim()), parseAlignment(styleValues[format.alignmentIndex].trim()),
parseColor(styleValues[format.primaryColorIndex].trim())); parseColor(styleValues[format.primaryColorIndex].trim()),
parseFontSize(styleValues[format.fontSizeIndex].trim()));
} 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;
@ -191,6 +198,15 @@ import java.util.regex.Pattern;
return Color.argb(a, r, g, b); return Color.argb(a, r, g, b);
} }
private static float parseFontSize(String fontSize) {
try {
return Float.parseFloat(fontSize);
} catch (NumberFormatException e) {
Log.w(TAG, "Failed to parse font size: '" + fontSize + "'", e);
return Cue.DIMEN_UNSET;
}
}
/** /**
* Represents a {@code Format:} line from the {@code [V4+ Styles]} section * Represents a {@code Format:} line from the {@code [V4+ Styles]} section
* *
@ -202,12 +218,15 @@ import java.util.regex.Pattern;
public final int nameIndex; public final int nameIndex;
public final int alignmentIndex; public final int alignmentIndex;
public final int primaryColorIndex; public final int primaryColorIndex;
public final int fontSizeIndex;
public final int length; public final int length;
private Format(int nameIndex, int alignmentIndex, int primaryColorIndex, int length) { private Format(
int nameIndex, int alignmentIndex, int primaryColorIndex, int fontSizeIndex, int length) {
this.nameIndex = nameIndex; this.nameIndex = nameIndex;
this.alignmentIndex = alignmentIndex; this.alignmentIndex = alignmentIndex;
this.primaryColorIndex = primaryColorIndex; this.primaryColorIndex = primaryColorIndex;
this.fontSizeIndex = fontSizeIndex;
this.length = length; this.length = length;
} }
@ -221,6 +240,7 @@ import java.util.regex.Pattern;
int nameIndex = C.INDEX_UNSET; int nameIndex = C.INDEX_UNSET;
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;
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++) {
@ -234,10 +254,13 @@ import java.util.regex.Pattern;
case "primarycolour": case "primarycolour":
primaryColorIndex = i; primaryColorIndex = i;
break; break;
case "fontsize":
fontSizeIndex = i;
break;
} }
} }
return nameIndex != C.INDEX_UNSET return nameIndex != C.INDEX_UNSET
? new Format(nameIndex, alignmentIndex, primaryColorIndex, keys.length) ? new Format(nameIndex, alignmentIndex, primaryColorIndex, fontSizeIndex, keys.length)
: null; : null;
} }
} }

View File

@ -47,7 +47,8 @@ public final class SsaDecoderTest {
private static final String INVALID_TIMECODES = "media/ssa/invalid_timecodes"; private static final String INVALID_TIMECODES = "media/ssa/invalid_timecodes";
private static final String INVALID_POSITIONS = "media/ssa/invalid_positioning"; private static final String INVALID_POSITIONS = "media/ssa/invalid_positioning";
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 COLORS = "media/ssa/colors"; private static final String STYLE_COLORS = "media/ssa/style_colors";
private static final String STYLE_FONT_SIZE = "media/ssa/style_font_size";
@Test @Test
public void decodeEmpty() throws IOException { public void decodeEmpty() throws IOException {
@ -274,7 +275,7 @@ public final class SsaDecoderTest {
@Test @Test
public void decodeColors() throws IOException { public void decodeColors() throws IOException {
SsaDecoder decoder = new SsaDecoder(); SsaDecoder decoder = new SsaDecoder();
byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), COLORS); byte[] bytes = TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), STYLE_COLORS);
Subtitle subtitle = decoder.decode(bytes, bytes.length, false); Subtitle subtitle = decoder.decode(bytes, bytes.length, false);
assertThat(subtitle.getEventTimeCount()).isEqualTo(14); assertThat(subtitle.getEventTimeCount()).isEqualTo(14);
// &H000000FF (AABBGGRR) -> #FFFF0000 (AARRGGBB) // &H000000FF (AABBGGRR) -> #FFFF0000 (AARRGGBB)
@ -319,6 +320,22 @@ public final class SsaDecoderTest {
.hasNoForegroundColorSpanBetween(0, seventhCueText.length()); .hasNoForegroundColorSpanBetween(0, seventhCueText.length());
} }
@Test
public void decodeFontSize() throws IOException {
SsaDecoder decoder = new SsaDecoder();
byte[] bytes =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), STYLE_FONT_SIZE);
Subtitle subtitle = decoder.decode(bytes, bytes.length, false);
assertThat(subtitle.getEventTimeCount()).isEqualTo(4);
Cue firstCue = Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(0)));
assertThat(firstCue.textSize).isWithin(1.0e-8f).of(30f / 720f);
assertThat(firstCue.textSizeType).isEqualTo(Cue.TEXT_SIZE_TYPE_FRACTIONAL_IGNORE_PADDING);
Cue secondCue = Iterables.getOnlyElement(subtitle.getCues(subtitle.getEventTime(2)));
assertThat(secondCue.textSize).isWithin(1.0e-8f).of(72.2f / 720f);
assertThat(secondCue.textSizeType).isEqualTo(Cue.TEXT_SIZE_TYPE_FRACTIONAL_IGNORE_PADDING);
}
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: Arnold Szabo
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: FontSizeSmall ,Roboto,30, &H000000FF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,3,0,2,50,50,70,1
Style: FontSizeBig ,Roboto,72.2,&H000000FF,&H000000FF,&H00000000,&H00000000,0,0,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.