Search in sources :

Example 1 with Entry

use of androidx.media3.common.Metadata.Entry in project media by androidx.

the class ServerSideAdInsertionMediaSource method setAdPlaybackStates.

/**
 * Sets the map of {@link AdPlaybackState ad playback states} published by this source. The key is
 * the period UID of a period in the {@link
 * AdPlaybackStateUpdater#onAdPlaybackStateUpdateRequested(Timeline)} content timeline}.
 *
 * <p>Each period has an {@link AdPlaybackState} that tells where in the period the ad groups
 * start and end. Must only contain server-side inserted ad groups. The number of ad groups and
 * the number of ads within an ad group may only increase. The durations of ads may change and the
 * positions of future ad groups may change. Post-roll ad groups with {@link C#TIME_END_OF_SOURCE}
 * must be empty and can be used as a placeholder for a future ad group.
 *
 * <p>May be called from any thread.
 *
 * @param adPlaybackStates The map of {@link AdPlaybackState} keyed by their period UID.
 */
public void setAdPlaybackStates(ImmutableMap<Object, AdPlaybackState> adPlaybackStates) {
    checkArgument(!adPlaybackStates.isEmpty());
    Object adsId = checkNotNull(adPlaybackStates.values().asList().get(0).adsId);
    for (Map.Entry<Object, AdPlaybackState> entry : adPlaybackStates.entrySet()) {
        Object periodUid = entry.getKey();
        AdPlaybackState adPlaybackState = entry.getValue();
        checkArgument(Util.areEqual(adsId, adPlaybackState.adsId));
        @Nullable AdPlaybackState oldAdPlaybackState = this.adPlaybackStates.get(periodUid);
        if (oldAdPlaybackState != null) {
            for (int i = adPlaybackState.removedAdGroupCount; i < adPlaybackState.adGroupCount; i++) {
                AdPlaybackState.AdGroup adGroup = adPlaybackState.getAdGroup(i);
                checkArgument(adGroup.isServerSideInserted);
                if (i < oldAdPlaybackState.adGroupCount) {
                    checkArgument(getAdCountInGroup(adPlaybackState, /* adGroupIndex= */
                    i) >= getAdCountInGroup(oldAdPlaybackState, /* adGroupIndex= */
                    i));
                }
                if (adGroup.timeUs == C.TIME_END_OF_SOURCE) {
                    checkArgument(getAdCountInGroup(adPlaybackState, /* adGroupIndex= */
                    i) == 0);
                }
            }
        }
    }
    synchronized (this) {
        if (playbackHandler == null) {
            this.adPlaybackStates = adPlaybackStates;
        } else {
            playbackHandler.post(() -> {
                for (SharedMediaPeriod mediaPeriod : mediaPeriods.values()) {
                    @Nullable AdPlaybackState adPlaybackState = adPlaybackStates.get(mediaPeriod.periodUid);
                    if (adPlaybackState != null) {
                        mediaPeriod.updateAdPlaybackState(adPlaybackState);
                    }
                }
                if (lastUsedMediaPeriod != null) {
                    @Nullable AdPlaybackState adPlaybackState = adPlaybackStates.get(lastUsedMediaPeriod.periodUid);
                    if (adPlaybackState != null) {
                        lastUsedMediaPeriod.updateAdPlaybackState(adPlaybackState);
                    }
                }
                this.adPlaybackStates = adPlaybackStates;
                if (contentTimeline != null) {
                    refreshSourceInfo(new ServerSideAdInsertionTimeline(contentTimeline, adPlaybackStates));
                }
            });
        }
    }
}
Also used : AdPlaybackState(androidx.media3.common.AdPlaybackState) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap) HashMap(java.util.HashMap) Nullable(androidx.annotation.Nullable)

Example 2 with Entry

use of androidx.media3.common.Metadata.Entry in project media by androidx.

the class VbriSeeker method create.

