Search in sources :

Example 41 with Segment

use of com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment in project ExoPlayer by google.

the class HlsMediaPeriod method buildAndPrepareMainSampleStreamWrapper.

/**
 * This method creates and starts preparation of the main {@link HlsSampleStreamWrapper}.
 *
 * <p>The main sample stream wrapper is the first element of {@link #sampleStreamWrappers}. It
 * provides {@link SampleStream}s for the variant urls in the multivariant playlist. It may be
 * adaptive and may contain multiple muxed tracks.
 *
 * <p>If chunkless preparation is allowed, the media period will try preparation without segment
 * downloads. This is only possible if variants contain the CODECS attribute. If not, traditional
 * preparation with segment downloads will take place. The following points apply to chunkless
 * preparation:
 *
 * <ul>
 *   <li>A muxed audio track will be exposed if the codecs list contain an audio entry and the
 *       multivariant playlist either contains an EXT-X-MEDIA tag without the URI attribute or
 *       does not contain any EXT-X-MEDIA tag.
 *   <li>Closed captions will only be exposed if they are declared by the multivariant playlist.
 *   <li>An ID3 track is exposed preemptively, in case the segments contain an ID3 track.
 * </ul>
 *
 * @param multivariantPlaylist The HLS multivariant playlist.
 * @param positionUs If preparation requires any chunk downloads, the position in microseconds at
 *     which downloading should start. Ignored otherwise.
 * @param sampleStreamWrappers List to which the built main sample stream wrapper should be added.
 * @param manifestUrlIndicesPerWrapper List to which the selected variant indices should be added.
 * @param overridingDrmInitData Overriding {@link DrmInitData}, keyed by protection scheme type
 *     (i.e. {@link DrmInitData#schemeType}).
 */
