Avoid re-encoding if video effects are no-op

This is to avoid regressions introduced by removing the convenience
methods from TransformationRequest.

PiperOrigin-RevId: 502864512
This commit is contained in:
kimvde 2023-01-18 14:54:00 +00:00 committed by christosts
parent 50f066d634
commit a043c8c204
3 changed files with 60 additions and 9 deletions

View File

@ -90,6 +90,13 @@ public final class ScaleToFitTransformation implements MatrixTransformation {
} }
} }
/** The multiplier by which the frame will scale horizontally, along the x-axis. */
public final float scaleX;
/** The multiplier by which the frame will scale vertically, along the y-axis. */
public final float scaleY;
/** How much to rotate the frame counterclockwise, in degrees. */
public final float rotationDegrees;
private final Matrix transformationMatrix; private final Matrix transformationMatrix;
private @MonotonicNonNull Matrix adjustedTransformationMatrix; private @MonotonicNonNull Matrix adjustedTransformationMatrix;
@ -101,6 +108,9 @@ public final class ScaleToFitTransformation implements MatrixTransformation {
* @param rotationDegrees How much to rotate the frame counterclockwise, in degrees. * @param rotationDegrees How much to rotate the frame counterclockwise, in degrees.
*/ */
private ScaleToFitTransformation(float scaleX, float scaleY, float rotationDegrees) { private ScaleToFitTransformation(float scaleX, float scaleY, float rotationDegrees) {
this.scaleX = scaleX;
this.scaleY = scaleY;
this.rotationDegrees = rotationDegrees;
transformationMatrix = new Matrix(); transformationMatrix = new Matrix();
transformationMatrix.postScale(scaleX, scaleY); transformationMatrix.postScale(scaleX, scaleY);
transformationMatrix.postRotate(rotationDegrees); transformationMatrix.postRotate(rotationDegrees);

View File

@ -35,6 +35,8 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.audio.AudioProcessor; import com.google.android.exoplayer2.audio.AudioProcessor;
import com.google.android.exoplayer2.effect.Presentation;
import com.google.android.exoplayer2.effect.ScaleToFitTransformation;
import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.mp4.SlowMotionData; import com.google.android.exoplayer2.metadata.mp4.SlowMotionData;
import com.google.android.exoplayer2.util.Clock; import com.google.android.exoplayer2.util.Clock;
@ -44,6 +46,7 @@ import com.google.android.exoplayer2.util.Effect;
import com.google.android.exoplayer2.util.FrameProcessor; import com.google.android.exoplayer2.util.FrameProcessor;
import com.google.android.exoplayer2.util.HandlerWrapper; import com.google.android.exoplayer2.util.HandlerWrapper;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Size;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
@ -577,16 +580,34 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
if (inputFormat.pixelWidthHeightRatio != 1f) { if (inputFormat.pixelWidthHeightRatio != 1f) {
return true; return true;
} }
// The decoder rotates encoded frames for display by inputFormat.rotationDegrees.
int decodedHeight = // TODO(b/265927935): consider generalizing this logic.
(inputFormat.rotationDegrees % 180 == 0) ? inputFormat.height : inputFormat.width; for (int i = 0; i < videoEffects.size(); i++) {
if (transformationRequest.outputHeight != C.LENGTH_UNSET Effect videoEffect = videoEffects.get(i);
&& transformationRequest.outputHeight != decodedHeight) { if (videoEffect instanceof Presentation) {
return true; Presentation presentation = (Presentation) videoEffect;
} // The decoder rotates encoded frames for display by inputFormat.rotationDegrees.
if (!videoEffects.isEmpty()) { int decodedWidth =
return true; (inputFormat.rotationDegrees % 180 == 0) ? inputFormat.width : inputFormat.height;
int decodedHeight =
(inputFormat.rotationDegrees % 180 == 0) ? inputFormat.height : inputFormat.width;
Size outputSize = presentation.configure(decodedWidth, decodedHeight);
if (outputSize.getWidth() != decodedWidth || outputSize.getHeight() != decodedHeight) {
return true;
}
} else if (videoEffect instanceof ScaleToFitTransformation) {
ScaleToFitTransformation scaleToFitTransformation =
(ScaleToFitTransformation) videoEffect;
if (scaleToFitTransformation.scaleX != 1f
|| scaleToFitTransformation.scaleY != 1f
|| scaleToFitTransformation.rotationDegrees != 0f) {
return true;
}
} else {
return true;
}
} }
return false; return false;
} }
} }

View File

@ -48,6 +48,8 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.audio.SonicAudioProcessor; import com.google.android.exoplayer2.audio.SonicAudioProcessor;
import com.google.android.exoplayer2.effect.Presentation;
import com.google.android.exoplayer2.effect.ScaleToFitTransformation;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory; import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.Extractor;
import com.google.android.exoplayer2.extractor.ExtractorInput; import com.google.android.exoplayer2.extractor.ExtractorInput;
@ -58,6 +60,7 @@ import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.testutil.DumpFileAsserts; import com.google.android.exoplayer2.testutil.DumpFileAsserts;
import com.google.android.exoplayer2.testutil.FakeClock; import com.google.android.exoplayer2.testutil.FakeClock;
import com.google.android.exoplayer2.util.Effect;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -728,6 +731,23 @@ public final class TransformerEndToEndTest {
assertThat(transformationException).hasCauseThat().isInstanceOf(IllegalStateException.class); assertThat(transformationException).hasCauseThat().isInstanceOf(IllegalStateException.class);
} }
@Test
public void startTransformation_withNoOpEffects_transmuxes() throws Exception {
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY);
int mediaItemHeightPixels = 720;
List<Effect> videoEffects = new ArrayList<>();
videoEffects.add(Presentation.createForHeight(mediaItemHeightPixels));
videoEffects.add(new ScaleToFitTransformation.Builder().build());
Transformer transformer =
createTransformerBuilder(/* enableFallback= */ false).setVideoEffects(videoEffects).build();
transformer.startTransformation(mediaItem, outputPath);
TransformerTestRunner.runLooper(transformer);
// Video transcoding in unit tests is not supported.
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_VIDEO_ONLY));
}
@Test @Test
public void getProgress_knownDuration_returnsConsistentStates() throws Exception { public void getProgress_knownDuration_returnsConsistentStates() throws Exception {
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build(); Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();