Skip to content

Commit

Permalink
Add a flag to control whether input bitmap resampling can be skipped
Browse files Browse the repository at this point in the history
Add DefaultVideosFrameProcessor experimental flag that controls
whether input Bitmaps are sampled once for a repeating sequence of
output frames with the same contents, or once for each output frame.

PiperOrigin-RevId: 637921350
  • Loading branch information
ychaparov authored and Copybara-Service committed May 28, 2024
1 parent 02df88e commit 3c998ac
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
// The queue holds all bitmaps with one or more frames pending to be sent downstream.
private final Queue<BitmapFrameSequenceInfo> pendingBitmaps;
private final GlObjectsProvider glObjectsProvider;
private final boolean signalRepeatingSequence;

private @MonotonicNonNull RepeatingGainmapShaderProgram repeatingGainmapShaderProgram;
@Nullable private GlTextureInfo currentSdrGlTextureInfo;
Expand All @@ -59,13 +60,18 @@
* @param glObjectsProvider The {@link GlObjectsProvider} for using EGL and GLES.
* @param videoFrameProcessingTaskExecutor The {@link VideoFrameProcessingTaskExecutor} that the
* methods of this class run on.
* @param signalRepeatingSequence Whether to repeat each input bitmap unchanged as a sequence of
* output frames. Defaults to {@code false}. That is, each output frame is treated as a new
* input bitmap.
*/
public BitmapTextureManager(
GlObjectsProvider glObjectsProvider,
VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor) {
VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor,
boolean signalRepeatingSequence) {
super(videoFrameProcessingTaskExecutor);
this.glObjectsProvider = glObjectsProvider;
pendingBitmaps = new LinkedBlockingQueue<>();
this.signalRepeatingSequence = signalRepeatingSequence;
}

/**
Expand Down Expand Up @@ -215,7 +221,9 @@ private void updateCurrentGlTextureInfo(FrameInfo frameInfo, Bitmap bitmap)
if (Util.SDK_INT >= 34 && bitmap.hasGainmap()) {
checkNotNull(repeatingGainmapShaderProgram).setGainmap(checkNotNull(bitmap.getGainmap()));
}
checkNotNull(repeatingGainmapShaderProgram).signalNewRepeatingFrameSequence();
if (signalRepeatingSequence) {
checkNotNull(repeatingGainmapShaderProgram).signalNewRepeatingFrameSequence();
}
} catch (GlUtil.GlException e) {
throw VideoFrameProcessingException.from(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ public static final class Builder {
private int textureOutputCapacity;
private boolean requireRegisteringAllInputFrames;
private boolean experimentalAdjustSurfaceTextureTransformationMatrix;
private boolean experimentalRepeatInputBitmapWithoutResampling;

/** Creates an instance. */
public Builder() {
Expand All @@ -159,6 +160,8 @@ private Builder(Factory factory) {
requireRegisteringAllInputFrames = !factory.repeatLastRegisteredFrame;
experimentalAdjustSurfaceTextureTransformationMatrix =
factory.experimentalAdjustSurfaceTextureTransformationMatrix;
experimentalRepeatInputBitmapWithoutResampling =
factory.experimentalRepeatInputBitmapWithoutResampling;
}

/**
Expand Down Expand Up @@ -276,6 +279,21 @@ public Builder setExperimentalAdjustSurfaceTextureTransformationMatrix(
return this;
}

/**
* Sets whether {@link BitmapTextureManager} will sample from the input bitmap only once for a
* sequence of output frames.
*
* <p>Defaults to {@code false}. That is, each output frame will sample from the full
* resolution input bitmap.
*/
@CanIgnoreReturnValue
public Builder setExperimentalRepeatInputBitmapWithoutResampling(
boolean experimentalRepeatInputBitmapWithoutResampling) {
this.experimentalRepeatInputBitmapWithoutResampling =
experimentalRepeatInputBitmapWithoutResampling;
return this;
}

/** Builds an {@link DefaultVideoFrameProcessor.Factory} instance. */
public DefaultVideoFrameProcessor.Factory build() {
return new DefaultVideoFrameProcessor.Factory(
Expand All @@ -285,7 +303,8 @@ public DefaultVideoFrameProcessor.Factory build() {
executorService,
textureOutputListener,
textureOutputCapacity,
experimentalAdjustSurfaceTextureTransformationMatrix);
experimentalAdjustSurfaceTextureTransformationMatrix,
experimentalRepeatInputBitmapWithoutResampling);
}
}

