Search in sources :

Example 1 with GaplessInfoHolder

use of androidx.media3.extractor.GaplessInfoHolder in project ExoPlayer by google.

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.
    @Nullable Metadata udtaMetaMetadata = null;
    @Nullable Metadata smtaMetadata = null;
    boolean isQuickTime = fileType == FILE_TYPE_QUICKTIME;
    GaplessInfoHolder gaplessInfoHolder = new GaplessInfoHolder();
    @Nullable Atom.LeafAtom udta = moov.getLeafAtomOfType(Atom.TYPE_udta);
    if (udta != null) {
        Pair<@NullableType Metadata, @NullableType Metadata> udtaMetadata = AtomParsers.parseUdta(udta);
        udtaMetaMetadata = udtaMetadata.first;
        smtaMetadata = udtaMetadata.second;
        if (udtaMetaMetadata != null) {
            gaplessInfoHolder.setFromMetadata(udtaMetaMetadata);
        }
    }
    @Nullable Metadata mdtaMetadata = null;
    @Nullable Atom.ContainerAtom meta = moov.getContainerAtomOfType(Atom.TYPE_meta);
    if (meta != null) {
        mdtaMetadata = AtomParsers.parseMdtaFromMeta(meta);
    }
    boolean ignoreEditLists = (flags & FLAG_WORKAROUND_IGNORE_EDIT_LISTS) != 0;
    List<TrackSampleTable> trackSampleTables = parseTraks(moov, gaplessInfoHolder, /* duration= */
    C.TIME_UNSET, /* drmInitData= */
    null, ignoreEditLists, isQuickTime, /* modifyTrackFunction= */
    track -> track);
    ExtractorOutput extractorOutput = checkNotNull(this.extractorOutput);
    int trackCount = trackSampleTables.size();
    for (int i = 0; i < trackCount; i++) {
        TrackSampleTable trackSampleTable = trackSampleTables.get(i);
        if (trackSampleTable.sampleCount == 0) {
            continue;
        }
        Track track = trackSampleTable.track;
        long trackDurationUs = track.durationUs != C.TIME_UNSET ? track.durationUs : trackSampleTable.durationUs;
        durationUs = max(durationUs, trackDurationUs);
        Mp4Track mp4Track = new Mp4Track(track, trackSampleTable, extractorOutput.track(i, track.type));
        int maxInputSize;
        if (MimeTypes.AUDIO_TRUEHD.equals(track.format.sampleMimeType)) {
            // TrueHD groups samples per chunks of TRUEHD_RECHUNK_SAMPLE_COUNT samples.
            maxInputSize = trackSampleTable.maximumSize * Ac3Util.TRUEHD_RECHUNK_SAMPLE_COUNT;
        } else {
            // 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.
            maxInputSize = trackSampleTable.maximumSize + 3 * 10;
        }
        Format.Builder formatBuilder = track.format.buildUpon();
        formatBuilder.setMaxInputSize(maxInputSize);
        if (track.type == C.TRACK_TYPE_VIDEO && trackDurationUs > 0 && trackSampleTable.sampleCount > 1) {
            float frameRate = trackSampleTable.sampleCount / (trackDurationUs / 1000000f);
            formatBuilder.setFrameRate(frameRate);
        }
        MetadataUtil.setFormatGaplessInfo(track.type, gaplessInfoHolder, formatBuilder);
        MetadataUtil.setFormatMetadata(track.type, udtaMetaMetadata, mdtaMetadata, formatBuilder, smtaMetadata, slowMotionMetadataEntries.isEmpty() ? null : new Metadata(slowMotionMetadataEntries));
        mp4Track.trackOutput.format(formatBuilder.build());
        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 : ExtractorOutput(com.google.android.exoplayer2.extractor.ExtractorOutput) ArrayList(java.util.ArrayList) MotionPhotoMetadata(com.google.android.exoplayer2.metadata.mp4.MotionPhotoMetadata) 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) Nullable(androidx.annotation.Nullable)

Example 2 with GaplessInfoHolder

