Search in sources :

Example 1 with Metadata

use of com.google.android.exoplayer2.metadata.Metadata in project react-native-video by react-native-community.

the class VideoEventEmitter method timedMetadata.

void timedMetadata(Metadata metadata) {
    WritableArray metadataArray = Arguments.createArray();
    for (int i = 0; i < metadata.length(); i++) {
        Id3Frame frame = (Id3Frame) metadata.get(i);
        String value = "";
        if (frame instanceof TxxxFrame) {
            TxxxFrame txxxFrame = (TxxxFrame) frame;
            value = txxxFrame.value;
        }
        String identifier = frame.id;
        WritableMap map = Arguments.createMap();
        map.putString("identifier", identifier);
        map.putString("value", value);
        metadataArray.pushMap(map);
    }
    WritableMap event = Arguments.createMap();
    event.putArray(EVENT_PROP_TIMED_METADATA, metadataArray);
    receiveEvent(EVENT_TIMED_METADATA, event);
}
Also used : WritableMap(com.facebook.react.bridge.WritableMap) WritableArray(com.facebook.react.bridge.WritableArray) TxxxFrame(com.google.android.exoplayer2.metadata.id3.TxxxFrame) Id3Frame(com.google.android.exoplayer2.metadata.id3.Id3Frame)

Example 2 with Metadata

use of com.google.android.exoplayer2.metadata.Metadata in project ExoPlayer by google.

the class AtomParsers method parseStbl.

/**
   * Parses an stbl atom (defined in 14496-12).
   *
   * @param track Track to which this sample table corresponds.
   * @param stblAtom stbl (sample table) atom to decode.
   * @param gaplessInfoHolder Holder to populate with gapless playback information.
   * @return Sample table described by the stbl atom.
   * @throws ParserException If the resulting sample sequence does not contain a sync sample.
   */
