mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Fix TextOverlay's overlay width measuring strategy
Before this CL, the text with a scale span would wrap text, with because the scale wasn't taken into account when measuring the width of the overlay. PiperOrigin-RevId: 548123626
This commit is contained in:
parent
42998d6400
commit
453431fef2
3 changed files with 60 additions and 16 deletions
|
|
@ -35,6 +35,7 @@ import android.opengl.Matrix;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.style.ForegroundColorSpan;
|
import android.text.style.ForegroundColorSpan;
|
||||||
|
import android.text.style.RelativeSizeSpan;
|
||||||
import androidx.media3.common.VideoFrameProcessingException;
|
import androidx.media3.common.VideoFrameProcessingException;
|
||||||
import androidx.media3.common.util.GlUtil;
|
import androidx.media3.common.util.GlUtil;
|
||||||
import androidx.media3.common.util.Size;
|
import androidx.media3.common.util.Size;
|
||||||
|
|
@ -71,6 +72,8 @@ public class OverlayShaderProgramPixelTest {
|
||||||
"media/bitmap/sample_mp4_first_frame/electrical_colors/overlay_bitmap_translucent.png";
|
"media/bitmap/sample_mp4_first_frame/electrical_colors/overlay_bitmap_translucent.png";
|
||||||
private static final String OVERLAY_TEXT_DEFAULT =
|
private static final String OVERLAY_TEXT_DEFAULT =
|
||||||
"media/bitmap/sample_mp4_first_frame/electrical_colors/overlay_text_default.png";
|
"media/bitmap/sample_mp4_first_frame/electrical_colors/overlay_text_default.png";
|
||||||
|
private static final String OVERLAY_TEXT_SPAN_SCALED =
|
||||||
|
"media/bitmap/sample_mp4_first_frame/electrical_colors/overlay_text_span_scaled.png";
|
||||||
private static final String OVERLAY_TEXT_TRANSLATE =
|
private static final String OVERLAY_TEXT_TRANSLATE =
|
||||||
"media/bitmap/sample_mp4_first_frame/electrical_colors/overlay_text_translate.png";
|
"media/bitmap/sample_mp4_first_frame/electrical_colors/overlay_text_translate.png";
|
||||||
private static final String OVERLAY_MULTIPLE =
|
private static final String OVERLAY_MULTIPLE =
|
||||||
|
|
@ -302,6 +305,33 @@ public class OverlayShaderProgramPixelTest {
|
||||||
assertThat(averagePixelAbsoluteDifference).isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE);
|
assertThat(averagePixelAbsoluteDifference).isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void drawFrame_textOverlayWithRelativeScaleSpan_blendsTextIntoFrame() throws Exception {
|
||||||
|
String testId = "drawFrame_textOverlayWithRelativeScaleSpan";
|
||||||
|
SpannableString overlayText = new SpannableString(/* source= */ "helllllloooo!!!");
|
||||||
|
overlayText.setSpan(
|
||||||
|
new RelativeSizeSpan(2f),
|
||||||
|
/* start= */ 0,
|
||||||
|
/* end= */ overlayText.length(),
|
||||||
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
TextOverlay staticTextOverlay = TextOverlay.createStaticTextOverlay(overlayText);
|
||||||
|
overlayShaderProgram =
|
||||||
|
new OverlayEffect(ImmutableList.of(staticTextOverlay))
|
||||||
|
.toGlShaderProgram(context, /* useHdr= */ false);
|
||||||
|
Size outputSize = overlayShaderProgram.configure(inputWidth, inputHeight);
|
||||||
|
setupOutputTexture(outputSize.getWidth(), outputSize.getHeight());
|
||||||
|
Bitmap expectedBitmap = readBitmap(OVERLAY_TEXT_SPAN_SCALED);
|
||||||
|
|
||||||
|
overlayShaderProgram.drawFrame(inputTexId, /* presentationTimeUs= */ 0);
|
||||||
|
Bitmap actualBitmap =
|
||||||
|
createArgb8888BitmapFromFocusedGlFramebuffer(outputSize.getWidth(), outputSize.getHeight());
|
||||||
|
|
||||||
|
maybeSaveTestBitmap(testId, /* bitmapLabel= */ "actual", actualBitmap, /* path= */ null);
|
||||||
|
float averagePixelAbsoluteDifference =
|
||||||
|
getBitmapAveragePixelAbsoluteDifferenceArgb8888(expectedBitmap, actualBitmap, testId);
|
||||||
|
assertThat(averagePixelAbsoluteDifference).isAtMost(MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void drawFrame_translatedTextOverlay_blendsTextIntoFrame() throws Exception {
|
public void drawFrame_translatedTextOverlay_blendsTextIntoFrame() throws Exception {
|
||||||
String testId = "drawFrame_translatedTextOverlay";
|
String testId = "drawFrame_translatedTextOverlay";
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ package androidx.media3.effect;
|
||||||
|
|
||||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||||
import static androidx.media3.common.util.Util.SDK_INT;
|
import static androidx.media3.common.util.Util.SDK_INT;
|
||||||
|
import static java.lang.Math.ceil;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
|
@ -87,7 +88,6 @@ public abstract class TextOverlay extends BitmapOverlay {
|
||||||
*/
|
*/
|
||||||
public abstract SpannableString getText(long presentationTimeUs);
|
public abstract SpannableString getText(long presentationTimeUs);
|
||||||
|
|
||||||
@SuppressLint("InlinedApi") // Inlined Layout constants.
|
|
||||||
@Override
|
@Override
|
||||||
public Bitmap getBitmap(long presentationTimeUs) {
|
public Bitmap getBitmap(long presentationTimeUs) {
|
||||||
SpannableString overlayText = getText(presentationTimeUs);
|
SpannableString overlayText = getText(presentationTimeUs);
|
||||||
|
|
@ -95,21 +95,8 @@ public abstract class TextOverlay extends BitmapOverlay {
|
||||||
lastText = overlayText;
|
lastText = overlayText;
|
||||||
TextPaint textPaint = new TextPaint();
|
TextPaint textPaint = new TextPaint();
|
||||||
textPaint.setTextSize(TEXT_SIZE_PIXELS);
|
textPaint.setTextSize(TEXT_SIZE_PIXELS);
|
||||||
StaticLayout staticLayout;
|
StaticLayout staticLayout =
|
||||||
int width = (int) textPaint.measureText(overlayText, /* start= */ 0, overlayText.length());
|
createStaticLayout(overlayText, textPaint, getSpannedTextWidth(overlayText, textPaint));
|
||||||
if (SDK_INT >= 23) {
|
|
||||||
staticLayout = Api23.getStaticLayout(overlayText, textPaint, width);
|
|
||||||
} else {
|
|
||||||
staticLayout =
|
|
||||||
new StaticLayout(
|
|
||||||
overlayText,
|
|
||||||
textPaint,
|
|
||||||
width,
|
|
||||||
Layout.Alignment.ALIGN_NORMAL,
|
|
||||||
Layout.DEFAULT_LINESPACING_MULTIPLIER,
|
|
||||||
Layout.DEFAULT_LINESPACING_ADDITION,
|
|
||||||
/* includepad= */ true);
|
|
||||||
}
|
|
||||||
lastBitmap =
|
lastBitmap =
|
||||||
Bitmap.createBitmap(
|
Bitmap.createBitmap(
|
||||||
staticLayout.getWidth(), staticLayout.getHeight(), Bitmap.Config.ARGB_8888);
|
staticLayout.getWidth(), staticLayout.getHeight(), Bitmap.Config.ARGB_8888);
|
||||||
|
|
@ -119,6 +106,33 @@ public abstract class TextOverlay extends BitmapOverlay {
|
||||||
return checkNotNull(lastBitmap);
|
return checkNotNull(lastBitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getSpannedTextWidth(SpannableString text, TextPaint textPaint) {
|
||||||
|
// measureText doesn't take scaling spans into account so using a StaticLayout to measure
|
||||||
|
// the actual text width, then use a different StaticLayout to draw the text onto a Bitmap.
|
||||||
|
int measureTextWidth = (int) textPaint.measureText(text, /* start= */ 0, text.length());
|
||||||
|
StaticLayout widthMeasuringLayout = createStaticLayout(text, textPaint, measureTextWidth);
|
||||||
|
int lineCount = widthMeasuringLayout.getLineCount();
|
||||||
|
float realTextWidth = 0;
|
||||||
|
for (int i = 0; i < lineCount; i++) {
|
||||||
|
realTextWidth += widthMeasuringLayout.getLineWidth(i);
|
||||||
|
}
|
||||||
|
return (int) ceil(realTextWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("InlinedApi") // Inlined Layout constants.
|
||||||
|
private StaticLayout createStaticLayout(SpannableString text, TextPaint textPaint, int width) {
|
||||||
|
return SDK_INT >= 23
|
||||||
|
? Api23.getStaticLayout(text, textPaint, width)
|
||||||
|
: new StaticLayout(
|
||||||
|
text,
|
||||||
|
textPaint,
|
||||||
|
width,
|
||||||
|
Layout.Alignment.ALIGN_NORMAL,
|
||||||
|
Layout.DEFAULT_LINESPACING_MULTIPLIER,
|
||||||
|
Layout.DEFAULT_LINESPACING_ADDITION,
|
||||||
|
/* includepad= */ true);
|
||||||
|
}
|
||||||
|
|
||||||
@RequiresApi(23)
|
@RequiresApi(23)
|
||||||
private static final class Api23 {
|
private static final class Api23 {
|
||||||
@DoNotInline
|
@DoNotInline
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 520 KiB |
Loading…
Reference in a new issue