private void buildAndPrepareMainSampleStreamWrapper(HlsMultivariantPlaylist multivariantPlaylist, long positionUs, List<HlsSampleStreamWrapper> sampleStreamWrappers, List<int[]> manifestUrlIndicesPerWrapper, Map<String, DrmInitData> overridingDrmInitData) {
    int[] variantTypes = new int[multivariantPlaylist.variants.size()];
    int videoVariantCount = 0;
    int audioVariantCount = 0;
    for (int i = 0; i < multivariantPlaylist.variants.size(); i++) {
        Variant variant = multivariantPlaylist.variants.get(i);
        Format format = variant.format;
        if (format.height > 0 || Util.getCodecsOfType(format.codecs, C.TRACK_TYPE_VIDEO) != null) {
            variantTypes[i] = C.TRACK_TYPE_VIDEO;
            videoVariantCount++;
        } else if (Util.getCodecsOfType(format.codecs, C.TRACK_TYPE_AUDIO) != null) {
            variantTypes[i] = C.TRACK_TYPE_AUDIO;
            audioVariantCount++;
        } else {
            variantTypes[i] = C.TRACK_TYPE_UNKNOWN;
        }
    }
    boolean useVideoVariantsOnly = false;
    boolean useNonAudioVariantsOnly = false;
    int selectedVariantsCount = variantTypes.length;
    if (videoVariantCount > 0) {
        // We've identified some variants as definitely containing video. Assume variants within the
        // multivariant playlist are marked consistently, and hence that we have the full set. Filter
        // out any other variants, which are likely to be audio only.
        useVideoVariantsOnly = true;
        selectedVariantsCount = videoVariantCount;
    } else if (audioVariantCount < variantTypes.length) {
        // We've identified some variants, but not all, as being audio only. Filter them out to leave
        // the remaining variants, which are likely to contain video.
        useNonAudioVariantsOnly = true;
        selectedVariantsCount = variantTypes.length - audioVariantCount;
    }
    Uri[] selectedPlaylistUrls = new Uri[selectedVariantsCount];
    Format[] selectedPlaylistFormats = new Format[selectedVariantsCount];
    int[] selectedVariantIndices = new int[selectedVariantsCount];
    int outIndex = 0;
    for (int i = 0; i < multivariantPlaylist.variants.size(); i++) {
        if ((!useVideoVariantsOnly || variantTypes[i] == C.TRACK_TYPE_VIDEO) && (!useNonAudioVariantsOnly || variantTypes[i] != C.TRACK_TYPE_AUDIO)) {
            Variant variant = multivariantPlaylist.variants.get(i);
            selectedPlaylistUrls[outIndex] = variant.url;
            selectedPlaylistFormats[outIndex] = variant.format;
            selectedVariantIndices[outIndex++] = i;
        }
    }
    String codecs = selectedPlaylistFormats[0].codecs;
    int numberOfVideoCodecs = Util.getCodecCountOfType(codecs, C.TRACK_TYPE_VIDEO);
    int numberOfAudioCodecs = Util.getCodecCountOfType(codecs, C.TRACK_TYPE_AUDIO);
    boolean codecsStringAllowsChunklessPreparation = numberOfAudioCodecs <= 1 && numberOfVideoCodecs <= 1 && numberOfAudioCodecs + numberOfVideoCodecs > 0;
    @C.TrackType int trackType = !useVideoVariantsOnly && numberOfAudioCodecs > 0 ? C.TRACK_TYPE_AUDIO : C.TRACK_TYPE_DEFAULT;
    String sampleStreamWrapperUid = "main";
    HlsSampleStreamWrapper sampleStreamWrapper = buildSampleStreamWrapper(sampleStreamWrapperUid, trackType, selectedPlaylistUrls, selectedPlaylistFormats, multivariantPlaylist.muxedAudioFormat, multivariantPlaylist.muxedCaptionFormats, overridingDrmInitData, positionUs);
    sampleStreamWrappers.add(sampleStreamWrapper);
    manifestUrlIndicesPerWrapper.add(selectedVariantIndices);
    if (allowChunklessPreparation && codecsStringAllowsChunklessPreparation) {
        List<TrackGroup> muxedTrackGroups = new ArrayList<>();
        if (numberOfVideoCodecs > 0) {
            Format[] videoFormats = new Format[selectedVariantsCount];
            for (int i = 0; i < videoFormats.length; i++) {
                videoFormats[i] = deriveVideoFormat(selectedPlaylistFormats[i]);
            }
            muxedTrackGroups.add(new TrackGroup(sampleStreamWrapperUid, videoFormats));
            if (numberOfAudioCodecs > 0 && (multivariantPlaylist.muxedAudioFormat != null || multivariantPlaylist.audios.isEmpty())) {
                muxedTrackGroups.add(new TrackGroup(/* id= */
                sampleStreamWrapperUid + ":audio", deriveAudioFormat(selectedPlaylistFormats[0], multivariantPlaylist.muxedAudioFormat, /* isPrimaryTrackInVariant= */
                false)));
            }
            List<Format> ccFormats = multivariantPlaylist.muxedCaptionFormats;
            if (ccFormats != null) {
                for (int i = 0; i < ccFormats.size(); i++) {
                    String ccId = sampleStreamWrapperUid + ":cc:" + i;
                    muxedTrackGroups.add(new TrackGroup(ccId, ccFormats.get(i)));
                }
            }
        } else /* numberOfAudioCodecs > 0 */
        {
            // Variants only contain audio.
            Format[] audioFormats = new Format[selectedVariantsCount];
            for (int i = 0; i < audioFormats.length; i++) {
                audioFormats[i] = deriveAudioFormat(/* variantFormat= */
                selectedPlaylistFormats[i], multivariantPlaylist.muxedAudioFormat, /* isPrimaryTrackInVariant= */
                true);
            }
            muxedTrackGroups.add(new TrackGroup(sampleStreamWrapperUid, audioFormats));
        }
        TrackGroup id3TrackGroup = new TrackGroup(/* id= */
        sampleStreamWrapperUid + ":id3", new Format.Builder().setId("ID3").setSampleMimeType(MimeTypes.APPLICATION_ID3).build());
        muxedTrackGroups.add(id3TrackGroup);
        sampleStreamWrapper.prepareWithMultivariantPlaylistInfo(muxedTrackGroups.toArray(new TrackGroup[0]), /* primaryTrackGroupIndex= */
        0, /* optionalTrackGroupsIndices...= */
        muxedTrackGroups.indexOf(id3TrackGroup));
    }
}
Also used : ArrayList(java.util.ArrayList) Uri(android.net.Uri) Variant(com.google.android.exoplayer2.source.hls.playlist.HlsMultivariantPlaylist.Variant) Format(com.google.android.exoplayer2.Format) TrackGroup(com.google.android.exoplayer2.source.TrackGroup)