public static TrackSampleTable parseStbl(Track track, Atom.ContainerAtom stblAtom, GaplessInfoHolder gaplessInfoHolder) throws ParserException {
    SampleSizeBox sampleSizeBox;
    Atom.LeafAtom stszAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_stsz);
    if (stszAtom != null) {
        sampleSizeBox = new StszSampleSizeBox(stszAtom);
    } else {
        Atom.LeafAtom stz2Atom = stblAtom.getLeafAtomOfType(Atom.TYPE_stz2);
        if (stz2Atom == null) {
            throw new ParserException("Track has no sample table size information");
        }
        sampleSizeBox = new Stz2SampleSizeBox(stz2Atom);
    }
    int sampleCount = sampleSizeBox.getSampleCount();
    if (sampleCount == 0) {
        return new TrackSampleTable(new long[0], new int[0], 0, new long[0], new int[0]);
    }
    // Entries are byte offsets of chunks.
    boolean chunkOffsetsAreLongs = false;
    Atom.LeafAtom chunkOffsetsAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_stco);
    if (chunkOffsetsAtom == null) {
        chunkOffsetsAreLongs = true;
        chunkOffsetsAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_co64);
    }
    ParsableByteArray chunkOffsets = chunkOffsetsAtom.data;
    // Entries are (chunk number, number of samples per chunk, sample description index).
    ParsableByteArray stsc = stblAtom.getLeafAtomOfType(Atom.TYPE_stsc).data;
    // Entries are (number of samples, timestamp delta between those samples).
    ParsableByteArray stts = stblAtom.getLeafAtomOfType(Atom.TYPE_stts).data;
    // Entries are the indices of samples that are synchronization samples.
    Atom.LeafAtom stssAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_stss);
    ParsableByteArray stss = stssAtom != null ? stssAtom.data : null;
    // Entries are (number of samples, timestamp offset).
    Atom.LeafAtom cttsAtom = stblAtom.getLeafAtomOfType(Atom.TYPE_ctts);
    ParsableByteArray ctts = cttsAtom != null ? cttsAtom.data : null;
    // Prepare to read chunk information.
    ChunkIterator chunkIterator = new ChunkIterator(stsc, chunkOffsets, chunkOffsetsAreLongs);
    // Prepare to read sample timestamps.
    stts.setPosition(Atom.FULL_HEADER_SIZE);
    int remainingTimestampDeltaChanges = stts.readUnsignedIntToInt() - 1;
    int remainingSamplesAtTimestampDelta = stts.readUnsignedIntToInt();
    int timestampDeltaInTimeUnits = stts.readUnsignedIntToInt();
    // Prepare to read sample timestamp offsets, if ctts is present.
    int remainingSamplesAtTimestampOffset = 0;
    int remainingTimestampOffsetChanges = 0;
    int timestampOffset = 0;
    if (ctts != null) {
        ctts.setPosition(Atom.FULL_HEADER_SIZE);
        remainingTimestampOffsetChanges = ctts.readUnsignedIntToInt();
    }
    int nextSynchronizationSampleIndex = C.INDEX_UNSET;
    int remainingSynchronizationSamples = 0;
    if (stss != null) {
        stss.setPosition(Atom.FULL_HEADER_SIZE);
        remainingSynchronizationSamples = stss.readUnsignedIntToInt();
        if (remainingSynchronizationSamples > 0) {
            nextSynchronizationSampleIndex = stss.readUnsignedIntToInt() - 1;
        } else {
            // Ignore empty stss boxes, which causes all samples to be treated as sync samples.
            stss = null;
        }
    }
    // True if we can rechunk fixed-sample-size data. Note that we only rechunk raw audio.
    boolean isRechunkable = sampleSizeBox.isFixedSampleSize() && MimeTypes.AUDIO_RAW.equals(track.format.sampleMimeType) && remainingTimestampDeltaChanges == 0 && remainingTimestampOffsetChanges == 0 && remainingSynchronizationSamples == 0;
    long[] offsets;
    int[] sizes;
    int maximumSize = 0;
    long[] timestamps;
    int[] flags;
    long timestampTimeUnits = 0;
    if (!isRechunkable) {
        offsets = new long[sampleCount];
        sizes = new int[sampleCount];
        timestamps = new long[sampleCount];
        flags = new int[sampleCount];
        long offset = 0;
        int remainingSamplesInChunk = 0;
        for (int i = 0; i < sampleCount; i++) {
            // Advance to the next chunk if necessary.
            while (remainingSamplesInChunk == 0) {
                Assertions.checkState(chunkIterator.moveNext());
                offset = chunkIterator.offset;
                remainingSamplesInChunk = chunkIterator.numSamples;
            }
            // Add on the timestamp offset if ctts is present.
            if (ctts != null) {
                while (remainingSamplesAtTimestampOffset == 0 && remainingTimestampOffsetChanges > 0) {
                    remainingSamplesAtTimestampOffset = ctts.readUnsignedIntToInt();
                    // The BMFF spec (ISO 14496-12) states that sample offsets should be unsigned integers
                    // in version 0 ctts boxes, however some streams violate the spec and use signed
                    // integers instead. It's safe to always decode sample offsets as signed integers here,
                    // because unsigned integers will still be parsed correctly (unless their top bit is
                    // set, which is never true in practice because sample offsets are always small).
                    timestampOffset = ctts.readInt();
                    remainingTimestampOffsetChanges--;
                }
                remainingSamplesAtTimestampOffset--;
            }
            offsets[i] = offset;
            sizes[i] = sampleSizeBox.readNextSampleSize();
            if (sizes[i] > maximumSize) {
                maximumSize = sizes[i];
            }
            timestamps[i] = timestampTimeUnits + timestampOffset;
            // All samples are synchronization samples if the stss is not present.
            flags[i] = stss == null ? C.BUFFER_FLAG_KEY_FRAME : 0;
            if (i == nextSynchronizationSampleIndex) {
                flags[i] = C.BUFFER_FLAG_KEY_FRAME;
                remainingSynchronizationSamples--;
                if (remainingSynchronizationSamples > 0) {
                    nextSynchronizationSampleIndex = stss.readUnsignedIntToInt() - 1;
                }
            }
            // Add on the duration of this sample.
            timestampTimeUnits += timestampDeltaInTimeUnits;
            remainingSamplesAtTimestampDelta--;
            if (remainingSamplesAtTimestampDelta == 0 && remainingTimestampDeltaChanges > 0) {
                remainingSamplesAtTimestampDelta = stts.readUnsignedIntToInt();
                timestampDeltaInTimeUnits = stts.readUnsignedIntToInt();
                remainingTimestampDeltaChanges--;
            }
            offset += sizes[i];
            remainingSamplesInChunk--;
        }
        Assertions.checkArgument(remainingSamplesAtTimestampOffset == 0);
        // Remove trailing ctts entries with 0-valued sample counts.
        while (remainingTimestampOffsetChanges > 0) {
            Assertions.checkArgument(ctts.readUnsignedIntToInt() == 0);
            // Ignore offset.
            ctts.readInt();
            remainingTimestampOffsetChanges--;
        }
        // still be playable.
        if (remainingSynchronizationSamples != 0 || remainingSamplesAtTimestampDelta != 0 || remainingSamplesInChunk != 0 || remainingTimestampDeltaChanges != 0) {
            Log.w(TAG, "Inconsistent stbl box for track " + track.id + ": remainingSynchronizationSamples " + remainingSynchronizationSamples + ", remainingSamplesAtTimestampDelta " + remainingSamplesAtTimestampDelta + ", remainingSamplesInChunk " + remainingSamplesInChunk + ", remainingTimestampDeltaChanges " + remainingTimestampDeltaChanges);
        }
    } else {
        long[] chunkOffsetsBytes = new long[chunkIterator.length];
        int[] chunkSampleCounts = new int[chunkIterator.length];
        while (chunkIterator.moveNext()) {
            chunkOffsetsBytes[chunkIterator.index] = chunkIterator.offset;
            chunkSampleCounts[chunkIterator.index] = chunkIterator.numSamples;
        }
        int fixedSampleSize = sampleSizeBox.readNextSampleSize();
        FixedSampleSizeRechunker.Results rechunkedResults = FixedSampleSizeRechunker.rechunk(fixedSampleSize, chunkOffsetsBytes, chunkSampleCounts, timestampDeltaInTimeUnits);
        offsets = rechunkedResults.offsets;
        sizes = rechunkedResults.sizes;
        maximumSize = rechunkedResults.maximumSize;
        timestamps = rechunkedResults.timestamps;
        flags = rechunkedResults.flags;
    }
    if (track.editListDurations == null || gaplessInfoHolder.hasGaplessInfo()) {
        // There is no edit list, or we are ignoring it as we already have gapless metadata to apply.
        // This implementation does not support applying both gapless metadata and an edit list.
        Util.scaleLargeTimestampsInPlace(timestamps, C.MICROS_PER_SECOND, track.timescale);
        return new TrackSampleTable(offsets, sizes, maximumSize, timestamps, flags);
    }
    if (track.editListDurations.length == 1 && track.type == C.TRACK_TYPE_AUDIO && timestamps.length >= 2) {
        // Handle the edit by setting gapless playback metadata, if possible. This implementation
        // assumes that only one "roll" sample is needed, which is the case for AAC, so the start/end
        // points of the edit must lie within the first/last samples respectively.
        long editStartTime = track.editListMediaTimes[0];
        long editEndTime = editStartTime + Util.scaleLargeTimestamp(track.editListDurations[0], track.timescale, track.movieTimescale);
        long lastSampleEndTime = timestampTimeUnits;
        if (timestamps[0] <= editStartTime && editStartTime < timestamps[1] && timestamps[timestamps.length - 1] < editEndTime && editEndTime <= lastSampleEndTime) {
            long paddingTimeUnits = lastSampleEndTime - editEndTime;
            long encoderDelay = Util.scaleLargeTimestamp(editStartTime - timestamps[0], track.format.sampleRate, track.timescale);
            long encoderPadding = Util.scaleLargeTimestamp(paddingTimeUnits, track.format.sampleRate, track.timescale);
            if ((encoderDelay != 0 || encoderPadding != 0) && encoderDelay <= Integer.MAX_VALUE && encoderPadding <= Integer.MAX_VALUE) {
                gaplessInfoHolder.encoderDelay = (int) encoderDelay;
                gaplessInfoHolder.encoderPadding = (int) encoderPadding;
                Util.scaleLargeTimestampsInPlace(timestamps, C.MICROS_PER_SECOND, track.timescale);
                return new TrackSampleTable(offsets, sizes, maximumSize, timestamps, flags);
            }
        }
    }
    if (track.editListDurations.length == 1 && track.editListDurations[0] == 0) {
        // samples in the edit.
        for (int i = 0; i < timestamps.length; i++) {
            timestamps[i] = Util.scaleLargeTimestamp(timestamps[i] - track.editListMediaTimes[0], C.MICROS_PER_SECOND, track.timescale);
        }
        return new TrackSampleTable(offsets, sizes, maximumSize, timestamps, flags);
    }
    // Omit any sample at the end point of an edit for audio tracks.
    boolean omitClippedSample = track.type == C.TRACK_TYPE_AUDIO;
    // Count the number of samples after applying edits.
    int editedSampleCount = 0;
    int nextSampleIndex = 0;
    boolean copyMetadata = false;
    for (int i = 0; i < track.editListDurations.length; i++) {
        long mediaTime = track.editListMediaTimes[i];
        if (mediaTime != -1) {
            long duration = Util.scaleLargeTimestamp(track.editListDurations[i], track.timescale, track.movieTimescale);
            int startIndex = Util.binarySearchCeil(timestamps, mediaTime, true, true);
            int endIndex = Util.binarySearchCeil(timestamps, mediaTime + duration, omitClippedSample, false);
            editedSampleCount += endIndex - startIndex;
            copyMetadata |= nextSampleIndex != startIndex;
            nextSampleIndex = endIndex;
        }
    }
    copyMetadata |= editedSampleCount != sampleCount;
    // Calculate edited sample timestamps and update the corresponding metadata arrays.
    long[] editedOffsets = copyMetadata ? new long[editedSampleCount] : offsets;
    int[] editedSizes = copyMetadata ? new int[editedSampleCount] : sizes;
    int editedMaximumSize = copyMetadata ? 0 : maximumSize;
    int[] editedFlags = copyMetadata ? new int[editedSampleCount] : flags;
    long[] editedTimestamps = new long[editedSampleCount];
    long pts = 0;
    int sampleIndex = 0;
    for (int i = 0; i < track.editListDurations.length; i++) {
        long mediaTime = track.editListMediaTimes[i];
        long duration = track.editListDurations[i];
        if (mediaTime != -1) {
            long endMediaTime = mediaTime + Util.scaleLargeTimestamp(duration, track.timescale, track.movieTimescale);
            int startIndex = Util.binarySearchCeil(timestamps, mediaTime, true, true);
            int endIndex = Util.binarySearchCeil(timestamps, endMediaTime, omitClippedSample, false);
            if (copyMetadata) {
                int count = endIndex - startIndex;
                System.arraycopy(offsets, startIndex, editedOffsets, sampleIndex, count);
                System.arraycopy(sizes, startIndex, editedSizes, sampleIndex, count);
                System.arraycopy(flags, startIndex, editedFlags, sampleIndex, count);
            }
            for (int j = startIndex; j < endIndex; j++) {
                long ptsUs = Util.scaleLargeTimestamp(pts, C.MICROS_PER_SECOND, track.movieTimescale);
                long timeInSegmentUs = Util.scaleLargeTimestamp(timestamps[j] - mediaTime, C.MICROS_PER_SECOND, track.timescale);
                editedTimestamps[sampleIndex] = ptsUs + timeInSegmentUs;
                if (copyMetadata && editedSizes[sampleIndex] > editedMaximumSize) {
                    editedMaximumSize = sizes[j];
                }
                sampleIndex++;
            }
        }
        pts += duration;
    }
    boolean hasSyncSample = false;
    for (int i = 0; i < editedFlags.length && !hasSyncSample; i++) {
        hasSyncSample |= (editedFlags[i] & C.BUFFER_FLAG_KEY_FRAME) != 0;
    }
    if (!hasSyncSample) {
        throw new ParserException("The edited sample sequence does not contain a sync sample.");
    }
    return new TrackSampleTable(editedOffsets, editedSizes, editedMaximumSize, editedTimestamps, editedFlags);
}
Also used : ParserException(com.google.android.exoplayer2.ParserException) ParsableByteArray(com.google.android.exoplayer2.util.ParsableByteArray)