/**
 * Returns a {@link VbriSeeker} for seeking in the stream, if required information is present.
 * Returns {@code null} if not. On returning, {@code frame}'s position is not specified so the
 * caller should reset it.
 *
 * @param inputLength The length of the stream in bytes, or {@link C#LENGTH_UNSET} if unknown.
 * @param position The position of the start of this frame in the stream.
 * @param mpegAudioHeader The MPEG audio header associated with the frame.
 * @param frame The data in this audio frame, with its position set to immediately after the
 *     'VBRI' tag.
 * @return A {@link VbriSeeker} for seeking in the stream, or {@code null} if the required
 *     information is not present.
 */
@Nullable
public static VbriSeeker create(long inputLength, long position, MpegAudioUtil.Header mpegAudioHeader, ParsableByteArray frame) {
    frame.skipBytes(10);
    int numFrames = frame.readInt();
    if (numFrames <= 0) {
        return null;
    }
    int sampleRate = mpegAudioHeader.sampleRate;
    long durationUs = Util.scaleLargeTimestamp(numFrames, C.MICROS_PER_SECOND * (sampleRate >= 32000 ? 1152 : 576), sampleRate);
    int entryCount = frame.readUnsignedShort();
    int scale = frame.readUnsignedShort();
    int entrySize = frame.readUnsignedShort();
    frame.skipBytes(2);
    long minPosition = position + mpegAudioHeader.frameSize;
    // Read table of contents entries.
    long[] timesUs = new long[entryCount];
    long[] positions = new long[entryCount];
    for (int index = 0; index < entryCount; index++) {
        timesUs[index] = (index * durationUs) / entryCount;
        // Ensure positions do not fall within the frame containing the VBRI header. This constraint
        // will normally only apply to the first entry in the table.
        positions[index] = max(position, minPosition);
        int segmentSize;
        switch(entrySize) {
            case 1:
                segmentSize = frame.readUnsignedByte();
                break;
            case 2:
                segmentSize = frame.readUnsignedShort();
                break;
            case 3:
                segmentSize = frame.readUnsignedInt24();
                break;
            case 4:
                segmentSize = frame.readUnsignedIntToInt();
                break;
            default:
                return null;
        }
        position += segmentSize * scale;
    }
    if (inputLength != C.LENGTH_UNSET && inputLength != position) {
        Log.w(TAG, "VBRI data size mismatch: " + inputLength + ", " + position);
    }
    return new VbriSeeker(timesUs, positions, durationUs, /* dataEndPosition= */
    position);
}
Also used : SeekPoint(androidx.media3.extractor.SeekPoint) Nullable(androidx.annotation.Nullable)

Example 3 with Entry

use of androidx.media3.common.Metadata.Entry in project media by androidx.

the class AtomParsers method parseMdtaFromMeta.

/**
 * Parses a metadata meta atom if it contains metadata with handler 'mdta'.
 *
 * @param meta The metadata atom to decode.
 * @return Parsed metadata, or null.
 */
