use of androidx.media3.extractor.mp4.Atom.ContainerAtom in project Telegram-FOSS by Telegram-FOSS-Team.
the class Mp4Extractor method processMoovAtom.
/**
* Updates the stored track metadata to reflect the contents of the specified moov atom.
*/
private void processMoovAtom(ContainerAtom moov) throws ParserException {
int firstVideoTrackIndex = C.INDEX_UNSET;
long durationUs = C.TIME_UNSET;
List<Mp4Track> tracks = new ArrayList<>();
// Process metadata.
Metadata udtaMetadata = null;
GaplessInfoHolder gaplessInfoHolder = new GaplessInfoHolder();
Atom.LeafAtom udta = moov.getLeafAtomOfType(Atom.TYPE_udta);
if (udta != null) {
udtaMetadata = AtomParsers.parseUdta(udta, isQuickTime);
if (udtaMetadata != null) {
gaplessInfoHolder.setFromMetadata(udtaMetadata);
}
}
Metadata mdtaMetadata = null;
Atom.ContainerAtom meta = moov.getContainerAtomOfType(Atom.TYPE_meta);
if (meta != null) {
mdtaMetadata = AtomParsers.parseMdtaFromMeta(meta);
}
boolean ignoreEditLists = (flags & FLAG_WORKAROUND_IGNORE_EDIT_LISTS) != 0;
ArrayList<TrackSampleTable> trackSampleTables = getTrackSampleTables(moov, gaplessInfoHolder, ignoreEditLists);
int trackCount = trackSampleTables.size();
for (int i = 0; i < trackCount; i++) {
TrackSampleTable trackSampleTable = trackSampleTables.get(i);
Track track = trackSampleTable.track;
long trackDurationUs = track.durationUs != C.TIME_UNSET ? track.durationUs : trackSampleTable.durationUs;
durationUs = Math.max(durationUs, trackDurationUs);
Mp4Track mp4Track = new Mp4Track(track, trackSampleTable, extractorOutput.track(i, track.type));
// Each sample has up to three bytes of overhead for the start code that replaces its length.
// Allow ten source samples per output sample, like the platform extractor.
int maxInputSize = trackSampleTable.maximumSize + 3 * 10;
Format format = track.format.copyWithMaxInputSize(maxInputSize);
if (track.type == C.TRACK_TYPE_VIDEO && trackDurationUs > 0 && trackSampleTable.sampleCount > 1) {
float frameRate = trackSampleTable.sampleCount / (trackDurationUs / 1000000f);
format = format.copyWithFrameRate(frameRate);
}
format = MetadataUtil.getFormatWithMetadata(track.type, format, udtaMetadata, mdtaMetadata, gaplessInfoHolder);
mp4Track.trackOutput.format(format);
if (track.type == C.TRACK_TYPE_VIDEO && firstVideoTrackIndex == C.INDEX_UNSET) {
firstVideoTrackIndex = tracks.size();
}
tracks.add(mp4Track);
}
this.firstVideoTrackIndex = firstVideoTrackIndex;
this.durationUs = durationUs;
this.tracks = tracks.toArray(new Mp4Track[0]);
accumulatedSampleSizes = calculateAccumulatedSampleSizes(this.tracks);
extractorOutput.endTracks();
extractorOutput.seekMap(this);
}
use of androidx.media3.extractor.mp4.Atom.ContainerAtom in project Telegram-FOSS by Telegram-FOSS-Team.
the class Mp4Extractor method processAtomEnded.
private void processAtomEnded(long atomEndPosition) throws ParserException {
while (!containerAtoms.isEmpty() && containerAtoms.peek().endPosition == atomEndPosition) {
Atom.ContainerAtom containerAtom = containerAtoms.pop();
if (containerAtom.type == Atom.TYPE_moov) {
// We've reached the end of the moov atom. Process it and prepare to read samples.
processMoovAtom(containerAtom);
containerAtoms.clear();
parserState = STATE_READING_SAMPLE;
} else if (!containerAtoms.isEmpty()) {
containerAtoms.peek().add(containerAtom);
}
}
if (parserState != STATE_READING_SAMPLE) {
enterReadingAtomHeaderState();
}
}
use of androidx.media3.extractor.mp4.Atom.ContainerAtom in project Telegram-FOSS by Telegram-FOSS-Team.
the class Mp4Extractor method readAtomHeader.
private boolean readAtomHeader(ExtractorInput input) throws IOException, InterruptedException {
if (atomHeaderBytesRead == 0) {
// Read the standard length atom header.
if (!input.readFully(atomHeader.data, 0, Atom.HEADER_SIZE, true)) {
return false;
}
atomHeaderBytesRead = Atom.HEADER_SIZE;
atomHeader.setPosition(0);
atomSize = atomHeader.readUnsignedInt();
atomType = atomHeader.readInt();
}
if (atomSize == Atom.DEFINES_LARGE_SIZE) {
// Read the large size.
int headerBytesRemaining = Atom.LONG_HEADER_SIZE - Atom.HEADER_SIZE;
input.readFully(atomHeader.data, Atom.HEADER_SIZE, headerBytesRemaining);
atomHeaderBytesRead += headerBytesRemaining;
atomSize = atomHeader.readUnsignedLongToLong();
} else if (atomSize == Atom.EXTENDS_TO_END_SIZE) {
// The atom extends to the end of the file. Note that if the atom is within a container we can
// work out its size even if the input length is unknown.
long endPosition = input.getLength();
if (endPosition == C.LENGTH_UNSET && !containerAtoms.isEmpty()) {
endPosition = containerAtoms.peek().endPosition;
}
if (endPosition != C.LENGTH_UNSET) {
atomSize = endPosition - input.getPosition() + atomHeaderBytesRead;
}
}
if (atomSize < atomHeaderBytesRead) {
throw new ParserException("Atom size less than header length (unsupported).");
}
if (shouldParseContainerAtom(atomType)) {
long endPosition = input.getPosition() + atomSize - atomHeaderBytesRead;
if (atomSize != atomHeaderBytesRead && atomType == Atom.TYPE_meta) {
maybeSkipRemainingMetaAtomHeaderBytes(input);
}
containerAtoms.push(new ContainerAtom(atomType, endPosition));
if (atomSize == atomHeaderBytesRead) {
processAtomEnded(endPosition);
} else {
// Start reading the first child atom.
enterReadingAtomHeaderState();
}
} else if (shouldParseLeafAtom(atomType)) {
// We don't support parsing of leaf atoms that define extended atom sizes, or that have
// lengths greater than Integer.MAX_VALUE.
Assertions.checkState(atomHeaderBytesRead == Atom.HEADER_SIZE);
Assertions.checkState(atomSize <= Integer.MAX_VALUE);
atomData = new ParsableByteArray((int) atomSize);
System.arraycopy(atomHeader.data, 0, atomData.data, 0, Atom.HEADER_SIZE);
parserState = STATE_READING_ATOM_PAYLOAD;
} else {
atomData = null;
parserState = STATE_READING_ATOM_PAYLOAD;
}
return true;
}
use of androidx.media3.extractor.mp4.Atom.ContainerAtom in project Telegram-FOSS by Telegram-FOSS-Team.
the class FragmentedMp4Extractor method parseTruns.
private static void parseTruns(ContainerAtom traf, TrackBundle trackBundle, long decodeTime, @Flags int flags) throws ParserException {
int trunCount = 0;
int totalSampleCount = 0;
List<LeafAtom> leafChildren = traf.leafChildren;
int leafChildrenSize = leafChildren.size();
for (int i = 0; i < leafChildrenSize; i++) {
LeafAtom atom = leafChildren.get(i);
if (atom.type == Atom.TYPE_trun) {
ParsableByteArray trunData = atom.data;
trunData.setPosition(Atom.FULL_HEADER_SIZE);
int trunSampleCount = trunData.readUnsignedIntToInt();
if (trunSampleCount > 0) {
totalSampleCount += trunSampleCount;
trunCount++;
}
}
}
trackBundle.currentTrackRunIndex = 0;
trackBundle.currentSampleInTrackRun = 0;
trackBundle.currentSampleIndex = 0;
trackBundle.fragment.initTables(trunCount, totalSampleCount);
int trunIndex = 0;
int trunStartPosition = 0;
for (int i = 0; i < leafChildrenSize; i++) {
LeafAtom trun = leafChildren.get(i);
if (trun.type == Atom.TYPE_trun) {
trunStartPosition = parseTrun(trackBundle, trunIndex++, decodeTime, flags, trun.data, trunStartPosition);
}
}
}
use of androidx.media3.extractor.mp4.Atom.ContainerAtom in project Telegram-FOSS by Telegram-FOSS-Team.
the class FragmentedMp4Extractor method onMoovContainerAtomRead.
private void onMoovContainerAtomRead(ContainerAtom moov) throws ParserException {
Assertions.checkState(sideloadedTrack == null, "Unexpected moov box.");
@Nullable DrmInitData drmInitData = getDrmInitDataFromAtoms(moov.leafChildren);
// Read declaration of track fragments in the Moov box.
ContainerAtom mvex = moov.getContainerAtomOfType(Atom.TYPE_mvex);
SparseArray<DefaultSampleValues> defaultSampleValuesArray = new SparseArray<>();
long duration = C.TIME_UNSET;
int mvexChildrenSize = mvex.leafChildren.size();
for (int i = 0; i < mvexChildrenSize; i++) {
Atom.LeafAtom atom = mvex.leafChildren.get(i);
if (atom.type == Atom.TYPE_trex) {
Pair<Integer, DefaultSampleValues> trexData = parseTrex(atom.data);
defaultSampleValuesArray.put(trexData.first, trexData.second);
} else if (atom.type == Atom.TYPE_mehd) {
duration = parseMehd(atom.data);
}
}
// Construction of tracks.
SparseArray<Track> tracks = new SparseArray<>();
int moovContainerChildrenSize = moov.containerChildren.size();
for (int i = 0; i < moovContainerChildrenSize; i++) {
Atom.ContainerAtom atom = moov.containerChildren.get(i);
if (atom.type == Atom.TYPE_trak) {
Track track = modifyTrack(AtomParsers.parseTrak(atom, moov.getLeafAtomOfType(Atom.TYPE_mvhd), duration, drmInitData, (flags & FLAG_WORKAROUND_IGNORE_EDIT_LISTS) != 0, false));
if (track != null) {
tracks.put(track.id, track);
}
}
}
int trackCount = tracks.size();
if (trackBundles.size() == 0) {
// We need to create the track bundles.
for (int i = 0; i < trackCount; i++) {
Track track = tracks.valueAt(i);
TrackBundle trackBundle = new TrackBundle(extractorOutput.track(i, track.type));
trackBundle.init(track, getDefaultSampleValues(defaultSampleValuesArray, track.id));
trackBundles.put(track.id, trackBundle);
durationUs = Math.max(durationUs, track.durationUs);
}
maybeInitExtraTracks();
extractorOutput.endTracks();
} else {
Assertions.checkState(trackBundles.size() == trackCount);
for (int i = 0; i < trackCount; i++) {
Track track = tracks.valueAt(i);
trackBundles.get(track.id).init(track, getDefaultSampleValues(defaultSampleValuesArray, track.id));
}
}
}
Aggregations