mirror of
https://github.com/androidx/media.git
synced 2025-05-04 06:00:37 +08:00
Update presentation time of metadata when the stream offset changes
The stream offset is used to calculate the presentation time of a metadata object when reading and later when playing, to calculate the current presentation time to decide whether to send the metadata to the output. Accordingly, the presentation time of a pending metadata that has been calculated with a given offset needs to be recalculated when the stream offset changes. #minor-release PiperOrigin-RevId: 472499943 (cherry picked from commit 0896c4dd3665980d89577db20d247ac13fcd236b)
This commit is contained in:
parent
0e6d0d7f38
commit
22f4fcb657
@ -154,6 +154,19 @@ public final class Metadata implements Parcelable {
|
||||
presentationTimeUs, Util.nullSafeArrayConcatenation(entries, entriesToAppend));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this metadata with the specified presentation time.
|
||||
*
|
||||
* @param presentationTimeUs The new presentation time, in microseconds.
|
||||
* @return The metadata instance with the new presentation time.
|
||||
*/
|
||||
public Metadata copyWithPresentationTimeUs(long presentationTimeUs) {
|
||||
if (this.presentationTimeUs == presentationTimeUs) {
|
||||
return this;
|
||||
}
|
||||
return new Metadata(presentationTimeUs, entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) {
|
||||
|
@ -142,6 +142,11 @@ public final class MetadataRenderer extends BaseRenderer implements Callback {
|
||||
@Override
|
||||
protected void onStreamChanged(Format[] formats, long startPositionUs, long offsetUs) {
|
||||
decoder = decoderFactory.createDecoder(formats[0]);
|
||||
if (pendingMetadata != null) {
|
||||
pendingMetadata =
|
||||
pendingMetadata.copyWithPresentationTimeUs(
|
||||
pendingMetadata.presentationTimeUs + outputStreamOffsetUs - offsetUs);
|
||||
}
|
||||
outputStreamOffsetUs = offsetUs;
|
||||
}
|
||||
|
||||
|
@ -221,6 +221,122 @@ public class MetadataRendererTest {
|
||||
assertThat(metadata.get(1).presentationTimeUs).isEqualTo(1_000_000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void replaceStream_withIncreasingOffsetUs_updatesPendingMetadataPresentationTime()
|
||||
throws Exception {
|
||||
EventMessage emsg =
|
||||
new EventMessage(
|
||||
"urn:test-scheme-id",
|
||||
/* value= */ "",
|
||||
/* durationMs= */ 1,
|
||||
/* id= */ 0,
|
||||
"Test data".getBytes(UTF_8));
|
||||
byte[] encodedEmsg = eventMessageEncoder.encode(emsg);
|
||||
List<Metadata> metadataOutput = new ArrayList<>();
|
||||
MetadataRenderer renderer =
|
||||
new MetadataRenderer(
|
||||
/* output= */ metadataOutput::add,
|
||||
/* outputLooper= */ null,
|
||||
MetadataDecoderFactory.DEFAULT,
|
||||
/* outputMetadataEarly= */ false);
|
||||
FakeSampleStream fakeSampleStream =
|
||||
createFakeSampleStream(
|
||||
ImmutableList.of(
|
||||
sample(/* timeUs= */ 100_000, C.BUFFER_FLAG_KEY_FRAME, encodedEmsg),
|
||||
sample(/* timeUs= */ 200_000, C.BUFFER_FLAG_KEY_FRAME, encodedEmsg),
|
||||
END_OF_STREAM_ITEM));
|
||||
fakeSampleStream.writeData(/* startPositionUs= */ 0);
|
||||
// Start of the first reading period.
|
||||
renderer.replaceStream(
|
||||
new Format[] {EMSG_FORMAT},
|
||||
fakeSampleStream,
|
||||
/* startPositionUs= */ 0L,
|
||||
/* offsetUs= */ 0L);
|
||||
// Read the format
|
||||
renderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0);
|
||||
|
||||
// Read and render the first metadata. The second metadata is immediately read as pending.
|
||||
// The offset is added to timeUs of the samples when reading (100_000 and 200_000).
|
||||
renderer.render(/* positionUs= */ 99_999, /* elapsedRealtimeUs= */ 0);
|
||||
assertThat(metadataOutput).isEmpty();
|
||||
renderer.render(/* positionUs= */ 100_000, /* elapsedRealtimeUs= */ 0);
|
||||
assertThat(metadataOutput).hasSize(1);
|
||||
|
||||
// Start of the 2nd reading period. Replace the stream with a different offset. This adjusts the
|
||||
// presentation time of the pending metadata.
|
||||
renderer.replaceStream(
|
||||
new Format[] {EMSG_FORMAT},
|
||||
fakeSampleStream,
|
||||
/* startPositionUs= */ 0L,
|
||||
/* offsetUs= */ 100_000L);
|
||||
renderer.render(/* positionUs= */ 199_999, /* elapsedRealtimeUs= */ 0);
|
||||
assertThat(metadataOutput).hasSize(1);
|
||||
|
||||
// Output second metadata.
|
||||
renderer.render(/* positionUs= */ 200_000, /* elapsedRealtimeUs= */ 0);
|
||||
assertThat(metadataOutput).hasSize(2);
|
||||
assertThat(metadataOutput.get(0).presentationTimeUs).isEqualTo(100_000);
|
||||
assertThat(metadataOutput.get(1).presentationTimeUs).isEqualTo(100_000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void replaceStream_withDecreasingOffsetUs_updatesPendingMetadataPresentationTime()
|
||||
throws Exception {
|
||||
EventMessage emsg =
|
||||
new EventMessage(
|
||||
"urn:test-scheme-id",
|
||||
/* value= */ "",
|
||||
/* durationMs= */ 1,
|
||||
/* id= */ 0,
|
||||
"Test data".getBytes(UTF_8));
|
||||
byte[] encodedEmsg = eventMessageEncoder.encode(emsg);
|
||||
List<Metadata> metadataOutput = new ArrayList<>();
|
||||
MetadataRenderer renderer =
|
||||
new MetadataRenderer(
|
||||
/* output= */ metadataOutput::add,
|
||||
/* outputLooper= */ null,
|
||||
MetadataDecoderFactory.DEFAULT,
|
||||
/* outputMetadataEarly= */ false);
|
||||
FakeSampleStream fakeSampleStream =
|
||||
createFakeSampleStream(
|
||||
ImmutableList.of(
|
||||
sample(/* timeUs= */ 100_000, C.BUFFER_FLAG_KEY_FRAME, encodedEmsg),
|
||||
sample(/* timeUs= */ 200_000, C.BUFFER_FLAG_KEY_FRAME, encodedEmsg),
|
||||
END_OF_STREAM_ITEM));
|
||||
fakeSampleStream.writeData(/* startPositionUs= */ 0);
|
||||
// Start of the first reading period.
|
||||
renderer.replaceStream(
|
||||
new Format[] {EMSG_FORMAT},
|
||||
fakeSampleStream,
|
||||
/* startPositionUs= */ 0L,
|
||||
/* offsetUs= */ 100_000L);
|
||||
// Read the format
|
||||
renderer.render(/* positionUs= */ 0, /* elapsedRealtimeUs= */ 0);
|
||||
|
||||
// Read and render the first metadata. The second metadata is immediately read as pending.
|
||||
// The offset of 0 is added to timeUs of the samples when reading (100_000 and 200_000).
|
||||
renderer.render(/* positionUs= */ 199_999, /* elapsedRealtimeUs= */ 0);
|
||||
assertThat(metadataOutput).isEmpty();
|
||||
renderer.render(/* positionUs= */ 200_000, /* elapsedRealtimeUs= */ 0);
|
||||
assertThat(metadataOutput).hasSize(1);
|
||||
|
||||
// Start of the 2nd reading period. Replace the stream with a different offset and adjust the
|
||||
// presentation time of the pending metadata.
|
||||
renderer.replaceStream(
|
||||
new Format[] {EMSG_FORMAT},
|
||||
fakeSampleStream,
|
||||
/* startPositionUs= */ 0L,
|
||||
/* offsetUs= */ 0L);
|
||||
renderer.render(/* positionUs= */ 299_999, /* elapsedRealtimeUs= */ 0);
|
||||
assertThat(metadataOutput).hasSize(1);
|
||||
|
||||
// Output second metadata.
|
||||
renderer.render(/* positionUs= */ 300_000, /* elapsedRealtimeUs= */ 0);
|
||||
assertThat(metadataOutput).hasSize(2);
|
||||
assertThat(metadataOutput.get(0).presentationTimeUs).isEqualTo(100_000);
|
||||
assertThat(metadataOutput.get(1).presentationTimeUs).isEqualTo(300_000);
|
||||
}
|
||||
|
||||
private static List<Metadata> runRenderer(byte[] input) throws ExoPlaybackException {
|
||||
List<Metadata> metadata = new ArrayList<>();
|
||||
MetadataRenderer renderer = new MetadataRenderer(metadata::add, /* outputLooper= */ null);
|
||||
|
Loading…
x
Reference in New Issue
Block a user