Example 3 with Metadata

use of com.google.android.exoplayer2.metadata.Metadata in project ExoPlayer by google.

the class SpliceInfoDecoder method decode.

@Override
public Metadata decode(MetadataInputBuffer inputBuffer) throws MetadataDecoderException {
    // Internal timestamps adjustment.
    if (timestampAdjuster == null || inputBuffer.subsampleOffsetUs != timestampAdjuster.getTimestampOffsetUs()) {
        timestampAdjuster = new TimestampAdjuster(inputBuffer.timeUs);
        timestampAdjuster.adjustSampleTimestamp(inputBuffer.timeUs - inputBuffer.subsampleOffsetUs);
    }
    ByteBuffer buffer = inputBuffer.data;
    byte[] data = buffer.array();
    int size = buffer.limit();
    sectionData.reset(data, size);
    sectionHeader.reset(data, size);
    // table_id(8), section_syntax_indicator(1), private_indicator(1), reserved(2),
    // section_length(12), protocol_version(8), encrypted_packet(1), encryption_algorithm(6).
    sectionHeader.skipBits(39);
    long ptsAdjustment = sectionHeader.readBits(1);
    ptsAdjustment = (ptsAdjustment << 32) | sectionHeader.readBits(32);
    // cw_index(8), tier(12).
    sectionHeader.skipBits(20);
    int spliceCommandLength = sectionHeader.readBits(12);
    int spliceCommandType = sectionHeader.readBits(8);
    SpliceCommand command = null;
    // Go to the start of the command by skipping all fields up to command_type.
    sectionData.skipBytes(14);
    switch(spliceCommandType) {
        case TYPE_SPLICE_NULL:
            command = new SpliceNullCommand();
            break;
        case TYPE_SPLICE_SCHEDULE:
            command = SpliceScheduleCommand.parseFromSection(sectionData);
            break;
        case TYPE_SPLICE_INSERT:
            command = SpliceInsertCommand.parseFromSection(sectionData, ptsAdjustment, timestampAdjuster);
            break;
        case TYPE_TIME_SIGNAL:
            command = TimeSignalCommand.parseFromSection(sectionData, ptsAdjustment, timestampAdjuster);
            break;
        case TYPE_PRIVATE_COMMAND:
            command = PrivateCommand.parseFromSection(sectionData, spliceCommandLength, ptsAdjustment);
            break;
        default:
            // Do nothing.
            break;
    }
    return command == null ? new Metadata() : new Metadata(command);
}
Also used : Metadata(com.google.android.exoplayer2.metadata.Metadata) TimestampAdjuster(com.google.android.exoplayer2.util.TimestampAdjuster) ByteBuffer(java.nio.ByteBuffer)

