mirror of
https://github.com/androidx/media.git
synced 2025-05-17 04:29:55 +08:00
Parse EMSG boxes in FragmentedMp4Extractor
Issue: #2176 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=143776526
This commit is contained in:
parent
f2634d11f5
commit
1da9e31d68
@ -44,6 +44,7 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
import java.util.UUID;
|
||||
@ -123,6 +124,7 @@ public final class FragmentedMp4Extractor implements Extractor {
|
||||
private final ParsableByteArray atomHeader;
|
||||
private final byte[] extendedTypeScratch;
|
||||
private final Stack<ContainerAtom> containerAtoms;
|
||||
private final LinkedList<MetadataSampleInfo> pendingMetadataSampleInfos;
|
||||
|
||||
private int parserState;
|
||||
private int atomType;
|
||||
@ -130,8 +132,10 @@ public final class FragmentedMp4Extractor implements Extractor {
|
||||
private int atomHeaderBytesRead;
|
||||
private ParsableByteArray atomData;
|
||||
private long endOfMdatPosition;
|
||||
private int pendingMetadataSampleBytes;
|
||||
|
||||
private long durationUs;
|
||||
private long segmentIndexEarliestPresentationTimeUs;
|
||||
private TrackBundle currentTrackBundle;
|
||||
private int sampleSize;
|
||||
private int sampleBytesWritten;
|
||||
@ -139,6 +143,7 @@ public final class FragmentedMp4Extractor implements Extractor {
|
||||
|
||||
// Extractor output.
|
||||
private ExtractorOutput extractorOutput;
|
||||
private TrackOutput metadataTrackOutput;
|
||||
|
||||
// Whether extractorOutput.seekMap has been called.
|
||||
private boolean haveOutputSeekMap;
|
||||
@ -172,8 +177,10 @@ public final class FragmentedMp4Extractor implements Extractor {
|
||||
encryptionSignalByte = new ParsableByteArray(1);
|
||||
extendedTypeScratch = new byte[16];
|
||||
containerAtoms = new Stack<>();
|
||||
pendingMetadataSampleInfos = new LinkedList<>();
|
||||
trackBundles = new SparseArray<>();
|
||||
durationUs = C.TIME_UNSET;
|
||||
segmentIndexEarliestPresentationTimeUs = C.TIME_UNSET;
|
||||
enterReadingAtomHeaderState();
|
||||
}
|
||||
|
||||
@ -199,6 +206,8 @@ public final class FragmentedMp4Extractor implements Extractor {
|
||||
for (int i = 0; i < trackCount; i++) {
|
||||
trackBundles.valueAt(i).reset();
|
||||
}
|
||||
pendingMetadataSampleInfos.clear();
|
||||
pendingMetadataSampleBytes = 0;
|
||||
containerAtoms.clear();
|
||||
enterReadingAtomHeaderState();
|
||||
}
|
||||
@ -336,11 +345,12 @@ public final class FragmentedMp4Extractor implements Extractor {
|
||||
if (!containerAtoms.isEmpty()) {
|
||||
containerAtoms.peek().add(leaf);
|
||||
} else if (leaf.type == Atom.TYPE_sidx) {
|
||||
ChunkIndex segmentIndex = parseSidx(leaf.data, inputPosition);
|
||||
extractorOutput.seekMap(segmentIndex);
|
||||
Pair<Long, ChunkIndex> result = parseSidx(leaf.data, inputPosition);
|
||||
segmentIndexEarliestPresentationTimeUs = result.first;
|
||||
extractorOutput.seekMap(result.second);
|
||||
haveOutputSeekMap = true;
|
||||
} else if (leaf.type == Atom.TYPE_emsg) {
|
||||
onEmsgLeafAtomRead(leaf);
|
||||
onEmsgLeafAtomRead(leaf.data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -419,8 +429,37 @@ public final class FragmentedMp4Extractor implements Extractor {
|
||||
}
|
||||
}
|
||||
|
||||
private void onEmsgLeafAtomRead(LeafAtom emsg) {
|
||||
// Do nothing.
|
||||
/**
|
||||
* Handles an emsg atom (defined in 23009-1).
|
||||
*/
|
||||
private void onEmsgLeafAtomRead(ParsableByteArray atom) {
|
||||
// TODO: Enable metadata output.
|
||||
if (metadataTrackOutput == null) {
|
||||
return;
|
||||
}
|
||||
// Parse the event's presentation time delta.
|
||||
atom.setPosition(Atom.FULL_HEADER_SIZE);
|
||||
atom.readNullTerminatedString(); // schemeIdUri
|
||||
atom.readNullTerminatedString(); // value
|
||||
long timescale = atom.readUnsignedInt();
|
||||
long presentationTimeDeltaUs =
|
||||
Util.scaleLargeTimestamp(atom.readUnsignedInt(), C.MICROS_PER_SECOND, timescale);
|
||||
// Output the sample data.
|
||||
atom.setPosition(Atom.FULL_HEADER_SIZE);
|
||||
int sampleSize = atom.bytesLeft();
|
||||
metadataTrackOutput.sampleData(atom, sampleSize);
|
||||
// Output the sample metadata.
|
||||
if (segmentIndexEarliestPresentationTimeUs != C.TIME_UNSET) {
|
||||
// We can output the sample metadata immediately.
|
||||
metadataTrackOutput.sampleMetadata(
|
||||
segmentIndexEarliestPresentationTimeUs + presentationTimeDeltaUs,
|
||||
C.BUFFER_FLAG_KEY_FRAME, sampleSize, 0 /* offset */, null);
|
||||
} else {
|
||||
// We need the first sample timestamp in the segment before we can output the metadata.
|
||||
pendingMetadataSampleInfos.addLast(
|
||||
new MetadataSampleInfo(presentationTimeDeltaUs, sampleSize));
|
||||
pendingMetadataSampleBytes += sampleSize;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -838,8 +877,13 @@ public final class FragmentedMp4Extractor implements Extractor {
|
||||
|
||||
/**
|
||||
* Parses a sidx atom (defined in 14496-12).
|
||||
*
|
||||
* @param atom The atom data.
|
||||
* @param inputPosition The input position of the first byte after the atom.
|
||||
* @return A pair consisting of the earliest presentation time in microseconds, and the parsed
|
||||
* {@link ChunkIndex}.
|
||||
*/
|
||||
private static ChunkIndex parseSidx(ParsableByteArray atom, long inputPosition)
|
||||
private static Pair<Long, ChunkIndex> parseSidx(ParsableByteArray atom, long inputPosition)
|
||||
throws ParserException {
|
||||
atom.setPosition(Atom.HEADER_SIZE);
|
||||
int fullAtom = atom.readInt();
|
||||
@ -856,6 +900,8 @@ public final class FragmentedMp4Extractor implements Extractor {
|
||||
earliestPresentationTime = atom.readUnsignedLongToLong();
|
||||
offset += atom.readUnsignedLongToLong();
|
||||
}
|
||||
long earliestPresentationTimeUs = Util.scaleLargeTimestamp(earliestPresentationTime,
|
||||
C.MICROS_PER_SECOND, timescale);
|
||||
|
||||
atom.skipBytes(2);
|
||||
|
||||
@ -866,7 +912,7 @@ public final class FragmentedMp4Extractor implements Extractor {
|
||||
long[] timesUs = new long[referenceCount];
|
||||
|
||||
long time = earliestPresentationTime;
|
||||
long timeUs = Util.scaleLargeTimestamp(time, C.MICROS_PER_SECOND, timescale);
|
||||
long timeUs = earliestPresentationTimeUs;
|
||||
for (int i = 0; i < referenceCount; i++) {
|
||||
int firstInt = atom.readInt();
|
||||
|
||||
@ -890,7 +936,8 @@ public final class FragmentedMp4Extractor implements Extractor {
|
||||
offset += sizes[i];
|
||||
}
|
||||
|
||||
return new ChunkIndex(sizes, offsets, durationsUs, timesUs);
|
||||
return Pair.create(earliestPresentationTimeUs,
|
||||
new ChunkIndex(sizes, offsets, durationsUs, timesUs));
|
||||
}
|
||||
|
||||
private void readEncryptionData(ExtractorInput input) throws IOException, InterruptedException {
|
||||
@ -1031,6 +1078,14 @@ public final class FragmentedMp4Extractor implements Extractor {
|
||||
}
|
||||
output.sampleMetadata(sampleTimeUs, sampleFlags, sampleSize, 0, encryptionKey);
|
||||
|
||||
while (!pendingMetadataSampleInfos.isEmpty()) {
|
||||
MetadataSampleInfo sampleInfo = pendingMetadataSampleInfos.removeFirst();
|
||||
pendingMetadataSampleBytes -= sampleInfo.size;
|
||||
metadataTrackOutput.sampleMetadata(
|
||||
sampleTimeUs + sampleInfo.presentationTimeDeltaUs,
|
||||
C.BUFFER_FLAG_KEY_FRAME, sampleInfo.size, pendingMetadataSampleBytes, null);
|
||||
}
|
||||
|
||||
currentTrackBundle.currentSampleIndex++;
|
||||
currentTrackBundle.currentSampleInTrackRun++;
|
||||
if (currentTrackBundle.currentSampleInTrackRun
|
||||
@ -1146,6 +1201,21 @@ public final class FragmentedMp4Extractor implements Extractor {
|
||||
|| atom == Atom.TYPE_traf || atom == Atom.TYPE_mvex || atom == Atom.TYPE_edts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds data corresponding to a metadata sample.
|
||||
*/
|
||||
private static final class MetadataSampleInfo {
|
||||
|
||||
public final long presentationTimeDeltaUs;
|
||||
public final int size;
|
||||
|
||||
public MetadataSampleInfo(long presentationTimeDeltaUs, int size) {
|
||||
this.presentationTimeDeltaUs = presentationTimeDeltaUs;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds data corresponding to a single track.
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user