diff --git a/RELEASENOTES.md b/RELEASENOTES.md index b51fa5dbb7..f6547bc68b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -11,6 +11,12 @@ map. * Add support for mu-law and A-law PCM with the ffmpeg extension ([#4360](https://github.com/google/ExoPlayer/issues/4360)). +* Captions: + * TTML: Fix an issue with TTML using font size as % of cell resolution that + makes `SubtitleView.setApplyEmbeddedFontSizes()` not work correctly. + ([#4491](https://github.com/google/ExoPlayer/issues/4491)). + * CEA-608: Improve handling of embedded styles + ([#4321](https://github.com/google/ExoPlayer/issues/4321)). * Allow apps to pass a `CacheKeyFactory` for setting custom cache keys when creating a `CacheDataSource`. * Turned on Java 8 compiler support for the ExoPlayer library. Apps that depend @@ -45,8 +51,6 @@ * Allow DrmInitData to carry a license server URL ([#3393](https://github.com/google/ExoPlayer/issues/3393)). * Add callback to `VideoListener` to notify of surface size changes. -* CEA-608: Improve handling of embedded styles - ([#4321](https://github.com/google/ExoPlayer/issues/4321)). * Fix bug when reporting buffered position for multi-period windows and add two additional convenience methods `Player.getTotalBufferedDuration` and `Player.getContentBufferedDuration` diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitlePainter.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitlePainter.java index 33f4467dc1..db46ee4912 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitlePainter.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitlePainter.java @@ -84,7 +84,8 @@ import com.google.android.exoplayer2.util.Util; private int edgeColor; @CaptionStyleCompat.EdgeType private int edgeType; - private float textSizePx; + private float defaultTextSizePx; + private float cueTextSizePx; private float bottomPaddingFraction; private int parentLeft; private int parentTop; @@ -124,8 +125,8 @@ import com.google.android.exoplayer2.util.Util; /** * Draws the provided {@link Cue} into a canvas with the specified styling. - *
- * A call to this method is able to use cached results of calculations made during the previous + * + *
A call to this method is able to use cached results of calculations made during the previous * call, and so an instance of this class is able to optimize repeated calls to this method in * which the same parameters are passed. * @@ -134,7 +135,8 @@ import com.google.android.exoplayer2.util.Util; * @param applyEmbeddedFontSizes If {@code applyEmbeddedStyles} is true, defines whether font * sizes embedded within the cue should be applied. Otherwise, it is ignored. * @param style The style to use when drawing the cue text. - * @param textSizePx The text size to use when drawing the cue text, in pixels. + * @param defaultTextSizePx The default text size to use when drawing the text, in pixels. + * @param cueTextSizePx The embedded text size of this cue, in pixels. * @param bottomPaddingFraction The bottom padding fraction to apply when {@link Cue#line} is * {@link Cue#DIMEN_UNSET}, as a fraction of the viewport height * @param canvas The canvas into which to draw. @@ -143,9 +145,19 @@ import com.google.android.exoplayer2.util.Util; * @param cueBoxRight The right position of the enclosing cue box. * @param cueBoxBottom The bottom position of the enclosing cue box. */ - public void draw(Cue cue, boolean applyEmbeddedStyles, boolean applyEmbeddedFontSizes, - CaptionStyleCompat style, float textSizePx, float bottomPaddingFraction, Canvas canvas, - int cueBoxLeft, int cueBoxTop, int cueBoxRight, int cueBoxBottom) { + public void draw( + Cue cue, + boolean applyEmbeddedStyles, + boolean applyEmbeddedFontSizes, + CaptionStyleCompat style, + float defaultTextSizePx, + float cueTextSizePx, + float bottomPaddingFraction, + Canvas canvas, + int cueBoxLeft, + int cueBoxTop, + int cueBoxRight, + int cueBoxBottom) { boolean isTextCue = cue.bitmap == null; int windowColor = Color.BLACK; if (isTextCue) { @@ -174,7 +186,8 @@ import com.google.android.exoplayer2.util.Util; && this.edgeType == style.edgeType && this.edgeColor == style.edgeColor && Util.areEqual(this.textPaint.getTypeface(), style.typeface) - && this.textSizePx == textSizePx + && this.defaultTextSizePx == defaultTextSizePx + && this.cueTextSizePx == cueTextSizePx && this.bottomPaddingFraction == bottomPaddingFraction && this.parentLeft == cueBoxLeft && this.parentTop == cueBoxTop @@ -203,7 +216,8 @@ import com.google.android.exoplayer2.util.Util; this.edgeType = style.edgeType; this.edgeColor = style.edgeColor; this.textPaint.setTypeface(style.typeface); - this.textSizePx = textSizePx; + this.defaultTextSizePx = defaultTextSizePx; + this.cueTextSizePx = cueTextSizePx; this.bottomPaddingFraction = bottomPaddingFraction; this.parentLeft = cueBoxLeft; this.parentTop = cueBoxTop; @@ -222,8 +236,8 @@ import com.google.android.exoplayer2.util.Util; int parentWidth = parentRight - parentLeft; int parentHeight = parentBottom - parentTop; - textPaint.setTextSize(textSizePx); - int textPaddingX = (int) (textSizePx * INNER_PADDING_RATIO + 0.5f); + textPaint.setTextSize(defaultTextSizePx); + int textPaddingX = (int) (defaultTextSizePx * INNER_PADDING_RATIO + 0.5f); int availableWidth = parentWidth - textPaddingX * 2; if (cueSize != Cue.DIMEN_UNSET) { @@ -234,14 +248,12 @@ import com.google.android.exoplayer2.util.Util; return; } + CharSequence cueText = this.cueText; // Remove embedded styling or font size if requested. - CharSequence cueText; - if (applyEmbeddedFontSizes && applyEmbeddedStyles) { - cueText = this.cueText; - } else if (!applyEmbeddedStyles) { - cueText = this.cueText.toString(); // Equivalent to erasing all spans. - } else { - SpannableStringBuilder newCueText = new SpannableStringBuilder(this.cueText); + if (!applyEmbeddedStyles) { + cueText = cueText.toString(); // Equivalent to erasing all spans. + } else if (!applyEmbeddedFontSizes) { + SpannableStringBuilder newCueText = new SpannableStringBuilder(cueText); int cueLength = newCueText.length(); AbsoluteSizeSpan[] absSpans = newCueText.getSpans(0, cueLength, AbsoluteSizeSpan.class); RelativeSizeSpan[] relSpans = newCueText.getSpans(0, cueLength, RelativeSizeSpan.class); @@ -252,6 +264,19 @@ import com.google.android.exoplayer2.util.Util; newCueText.removeSpan(relSpan); } cueText = newCueText; + } else { + // Apply embedded styles & font size. + if (cueTextSizePx > 0) { + // Use a SpannableStringBuilder encompassing the whole cue text to apply the default + // cueTextSizePx. + SpannableStringBuilder newCueText = new SpannableStringBuilder(cueText); + newCueText.setSpan( + new AbsoluteSizeSpan((int) cueTextSizePx), + /* start= */ 0, + /* end= */ newCueText.length(), + Spanned.SPAN_PRIORITY); + cueText = newCueText; + } } if (Color.alpha(backgroundColor) > 0) { diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitleView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitleView.java index 733656b32a..7426671041 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitleView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/SubtitleView.java @@ -271,15 +271,15 @@ public final class SubtitleView extends View implements TextOutput { for (int i = 0; i < cueCount; i++) { Cue cue = cues.get(i); - float textSizePx = - resolveTextSizeForCue(cue, rawViewHeight, viewHeightMinusPadding, defaultViewTextSizePx); + float cueTextSizePx = resolveCueTextSize(cue, rawViewHeight, viewHeightMinusPadding); SubtitlePainter painter = painters.get(i); painter.draw( cue, applyEmbeddedStyles, applyEmbeddedFontSizes, style, - textSizePx, + defaultViewTextSizePx, + cueTextSizePx, bottomPaddingFraction, canvas, left, @@ -289,14 +289,13 @@ public final class SubtitleView extends View implements TextOutput { } } - private float resolveTextSizeForCue( - Cue cue, int rawViewHeight, int viewHeightMinusPadding, float defaultViewTextSizePx) { + private float resolveCueTextSize(Cue cue, int rawViewHeight, int viewHeightMinusPadding) { if (cue.textSizeType == Cue.TYPE_UNSET || cue.textSize == Cue.DIMEN_UNSET) { - return defaultViewTextSizePx; + return 0; } float defaultCueTextSizePx = resolveTextSize(cue.textSizeType, cue.textSize, rawViewHeight, viewHeightMinusPadding); - return defaultCueTextSizePx > 0 ? defaultCueTextSizePx : defaultViewTextSizePx; + return Math.max(defaultCueTextSizePx, 0); } private float resolveTextSize(