Expand All @@ -296,6 +315,7 @@ public DefaultVideoFrameProcessor.Factory build() {
@Nullable private final GlTextureProducer.Listener textureOutputListener;
private final int textureOutputCapacity;
private final boolean experimentalAdjustSurfaceTextureTransformationMatrix;
private final boolean experimentalRepeatInputBitmapWithoutResampling;

private Factory(
@WorkingColorSpace int sdrWorkingColorSpace,
Expand All @@ -304,7 +324,8 @@ private Factory(
@Nullable ExecutorService executorService,
@Nullable GlTextureProducer.Listener textureOutputListener,
int textureOutputCapacity,
boolean experimentalAdjustSurfaceTextureTransformationMatrix) {
boolean experimentalAdjustSurfaceTextureTransformationMatrix,
boolean experimentalRepeatInputBitmapWithoutResampling) {
this.sdrWorkingColorSpace = sdrWorkingColorSpace;
this.repeatLastRegisteredFrame = repeatLastRegisteredFrame;
this.glObjectsProvider = glObjectsProvider;
Expand All @@ -313,6 +334,8 @@ private Factory(
this.textureOutputCapacity = textureOutputCapacity;
this.experimentalAdjustSurfaceTextureTransformationMatrix =
experimentalAdjustSurfaceTextureTransformationMatrix;
this.experimentalRepeatInputBitmapWithoutResampling =
experimentalRepeatInputBitmapWithoutResampling;
}

public Builder buildUpon() {
Expand Down Expand Up @@ -376,7 +399,8 @@ public DefaultVideoFrameProcessor create(
textureOutputListener,
textureOutputCapacity,
repeatLastRegisteredFrame,
experimentalAdjustSurfaceTextureTransformationMatrix));
experimentalAdjustSurfaceTextureTransformationMatrix,
experimentalRepeatInputBitmapWithoutResampling));

try {
return defaultVideoFrameProcessorFuture.get();
Expand Down Expand Up @@ -745,7 +769,8 @@ private static DefaultVideoFrameProcessor createOpenGlObjectsAndFrameProcessor(
@Nullable GlTextureProducer.Listener textureOutputListener,
int textureOutputCapacity,
boolean repeatLastRegisteredFrame,
boolean experimentalAdjustSurfaceTextureTransformationMatrix)
boolean experimentalAdjustSurfaceTextureTransformationMatrix,
boolean experimentalRepeatInputBitmapWithoutResampling)
throws GlUtil.GlException, VideoFrameProcessingException {
EGLDisplay eglDisplay = GlUtil.getDefaultEglDisplay();
int[] configAttributes =
Expand Down Expand Up @@ -777,7 +802,8 @@ private static DefaultVideoFrameProcessor createOpenGlObjectsAndFrameProcessor(
/* samplingShaderProgramErrorListener= */ listener::onError,
sdrWorkingColorSpace,
repeatLastRegisteredFrame,
experimentalAdjustSurfaceTextureTransformationMatrix);
experimentalAdjustSurfaceTextureTransformationMatrix,
experimentalRepeatInputBitmapWithoutResampling);

FinalShaderProgramWrapper finalShaderProgramWrapper =
new FinalShaderProgramWrapper(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ public InputSwitcher(
GlShaderProgram.ErrorListener samplingShaderProgramErrorListener,
@WorkingColorSpace int sdrWorkingColorSpace,
boolean repeatLastRegisteredFrame,
boolean experimentalAdjustSurfaceTextureTransformationMatrix)
boolean experimentalAdjustSurfaceTextureTransformationMatrix,
boolean experimentalRepeatInputBitmapWithoutResampling)
throws VideoFrameProcessingException {
this.context = context;
this.outputColorInfo = outputColorInfo;
Expand All @@ -91,7 +92,11 @@ public InputSwitcher(
experimentalAdjustSurfaceTextureTransformationMatrix)));
inputs.put(
INPUT_TYPE_BITMAP,
new Input(new BitmapTextureManager(glObjectsProvider, videoFrameProcessingTaskExecutor)));
new Input(
new BitmapTextureManager(
glObjectsProvider,
videoFrameProcessingTaskExecutor,
/* signalRepeatingSequence= */ experimentalRepeatInputBitmapWithoutResampling)));
inputs.put(
INPUT_TYPE_TEXTURE_ID,
new Input(new TexIdTextureManager(glObjectsProvider, videoFrameProcessingTaskExecutor)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@

import android.content.Context;
import android.net.Uri;
import android.os.Build;
import androidx.media3.common.Format;
import androidx.media3.common.MediaItem;
import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.Util;
import androidx.media3.effect.DefaultVideoFrameProcessor;
import androidx.media3.effect.Presentation;
import androidx.media3.transformer.AndroidTestUtil;
import androidx.media3.transformer.EditedMediaItem;
Expand Down Expand Up @@ -103,9 +103,22 @@ public void exportImage_to720p_completesWithHighThroughput() throws Exception {
testId,
/* inputFormat= */ AndroidTestUtil.MP4_LONG_ASSET_WITH_INCREASING_TIMESTAMPS_FORMAT,
outputFormat);
DefaultVideoFrameProcessor.Factory videoFrameProcessorFactory =
new DefaultVideoFrameProcessor.Factory.Builder()
.setExperimentalRepeatInputBitmapWithoutResampling(true)
.build();
Transformer transformer =
new Transformer.Builder(context).setVideoMimeType(MimeTypes.VIDEO_H264).build();
boolean isHighPerformance = Util.SDK_INT >= 31 && Build.SOC_MODEL.startsWith("Tensor");
new Transformer.Builder(context)
.setVideoMimeType(MimeTypes.VIDEO_H264)
.setVideoFrameProcessorFactory(videoFrameProcessorFactory)
.build();
boolean isHighPerformance =
Ascii.toLowerCase(Util.MODEL).contains("pixel")
&& (Ascii.toLowerCase(Util.MODEL).contains("6")
|| Ascii.toLowerCase(Util.MODEL).contains("7")
|| Ascii.toLowerCase(Util.MODEL).contains("8")
|| Ascii.toLowerCase(Util.MODEL).contains("fold")
|| Ascii.toLowerCase(Util.MODEL).contains("tablet"));
if (Util.SDK_INT == 33 && Ascii.toLowerCase(Util.MODEL).contains("pixel 6")) {
// Pixel 6 is usually quick, unless it's on API 33.
isHighPerformance = false;
Expand Down

0 comments on commit 3c998ac

Please sign in to comment.