mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Match with ExoPlayer seeking when using CompositionPlayer
In a image sequence, seek to after the image duration should render the final image frame. But currently it hangs as ConstantRateTimestampIterator doesn't output any timestamp in this case PiperOrigin-RevId: 724295475
This commit is contained in:
parent
5e6fb88372
commit
babc2dd416
@ -17,6 +17,7 @@ package androidx.media3.common.util;
|
|||||||
|
|
||||||
import static androidx.media3.common.util.Assertions.checkArgument;
|
import static androidx.media3.common.util.Assertions.checkArgument;
|
||||||
import static androidx.media3.common.util.Assertions.checkState;
|
import static androidx.media3.common.util.Assertions.checkState;
|
||||||
|
import static java.lang.Math.max;
|
||||||
import static java.lang.Math.round;
|
import static java.lang.Math.round;
|
||||||
|
|
||||||
import androidx.annotation.FloatRange;
|
import androidx.annotation.FloatRange;
|
||||||
@ -70,7 +71,8 @@ public final class ConstantRateTimestampIterator implements TimestampIterator {
|
|||||||
this.endPositionUs = endPositionUs;
|
this.endPositionUs = endPositionUs;
|
||||||
this.frameRate = frameRate;
|
this.frameRate = frameRate;
|
||||||
float durationSecs = (endPositionUs - startPositionUs) / (float) C.MICROS_PER_SECOND;
|
float durationSecs = (endPositionUs - startPositionUs) / (float) C.MICROS_PER_SECOND;
|
||||||
this.totalNumberOfFramesToAdd = round(frameRate * durationSecs);
|
// Generate at least one timestamp so that at least one frame is produced when seeking.
|
||||||
|
this.totalNumberOfFramesToAdd = max(round(frameRate * durationSecs), 1);
|
||||||
framesDurationUs = C.MICROS_PER_SECOND / frameRate;
|
framesDurationUs = C.MICROS_PER_SECOND / frameRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,12 +67,12 @@ public class ConstantRateTimestampIteratorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void timestampIterator_smallDuration_generatesEmptyIterator() {
|
public void timestampIterator_smallDuration_generatesOneTimestamp() {
|
||||||
ConstantRateTimestampIterator constantRateTimestampIterator =
|
ConstantRateTimestampIterator constantRateTimestampIterator =
|
||||||
new ConstantRateTimestampIterator(/* durationUs= */ 1, /* frameRate= */ 2);
|
new ConstantRateTimestampIterator(/* durationUs= */ 1, /* frameRate= */ 2);
|
||||||
|
|
||||||
assertThat(generateList(constantRateTimestampIterator)).isEmpty();
|
assertThat(generateList(constantRateTimestampIterator)).containsExactly(0L);
|
||||||
assertThat(constantRateTimestampIterator.getLastTimestampUs()).isEqualTo(C.TIME_UNSET);
|
assertThat(constantRateTimestampIterator.getLastTimestampUs()).isEqualTo(0L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -110,15 +110,15 @@ public class ConstantRateTimestampIteratorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void timestampIterator_withNoTimestampsWithinParameters_generatesNoTimestamp() {
|
public void timestampIterator_withNoTimestampsWithinParameters_generatesOneTimestamp() {
|
||||||
ConstantRateTimestampIterator constantRateTimestampIterator =
|
ConstantRateTimestampIterator constantRateTimestampIterator =
|
||||||
new ConstantRateTimestampIterator(
|
new ConstantRateTimestampIterator(
|
||||||
/* startPositionUs= */ 900_000L,
|
/* startPositionUs= */ 900_000L,
|
||||||
/* endPositionUs= */ C.MICROS_PER_SECOND,
|
/* endPositionUs= */ C.MICROS_PER_SECOND,
|
||||||
/* frameRate= */ 3);
|
/* frameRate= */ 3);
|
||||||
|
|
||||||
assertThat(generateList(constantRateTimestampIterator)).isEmpty();
|
assertThat(generateList(constantRateTimestampIterator)).containsExactly(900_000L);
|
||||||
assertThat(constantRateTimestampIterator.getLastTimestampUs()).isEqualTo(C.TIME_UNSET);
|
assertThat(constantRateTimestampIterator.getLastTimestampUs()).isEqualTo(900_000L);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Long> generateList(TimestampIterator iterator) {
|
private static List<Long> generateList(TimestampIterator iterator) {
|
||||||
|
@ -355,6 +355,47 @@ public class CompositionPlayerSeekTest {
|
|||||||
.isEqualTo(sequenceTimestampsUs);
|
.isEqualTo(sequenceTimestampsUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void seekToEndOfSecondImage_afterPlayingSingleSequenceOfTwoImages() throws Exception {
|
||||||
|
// Seeks to the end of the second image
|
||||||
|
long seekTimeMs = usToMs(2 * IMAGE_DURATION_US);
|
||||||
|
ImmutableList<Long> sequenceTimestampsUs =
|
||||||
|
new ImmutableList.Builder<Long>()
|
||||||
|
// Plays the first image
|
||||||
|
.addAll(IMAGE_TIMESTAMPS_US)
|
||||||
|
// Plays the second image
|
||||||
|
.addAll(
|
||||||
|
transform(IMAGE_TIMESTAMPS_US, timestampUs -> (IMAGE_DURATION_US + timestampUs)))
|
||||||
|
// Plays the last image frame, which is one microsecond smaller than the total duration.
|
||||||
|
.add(399_999L)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
playSequenceUntilEndedAndSeekAndGetTimestampsUs(
|
||||||
|
ImmutableList.of(IMAGE_MEDIA_ITEM, IMAGE_MEDIA_ITEM), seekTimeMs))
|
||||||
|
.isEqualTo(sequenceTimestampsUs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void seekToAfterEndOfSecondImage_afterPlayingSingleSequenceOfTwoImages() throws Exception {
|
||||||
|
long seekTimeMs = usToMs(3 * IMAGE_DURATION_US);
|
||||||
|
ImmutableList<Long> sequenceTimestampsUs =
|
||||||
|
new ImmutableList.Builder<Long>()
|
||||||
|
// Plays the first image
|
||||||
|
.addAll(IMAGE_TIMESTAMPS_US)
|
||||||
|
// Plays the second image
|
||||||
|
.addAll(
|
||||||
|
transform(IMAGE_TIMESTAMPS_US, timestampUs -> (IMAGE_DURATION_US + timestampUs)))
|
||||||
|
// Plays the last image frame, which is one microsecond smaller than the total duration.
|
||||||
|
.add(399_999L)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
playSequenceUntilEndedAndSeekAndGetTimestampsUs(
|
||||||
|
ImmutableList.of(IMAGE_MEDIA_ITEM, IMAGE_MEDIA_ITEM), seekTimeMs))
|
||||||
|
.isEqualTo(sequenceTimestampsUs);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void seekToZero_afterPlayingSingleSequenceOfVideoAndImage() throws Exception {
|
public void seekToZero_afterPlayingSingleSequenceOfVideoAndImage() throws Exception {
|
||||||
maybeSkipTest();
|
maybeSkipTest();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user