Skip to content

Commit 8faee05

Browse files
Googlercopybara-github
authored andcommitted
Rollback of 50df607
PiperOrigin-RevId: 787287970
1 parent 7a473e8 commit 8faee05

File tree

5 files changed

+176
-444
lines changed

5 files changed

+176
-444
lines changed

libraries/transformer/src/androidTest/java/androidx/media3/transformer/CompositionPlayerSetCompositionTest.java

Lines changed: 58 additions & 256 deletions
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,18 @@
2929
import androidx.media3.common.Effect;
3030
import androidx.media3.common.MediaItem;
3131
import androidx.media3.common.Player;
32+
import androidx.media3.common.Player.State;
3233
import androidx.media3.common.Timeline;
3334
import androidx.media3.common.audio.AudioProcessor;
34-
import androidx.media3.common.audio.BaseAudioProcessor;
3535
import androidx.media3.common.audio.SpeedProvider;
3636
import androidx.media3.common.util.ConditionVariable;
37-
import androidx.media3.common.util.Util;
3837
import androidx.media3.effect.GlEffect;
3938
import androidx.test.ext.junit.rules.ActivityScenarioRule;
4039
import androidx.test.ext.junit.runners.AndroidJUnit4;
4140
import com.google.common.collect.ImmutableList;
4241
import com.google.common.collect.Iterables;
43-
import java.nio.ByteBuffer;
44-
import java.util.Collections;
45-
import java.util.List;
4642
import java.util.concurrent.CopyOnWriteArrayList;
4743
import java.util.concurrent.atomic.AtomicBoolean;
48-
import java.util.concurrent.atomic.AtomicLong;
4944
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
5045
import org.junit.After;
5146
import org.junit.Before;
@@ -56,7 +51,6 @@
5651
/** Tests for setting {@link Composition} on {@link CompositionPlayer}. */
5752
@RunWith(AndroidJUnit4.class)
5853
public class CompositionPlayerSetCompositionTest {
59-
// TODO: b/412585856: Keep tests focused or make them parameterized.
6054
private static final long TEST_TIMEOUT_MS = isRunningOnEmulator() ? 20_000 : 10_000;
6155

6256
private @MonotonicNonNull CompositionPlayer compositionPlayer;
@@ -128,6 +122,55 @@ public void composition_changeComposition() throws Exception {
128122
.hasSize(2);
129123
}
130124

125+
@Test
126+
public void setComposition_withChangedRemoveAudio_playbackCompletes() throws Exception {
127+
EditedMediaItem mediaItem =
128+
new EditedMediaItem.Builder(MediaItem.fromUri(MP4_ASSET.uri))
129+
.setDurationUs(MP4_ASSET.videoDurationUs)
130+
.build();
131+
EditedMediaItem mediaItemRemoveAudio = mediaItem.buildUpon().setRemoveAudio(true).build();
132+
AtomicBoolean changedComposition = new AtomicBoolean();
133+
ConditionVariable playerEnded = new ConditionVariable();
134+
CopyOnWriteArrayList<Integer> playerStates = new CopyOnWriteArrayList<>();
135+
136+
instrumentation.runOnMainSync(
137+
() -> {
138+
compositionPlayer = new CompositionPlayer.Builder(context).build();
139+
compositionPlayer.setVideoSurfaceView(surfaceView);
140+
compositionPlayer.addListener(playerTestListener);
141+
compositionPlayer.addListener(
142+
new Player.Listener() {
143+
@Override
144+
public void onPlaybackStateChanged(@State int playbackState) {
145+
playerStates.add(playbackState);
146+
if (playbackState == Player.STATE_READY) {
147+
if (!changedComposition.get()) {
148+
compositionPlayer.setComposition(
149+
createSingleSequenceComposition(
150+
mediaItemRemoveAudio, mediaItemRemoveAudio));
151+
compositionPlayer.play();
152+
changedComposition.set(true);
153+
}
154+
} else if (playbackState == Player.STATE_ENDED) {
155+
playerEnded.open();
156+
}
157+
}
158+
});
159+
compositionPlayer.setComposition(createSingleSequenceComposition(mediaItem, mediaItem));
160+
compositionPlayer.prepare();
161+
});
162+
163+
// Wait until the final state is added to playerStates.
164+
playerEnded.block(TEST_TIMEOUT_MS);
165+
// waitUntilPlayerEnded should return immediate and will throw any player error.
166+
playerTestListener.waitUntilPlayerEnded();
167+
// Asserts that changing removeAudio does not cause the player to get back to buffering state,
168+
// because the player should not be re-prepared.
169+
assertThat(playerStates)
170+
.containsExactly(Player.STATE_BUFFERING, Player.STATE_READY, Player.STATE_ENDED)
171+
.inOrder();
172+
}
173+
131174
@Test
132175
public void setComposition_withChangedSpeed_playbackCompletes() throws Exception {
133176
EditedMediaItem fastMediaItem = createEditedMediaItemWithSpeed(MP4_ASSET, 3.f);
@@ -164,228 +207,6 @@ public void onTimelineChanged(Timeline timeline, int reason) {
164207
assertThat(playerDurations).containsExactly(341333L, 3071999L).inOrder();
165208
}
166209

167-
@Test
168-
public void setComposition_withStartPosition_playbackStartsFromSetPosition() throws Exception {
169-
assertThat(
170-
getFirstVideoFrameTimestampUsWithStartPosition(
171-
/* startPositionUs= */ 500_000L, /* numberOfItemsInSequence= */ 1))
172-
.isEqualTo(500_500L);
173-
}
174-
175-
@Test
176-
public void setComposition_withZeroStartPosition_playbackStartsFromZero() throws Exception {
177-
assertThat(
178-
getFirstVideoFrameTimestampUsWithStartPosition(
179-
/* startPositionUs= */ 0, /* numberOfItemsInSequence= */ 1))
180-
.isEqualTo(0);
181-
}
182-
183-
@Test
184-
public void setComposition_withStartPositionPastVideoDuration_playbackStopsAtLastFrame()
185-
throws Exception {
186-
assertThat(
187-
getFirstVideoFrameTimestampUsWithStartPosition(
188-
/* startPositionUs= */ 100_000_000L, /* numberOfItemsInSequence= */ 1))
189-
.isEqualTo(967633L);
190-
}
191-
192-
@Test
193-
public void
194-
setComposition_withStartPositionPastVideoDurationInMultiItemSequence_playbackStopsAtLastFrame()
195-
throws Exception {
196-
assertThat(
197-
getFirstVideoFrameTimestampUsWithStartPosition(
198-
/* startPositionUs= */ 100_000_000L, /* numberOfItemsInSequence= */ 5))
199-
.isEqualTo(5_063_633L);
200-
}
201-
202-
@Test
203-
public void setComposition_withStartPositionInMultiItemSequence_playbackStartsFromSetPosition()
204-
throws Exception {
205-
assertThat(
206-
getFirstVideoFrameTimestampUsWithStartPosition(
207-
/* startPositionUs= */ 1_500_000L, /* numberOfItemsInSequence= */ 2))
208-
.isEqualTo(1_524_500);
209-
}
210-
211-
@Test
212-
public void
213-
setComposition_withStartPositionSingleItemAudioSequence_reportsCorrectAudioProcessorPositionOffset()
214-
throws Exception {
215-
Pair<Long, Long> lastAudioPositionOffsetWithStartPosition =
216-
getLastAudioPositionOffsetWithStartPosition(
217-
/* startPositionUs= */ 500_000L, /* numberOfItemsInSequence= */ 1);
218-
219-
assertThat(lastAudioPositionOffsetWithStartPosition.first).isEqualTo(500_000);
220-
assertThat(lastAudioPositionOffsetWithStartPosition.second).isEqualTo(500_000);
221-
}
222-
223-
@Test
224-
public void
225-
setComposition_withStartPositionTwoItemsAudioSequence_reportsCorrectAudioProcessorPositionOffset()
226-
throws Exception {
227-
Pair<Long, Long> lastAudioPositionOffsetWithStartPosition =
228-
getLastAudioPositionOffsetWithStartPosition(
229-
/* startPositionUs= */ 1_500_000L, /* numberOfItemsInSequence= */ 2);
230-
231-
assertThat(lastAudioPositionOffsetWithStartPosition.first).isEqualTo(500_000);
232-
assertThat(lastAudioPositionOffsetWithStartPosition.second).isEqualTo(1_500_000);
233-
}
234-
235-
@Test
236-
public void setComposition_withNewCompositionAudioProcessor_recreatesAudioPipeline()
237-
throws Exception {
238-
AtomicBoolean firstCompositionSentDataToAudioPipeline = new AtomicBoolean();
239-
AtomicBoolean secondCompositionSentDataToAudioPipeline = new AtomicBoolean();
240-
ConditionVariable firstCompositionProcessedData = new ConditionVariable();
241-
PassthroughAudioProcessor firstCompositionAudioProcessor =
242-
new PassthroughAudioProcessor() {
243-
@Override
244-
public void queueInput(ByteBuffer inputBuffer) {
245-
super.queueInput(inputBuffer);
246-
firstCompositionSentDataToAudioPipeline.set(true);
247-
firstCompositionProcessedData.open();
248-
}
249-
};
250-
PassthroughAudioProcessor secondCompositionAudioProcessor =
251-
new PassthroughAudioProcessor() {
252-
@Override
253-
public void queueInput(ByteBuffer inputBuffer) {
254-
super.queueInput(inputBuffer);
255-
secondCompositionSentDataToAudioPipeline.set(true);
256-
}
257-
};
258-
EditedMediaItem editedMediaItem =
259-
new EditedMediaItem.Builder(MediaItem.fromUri(AndroidTestUtil.WAV_ASSET.uri))
260-
.setDurationUs(1_000_000L)
261-
.setEffects(
262-
new Effects(
263-
/* audioProcessors= */ ImmutableList.of(firstCompositionAudioProcessor),
264-
/* videoEffects= */ ImmutableList.of()))
265-
.build();
266-
Composition firstComposition =
267-
new Composition.Builder(
268-
new EditedMediaItemSequence.Builder(Collections.nCopies(5, editedMediaItem))
269-
.build())
270-
.setEffects(
271-
new Effects(
272-
/* audioProcessors= */ ImmutableList.of(firstCompositionAudioProcessor),
273-
/* videoEffects= */ ImmutableList.of()))
274-
.build();
275-
Composition secondComposition =
276-
new Composition.Builder(
277-
new EditedMediaItemSequence.Builder(Collections.nCopies(5, editedMediaItem))
278-
.build())
279-
.setEffects(
280-
new Effects(
281-
/* audioProcessors= */ ImmutableList.of(secondCompositionAudioProcessor),
282-
/* videoEffects= */ ImmutableList.of()))
283-
.build();
284-
285-
getInstrumentation()
286-
.runOnMainSync(
287-
() -> {
288-
compositionPlayer = new CompositionPlayer.Builder(context).build();
289-
compositionPlayer.addListener(playerTestListener);
290-
compositionPlayer.setComposition(firstComposition);
291-
compositionPlayer.prepare();
292-
});
293-
playerTestListener.waitUntilPlayerReady();
294-
firstCompositionProcessedData.block(TEST_TIMEOUT_MS);
295-
assertThat(firstCompositionSentDataToAudioPipeline.get()).isTrue();
296-
assertThat(secondCompositionSentDataToAudioPipeline.get()).isFalse();
297-
298-
playerTestListener.resetStatus();
299-
getInstrumentation()
300-
.runOnMainSync(
301-
() -> {
302-
compositionPlayer.setComposition(secondComposition);
303-
compositionPlayer.play();
304-
});
305-
playerTestListener.waitUntilPlayerEnded();
306-
307-
assertThat(secondCompositionSentDataToAudioPipeline.get()).isTrue();
308-
}
309-
310-
private Pair<Long, Long> getLastAudioPositionOffsetWithStartPosition(
311-
long startPositionUs, int numberOfItemsInSequence) throws Exception {
312-
AtomicLong lastItemPositionOffsetUs = new AtomicLong(C.TIME_UNSET);
313-
AtomicLong lastCompositionPositionOffsetUs = new AtomicLong(C.TIME_UNSET);
314-
PassthroughAudioProcessor itemAudioProcessor =
315-
new PassthroughAudioProcessor() {
316-
@Override
317-
protected void onFlush(AudioProcessor.StreamMetadata streamMetadata) {
318-
lastItemPositionOffsetUs.set(streamMetadata.positionOffsetUs);
319-
}
320-
};
321-
PassthroughAudioProcessor compositionAudioProcessor =
322-
new PassthroughAudioProcessor() {
323-
@Override
324-
protected void onFlush(AudioProcessor.StreamMetadata streamMetadata) {
325-
lastCompositionPositionOffsetUs.set(streamMetadata.positionOffsetUs);
326-
}
327-
};
328-
EditedMediaItem editedMediaItem =
329-
new EditedMediaItem.Builder(MediaItem.fromUri(AndroidTestUtil.WAV_ASSET.uri))
330-
.setDurationUs(1_000_000L)
331-
.setEffects(
332-
new Effects(
333-
/* audioProcessors= */ ImmutableList.of(itemAudioProcessor),
334-
/* videoEffects= */ ImmutableList.of()))
335-
.build();
336-
final Composition composition =
337-
new Composition.Builder(
338-
new EditedMediaItemSequence.Builder(
339-
Collections.nCopies(numberOfItemsInSequence, editedMediaItem))
340-
.build())
341-
.setEffects(
342-
new Effects(
343-
/* audioProcessors= */ ImmutableList.of(compositionAudioProcessor),
344-
/* videoEffects= */ ImmutableList.of()))
345-
.build();
346-
347-
getInstrumentation()
348-
.runOnMainSync(
349-
() -> {
350-
compositionPlayer = new CompositionPlayer.Builder(context).build();
351-
compositionPlayer.addListener(playerTestListener);
352-
compositionPlayer.setComposition(composition, Util.usToMs(startPositionUs));
353-
compositionPlayer.prepare();
354-
});
355-
playerTestListener.waitUntilPlayerReady();
356-
return Pair.create(lastItemPositionOffsetUs.get(), lastCompositionPositionOffsetUs.get());
357-
}
358-
359-
private long getFirstVideoFrameTimestampUsWithStartPosition(
360-
long startPositionUs, int numberOfItemsInSequence) throws Exception {
361-
EditedMediaItem editedMediaItem =
362-
new EditedMediaItem.Builder(MediaItem.fromUri(MP4_ASSET.uri))
363-
.setDurationUs(MP4_ASSET.videoDurationUs)
364-
.build();
365-
AtomicLong firstFrameTimestampUs = new AtomicLong(C.TIME_UNSET);
366-
367-
instrumentation.runOnMainSync(
368-
() -> {
369-
compositionPlayer = new CompositionPlayer.Builder(context).build();
370-
compositionPlayer.setVideoSurfaceView(surfaceView);
371-
compositionPlayer.addListener(playerTestListener);
372-
compositionPlayer.setVideoFrameMetadataListener(
373-
(presentationTimeUs, releaseTimeNs, format, mediaFormat) -> {
374-
if (firstFrameTimestampUs.compareAndSet(C.TIME_UNSET, presentationTimeUs)) {
375-
instrumentation.runOnMainSync(compositionPlayer::play);
376-
}
377-
});
378-
compositionPlayer.setComposition(
379-
createSingleSequenceComposition(
380-
Collections.nCopies(numberOfItemsInSequence, editedMediaItem)),
381-
Util.usToMs(startPositionUs));
382-
compositionPlayer.prepare();
383-
});
384-
385-
playerTestListener.waitUntilPlayerEnded();
386-
return firstFrameTimestampUs.get();
387-
}
388-
389210
private static EditedMediaItem createEditedMediaItemWithSpeed(
390211
AndroidTestUtil.AssetInfo assetInfo, float speed) {
391212
Pair<AudioProcessor, Effect> speedChangingEffect =
@@ -399,19 +220,16 @@ private static EditedMediaItem createEditedMediaItemWithSpeed(
399220
.build();
400221
}
401222

402-
private static Composition createSingleSequenceComposition(
403-
List<EditedMediaItem> editedMediaItems) {
404-
return new Composition.Builder(new EditedMediaItemSequence.Builder(editedMediaItems).build())
405-
.build();
406-
}
407-
408223
private static Composition createSingleSequenceComposition(
409224
EditedMediaItem editedMediaItem, EditedMediaItem... moreEditedMediaItems) {
410-
return createSingleSequenceComposition(
411-
new ImmutableList.Builder<EditedMediaItem>()
412-
.add(editedMediaItem)
413-
.add(moreEditedMediaItems)
414-
.build());
225+
return new Composition.Builder(
226+
new EditedMediaItemSequence.Builder(
227+
new ImmutableList.Builder<EditedMediaItem>()
228+
.add(editedMediaItem)
229+
.add(moreEditedMediaItems)
230+
.build())
231+
.build())
232+
.build();
415233
}
416234

417235
private static final class SimpleSpeedProvider implements SpeedProvider {
@@ -433,20 +251,4 @@ public long getNextSpeedChangeTimeUs(long timeUs) {
433251
return C.TIME_UNSET;
434252
}
435253
}
436-
437-
private static class PassthroughAudioProcessor extends BaseAudioProcessor {
438-
@Override
439-
public void queueInput(ByteBuffer inputBuffer) {
440-
if (!inputBuffer.hasRemaining()) {
441-
return;
442-
}
443-
ByteBuffer buffer = this.replaceOutputBuffer(inputBuffer.remaining());
444-
buffer.put(inputBuffer).flip();
445-
}
446-
447-
@Override
448-
protected AudioFormat onConfigure(AudioFormat inputAudioFormat) {
449-
return inputAudioFormat;
450-
}
451-
}
452254
}

0 commit comments

Comments
 (0)