use of androidx.media3.extractor.GaplessInfoHolder in project media by androidx.

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.
    @Nullable Metadata udtaMetaMetadata = null;
    @Nullable Metadata smtaMetadata = null;
    boolean isQuickTime = fileType == FILE_TYPE_QUICKTIME;
    GaplessInfoHolder gaplessInfoHolder = new GaplessInfoHolder();
    @Nullable Atom.LeafAtom udta = moov.getLeafAtomOfType(Atom.TYPE_udta);
    if (udta != null) {
        Pair<@NullableType Metadata, @NullableType Metadata> udtaMetadata = AtomParsers.parseUdta(udta);
        udtaMetaMetadata = udtaMetadata.first;
        smtaMetadata = udtaMetadata.second;
        if (udtaMetaMetadata != null) {
            gaplessInfoHolder.setFromMetadata(udtaMetaMetadata);
        }
    }
    @Nullable Metadata mdtaMetadata = null;
    @Nullable Atom.ContainerAtom meta = moov.getContainerAtomOfType(Atom.TYPE_meta);
    if (meta != null) {
        mdtaMetadata = AtomParsers.parseMdtaFromMeta(meta);
    }
    boolean ignoreEditLists = (flags & FLAG_WORKAROUND_IGNORE_EDIT_LISTS) != 0;
    List<TrackSampleTable> trackSampleTables = parseTraks(moov, gaplessInfoHolder, /* duration= */
    C.TIME_UNSET, /* drmInitData= */
    null, ignoreEditLists, isQuickTime, /* modifyTrackFunction= */
    track -> track);
    ExtractorOutput extractorOutput = checkNotNull(this.extractorOutput);
    int trackCount = trackSampleTables.size();
    for (int i = 0; i < trackCount; i++) {
        TrackSampleTable trackSampleTable = trackSampleTables.get(i);
        if (trackSampleTable.sampleCount == 0) {
            continue;
        }
        Track track = trackSampleTable.track;
        long trackDurationUs = track.durationUs != C.TIME_UNSET ? track.durationUs : trackSampleTable.durationUs;
        durationUs = max(durationUs, trackDurationUs);
        Mp4Track mp4Track = new Mp4Track(track, trackSampleTable, extractorOutput.track(i, track.type));
        int maxInputSize;
        if (MimeTypes.AUDIO_TRUEHD.equals(track.format.sampleMimeType)) {
            // TrueHD groups samples per chunks of TRUEHD_RECHUNK_SAMPLE_COUNT samples.
            maxInputSize = trackSampleTable.maximumSize * Ac3Util.TRUEHD_RECHUNK_SAMPLE_COUNT;
        } else {
            // 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.
            maxInputSize = trackSampleTable.maximumSize + 3 * 10;
        }
        Format.Builder formatBuilder = track.format.buildUpon();
        formatBuilder.setMaxInputSize(maxInputSize);
        if (track.type == C.TRACK_TYPE_VIDEO && trackDurationUs > 0 && trackSampleTable.sampleCount > 1) {
            float frameRate = trackSampleTable.sampleCount / (trackDurationUs / 1000000f);
            formatBuilder.setFrameRate(frameRate);
        }
        MetadataUtil.setFormatGaplessInfo(track.type, gaplessInfoHolder, formatBuilder);
        MetadataUtil.setFormatMetadata(track.type, udtaMetaMetadata, mdtaMetadata, formatBuilder, smtaMetadata, slowMotionMetadataEntries.isEmpty() ? null : new Metadata(slowMotionMetadataEntries));
        mp4Track.trackOutput.format(formatBuilder.build());
        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 : ExtractorOutput(androidx.media3.extractor.ExtractorOutput) ArrayList(java.util.ArrayList) Metadata(androidx.media3.common.Metadata) MotionPhotoMetadata(androidx.media3.extractor.metadata.mp4.MotionPhotoMetadata) ContainerAtom(androidx.media3.extractor.mp4.Atom.ContainerAtom) SeekPoint(androidx.media3.extractor.SeekPoint) ContainerAtom(androidx.media3.extractor.mp4.Atom.ContainerAtom) Format(androidx.media3.common.Format) GaplessInfoHolder(androidx.media3.extractor.GaplessInfoHolder) Nullable(androidx.annotation.Nullable)

Example 3 with GaplessInfoHolder

use of androidx.media3.extractor.GaplessInfoHolder in project ExoPlayer by google.

the class FragmentedMp4Extractor method onMoovContainerAtomRead.

private void onMoovContainerAtomRead(ContainerAtom moov) throws ParserException {
    checkState(sideloadedTrack == null, "Unexpected moov box.");
    @Nullable DrmInitData drmInitData = getDrmInitDataFromAtoms(moov.leafChildren);
    // Read declaration of track fragments in the moov box.
    ContainerAtom mvex = checkNotNull(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 and sample tables.
    List<TrackSampleTable> sampleTables = parseTraks(moov, new GaplessInfoHolder(), duration, drmInitData, /* ignoreEditLists= */
    (flags & FLAG_WORKAROUND_IGNORE_EDIT_LISTS) != 0, /* isQuickTime= */
    false, this::modifyTrack);
    int trackCount = sampleTables.size();
    if (trackBundles.size() == 0) {
        // We need to create the track bundles.
        for (int i = 0; i < trackCount; i++) {
            TrackSampleTable sampleTable = sampleTables.get(i);
            Track track = sampleTable.track;
            TrackBundle trackBundle = new TrackBundle(extractorOutput.track(i, track.type), sampleTable, getDefaultSampleValues(defaultSampleValuesArray, track.id));
            trackBundles.put(track.id, trackBundle);
            durationUs = max(durationUs, track.durationUs);
        }
        extractorOutput.endTracks();
    } else {
        checkState(trackBundles.size() == trackCount);
        for (int i = 0; i < trackCount; i++) {
            TrackSampleTable sampleTable = sampleTables.get(i);
            Track track = sampleTable.track;
            trackBundles.get(track.id).reset(sampleTable, 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) LeafAtom(com.google.android.exoplayer2.extractor.mp4.Atom.LeafAtom) SparseArray(android.util.SparseArray) DrmInitData(com.google.android.exoplayer2.drm.DrmInitData) GaplessInfoHolder(com.google.android.exoplayer2.extractor.GaplessInfoHolder) Nullable(androidx.annotation.Nullable)

Example 4 with GaplessInfoHolder

use of androidx.media3.extractor.GaplessInfoHolder 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 5 with GaplessInfoHolder

use of androidx.media3.extractor.GaplessInfoHolder in project media by androidx.

the class FragmentedMp4Extractor method onMoovContainerAtomRead.

private void onMoovContainerAtomRead(ContainerAtom moov) throws ParserException {
    checkState(sideloadedTrack == null, "Unexpected moov box.");
    @Nullable DrmInitData drmInitData = getDrmInitDataFromAtoms(moov.leafChildren);
    // Read declaration of track fragments in the moov box.
    ContainerAtom mvex = checkNotNull(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 and sample tables.
    List<TrackSampleTable> sampleTables = parseTraks(moov, new GaplessInfoHolder(), duration, drmInitData, /* ignoreEditLists= */
    (flags & FLAG_WORKAROUND_IGNORE_EDIT_LISTS) != 0, /* isQuickTime= */
    false, this::modifyTrack);
    int trackCount = sampleTables.size();
    if (trackBundles.size() == 0) {
        // We need to create the track bundles.
        for (int i = 0; i < trackCount; i++) {
            TrackSampleTable sampleTable = sampleTables.get(i);
            Track track = sampleTable.track;
            TrackBundle trackBundle = new TrackBundle(extractorOutput.track(i, track.type), sampleTable, getDefaultSampleValues(defaultSampleValuesArray, track.id));
            trackBundles.put(track.id, trackBundle);
            durationUs = max(durationUs, track.durationUs);
        }
        extractorOutput.endTracks();
    } else {
        checkState(trackBundles.size() == trackCount);
        for (int i = 0; i < trackCount; i++) {
            TrackSampleTable sampleTable = sampleTables.get(i);
            Track track = sampleTable.track;
            trackBundles.get(track.id).reset(sampleTable, getDefaultSampleValues(defaultSampleValuesArray, track.id));
        }
    }
}
Also used : ContainerAtom(androidx.media3.extractor.mp4.Atom.ContainerAtom) LeafAtom(androidx.media3.extractor.mp4.Atom.LeafAtom) ContainerAtom(androidx.media3.extractor.mp4.Atom.ContainerAtom) LeafAtom(androidx.media3.extractor.mp4.Atom.LeafAtom) SparseArray(android.util.SparseArray) DrmInitData(androidx.media3.common.DrmInitData) GaplessInfoHolder(androidx.media3.extractor.GaplessInfoHolder) Nullable(androidx.annotation.Nullable)

Aggregations

Nullable (androidx.annotation.Nullable)5 GaplessInfoHolder (com.google.android.exoplayer2.extractor.GaplessInfoHolder)4 ContainerAtom (com.google.android.exoplayer2.extractor.mp4.Atom.ContainerAtom)4 ArrayList (java.util.ArrayList)4 Format (com.google.android.exoplayer2.Format)3 SeekPoint (com.google.android.exoplayer2.extractor.SeekPoint)3 Metadata (com.google.android.exoplayer2.metadata.Metadata)3 SparseArray (android.util.SparseArray)2 GaplessInfoHolder (androidx.media3.extractor.GaplessInfoHolder)2 ContainerAtom (androidx.media3.extractor.mp4.Atom.ContainerAtom)2 DrmInitData (androidx.media3.common.DrmInitData)1 Format (androidx.media3.common.Format)1 Metadata (androidx.media3.common.Metadata)1 ParsableByteArray (androidx.media3.common.util.ParsableByteArray)1 ExtractorOutput (androidx.media3.extractor.ExtractorOutput)1 SeekPoint (androidx.media3.extractor.SeekPoint)1 MotionPhotoMetadata (androidx.media3.extractor.metadata.mp4.MotionPhotoMetadata)1 LeafAtom (androidx.media3.extractor.mp4.Atom.LeafAtom)1 DrmInitData (com.google.android.exoplayer2.drm.DrmInitData)1 ExtractorOutput (com.google.android.exoplayer2.extractor.ExtractorOutput)1