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:
parent
244777234b
commit
ef1788dcea
@ -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();
|
||||||
|
|
||||||
|
@ -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,17 +80,23 @@ import java.io.IOException;
|
|||||||
throw createRendererException(
|
throw createRendererException(
|
||||||
e, rendererIndex, inputFormat, PlaybackException.ERROR_CODE_UNSPECIFIED);
|
e, rendererIndex, inputFormat, PlaybackException.ERROR_CODE_UNSPECIFIED);
|
||||||
}
|
}
|
||||||
frameEditor =
|
if (inputFormat.height != transformation.outputHeight
|
||||||
FrameEditor.create(
|
|| !transformation.transformationMatrix.isIdentity()) {
|
||||||
context,
|
frameEditor =
|
||||||
outputWidth,
|
FrameEditor.create(
|
||||||
outputHeight,
|
context,
|
||||||
transformation.transformationMatrix,
|
outputWidth,
|
||||||
/* outputSurface= */ checkNotNull(encoder.getInputSurface()));
|
outputHeight,
|
||||||
|
transformation.transformationMatrix,
|
||||||
|
/* 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,24 +109,27 @@ import java.io.IOException;
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frameEditor.hasInputData()) {
|
if (frameEditor != null) {
|
||||||
waitingForPopulatedDecoderSurface = false;
|
if (frameEditor.hasInputData()) {
|
||||||
frameEditor.processData();
|
waitingForFrameEditorInput = false;
|
||||||
return true;
|
frameEditor.processData();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (waitingForFrameEditorInput) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (waitingForPopulatedDecoderSurface) {
|
boolean decoderHasOutputBuffer = decoder.getOutputBufferInfo() != null;
|
||||||
return false;
|
if (decoderHasOutputBuffer) {
|
||||||
}
|
|
||||||
|
|
||||||
if (decoder.getOutputBufferInfo() != null) {
|
|
||||||
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
|
||||||
@ -164,7 +174,9 @@ import java.io.IOException;
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void release() {
|
public void release() {
|
||||||
frameEditor.release();
|
if (frameEditor != null) {
|
||||||
|
frameEditor.release();
|
||||||
|
}
|
||||||
decoder.release();
|
decoder.release();
|
||||||
encoder.release();
|
encoder.release();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user