Example 4 with Metadata

use of com.google.android.exoplayer2.metadata.Metadata 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 {
    long durationUs = C.TIME_UNSET;
    List<Mp4Track> tracks = new ArrayList<>();
    long earliestSampleOffset = Long.MAX_VALUE;
    Metadata metadata = null;
    GaplessInfoHolder gaplessInfoHolder = new GaplessInfoHolder();
    Atom.LeafAtom udta = moov.getLeafAtomOfType(Atom.TYPE_udta);
    if (udta != null) {
        metadata = AtomParsers.parseUdta(udta, isQuickTime);
        if (metadata != null) {
            gaplessInfoHolder.setFromMetadata(metadata);
        }
    }
    for (int i = 0; i < moov.containerChildren.size(); i++) {
        Atom.ContainerAtom atom = moov.containerChildren.get(i);
        if (atom.type != Atom.TYPE_trak) {
            continue;
        }
        Track track = AtomParsers.parseTrak(atom, moov.getLeafAtomOfType(Atom.TYPE_mvhd), C.TIME_UNSET, null, isQuickTime);
        if (track == null) {
            continue;
        }
        Atom.ContainerAtom stblAtom = atom.getContainerAtomOfType(Atom.TYPE_mdia).getContainerAtomOfType(Atom.TYPE_minf).getContainerAtomOfType(Atom.TYPE_stbl);
        TrackSampleTable trackSampleTable = AtomParsers.parseStbl(track, stblAtom, gaplessInfoHolder);
        if (trackSampleTable.sampleCount == 0) {
            continue;
        }
        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_AUDIO) {
            if (gaplessInfoHolder.hasGaplessInfo()) {
                format = format.copyWithGaplessInfo(gaplessInfoHolder.encoderDelay, gaplessInfoHolder.encoderPadding);
            }
            if (metadata != null) {
                format = format.copyWithMetadata(metadata);
            }
        }
        mp4Track.trackOutput.format(format);
        durationUs = Math.max(durationUs, track.durationUs);
        tracks.add(mp4Track);
        long firstSampleOffset = trackSampleTable.offsets[0];
        if (firstSampleOffset < earliestSampleOffset) {
            earliestSampleOffset = firstSampleOffset;
        }
    }
    this.durationUs = durationUs;
    this.tracks = tracks.toArray(new Mp4Track[tracks.size()]);
    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) 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 Metadata

