Add a flag to control whether input bitmap resampling can be skipped
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
This commit is contained in:
parent
02df88e5d9
commit
3c998ac408
@ -46,6 +46,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
|||||||
// The queue holds all bitmaps with one or more frames pending to be sent downstream.
|
// The queue holds all bitmaps with one or more frames pending to be sent downstream.
|
||||||
private final Queue<BitmapFrameSequenceInfo> pendingBitmaps;
|
private final Queue<BitmapFrameSequenceInfo> pendingBitmaps;
|
||||||
private final GlObjectsProvider glObjectsProvider;
|
private final GlObjectsProvider glObjectsProvider;
|
||||||
|
private final boolean signalRepeatingSequence;
|
||||||
|
|
||||||
private @MonotonicNonNull RepeatingGainmapShaderProgram repeatingGainmapShaderProgram;
|
private @MonotonicNonNull RepeatingGainmapShaderProgram repeatingGainmapShaderProgram;
|
||||||
@Nullable private GlTextureInfo currentSdrGlTextureInfo;
|
@Nullable private GlTextureInfo currentSdrGlTextureInfo;
|
||||||
@ -59,13 +60,18 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
|||||||
* @param glObjectsProvider The {@link GlObjectsProvider} for using EGL and GLES.
|
* @param glObjectsProvider The {@link GlObjectsProvider} for using EGL and GLES.
|
||||||
* @param videoFrameProcessingTaskExecutor The {@link VideoFrameProcessingTaskExecutor} that the
|
* @param videoFrameProcessingTaskExecutor The {@link VideoFrameProcessingTaskExecutor} that the
|
||||||
* methods of this class run on.
|
* 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(
|
public BitmapTextureManager(
|
||||||
GlObjectsProvider glObjectsProvider,
|
GlObjectsProvider glObjectsProvider,
|
||||||
VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor) {
|
VideoFrameProcessingTaskExecutor videoFrameProcessingTaskExecutor,
|
||||||
|
boolean signalRepeatingSequence) {
|
||||||
super(videoFrameProcessingTaskExecutor);
|
super(videoFrameProcessingTaskExecutor);
|
||||||
this.glObjectsProvider = glObjectsProvider;
|
this.glObjectsProvider = glObjectsProvider;
|
||||||
pendingBitmaps = new LinkedBlockingQueue<>();
|
pendingBitmaps = new LinkedBlockingQueue<>();
|
||||||
|
this.signalRepeatingSequence = signalRepeatingSequence;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -215,7 +221,9 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
|||||||
if (Util.SDK_INT >= 34 && bitmap.hasGainmap()) {
|
if (Util.SDK_INT >= 34 && bitmap.hasGainmap()) {
|
||||||
checkNotNull(repeatingGainmapShaderProgram).setGainmap(checkNotNull(bitmap.getGainmap()));
|
checkNotNull(repeatingGainmapShaderProgram).setGainmap(checkNotNull(bitmap.getGainmap()));
|
||||||
}
|
}
|
||||||
checkNotNull(repeatingGainmapShaderProgram).signalNewRepeatingFrameSequence();
|
if (signalRepeatingSequence) {
|
||||||
|
checkNotNull(repeatingGainmapShaderProgram).signalNewRepeatingFrameSequence();
|
||||||
|
}
|
||||||
} catch (GlUtil.GlException e) {
|
} catch (GlUtil.GlException e) {
|
||||||
throw VideoFrameProcessingException.from(e);
|
throw VideoFrameProcessingException.from(e);
|
||||||
}
|
}
|
||||||
|
@ -143,6 +143,7 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
|||||||
private int textureOutputCapacity;
|
private int textureOutputCapacity;
|
||||||
private boolean requireRegisteringAllInputFrames;
|
private boolean requireRegisteringAllInputFrames;
|
||||||
private boolean experimentalAdjustSurfaceTextureTransformationMatrix;
|
private boolean experimentalAdjustSurfaceTextureTransformationMatrix;
|
||||||
|
private boolean experimentalRepeatInputBitmapWithoutResampling;
|
||||||
|
|
||||||
/** Creates an instance. */
|
/** Creates an instance. */
|
||||||
public Builder() {
|
public Builder() {
|
||||||
@ -159,6 +160,8 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
|||||||
requireRegisteringAllInputFrames = !factory.repeatLastRegisteredFrame;
|
requireRegisteringAllInputFrames = !factory.repeatLastRegisteredFrame;
|
||||||
experimentalAdjustSurfaceTextureTransformationMatrix =
|
experimentalAdjustSurfaceTextureTransformationMatrix =
|
||||||
factory.experimentalAdjustSurfaceTextureTransformationMatrix;
|
factory.experimentalAdjustSurfaceTextureTransformationMatrix;
|
||||||
|
experimentalRepeatInputBitmapWithoutResampling =
|
||||||
|
factory.experimentalRepeatInputBitmapWithoutResampling;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -276,6 +279,21 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
|||||||
return this;
|
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. */
|
/** Builds an {@link DefaultVideoFrameProcessor.Factory} instance. */
|
||||||
public DefaultVideoFrameProcessor.Factory build() {
|
public DefaultVideoFrameProcessor.Factory build() {
|
||||||
return new DefaultVideoFrameProcessor.Factory(
|
return new DefaultVideoFrameProcessor.Factory(
|
||||||
@ -285,7 +303,8 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
|||||||
executorService,
|
executorService,
|
||||||
textureOutputListener,
|
textureOutputListener,
|
||||||
textureOutputCapacity,
|
textureOutputCapacity,
|
||||||
experimentalAdjustSurfaceTextureTransformationMatrix);
|
experimentalAdjustSurfaceTextureTransformationMatrix,
|
||||||
|
experimentalRepeatInputBitmapWithoutResampling);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,6 +315,7 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
|||||||
@Nullable private final GlTextureProducer.Listener textureOutputListener;
|
@Nullable private final GlTextureProducer.Listener textureOutputListener;
|
||||||
private final int textureOutputCapacity;
|
private final int textureOutputCapacity;
|
||||||
private final boolean experimentalAdjustSurfaceTextureTransformationMatrix;
|
private final boolean experimentalAdjustSurfaceTextureTransformationMatrix;
|
||||||
|
private final boolean experimentalRepeatInputBitmapWithoutResampling;
|
||||||
|
|
||||||
private Factory(
|
private Factory(
|
||||||
@WorkingColorSpace int sdrWorkingColorSpace,
|
@WorkingColorSpace int sdrWorkingColorSpace,
|
||||||
@ -304,7 +324,8 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
|||||||
@Nullable ExecutorService executorService,
|
@Nullable ExecutorService executorService,
|
||||||
@Nullable GlTextureProducer.Listener textureOutputListener,
|
@Nullable GlTextureProducer.Listener textureOutputListener,
|
||||||
int textureOutputCapacity,
|
int textureOutputCapacity,
|
||||||
boolean experimentalAdjustSurfaceTextureTransformationMatrix) {
|
boolean experimentalAdjustSurfaceTextureTransformationMatrix,
|
||||||
|
boolean experimentalRepeatInputBitmapWithoutResampling) {
|
||||||
this.sdrWorkingColorSpace = sdrWorkingColorSpace;
|
this.sdrWorkingColorSpace = sdrWorkingColorSpace;
|
||||||
this.repeatLastRegisteredFrame = repeatLastRegisteredFrame;
|
this.repeatLastRegisteredFrame = repeatLastRegisteredFrame;
|
||||||
this.glObjectsProvider = glObjectsProvider;
|
this.glObjectsProvider = glObjectsProvider;
|
||||||
@ -313,6 +334,8 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
|||||||
this.textureOutputCapacity = textureOutputCapacity;
|
this.textureOutputCapacity = textureOutputCapacity;
|
||||||
this.experimentalAdjustSurfaceTextureTransformationMatrix =
|
this.experimentalAdjustSurfaceTextureTransformationMatrix =
|
||||||
experimentalAdjustSurfaceTextureTransformationMatrix;
|
experimentalAdjustSurfaceTextureTransformationMatrix;
|
||||||
|
this.experimentalRepeatInputBitmapWithoutResampling =
|
||||||
|
experimentalRepeatInputBitmapWithoutResampling;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder buildUpon() {
|
public Builder buildUpon() {
|
||||||
@ -376,7 +399,8 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
|||||||
textureOutputListener,
|
textureOutputListener,
|
||||||
textureOutputCapacity,
|
textureOutputCapacity,
|
||||||
repeatLastRegisteredFrame,
|
repeatLastRegisteredFrame,
|
||||||
experimentalAdjustSurfaceTextureTransformationMatrix));
|
experimentalAdjustSurfaceTextureTransformationMatrix,
|
||||||
|
experimentalRepeatInputBitmapWithoutResampling));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return defaultVideoFrameProcessorFuture.get();
|
return defaultVideoFrameProcessorFuture.get();
|
||||||
@ -745,7 +769,8 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
|||||||
@Nullable GlTextureProducer.Listener textureOutputListener,
|
@Nullable GlTextureProducer.Listener textureOutputListener,
|
||||||
int textureOutputCapacity,
|
int textureOutputCapacity,
|
||||||
boolean repeatLastRegisteredFrame,
|
boolean repeatLastRegisteredFrame,
|
||||||
boolean experimentalAdjustSurfaceTextureTransformationMatrix)
|
boolean experimentalAdjustSurfaceTextureTransformationMatrix,
|
||||||
|
boolean experimentalRepeatInputBitmapWithoutResampling)
|
||||||
throws GlUtil.GlException, VideoFrameProcessingException {
|
throws GlUtil.GlException, VideoFrameProcessingException {
|
||||||
EGLDisplay eglDisplay = GlUtil.getDefaultEglDisplay();
|
EGLDisplay eglDisplay = GlUtil.getDefaultEglDisplay();
|
||||||
int[] configAttributes =
|
int[] configAttributes =
|
||||||
@ -777,7 +802,8 @@ public final class DefaultVideoFrameProcessor implements VideoFrameProcessor {
|
|||||||
/* samplingShaderProgramErrorListener= */ listener::onError,
|
/* samplingShaderProgramErrorListener= */ listener::onError,
|
||||||
sdrWorkingColorSpace,
|
sdrWorkingColorSpace,
|
||||||
repeatLastRegisteredFrame,
|
repeatLastRegisteredFrame,
|
||||||
experimentalAdjustSurfaceTextureTransformationMatrix);
|
experimentalAdjustSurfaceTextureTransformationMatrix,
|
||||||
|
experimentalRepeatInputBitmapWithoutResampling);
|
||||||
|
|
||||||
FinalShaderProgramWrapper finalShaderProgramWrapper =
|
FinalShaderProgramWrapper finalShaderProgramWrapper =
|
||||||
new FinalShaderProgramWrapper(
|
new FinalShaderProgramWrapper(
|
||||||
|
@ -67,7 +67,8 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
|||||||
GlShaderProgram.ErrorListener samplingShaderProgramErrorListener,
|
GlShaderProgram.ErrorListener samplingShaderProgramErrorListener,
|
||||||
@WorkingColorSpace int sdrWorkingColorSpace,
|
@WorkingColorSpace int sdrWorkingColorSpace,
|
||||||
boolean repeatLastRegisteredFrame,
|
boolean repeatLastRegisteredFrame,
|
||||||
boolean experimentalAdjustSurfaceTextureTransformationMatrix)
|
boolean experimentalAdjustSurfaceTextureTransformationMatrix,
|
||||||
|
boolean experimentalRepeatInputBitmapWithoutResampling)
|
||||||
throws VideoFrameProcessingException {
|
throws VideoFrameProcessingException {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.outputColorInfo = outputColorInfo;
|
this.outputColorInfo = outputColorInfo;
|
||||||
@ -91,7 +92,11 @@ import org.checkerframework.checker.nullness.qual.Nullable;
|
|||||||
experimentalAdjustSurfaceTextureTransformationMatrix)));
|
experimentalAdjustSurfaceTextureTransformationMatrix)));
|
||||||
inputs.put(
|
inputs.put(
|
||||||
INPUT_TYPE_BITMAP,
|
INPUT_TYPE_BITMAP,
|
||||||
new Input(new BitmapTextureManager(glObjectsProvider, videoFrameProcessingTaskExecutor)));
|
new Input(
|
||||||
|
new BitmapTextureManager(
|
||||||
|
glObjectsProvider,
|
||||||
|
videoFrameProcessingTaskExecutor,
|
||||||
|
/* signalRepeatingSequence= */ experimentalRepeatInputBitmapWithoutResampling)));
|
||||||
inputs.put(
|
inputs.put(
|
||||||
INPUT_TYPE_TEXTURE_ID,
|
INPUT_TYPE_TEXTURE_ID,
|
||||||
new Input(new TexIdTextureManager(glObjectsProvider, videoFrameProcessingTaskExecutor)));
|
new Input(new TexIdTextureManager(glObjectsProvider, videoFrameProcessingTaskExecutor)));
|
||||||
|
@ -23,11 +23,11 @@ import static com.google.common.truth.Truth.assertThat;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
|
||||||
import androidx.media3.common.Format;
|
import androidx.media3.common.Format;
|
||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
import androidx.media3.common.MimeTypes;
|
import androidx.media3.common.MimeTypes;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
|
import androidx.media3.effect.DefaultVideoFrameProcessor;
|
||||||
import androidx.media3.effect.Presentation;
|
import androidx.media3.effect.Presentation;
|
||||||
import androidx.media3.transformer.AndroidTestUtil;
|
import androidx.media3.transformer.AndroidTestUtil;
|
||||||
import androidx.media3.transformer.EditedMediaItem;
|
import androidx.media3.transformer.EditedMediaItem;
|
||||||
@ -103,9 +103,22 @@ public class TranscodeSpeedTest {
|
|||||||
testId,
|
testId,
|
||||||
/* inputFormat= */ AndroidTestUtil.MP4_LONG_ASSET_WITH_INCREASING_TIMESTAMPS_FORMAT,
|
/* inputFormat= */ AndroidTestUtil.MP4_LONG_ASSET_WITH_INCREASING_TIMESTAMPS_FORMAT,
|
||||||
outputFormat);
|
outputFormat);
|
||||||
|
DefaultVideoFrameProcessor.Factory videoFrameProcessorFactory =
|
||||||
|
new DefaultVideoFrameProcessor.Factory.Builder()
|
||||||
|
.setExperimentalRepeatInputBitmapWithoutResampling(true)
|
||||||
|
.build();
|
||||||
Transformer transformer =
|
Transformer transformer =
|
||||||
new Transformer.Builder(context).setVideoMimeType(MimeTypes.VIDEO_H264).build();
|
new Transformer.Builder(context)
|
||||||
boolean isHighPerformance = Util.SDK_INT >= 31 && Build.SOC_MODEL.startsWith("Tensor");
|
.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")) {
|
if (Util.SDK_INT == 33 && Ascii.toLowerCase(Util.MODEL).contains("pixel 6")) {
|
||||||
// Pixel 6 is usually quick, unless it's on API 33.
|
// Pixel 6 is usually quick, unless it's on API 33.
|
||||||
isHighPerformance = false;
|
isHighPerformance = false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user