mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Set MediaItem's image duration for image export
This field will become mandatory PiperOrigin-RevId: 678656879
This commit is contained in:
parent
f83d2b1392
commit
eaec7a4a61
@ -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<AudioProcessor> audioProcessors = createAudioProcessorsFromBundle(bundle);
|
||||
ImmutableList<Effect> videoEffects = createVideoEffectsFromBundle(bundle);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,10 +102,10 @@ public final class SequenceEffectTestUtil {
|
||||
* effects} applied.
|
||||
*/
|
||||
public static EditedMediaItem oneFrameFromImage(String uri, List<Effect> 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();
|
||||
|
@ -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<Effect> 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 =
|
||||
|
@ -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<Effect> 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)))
|
||||
|
@ -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(),
|
||||
|
@ -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(),
|
||||
|
@ -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(
|
||||
|
Loading…
x
Reference in New Issue
Block a user