use of androidx.media3.common.util.TimestampAdjuster in project media by androidx.
the class FragmentedMp4Extractor method onEmsgLeafAtomRead.
/**
* Handles an emsg atom (defined in 23009-1).
*/
private void onEmsgLeafAtomRead(ParsableByteArray atom) {
if (emsgTrackOutputs.length == 0) {
return;
}
atom.setPosition(Atom.HEADER_SIZE);
int fullAtom = atom.readInt();
int version = Atom.parseFullAtomVersion(fullAtom);
String schemeIdUri;
String value;
long timescale;
// Only set if version == 0
long presentationTimeDeltaUs = C.TIME_UNSET;
long sampleTimeUs = C.TIME_UNSET;
long durationMs;
long id;
switch(version) {
case 0:
schemeIdUri = checkNotNull(atom.readNullTerminatedString());
value = checkNotNull(atom.readNullTerminatedString());
timescale = atom.readUnsignedInt();
presentationTimeDeltaUs = Util.scaleLargeTimestamp(atom.readUnsignedInt(), C.MICROS_PER_SECOND, timescale);
if (segmentIndexEarliestPresentationTimeUs != C.TIME_UNSET) {
sampleTimeUs = segmentIndexEarliestPresentationTimeUs + presentationTimeDeltaUs;
}
durationMs = Util.scaleLargeTimestamp(atom.readUnsignedInt(), C.MILLIS_PER_SECOND, timescale);
id = atom.readUnsignedInt();
break;
case 1:
timescale = atom.readUnsignedInt();
sampleTimeUs = Util.scaleLargeTimestamp(atom.readUnsignedLongToLong(), C.MICROS_PER_SECOND, timescale);
durationMs = Util.scaleLargeTimestamp(atom.readUnsignedInt(), C.MILLIS_PER_SECOND, timescale);
id = atom.readUnsignedInt();
schemeIdUri = checkNotNull(atom.readNullTerminatedString());
value = checkNotNull(atom.readNullTerminatedString());
break;
default:
Log.w(TAG, "Skipping unsupported emsg version: " + version);
return;
}
byte[] messageData = new byte[atom.bytesLeft()];
atom.readBytes(messageData, /*offset=*/
0, atom.bytesLeft());
EventMessage eventMessage = new EventMessage(schemeIdUri, value, durationMs, id, messageData);
ParsableByteArray encodedEventMessage = new ParsableByteArray(eventMessageEncoder.encode(eventMessage));
int sampleSize = encodedEventMessage.bytesLeft();
// Output the sample data.
for (TrackOutput emsgTrackOutput : emsgTrackOutputs) {
encodedEventMessage.setPosition(0);
emsgTrackOutput.sampleData(encodedEventMessage, sampleSize);
}
// Output the sample metadata.
if (sampleTimeUs == C.TIME_UNSET) {
// We're processing a v0 emsg atom, which contains a presentation time delta, and cannot yet
// calculate its absolute sample timestamp. Defer outputting the metadata until we can.
pendingMetadataSampleInfos.addLast(new MetadataSampleInfo(presentationTimeDeltaUs, /* sampleTimeIsRelative= */
true, sampleSize));
pendingMetadataSampleBytes += sampleSize;
} else if (!pendingMetadataSampleInfos.isEmpty()) {
// We also need to defer outputting metadata if pendingMetadataSampleInfos is non-empty, else
// we will output metadata for samples in the wrong order. See:
// https://github.com/google/ExoPlayer/issues/9996.
pendingMetadataSampleInfos.addLast(new MetadataSampleInfo(sampleTimeUs, /* sampleTimeIsRelative= */
false, sampleSize));
pendingMetadataSampleBytes += sampleSize;
} else {
// We can output the sample metadata immediately.
if (timestampAdjuster != null) {
sampleTimeUs = timestampAdjuster.adjustSampleTimestamp(sampleTimeUs);
}
for (TrackOutput emsgTrackOutput : emsgTrackOutputs) {
emsgTrackOutput.sampleMetadata(sampleTimeUs, C.BUFFER_FLAG_KEY_FRAME, sampleSize, /* offset= */
0, null);
}
}
}
use of androidx.media3.common.util.TimestampAdjuster in project media by androidx.
the class FragmentedMp4Extractor method outputPendingMetadataSamples.
/**
* Called immediately after outputting a non-metadata sample, to output any pending metadata
* samples.
*
* @param sampleTimeUs The timestamp of the non-metadata sample that was just output.
*/
private void outputPendingMetadataSamples(long sampleTimeUs) {
while (!pendingMetadataSampleInfos.isEmpty()) {
MetadataSampleInfo metadataSampleInfo = pendingMetadataSampleInfos.removeFirst();
pendingMetadataSampleBytes -= metadataSampleInfo.size;
long metadataSampleTimeUs = metadataSampleInfo.sampleTimeUs;
if (metadataSampleInfo.sampleTimeIsRelative) {
// The metadata sample timestamp is relative to the timestamp of the non-metadata sample
// that was just output. Make it absolute.
metadataSampleTimeUs += sampleTimeUs;
}
if (timestampAdjuster != null) {
metadataSampleTimeUs = timestampAdjuster.adjustSampleTimestamp(metadataSampleTimeUs);
}
for (TrackOutput emsgTrackOutput : emsgTrackOutputs) {
emsgTrackOutput.sampleMetadata(metadataSampleTimeUs, C.BUFFER_FLAG_KEY_FRAME, metadataSampleInfo.size, pendingMetadataSampleBytes, null);
}
}
}
use of androidx.media3.common.util.TimestampAdjuster in project media by androidx.
the class TsExtractor method seek.
@Override
public void seek(long position, long timeUs) {
Assertions.checkState(mode != MODE_HLS);
int timestampAdjustersCount = timestampAdjusters.size();
for (int i = 0; i < timestampAdjustersCount; i++) {
TimestampAdjuster timestampAdjuster = timestampAdjusters.get(i);
// If the timestamp adjuster has not yet established a timestamp offset, we need to reset its
// expected first sample timestamp to be the new seek position. Without this, the timestamp
// adjuster would incorrectly establish its timestamp offset assuming that the first sample
// after this seek corresponds to the start of the stream (or a previous seek position, if
// there was one).
boolean resetTimestampAdjuster = timestampAdjuster.getTimestampOffsetUs() == C.TIME_UNSET;
if (!resetTimestampAdjuster) {
long adjusterFirstSampleTimestampUs = timestampAdjuster.getFirstSampleTimestampUs();
// Also reset the timestamp adjuster if its offset was calculated based on a non-zero
// position in the stream (other than the position being seeked to), since in this case the
// offset may not be accurate.
resetTimestampAdjuster = adjusterFirstSampleTimestampUs != C.TIME_UNSET && adjusterFirstSampleTimestampUs != 0 && adjusterFirstSampleTimestampUs != timeUs;
}
if (resetTimestampAdjuster) {
timestampAdjuster.reset(timeUs);
}
}
if (timeUs != 0 && tsBinarySearchSeeker != null) {
tsBinarySearchSeeker.setSeekTargetUs(timeUs);
}
tsPacketBuffer.reset(/* limit= */
0);
continuityCounters.clear();
for (int i = 0; i < tsPayloadReaders.size(); i++) {
tsPayloadReaders.valueAt(i).seek();
}
bytesSinceLastSync = 0;
}
use of androidx.media3.common.util.TimestampAdjuster in project media by androidx.
the class TsExtractorTest method customPesReader.
@Test
public void customPesReader() throws Exception {
CustomTsPayloadReaderFactory factory = new CustomTsPayloadReaderFactory(true, false);
TsExtractor tsExtractor = new TsExtractor(TsExtractor.MODE_MULTI_PMT, new TimestampAdjuster(0), factory);
FakeExtractorInput input = new FakeExtractorInput.Builder().setData(TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), "media/ts/sample_h262_mpeg_audio.ts")).setSimulateIOErrors(false).setSimulateUnknownLength(false).setSimulatePartialReads(false).build();
FakeExtractorOutput output = new FakeExtractorOutput();
tsExtractor.init(output);
PositionHolder seekPositionHolder = new PositionHolder();
int readResult = Extractor.RESULT_CONTINUE;
while (readResult != Extractor.RESULT_END_OF_INPUT) {
readResult = tsExtractor.read(input, seekPositionHolder);
if (readResult == Extractor.RESULT_SEEK) {
input.setPosition((int) seekPositionHolder.position);
}
}
CustomEsReader reader = factory.esReader;
assertThat(reader.packetsRead).isEqualTo(2);
TrackOutput trackOutput = reader.getTrackOutput();
assertThat(trackOutput == output.trackOutputs.get(257)).isTrue();
assertThat(((FakeTrackOutput) trackOutput).lastFormat).isEqualTo(new Format.Builder().setId("1/257").setSampleMimeType("mime").setLanguage("und").build());
}
use of androidx.media3.common.util.TimestampAdjuster in project media by androidx.
the class TsExtractorTest method customInitialSectionReader.
@Test
public void customInitialSectionReader() throws Exception {
CustomTsPayloadReaderFactory factory = new CustomTsPayloadReaderFactory(false, true);
TsExtractor tsExtractor = new TsExtractor(TsExtractor.MODE_MULTI_PMT, new TimestampAdjuster(0), factory);
FakeExtractorInput input = new FakeExtractorInput.Builder().setData(TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), "media/ts/sample_with_sdt.ts")).setSimulateIOErrors(false).setSimulateUnknownLength(false).setSimulatePartialReads(false).build();
tsExtractor.init(new FakeExtractorOutput());
PositionHolder seekPositionHolder = new PositionHolder();
int readResult = Extractor.RESULT_CONTINUE;
while (readResult != Extractor.RESULT_END_OF_INPUT) {
readResult = tsExtractor.read(input, seekPositionHolder);
if (readResult == Extractor.RESULT_SEEK) {
input.setPosition((int) seekPositionHolder.position);
}
}
assertThat(factory.sdtReader.consumedSdts).isEqualTo(2);
}
Aggregations