From eaec7a4a613da75ccc0c682c8865f0a44e9a5e82 Mon Sep 17 00:00:00 2001 From: kimvde Date: Wed, 25 Sep 2024 05:20:13 -0700 Subject: [PATCH] Set MediaItem's image duration for image export This field will become mandatory PiperOrigin-RevId: 678656879 --- .../demo/transformer/TransformerActivity.java | 7 ++- .../ParameterizedAndroidTestUtil.java | 33 ++++++------- .../transformer/SequenceEffectTestUtil.java | 6 +-- .../transformer/TransformerEndToEndTest.java | 46 +++++++++++-------- ...ansformerMultiSequenceCompositionTest.java | 5 +- .../TransformerSequenceEffectTest.java | 14 ++++-- .../transformer/mh/TranscodeSpeedTest.java | 7 ++- .../transformer/ImageAssetLoaderTest.java | 4 +- 8 files changed, 69 insertions(+), 53 deletions(-) diff --git a/demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java b/demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java index 91658b8bcb..a006971fc3 100644 --- a/demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java +++ b/demos/transformer/src/main/java/androidx/media3/demo/transformer/TransformerActivity.java @@ -121,6 +121,8 @@ import org.json.JSONObject; /** An {@link Activity} that exports and plays media using {@link Transformer}. */ public final class TransformerActivity extends AppCompatActivity { private static final String TAG = "TransformerActivity"; + private static final int IMAGE_DURATION_MS = 5_000; + private static final int IMAGE_FRAME_RATE_FPS = 30; private static int LOAD_CONTROL_MIN_BUFFER_MS = 5_000; private static int LOAD_CONTROL_MAX_BUFFER_MS = 5_000; @@ -267,7 +269,8 @@ public final class TransformerActivity extends AppCompatActivity { } private MediaItem createMediaItem(@Nullable Bundle bundle, Uri uri) { - MediaItem.Builder mediaItemBuilder = new MediaItem.Builder().setUri(uri); + MediaItem.Builder mediaItemBuilder = + new MediaItem.Builder().setUri(uri).setImageDurationMs(IMAGE_DURATION_MS); if (bundle != null) { long trimStartMs = bundle.getLong(ConfigurationActivity.TRIM_START_MS, /* defaultValue= */ C.TIME_UNSET); @@ -359,7 +362,7 @@ public final class TransformerActivity extends AppCompatActivity { private Composition createComposition(MediaItem mediaItem, @Nullable Bundle bundle) { EditedMediaItem.Builder editedMediaItemBuilder = new EditedMediaItem.Builder(mediaItem); // For image inputs. Automatically ignored if input is audio/video. - editedMediaItemBuilder.setDurationUs(5_000_000).setFrameRate(30); + editedMediaItemBuilder.setFrameRate(IMAGE_FRAME_RATE_FPS); if (bundle != null) { ImmutableList audioProcessors = createAudioProcessorsFromBundle(bundle); ImmutableList videoEffects = createVideoEffectsFromBundle(bundle); diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/ParameterizedAndroidTestUtil.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/ParameterizedAndroidTestUtil.java index 589db4019a..61ebefbd87 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/ParameterizedAndroidTestUtil.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/ParameterizedAndroidTestUtil.java @@ -105,7 +105,7 @@ import java.util.Objects; protected final Effects effects; - private final String uri; + protected final String uri; public ItemConfig( String uri, @@ -120,20 +120,7 @@ import java.util.Objects; this.effects = effects; } - public final EditedMediaItem build() { - EditedMediaItem.Builder builder = - new EditedMediaItem.Builder(MediaItem.fromUri(uri)).setEffects(effects); - onBuild(builder); - return builder.build(); - } - - /** - * Called when an {@link EditedMediaItem} is being {@linkplain #build() built}. - * - * @param builder The {@link EditedMediaItem.Builder} to optionally modify before the item is - * built. - */ - protected abstract void onBuild(EditedMediaItem.Builder builder); + protected abstract EditedMediaItem build(); @Override public String toString() { @@ -178,8 +165,13 @@ import java.util.Objects; } @Override - protected void onBuild(EditedMediaItem.Builder builder) { - builder.setFrameRate(frameRate).setDurationUs(durationUs); + protected EditedMediaItem build() { + MediaItem mediaItem = + new MediaItem.Builder().setUri(uri).setImageDurationMs(Util.usToMs(durationUs)).build(); + return new EditedMediaItem.Builder(mediaItem) + .setEffects(effects) + .setFrameRate(frameRate) + .build(); } } @@ -194,8 +186,11 @@ import java.util.Objects; } @Override - protected void onBuild(EditedMediaItem.Builder builder) { - builder.setRemoveAudio(true); + protected EditedMediaItem build() { + return new EditedMediaItem.Builder(MediaItem.fromUri(uri)) + .setEffects(effects) + .setRemoveAudio(true) + .build(); } } diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/SequenceEffectTestUtil.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/SequenceEffectTestUtil.java index 27bdbd0215..0e11c9a107 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/SequenceEffectTestUtil.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/SequenceEffectTestUtil.java @@ -102,10 +102,10 @@ public final class SequenceEffectTestUtil { * effects} applied. */ public static EditedMediaItem oneFrameFromImage(String uri, List effects) { - return new EditedMediaItem.Builder(MediaItem.fromUri(uri)) - // 50ms for a 20-fps video is one frame. + // 50ms for a 20-fps video is one frame. + return new EditedMediaItem.Builder( + new MediaItem.Builder().setUri(uri).setImageDurationMs(50).build()) .setFrameRate(20) - .setDurationUs(50_000) .setEffects( new Effects(/* audioProcessors= */ ImmutableList.of(), ImmutableList.copyOf(effects))) .build(); diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerEndToEndTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerEndToEndTest.java index f9025c9c6b..7d52185101 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerEndToEndTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerEndToEndTest.java @@ -145,8 +145,8 @@ public class TransformerEndToEndTest { ImmutableList.of(RgbFilter.createInvertedFilter()))) .build(); EditedMediaItem imageItem = - new EditedMediaItem.Builder(MediaItem.fromUri(JPG_ASSET.uri)) - .setDurationUs(1_500_000) + new EditedMediaItem.Builder( + new MediaItem.Builder().setUri(JPG_ASSET.uri).setImageDurationMs(1500).build()) .setFrameRate(30) .build(); @@ -209,8 +209,8 @@ public class TransformerEndToEndTest { /* inputFormat= */ MP4_ASSET.videoFormat, /* outputFormat= */ MP4_ASSET.videoFormat); EditedMediaItem imageItem = - new EditedMediaItem.Builder(MediaItem.fromUri(JPG_ASSET.uri)) - .setDurationUs(500_000) + new EditedMediaItem.Builder( + new MediaItem.Builder().setUri(JPG_ASSET.uri).setImageDurationMs(500).build()) .setFrameRate(30) .build(); @@ -251,9 +251,13 @@ public class TransformerEndToEndTest { ImmutableList videoEffects = ImmutableList.of(Presentation.createForHeight(480)); Effects effects = new Effects(/* audioProcessors= */ ImmutableList.of(), videoEffects); int expectedFrameCount = 40; + MediaItem mediaItem = + new MediaItem.Builder() + .setUri(PNG_ASSET.uri) + .setImageDurationMs(C.MILLIS_PER_SECOND) + .build(); EditedMediaItem editedMediaItem = - new EditedMediaItem.Builder(MediaItem.fromUri(PNG_ASSET.uri)) - .setDurationUs(C.MICROS_PER_SECOND) + new EditedMediaItem.Builder(mediaItem) .setFrameRate(expectedFrameCount) .setEffects(effects) .build(); @@ -275,8 +279,11 @@ public class TransformerEndToEndTest { Transformer transformer = new Transformer.Builder(context).build(); int expectedFrameCount = 40; EditedMediaItem editedMediaItem = - new EditedMediaItem.Builder(MediaItem.fromUri(PNG_ASSET.uri)) - .setDurationUs(C.MICROS_PER_SECOND) + new EditedMediaItem.Builder( + new MediaItem.Builder() + .setUri(PNG_ASSET.uri) + .setImageDurationMs(C.MILLIS_PER_SECOND) + .build()) .setFrameRate(expectedFrameCount) .build(); ExportTestResult result = @@ -299,8 +306,11 @@ public class TransformerEndToEndTest { Effects effects = new Effects(/* audioProcessors= */ ImmutableList.of(), videoEffects); int expectedFrameCount = 40; EditedMediaItem editedMediaItem = - new EditedMediaItem.Builder(MediaItem.fromUri(WEBP_LARGE.uri)) - .setDurationUs(C.MICROS_PER_SECOND) + new EditedMediaItem.Builder( + new MediaItem.Builder() + .setUri(WEBP_LARGE.uri) + .setImageDurationMs(C.MILLIS_PER_SECOND) + .build()) .setFrameRate(expectedFrameCount) .setEffects(effects) .build(); @@ -516,14 +526,14 @@ public class TransformerEndToEndTest { .build(); EditedMediaItem image1 = - new EditedMediaItem.Builder(MediaItem.fromUri(PNG_ASSET.uri)) - .setDurationUs(100_000) + new EditedMediaItem.Builder( + new MediaItem.Builder().setUri(PNG_ASSET.uri).setImageDurationMs(100).build()) .setFrameRate(30) .build(); int image1FrameCount = 3; EditedMediaItem image2 = - new EditedMediaItem.Builder(MediaItem.fromUri(JPG_ASSET.uri)) - .setDurationUs(200_000) + new EditedMediaItem.Builder( + new MediaItem.Builder().setUri(JPG_ASSET.uri).setImageDurationMs(200).build()) .setFrameRate(30) .build(); int image2FrameCount = 6; @@ -1459,8 +1469,8 @@ public class TransformerEndToEndTest { audioEditedMediaItem, audioEditedMediaItem, audioEditedMediaItem) .build(); EditedMediaItem imageEditedMediaItem = - new EditedMediaItem.Builder(MediaItem.fromUri(PNG_ASSET.uri)) - .setDurationUs(1_000_000) + new EditedMediaItem.Builder( + new MediaItem.Builder().setUri(PNG_ASSET.uri).setImageDurationMs(1000).build()) .setFrameRate(30) .build(); EditedMediaItemSequence loopingImageSequence = @@ -1496,8 +1506,8 @@ public class TransformerEndToEndTest { EditedMediaItemSequence audioSequence = new EditedMediaItemSequence.Builder(audioEditedMediaItem).build(); EditedMediaItem imageEditedMediaItem = - new EditedMediaItem.Builder(MediaItem.fromUri(PNG_ASSET.uri)) - .setDurationUs(1_050_000) + new EditedMediaItem.Builder( + new MediaItem.Builder().setUri(PNG_ASSET.uri).setImageDurationMs(1050).build()) .setFrameRate(20) .build(); EditedMediaItemSequence loopingImageSequence = diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerMultiSequenceCompositionTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerMultiSequenceCompositionTest.java index 8da5bd7e63..c8ffc1df08 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerMultiSequenceCompositionTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerMultiSequenceCompositionTest.java @@ -17,7 +17,6 @@ package androidx.media3.transformer; import static androidx.media3.common.util.Assertions.checkNotNull; -import static androidx.media3.common.util.Util.msToUs; import static androidx.media3.test.utils.BitmapPixelTestUtil.MAXIMUM_AVERAGE_PIXEL_ABSOLUTE_DIFFERENCE_LUMA; import static androidx.media3.test.utils.BitmapPixelTestUtil.getBitmapAveragePixelAbsoluteDifferenceArgb8888; import static androidx.media3.test.utils.BitmapPixelTestUtil.maybeSaveTestBitmap; @@ -286,9 +285,9 @@ public final class TransformerMultiSequenceCompositionTest { } private static EditedMediaItem editedMediaItemOfOneFrameImage(String uri, List effects) { - return new EditedMediaItem.Builder(MediaItem.fromUri(uri)) + return new EditedMediaItem.Builder( + new MediaItem.Builder().setUri(uri).setImageDurationMs(ONE_FRAME_DURATION_MS).build()) .setRemoveAudio(true) - .setDurationUs(msToUs(ONE_FRAME_DURATION_MS)) .setFrameRate((int) (1000 / ONE_FRAME_DURATION_MS)) .setEffects( new Effects(/* audioProcessors= */ ImmutableList.of(), ImmutableList.copyOf(effects))) diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerSequenceEffectTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerSequenceEffectTest.java index f36254a803..5a0484d0eb 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerSequenceEffectTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/TransformerSequenceEffectTest.java @@ -352,9 +352,12 @@ public final class TransformerSequenceEffectTest { Composition composition = createComposition( /* presentation= */ null, - new EditedMediaItem.Builder(MediaItem.fromUri(PNG_ASSET_LINES_1080P.uri)) + new EditedMediaItem.Builder( + new MediaItem.Builder() + .setUri(PNG_ASSET_LINES_1080P.uri) + .setImageDurationMs(C.MILLIS_PER_SECOND / 4) + .build()) .setFrameRate(30) - .setDurationUs(C.MICROS_PER_SECOND / 4) .build()); // Some devices need a very high bitrate to avoid encoding artifacts. int bitrate = 30_000_000; @@ -417,9 +420,12 @@ public final class TransformerSequenceEffectTest { Composition composition = createComposition( /* presentation= */ null, - new EditedMediaItem.Builder(MediaItem.fromUri(PNG_ASSET_LINES_1080P.uri)) + new EditedMediaItem.Builder( + new MediaItem.Builder() + .setUri(PNG_ASSET_LINES_1080P.uri) + .setImageDurationMs(C.MILLIS_PER_SECOND / 4) + .build()) .setFrameRate(30) - .setDurationUs(C.MICROS_PER_SECOND / 4) .setEffects( new Effects( ImmutableList.of(), diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/TranscodeSpeedTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/TranscodeSpeedTest.java index aa166650df..e913f60312 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/TranscodeSpeedTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/TranscodeSpeedTest.java @@ -130,9 +130,12 @@ public class TranscodeSpeedTest { // This test uses ULTRA_HDR_URI_STRING because it's high resolution. // Ultra HDR gainmap is ignored. EditedMediaItem editedMediaItem = - new EditedMediaItem.Builder(MediaItem.fromUri(JPG_ULTRA_HDR_ASSET.uri)) + new EditedMediaItem.Builder( + new MediaItem.Builder() + .setUri(JPG_ULTRA_HDR_ASSET.uri) + .setImageDurationMs(isHighPerformance ? 45_000 : 15_000) + .build()) .setFrameRate(30) - .setDurationUs(isHighPerformance ? 45_000_000 : 15_000_000) .setEffects( new Effects( /* audioProcessors= */ ImmutableList.of(), diff --git a/libraries/transformer/src/test/java/androidx/media3/transformer/ImageAssetLoaderTest.java b/libraries/transformer/src/test/java/androidx/media3/transformer/ImageAssetLoaderTest.java index 28f978c552..5692de4a2c 100644 --- a/libraries/transformer/src/test/java/androidx/media3/transformer/ImageAssetLoaderTest.java +++ b/libraries/transformer/src/test/java/androidx/media3/transformer/ImageAssetLoaderTest.java @@ -167,8 +167,8 @@ public class ImageAssetLoaderTest { private static AssetLoader getAssetLoader(AssetLoader.Listener listener, String uri) { Context context = ApplicationProvider.getApplicationContext(); EditedMediaItem editedMediaItem = - new EditedMediaItem.Builder(MediaItem.fromUri(uri)) - .setDurationUs(1_000_000) + new EditedMediaItem.Builder( + new MediaItem.Builder().setUri(uri).setImageDurationMs(1000).build()) .setFrameRate(30) .build(); return new ImageAssetLoader.Factory(