Search in sources :

Example 21 with ContainerAtom

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);
}
Also used : ArrayList(java.util.ArrayList) Metadata(com.google.android.exoplayer2.metadata.Metadata) ContainerAtom(com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom) SeekPoint(com.google.android.exoplayer2.extractor.SeekPoint) ContainerAtom(com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom) Format(com.google.android.exoplayer2.Format) GaplessInfoHolder(com.google.android.exoplayer2.extractor.GaplessInfoHolder)

Example 22 with ContainerAtom

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();
    }
}
Also used : ContainerAtom(com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom) ContainerAtom(com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom)

Example 23 with ContainerAtom

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;
}
Also used : ParsableByteArray(com.google.android.exoplayer2.util.ParsableByteArray) ParserException(com.google.android.exoplayer2.ParserException) ContainerAtom(com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom) SeekPoint(com.google.android.exoplayer2.extractor.SeekPoint)

Example 24 with ContainerAtom

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);
        }
    }
}
Also used : ParsableByteArray(com.google.android.exoplayer2.util.ParsableByteArray) LeafAtom(com.google.android.exoplayer2.extractor.mp4.Atom.LeafAtom)

Example 25 with ContainerAtom

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));
        }
    }
}
Also used : ContainerAtom(com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom) LeafAtom(com.google.android.exoplayer2.extractor.mp4.Atom.LeafAtom) ContainerAtom(com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom) ContainerAtom(com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom) LeafAtom(com.google.android.exoplayer2.extractor.mp4.Atom.LeafAtom) SparseArray(android.util.SparseArray) DrmInitData(com.google.android.exoplayer2.drm.DrmInitData) Nullable(androidx.annotation.Nullable)

Aggregations

ContainerAtom (com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom)11 Nullable (androidx.annotation.Nullable)10 LeafAtom (com.google.android.exoplayer2.extractor.mp4.Atom.LeafAtom)9 ParsableByteArray (com.google.android.exoplayer2.util.ParsableByteArray)8 ContainerAtom (androidx.media3.extractor.mp4.Atom.ContainerAtom)5 SeekPoint (com.google.android.exoplayer2.extractor.SeekPoint)5 ParsableByteArray (androidx.media3.common.util.ParsableByteArray)4 LeafAtom (androidx.media3.extractor.mp4.Atom.LeafAtom)4 ArrayList (java.util.ArrayList)4 SuppressLint (android.annotation.SuppressLint)3 SparseArray (android.util.SparseArray)3 ContainerAtom (com.google.android.exoplayer.parser.mp4.Atom.ContainerAtom)3 GaplessInfoHolder (com.google.android.exoplayer2.extractor.GaplessInfoHolder)3 DrmInitData (androidx.media3.common.DrmInitData)2 GaplessInfoHolder (androidx.media3.extractor.GaplessInfoHolder)2 SeekPoint (androidx.media3.extractor.SeekPoint)2 Format (com.google.android.exoplayer2.Format)2 ParserException (com.google.android.exoplayer2.ParserException)2 DrmInitData (com.google.android.exoplayer2.drm.DrmInitData)2 SeekMap (com.google.android.exoplayer2.extractor.SeekMap)2