use of com.google.android.exoplayer2.metadata.Metadata in project ExoPlayer by google.

the class EventMessageDecoderTest method testDecodeEventMessage.

public void testDecodeEventMessage() {
    byte[] rawEmsgBody = new byte[] { // scheme_id_uri = "urn:test"
    117, // scheme_id_uri = "urn:test"
    114, // scheme_id_uri = "urn:test"
    110, // scheme_id_uri = "urn:test"
    58, // scheme_id_uri = "urn:test"
    116, // scheme_id_uri = "urn:test"
    101, // scheme_id_uri = "urn:test"
    115, // scheme_id_uri = "urn:test"
    116, // scheme_id_uri = "urn:test"
    0, // value = "123"
    49, // value = "123"
    50, // value = "123"
    51, // value = "123"
    0, // timescale = 48000
    0, // timescale = 48000
    0, // timescale = 48000
    -69, // timescale = 48000
    -128, // presentation_time_delta (ignored) = 0
    0, // presentation_time_delta (ignored) = 0
    0, // presentation_time_delta (ignored) = 0
    0, // presentation_time_delta (ignored) = 0
    0, // event_duration = 144000
    0, // event_duration = 144000
    2, // event_duration = 144000
    50, // event_duration = 144000
    -128, // id = 1000403
    0, // id = 1000403
    15, // id = 1000403
    67, // id = 1000403
    -45, 0, 1, 2, 3, // message_data = {0, 1, 2, 3, 4}
    4 };
    EventMessageDecoder decoder = new EventMessageDecoder();
    MetadataInputBuffer buffer = new MetadataInputBuffer();
    buffer.data = ByteBuffer.allocate(rawEmsgBody.length).put(rawEmsgBody);
    Metadata metadata = decoder.decode(buffer);
    assertEquals(1, metadata.length());
    EventMessage eventMessage = (EventMessage) metadata.get(0);
    assertEquals("urn:test", eventMessage.schemeIdUri);
    assertEquals("123", eventMessage.value);
    assertEquals(3000, eventMessage.durationMs);
    assertEquals(1000403, eventMessage.id);
    MoreAsserts.assertEquals(new byte[] { 0, 1, 2, 3, 4 }, eventMessage.messageData);
}
Also used : MetadataInputBuffer(com.google.android.exoplayer2.metadata.MetadataInputBuffer) Metadata(com.google.android.exoplayer2.metadata.Metadata)