@Nullable
public static Metadata parseMdtaFromMeta(Atom.ContainerAtom meta) {
    @Nullable Atom.LeafAtom hdlrAtom = meta.getLeafAtomOfType(Atom.TYPE_hdlr);
    @Nullable Atom.LeafAtom keysAtom = meta.getLeafAtomOfType(Atom.TYPE_keys);
    @Nullable Atom.LeafAtom ilstAtom = meta.getLeafAtomOfType(Atom.TYPE_ilst);
    if (hdlrAtom == null || keysAtom == null || ilstAtom == null || parseHdlr(hdlrAtom.data) != TYPE_mdta) {
        // There isn't enough information to parse the metadata, or the handler type is unexpected.
        return null;
    }
    // Parse metadata keys.
    ParsableByteArray keys = keysAtom.data;
    keys.setPosition(Atom.FULL_HEADER_SIZE);
    int entryCount = keys.readInt();
    String[] keyNames = new String[entryCount];
    for (int i = 0; i < entryCount; i++) {
        int entrySize = keys.readInt();
        // keyNamespace
        keys.skipBytes(4);
        int keySize = entrySize - 8;
        keyNames[i] = keys.readString(keySize);
    }
    // Parse metadata items.
    ParsableByteArray ilst = ilstAtom.data;
    ilst.setPosition(Atom.HEADER_SIZE);
    ArrayList<Metadata.Entry> entries = new ArrayList<>();
    while (ilst.bytesLeft() > Atom.HEADER_SIZE) {
        int atomPosition = ilst.getPosition();
        int atomSize = ilst.readInt();
        int keyIndex = ilst.readInt() - 1;
        if (keyIndex >= 0 && keyIndex < keyNames.length) {
            String key = keyNames[keyIndex];
            @Nullable Metadata.Entry entry = MetadataUtil.parseMdtaMetadataEntryFromIlst(ilst, atomPosition + atomSize, key);
            if (entry != null) {
                entries.add(entry);
            }
        } else {
            Log.w(TAG, "Skipped metadata with unknown key index: " + keyIndex);
        }
        ilst.setPosition(atomPosition + atomSize);
    }
    return entries.isEmpty() ? null : new Metadata(entries);
}
Also used : ParsableByteArray(androidx.media3.common.util.ParsableByteArray) SmtaMetadataEntry(androidx.media3.extractor.metadata.mp4.SmtaMetadataEntry) ArrayList(java.util.ArrayList) Metadata(androidx.media3.common.Metadata) Nullable(androidx.annotation.Nullable) Nullable(androidx.annotation.Nullable)

Example 4 with Entry

use of androidx.media3.common.Metadata.Entry in project media by androidx.

the class TextInformationFrameTest method populateMediaMetadata_setsBuilderValues.

@Test
public void populateMediaMetadata_setsBuilderValues() {
    String title = "the title";
    String artist = "artist";
    String albumTitle = "album title";
    String albumArtist = "album Artist";
    String trackNumberInfo = "11/17";
    String recordingYear = "2000";
    String recordingMonth = "07";
    String recordingDay = "10";
    String releaseDate = "2001-01-02T00:00:00";
    String composer = "composer";
    String conductor = "conductor";
    String writer = "writer";
    List<Metadata.Entry> entries = ImmutableList.of(new TextInformationFrame(/* id= */
    "TT2", /* description= */
    null, /* value= */
    title), new TextInformationFrame(/* id= */
    "TP1", /* description= */
    null, /* value= */
    artist), new TextInformationFrame(/* id= */
    "TAL", /* description= */
    null, /* value= */
    albumTitle), new TextInformationFrame(/* id= */
    "TP2", /* description= */
    null, /* value= */
    albumArtist), new TextInformationFrame(/* id= */
    "TRK", /* description= */
    null, /* value= */
    trackNumberInfo), new TextInformationFrame(/* id= */
    "TYE", /* description= */
    null, /* value= */
    recordingYear), new TextInformationFrame(/* id= */
    "TDA", /* description= */
    null, /* value= */
    recordingDay + recordingMonth), new TextInformationFrame(/* id= */
    "TDRL", /* description= */
    null, /* value= */
    releaseDate), new TextInformationFrame(/* id= */
    "TCM", /* description= */
    null, /* value= */
    composer), new TextInformationFrame(/* id= */
    "TP3", /* description= */
    null, /* value= */
    conductor), new TextInformationFrame(/* id= */
    "TXT", /* description= */
    null, /* value= */
    writer));
    MediaMetadata.Builder builder = MediaMetadata.EMPTY.buildUpon();
    for (Metadata.Entry entry : entries) {
        entry.populateMediaMetadata(builder);
    }
    MediaMetadata mediaMetadata = builder.build();
    assertThat(mediaMetadata.title.toString()).isEqualTo(title);
    assertThat(mediaMetadata.artist.toString()).isEqualTo(artist);
    assertThat(mediaMetadata.albumTitle.toString()).isEqualTo(albumTitle);
    assertThat(mediaMetadata.albumArtist.toString()).isEqualTo(albumArtist);
    assertThat(mediaMetadata.trackNumber).isEqualTo(11);
    assertThat(mediaMetadata.totalTrackCount).isEqualTo(17);
    assertThat(mediaMetadata.recordingYear).isEqualTo(2000);
    assertThat(mediaMetadata.recordingMonth).isEqualTo(7);
    assertThat(mediaMetadata.recordingDay).isEqualTo(10);
    assertThat(mediaMetadata.releaseYear).isEqualTo(2001);
    assertThat(mediaMetadata.releaseMonth).isEqualTo(1);
    assertThat(mediaMetadata.releaseDay).isEqualTo(2);
    assertThat(mediaMetadata.composer.toString()).isEqualTo(composer);
    assertThat(mediaMetadata.conductor.toString()).isEqualTo(conductor);
    assertThat(mediaMetadata.writer.toString()).isEqualTo(writer);
}
Also used : MediaMetadata(androidx.media3.common.MediaMetadata) Metadata(androidx.media3.common.Metadata) MediaMetadata(androidx.media3.common.MediaMetadata) Test(org.junit.Test)

