Defer outputting the metadata sample when TimestampAdjuster isn't initialized

The sample timestamp carried by the emsg box can have a significant delta when comparing to the earliest presentation timestamp of the segment. Using this timestamp to intialize the timestamp offset in TimestampAdjuster will cause the media sample to have a wrong adjusted timestamp. So we should defer adjusting the metadata sample timestamp until the TimestampAdjuster is initialized with a real media sample.

PiperOrigin-RevId: 538172841
This commit is contained in:
tianyifeng 2023-06-06 14:13:44 +00:00 committed by Tofunmi Adigun-Hameed
parent 08e7158be5
commit f4bf376e89
3 changed files with 18 additions and 4 deletions

View File

@ -14,6 +14,9 @@
* Parse EXIF rotation data for image inputs. * Parse EXIF rotation data for image inputs.
* Track Selection: * Track Selection:
* Extractors: * Extractors:
* FMP4: Fix issue where `TimestampAdjuster` initializes a wrong timestamp
offset with metadata sample time from emsg atom
([#356](https://github.com/androidx/media/issues/356)).
* Audio: * Audio:
* Audio Offload: * Audio Offload:
* Add `AudioSink.getFormatOffloadSupport(Format)` that retrieves level of * Add `AudioSink.getFormatOffloadSupport(Format)` that retrieves level of

View File

@ -106,14 +106,13 @@ public final class TimestampAdjuster {
public synchronized void sharedInitializeOrWait(boolean canInitialize, long nextSampleTimestampUs) public synchronized void sharedInitializeOrWait(boolean canInitialize, long nextSampleTimestampUs)
throws InterruptedException { throws InterruptedException {
Assertions.checkState(firstSampleTimestampUs == MODE_SHARED); Assertions.checkState(firstSampleTimestampUs == MODE_SHARED);
if (timestampOffsetUs != C.TIME_UNSET) { if (isInitialized()) {
// Already initialized.
return; return;
} else if (canInitialize) { } else if (canInitialize) {
this.nextSampleTimestampUs.set(nextSampleTimestampUs); this.nextSampleTimestampUs.set(nextSampleTimestampUs);
} else { } else {
// Wait for another calling thread to complete initialization. // Wait for another calling thread to complete initialization.
while (timestampOffsetUs == C.TIME_UNSET) { while (!isInitialized()) {
wait(); wait();
} }
} }
@ -195,7 +194,7 @@ public final class TimestampAdjuster {
if (timeUs == C.TIME_UNSET) { if (timeUs == C.TIME_UNSET) {
return C.TIME_UNSET; return C.TIME_UNSET;
} }
if (timestampOffsetUs == C.TIME_UNSET) { if (!isInitialized()) {
long desiredSampleTimestampUs = long desiredSampleTimestampUs =
firstSampleTimestampUs == MODE_SHARED firstSampleTimestampUs == MODE_SHARED
? Assertions.checkNotNull(nextSampleTimestampUs.get()) ? Assertions.checkNotNull(nextSampleTimestampUs.get())
@ -208,6 +207,11 @@ public final class TimestampAdjuster {
return timeUs + timestampOffsetUs; return timeUs + timestampOffsetUs;
} }
/** Returns whether the instance is initialized with a timestamp offset. */
public synchronized boolean isInitialized() {
return timestampOffsetUs != C.TIME_UNSET;
}
/** /**
* Converts a 90 kHz clock timestamp to a timestamp in microseconds. * Converts a 90 kHz clock timestamp to a timestamp in microseconds.
* *

View File

@ -683,6 +683,13 @@ public class FragmentedMp4Extractor implements Extractor {
pendingMetadataSampleInfos.addLast( pendingMetadataSampleInfos.addLast(
new MetadataSampleInfo(sampleTimeUs, /* sampleTimeIsRelative= */ false, sampleSize)); new MetadataSampleInfo(sampleTimeUs, /* sampleTimeIsRelative= */ false, sampleSize));
pendingMetadataSampleBytes += sampleSize; pendingMetadataSampleBytes += sampleSize;
} else if (timestampAdjuster != null && !timestampAdjuster.isInitialized()) {
// We also need to defer outputting metadata if the timestampAdjuster is not initialized,
// else we will set a wrong timestampOffsetUs in timestampAdjuster. See:
// https://github.com/androidx/media/issues/356.
pendingMetadataSampleInfos.addLast(
new MetadataSampleInfo(sampleTimeUs, /* sampleTimeIsRelative= */ false, sampleSize));
pendingMetadataSampleBytes += sampleSize;
} else { } else {
// We can output the sample metadata immediately. // We can output the sample metadata immediately.
if (timestampAdjuster != null) { if (timestampAdjuster != null) {