Aggregations

Metadata (com.google.android.exoplayer2.metadata.Metadata)18 Metadata (org.hisp.dhis.dxf2.metadata.Metadata)10 ParsableByteArray (com.google.android.exoplayer2.util.ParsableByteArray)6 IOException (java.io.IOException)5 Format (com.google.android.exoplayer2.Format)3 ArrayList (java.util.ArrayList)3 MediaFormat (android.media.MediaFormat)2 DrmInitData (com.google.android.exoplayer2.drm.DrmInitData)2 ApicFrame (com.google.android.exoplayer2.metadata.id3.ApicFrame)2 Id3Frame (com.google.android.exoplayer2.metadata.id3.Id3Frame)2 PrivFrame (com.google.android.exoplayer2.metadata.id3.PrivFrame)2 TextInformationFrame (com.google.android.exoplayer2.metadata.id3.TextInformationFrame)2 TrackGroup (com.google.android.exoplayer2.source.TrackGroup)2 TrackGroupArray (com.google.android.exoplayer2.source.TrackGroupArray)2 TrackSelection (com.google.android.exoplayer2.trackselection.TrackSelection)2 FlacStreamInfo (com.google.android.exoplayer2.util.FlacStreamInfo)2 ByteArrayInputStream (java.io.ByteArrayInputStream)2 InputStream (java.io.InputStream)2 ByteBuffer (java.nio.ByteBuffer)2 MetadataImportParams (org.hisp.dhis.dxf2.metadata.MetadataImportParams)2