Example 5 with Entry

use of androidx.media3.common.Metadata.Entry in project media by androidx.

the class VorbisCommentTest method populateMediaMetadata_setsMediaMetadataValues.

@Test
public void populateMediaMetadata_setsMediaMetadataValues() {
    String title = "the title";
    String artist = "artist";
    String albumTitle = "album title";
    String albumArtist = "album Artist";
    String description = "a description about the audio.";
    List<Metadata.Entry> entries = ImmutableList.of(new VorbisComment("TITLE", title), new VorbisComment("ARTIST", artist), new VorbisComment("ALBUM", albumTitle), new VorbisComment("ALBUMARTIST", albumArtist), new VorbisComment("DESCRIPTION", description));
    MediaMetadata.Builder builder = MediaMetadata.EMPTY.buildUpon();
    for (Metadata.Entry entry : entries) {
        entry.populateMediaMetadata(builder);
    }
    MediaMetadata mediaMetadata = builder.build();
    assertThat(mediaMetadata.title.toString()).isEqualTo(title);
    assertThat(mediaMetadata.artist.toString()).isEqualTo(artist);
    assertThat(mediaMetadata.albumTitle.toString()).isEqualTo(albumTitle);
    assertThat(mediaMetadata.albumArtist.toString()).isEqualTo(albumArtist);
    assertThat(mediaMetadata.description.toString()).isEqualTo(description);
}
Also used : MediaMetadata(androidx.media3.common.MediaMetadata) Metadata(androidx.media3.common.Metadata) MediaMetadata(androidx.media3.common.MediaMetadata) Test(org.junit.Test)

Aggregations

Metadata (androidx.media3.common.Metadata)11 Nullable (androidx.annotation.Nullable)10 ArrayList (java.util.ArrayList)7 MediaMetadata (androidx.media3.common.MediaMetadata)4 Test (org.junit.Test)4 ParsableByteArray (androidx.media3.common.util.ParsableByteArray)3 SmtaMetadataEntry (androidx.media3.extractor.metadata.mp4.SmtaMetadataEntry)3 Format (androidx.media3.common.Format)2 TrackGroup (androidx.media3.common.TrackGroup)2 SlowMotionData (androidx.media3.extractor.metadata.mp4.SlowMotionData)2 HashMap (java.util.HashMap)2 Map (java.util.Map)2 Bitmap (android.graphics.Bitmap)1 Uri (android.net.Uri)1 SpannableStringBuilder (android.text.SpannableStringBuilder)1 Pair (android.util.Pair)1 AdPlaybackState (androidx.media3.common.AdPlaybackState)1 SchemeData (androidx.media3.common.DrmInitData.SchemeData)1 Entry (androidx.media3.common.Metadata.Entry)1 TrackGroupArray (androidx.media3.common.TrackGroupArray)1