Only use a FrameEditor if editing is needed.

When no editing is needed, the OpenGL steps can be skipped.

PiperOrigin-RevId: 413884305
This commit is contained in:
hschlueter 2021-12-03 10:34:55 +00:00 committed by Ian Baker
parent 244777234b
commit ef1788dcea
2 changed files with 42 additions and 23 deletions

View File

@ -19,6 +19,7 @@ import static androidx.media3.transformer.mh.AndroidTestUtil.runTransformer;
import static com.google.common.truth.Truth.assertWithMessage; import static com.google.common.truth.Truth.assertWithMessage;
import android.content.Context; import android.content.Context;
import android.graphics.Matrix;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.transformer.Transformer; import androidx.media3.transformer.Transformer;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
@ -38,9 +39,12 @@ public final class RepeatedTranscodeTransformationTest {
@Test @Test
public void repeatedTranscode_givesConsistentLengthOutput() throws Exception { public void repeatedTranscode_givesConsistentLengthOutput() throws Exception {
Context context = ApplicationProvider.getApplicationContext(); Context context = ApplicationProvider.getApplicationContext();
Matrix transformationMatrix = new Matrix();
transformationMatrix.postTranslate((float) 0.1, (float) 0.1);
Transformer transformer = Transformer transformer =
new Transformer.Builder(context) new Transformer.Builder(context)
.setVideoMimeType(MimeTypes.VIDEO_H265) .setVideoMimeType(MimeTypes.VIDEO_H265)
.setTransformationMatrix(transformationMatrix)
.setAudioMimeType(MimeTypes.AUDIO_AMR_NB) .setAudioMimeType(MimeTypes.AUDIO_AMR_NB)
.build(); .build();
@ -66,9 +70,12 @@ public final class RepeatedTranscodeTransformationTest {
@Test @Test
public void repeatedTranscodeNoAudio_givesConsistentLengthOutput() throws Exception { public void repeatedTranscodeNoAudio_givesConsistentLengthOutput() throws Exception {
Context context = ApplicationProvider.getApplicationContext(); Context context = ApplicationProvider.getApplicationContext();
Matrix transformationMatrix = new Matrix();
transformationMatrix.postTranslate((float) 0.1, (float) 0.1);
Transformer transformer = Transformer transformer =
new Transformer.Builder(context) new Transformer.Builder(context)
.setVideoMimeType(MimeTypes.VIDEO_H265) .setVideoMimeType(MimeTypes.VIDEO_H265)
.setTransformationMatrix(transformationMatrix)
.setRemoveAudio(true) .setRemoveAudio(true)
.build(); .build();

View File

@ -28,6 +28,7 @@ import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.exoplayer.ExoPlaybackException; import androidx.media3.exoplayer.ExoPlaybackException;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import java.io.IOException; import java.io.IOException;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/** /**
* Pipeline to decode video samples, apply transformations on the raw samples, and re-encode them. * Pipeline to decode video samples, apply transformations on the raw samples, and re-encode them.
@ -39,12 +40,12 @@ import java.io.IOException;
private final DecoderInputBuffer decoderInputBuffer; private final DecoderInputBuffer decoderInputBuffer;
private final MediaCodecAdapterWrapper decoder; private final MediaCodecAdapterWrapper decoder;
private final FrameEditor frameEditor;
private final MediaCodecAdapterWrapper encoder; private final MediaCodecAdapterWrapper encoder;
private final DecoderInputBuffer encoderOutputBuffer; private final DecoderInputBuffer encoderOutputBuffer;
private boolean waitingForPopulatedDecoderSurface; private @MonotonicNonNull FrameEditor frameEditor;
private boolean waitingForFrameEditorInput;
public VideoSamplePipeline( public VideoSamplePipeline(
Context context, Format inputFormat, Transformation transformation, int rendererIndex) Context context, Format inputFormat, Transformation transformation, int rendererIndex)
@ -79,6 +80,8 @@ import java.io.IOException;
throw createRendererException( throw createRendererException(
e, rendererIndex, inputFormat, PlaybackException.ERROR_CODE_UNSPECIFIED); e, rendererIndex, inputFormat, PlaybackException.ERROR_CODE_UNSPECIFIED);
} }
if (inputFormat.height != transformation.outputHeight
|| !transformation.transformationMatrix.isIdentity()) {
frameEditor = frameEditor =
FrameEditor.create( FrameEditor.create(
context, context,
@ -86,10 +89,14 @@ import java.io.IOException;
outputHeight, outputHeight,
transformation.transformationMatrix, transformation.transformationMatrix,
/* outputSurface= */ checkNotNull(encoder.getInputSurface())); /* outputSurface= */ checkNotNull(encoder.getInputSurface()));
}
try { try {
decoder = decoder =
MediaCodecAdapterWrapper.createForVideoDecoding( MediaCodecAdapterWrapper.createForVideoDecoding(
inputFormat, frameEditor.getInputSurface()); inputFormat,
frameEditor == null
? checkNotNull(encoder.getInputSurface())
: frameEditor.getInputSurface());
} catch (IOException e) { } catch (IOException e) {
throw createRendererException( throw createRendererException(
e, rendererIndex, inputFormat, PlaybackException.ERROR_CODE_DECODER_INIT_FAILED); e, rendererIndex, inputFormat, PlaybackException.ERROR_CODE_DECODER_INIT_FAILED);
@ -102,25 +109,28 @@ import java.io.IOException;
return false; return false;
} }
if (frameEditor != null) {
if (frameEditor.hasInputData()) { if (frameEditor.hasInputData()) {
waitingForPopulatedDecoderSurface = false; waitingForFrameEditorInput = false;
frameEditor.processData(); frameEditor.processData();
return true; return true;
} }
if (waitingForFrameEditorInput) {
if (waitingForPopulatedDecoderSurface) {
return false; return false;
} }
}
if (decoder.getOutputBufferInfo() != null) { boolean decoderHasOutputBuffer = decoder.getOutputBufferInfo() != null;
if (decoderHasOutputBuffer) {
decoder.releaseOutputBuffer(/* render= */ true); decoder.releaseOutputBuffer(/* render= */ true);
waitingForPopulatedDecoderSurface = true; waitingForFrameEditorInput = frameEditor != null;
} }
if (decoder.isEnded()) { if (decoder.isEnded()) {
encoder.signalEndOfInputStream(); encoder.signalEndOfInputStream();
}
return false; return false;
} }
return decoderHasOutputBuffer && !waitingForFrameEditorInput;
}
@Override @Override
@Nullable @Nullable
@ -164,7 +174,9 @@ import java.io.IOException;
@Override @Override
public void release() { public void release() {
if (frameEditor != null) {
frameEditor.release(); frameEditor.release();
}
decoder.release(); decoder.release();
encoder.release(); encoder.release();
} }