Example 42 with Segment

use of com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment in project ExoPlayer by google.

the class DefaultHlsPlaylistTracker method getLoadedPlaylistStartTimeUs.

private long getLoadedPlaylistStartTimeUs(@Nullable HlsMediaPlaylist oldPlaylist, HlsMediaPlaylist loadedPlaylist) {
    if (loadedPlaylist.hasProgramDateTime) {
        return loadedPlaylist.startTimeUs;
    }
    long primarySnapshotStartTimeUs = primaryMediaPlaylistSnapshot != null ? primaryMediaPlaylistSnapshot.startTimeUs : 0;
    if (oldPlaylist == null) {
        return primarySnapshotStartTimeUs;
    }
    int oldPlaylistSize = oldPlaylist.segments.size();
    Segment firstOldOverlappingSegment = getFirstOldOverlappingSegment(oldPlaylist, loadedPlaylist);
    if (firstOldOverlappingSegment != null) {
        return oldPlaylist.startTimeUs + firstOldOverlappingSegment.relativeStartTimeUs;
    } else if (oldPlaylistSize == loadedPlaylist.mediaSequence - oldPlaylist.mediaSequence) {
        return oldPlaylist.getEndTimeUs();
    } else {
        // No segments overlap, we assume the new playlist start coincides with the primary playlist.
        return primarySnapshotStartTimeUs;
    }
}
Also used : Segment(com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment)

Example 43 with Segment

use of com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment in project ExoPlayer by google.

the class DashMediaSourceTest method prepare_targetLiveOffsetTooLong_correctedTargetOffsetAndAlignedWindowStartPosition.

@Test
public void prepare_targetLiveOffsetTooLong_correctedTargetOffsetAndAlignedWindowStartPosition() throws InterruptedException {
    DashMediaSource mediaSource = new DashMediaSource.Factory(() -> createSampleMpdDataSource(SAMPLE_MPD_LIVE_WITH_OFFSET_TOO_LONG)).createMediaSource(MediaItem.fromUri(Uri.EMPTY));
    Window window = prepareAndWaitForTimelineRefresh(mediaSource);
    // Expect the default position at the first segment start below the minimum live start position.
    assertThat(window.getDefaultPositionMs()).isEqualTo(4_000);
    // Expect the target live offset reaching from now time to the minimum live start position.
    assertThat(window.liveConfiguration.targetOffsetMs).isEqualTo(9000);
}
Also used : Window(com.google.android.exoplayer2.Timeline.Window) Test(org.junit.Test)

Example 44 with Segment

use of com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment in project ExoPlayer by google.

the class DashDownloader method getSegments.

@Override
protected List<Segment> getSegments(DataSource dataSource, DashManifest manifest, boolean removing) throws IOException, InterruptedException {
    ArrayList<Segment> segments = new ArrayList<>();
    for (int i = 0; i < manifest.getPeriodCount(); i++) {
        Period period = manifest.getPeriod(i);
        long periodStartUs = Util.msToUs(period.startMs);
        long periodDurationUs = manifest.getPeriodDurationUs(i);
        List<AdaptationSet> adaptationSets = period.adaptationSets;
        for (int j = 0; j < adaptationSets.size(); j++) {
            addSegmentsForAdaptationSet(dataSource, adaptationSets.get(j), periodStartUs, periodDurationUs, removing, segments);
        }
    }
    return segments;
}
Also used : ArrayList(java.util.ArrayList) Period(com.google.android.exoplayer2.source.dash.manifest.Period) AdaptationSet(com.google.android.exoplayer2.source.dash.manifest.AdaptationSet)

Example 45 with Segment

use of com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment in project ExoPlayer by google.

the class DashDownloader method addSegmentsForAdaptationSet.

private void addSegmentsForAdaptationSet(DataSource dataSource, AdaptationSet adaptationSet, long periodStartUs, long periodDurationUs, boolean removing, ArrayList<Segment> out) throws IOException, InterruptedException {
    for (int i = 0; i < adaptationSet.representations.size(); i++) {
        Representation representation = adaptationSet.representations.get(i);
        DashSegmentIndex index;
        try {
            index = getSegmentIndex(dataSource, adaptationSet.type, representation, removing);
            if (index == null) {
                // Loading succeeded but there was no index.
                throw new DownloadException("Missing segment index");
            }
        } catch (IOException e) {
            if (!removing) {
                throw e;
            }
            // Generating an incomplete segment list is allowed. Advance to the next representation.
            continue;
        }
        long segmentCount = index.getSegmentCount(periodDurationUs);
        if (segmentCount == DashSegmentIndex.INDEX_UNBOUNDED) {
            throw new DownloadException("Unbounded segment index");
        }
        String baseUrl = castNonNull(baseUrlExclusionList.selectBaseUrl(representation.baseUrls)).url;
        @Nullable RangedUri initializationUri = representation.getInitializationUri();
        if (initializationUri != null) {
            out.add(createSegment(representation, baseUrl, periodStartUs, initializationUri));
        }
        @Nullable RangedUri indexUri = representation.getIndexUri();
        if (indexUri != null) {
            out.add(createSegment(representation, baseUrl, periodStartUs, indexUri));
        }
        long firstSegmentNum = index.getFirstSegmentNum();
        long lastSegmentNum = firstSegmentNum + segmentCount - 1;
        for (long j = firstSegmentNum; j <= lastSegmentNum; j++) {
            out.add(createSegment(representation, baseUrl, periodStartUs + index.getTimeUs(j), index.getSegmentUrl(j)));
        }
    }
}
Also used : DownloadException(com.google.android.exoplayer2.offline.DownloadException) RangedUri(com.google.android.exoplayer2.source.dash.manifest.RangedUri) Representation(com.google.android.exoplayer2.source.dash.manifest.Representation) IOException(java.io.IOException) DashSegmentIndex(com.google.android.exoplayer2.source.dash.DashSegmentIndex) Nullable(androidx.annotation.Nullable)

Aggregations

Test (org.junit.Test)20 Uri (android.net.Uri)18 Segment (com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist.Segment)18 Nullable (androidx.annotation.Nullable)16 DataSpec (com.google.android.exoplayer2.upstream.DataSpec)11 ByteArrayInputStream (java.io.ByteArrayInputStream)9 IOException (java.io.IOException)9 InputStream (java.io.InputStream)9 ArrayList (java.util.ArrayList)9 HlsMediaPlaylist (com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist)8 Format (com.google.android.exoplayer2.Format)6 SlowMotionData (com.google.android.exoplayer2.metadata.mp4.SlowMotionData)5 SingleSampleMediaChunk (com.google.android.exoplayer2.source.chunk.SingleSampleMediaChunk)5 RangedUri (com.google.android.exoplayer2.source.dash.manifest.RangedUri)5 Representation (com.google.android.exoplayer2.source.dash.manifest.Representation)5 BehindLiveWindowException (com.google.android.exoplayer2.source.BehindLiveWindowException)4 ContainerMediaChunk (com.google.android.exoplayer2.source.chunk.ContainerMediaChunk)4 Segment (com.google.android.exoplayer2.testutil.FakeDataSet.FakeData.Segment)4 Window (com.google.android.exoplayer2.Timeline.Window)3 Segment (com.google.android.exoplayer2.metadata.mp4.SlowMotionData.Segment)3