Search in sources :

Example 1 with BaseUrl

use of com.google.android.exoplayer2.source.dash.manifest.BaseUrl in project ExoPlayer by google.

the class DashManifestParser method parseMediaPresentationDescription.

protected DashManifest parseMediaPresentationDescription(XmlPullParser xpp, String baseUrl) throws XmlPullParserException, IOException {
    long availabilityStartTime = parseDateTime(xpp, "availabilityStartTime", C.TIME_UNSET);
    long durationMs = parseDuration(xpp, "mediaPresentationDuration", C.TIME_UNSET);
    long minBufferTimeMs = parseDuration(xpp, "minBufferTime", C.TIME_UNSET);
    String typeString = xpp.getAttributeValue(null, "type");
    boolean dynamic = typeString != null && typeString.equals("dynamic");
    long minUpdateTimeMs = dynamic ? parseDuration(xpp, "minimumUpdatePeriod", C.TIME_UNSET) : C.TIME_UNSET;
    long timeShiftBufferDepthMs = dynamic ? parseDuration(xpp, "timeShiftBufferDepth", C.TIME_UNSET) : C.TIME_UNSET;
    long suggestedPresentationDelayMs = dynamic ? parseDuration(xpp, "suggestedPresentationDelay", C.TIME_UNSET) : C.TIME_UNSET;
    UtcTimingElement utcTiming = null;
    Uri location = null;
    List<Period> periods = new ArrayList<>();
    long nextPeriodStartMs = dynamic ? C.TIME_UNSET : 0;
    boolean seenEarlyAccessPeriod = false;
    boolean seenFirstBaseUrl = false;
    do {
        xpp.next();
        if (XmlPullParserUtil.isStartTag(xpp, "BaseURL")) {
            if (!seenFirstBaseUrl) {
                baseUrl = parseBaseUrl(xpp, baseUrl);
                seenFirstBaseUrl = true;
            }
        } else if (XmlPullParserUtil.isStartTag(xpp, "UTCTiming")) {
            utcTiming = parseUtcTiming(xpp);
        } else if (XmlPullParserUtil.isStartTag(xpp, "Location")) {
            location = Uri.parse(xpp.nextText());
        } else if (XmlPullParserUtil.isStartTag(xpp, "Period") && !seenEarlyAccessPeriod) {
            Pair<Period, Long> periodWithDurationMs = parsePeriod(xpp, baseUrl, nextPeriodStartMs);
            Period period = periodWithDurationMs.first;
            if (period.startMs == C.TIME_UNSET) {
                if (dynamic) {
                    // This is an early access period. Ignore it. All subsequent periods must also be
                    // early access.
                    seenEarlyAccessPeriod = true;
                } else {
                    throw new ParserException("Unable to determine start of period " + periods.size());
                }
            } else {
                long periodDurationMs = periodWithDurationMs.second;
                nextPeriodStartMs = periodDurationMs == C.TIME_UNSET ? C.TIME_UNSET : (period.startMs + periodDurationMs);
                periods.add(period);
            }
        }
    } while (!XmlPullParserUtil.isEndTag(xpp, "MPD"));
    if (durationMs == C.TIME_UNSET) {
        if (nextPeriodStartMs != C.TIME_UNSET) {
            // If we know the end time of the final period, we can use it as the duration.
            durationMs = nextPeriodStartMs;
        } else if (!dynamic) {
            throw new ParserException("Unable to determine duration of static manifest.");
        }
    }
    if (periods.isEmpty()) {
        throw new ParserException("No periods found.");
    }
    return buildMediaPresentationDescription(availabilityStartTime, durationMs, minBufferTimeMs, dynamic, minUpdateTimeMs, timeShiftBufferDepthMs, suggestedPresentationDelayMs, utcTiming, location, periods);
}
Also used : ParserException(com.google.android.exoplayer2.ParserException) XmlPullParserException(org.xmlpull.v1.XmlPullParserException) ArrayList(java.util.ArrayList) Uri(android.net.Uri) Pair(android.util.Pair)

Example 2 with BaseUrl

use of com.google.android.exoplayer2.source.dash.manifest.BaseUrl in project ExoPlayer by google.

the class DefaultDashChunkSource method newMediaChunk.

private static Chunk newMediaChunk(RepresentationHolder representationHolder, DataSource dataSource, Format trackFormat, int trackSelectionReason, Object trackSelectionData, int firstSegmentNum, int maxSegmentCount) {
    Representation representation = representationHolder.representation;
    long startTimeUs = representationHolder.getSegmentStartTimeUs(firstSegmentNum);
    RangedUri segmentUri = representationHolder.getSegmentUrl(firstSegmentNum);
    String baseUrl = representation.baseUrl;
    if (representationHolder.extractorWrapper == null) {
        long endTimeUs = representationHolder.getSegmentEndTimeUs(firstSegmentNum);
        DataSpec dataSpec = new DataSpec(segmentUri.resolveUri(baseUrl), segmentUri.start, segmentUri.length, representation.getCacheKey());
        return new SingleSampleMediaChunk(dataSource, dataSpec, trackFormat, trackSelectionReason, trackSelectionData, startTimeUs, endTimeUs, firstSegmentNum, representationHolder.trackType, trackFormat);
    } else {
        int segmentCount = 1;
        for (int i = 1; i < maxSegmentCount; i++) {
            RangedUri nextSegmentUri = representationHolder.getSegmentUrl(firstSegmentNum + i);
            RangedUri mergedSegmentUri = segmentUri.attemptMerge(nextSegmentUri, baseUrl);
            if (mergedSegmentUri == null) {
                // Unable to merge segment fetches because the URIs do not merge.
                break;
            }
            segmentUri = mergedSegmentUri;
            segmentCount++;
        }
        long endTimeUs = representationHolder.getSegmentEndTimeUs(firstSegmentNum + segmentCount - 1);
        DataSpec dataSpec = new DataSpec(segmentUri.resolveUri(baseUrl), segmentUri.start, segmentUri.length, representation.getCacheKey());
        long sampleOffsetUs = -representation.presentationTimeOffsetUs;
        return new ContainerMediaChunk(dataSource, dataSpec, trackFormat, trackSelectionReason, trackSelectionData, startTimeUs, endTimeUs, firstSegmentNum, segmentCount, sampleOffsetUs, representationHolder.extractorWrapper);
    }
}
Also used : SingleSampleMediaChunk(com.google.android.exoplayer2.source.chunk.SingleSampleMediaChunk) RangedUri(com.google.android.exoplayer2.source.dash.manifest.RangedUri) DataSpec(com.google.android.exoplayer2.upstream.DataSpec) Representation(com.google.android.exoplayer2.source.dash.manifest.Representation) ContainerMediaChunk(com.google.android.exoplayer2.source.chunk.ContainerMediaChunk)

Example 3 with BaseUrl

use of com.google.android.exoplayer2.source.dash.manifest.BaseUrl in project ExoPlayer by google.

the class DashManifestParser method parsePeriod.

protected Pair<Period, Long> parsePeriod(XmlPullParser xpp, String baseUrl, long defaultStartMs) throws XmlPullParserException, IOException {
    String id = xpp.getAttributeValue(null, "id");
    long startMs = parseDuration(xpp, "start", defaultStartMs);
    long durationMs = parseDuration(xpp, "duration", C.TIME_UNSET);
    SegmentBase segmentBase = null;
    List<AdaptationSet> adaptationSets = new ArrayList<>();
    boolean seenFirstBaseUrl = false;
    do {
        xpp.next();
        if (XmlPullParserUtil.isStartTag(xpp, "BaseURL")) {
            if (!seenFirstBaseUrl) {
                baseUrl = parseBaseUrl(xpp, baseUrl);
                seenFirstBaseUrl = true;
            }
        } else if (XmlPullParserUtil.isStartTag(xpp, "AdaptationSet")) {
            adaptationSets.add(parseAdaptationSet(xpp, baseUrl, segmentBase));
        } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) {
            segmentBase = parseSegmentBase(xpp, null);
        } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
            segmentBase = parseSegmentList(xpp, null);
        } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
            segmentBase = parseSegmentTemplate(xpp, null);
        }
    } while (!XmlPullParserUtil.isEndTag(xpp, "Period"));
    return Pair.create(buildPeriod(id, startMs, adaptationSets), durationMs);
}
Also used : SingleSegmentBase(com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SingleSegmentBase) ArrayList(java.util.ArrayList)

Example 4 with BaseUrl

use of com.google.android.exoplayer2.source.dash.manifest.BaseUrl in project ExoPlayer by google.

the class DashManifestParser method parseRepresentation.

// Representation parsing.
protected RepresentationInfo parseRepresentation(XmlPullParser xpp, String baseUrl, String adaptationSetMimeType, String adaptationSetCodecs, int adaptationSetWidth, int adaptationSetHeight, float adaptationSetFrameRate, int adaptationSetAudioChannels, int adaptationSetAudioSamplingRate, String adaptationSetLanguage, @C.SelectionFlags int adaptationSetSelectionFlags, List<SchemeValuePair> adaptationSetAccessibilityDescriptors, SegmentBase segmentBase) throws XmlPullParserException, IOException {
    String id = xpp.getAttributeValue(null, "id");
    int bandwidth = parseInt(xpp, "bandwidth", Format.NO_VALUE);
    String mimeType = parseString(xpp, "mimeType", adaptationSetMimeType);
    String codecs = parseString(xpp, "codecs", adaptationSetCodecs);
    int width = parseInt(xpp, "width", adaptationSetWidth);
    int height = parseInt(xpp, "height", adaptationSetHeight);
    float frameRate = parseFrameRate(xpp, adaptationSetFrameRate);
    int audioChannels = adaptationSetAudioChannels;
    int audioSamplingRate = parseInt(xpp, "audioSamplingRate", adaptationSetAudioSamplingRate);
    ArrayList<SchemeData> drmSchemeDatas = new ArrayList<>();
    ArrayList<SchemeValuePair> inbandEventStreams = new ArrayList<>();
    boolean seenFirstBaseUrl = false;
    do {
        xpp.next();
        if (XmlPullParserUtil.isStartTag(xpp, "BaseURL")) {
            if (!seenFirstBaseUrl) {
                baseUrl = parseBaseUrl(xpp, baseUrl);
                seenFirstBaseUrl = true;
            }
        } else if (XmlPullParserUtil.isStartTag(xpp, "AudioChannelConfiguration")) {
            audioChannels = parseAudioChannelConfiguration(xpp);
        } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentBase")) {
            segmentBase = parseSegmentBase(xpp, (SingleSegmentBase) segmentBase);
        } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentList")) {
            segmentBase = parseSegmentList(xpp, (SegmentList) segmentBase);
        } else if (XmlPullParserUtil.isStartTag(xpp, "SegmentTemplate")) {
            segmentBase = parseSegmentTemplate(xpp, (SegmentTemplate) segmentBase);
        } else if (XmlPullParserUtil.isStartTag(xpp, "ContentProtection")) {
            SchemeData contentProtection = parseContentProtection(xpp);
            if (contentProtection != null) {
                drmSchemeDatas.add(contentProtection);
            }
        } else if (XmlPullParserUtil.isStartTag(xpp, "InbandEventStream")) {
            inbandEventStreams.add(parseInbandEventStream(xpp));
        }
    } while (!XmlPullParserUtil.isEndTag(xpp, "Representation"));
    Format format = buildFormat(id, mimeType, width, height, frameRate, audioChannels, audioSamplingRate, bandwidth, adaptationSetLanguage, adaptationSetSelectionFlags, adaptationSetAccessibilityDescriptors, codecs);
    segmentBase = segmentBase != null ? segmentBase : new SingleSegmentBase();
    return new RepresentationInfo(format, baseUrl, segmentBase, drmSchemeDatas, inbandEventStreams);
}
Also used : SingleSegmentBase(com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SingleSegmentBase) ArrayList(java.util.ArrayList) SchemeData(com.google.android.exoplayer2.drm.DrmInitData.SchemeData) SegmentTemplate(com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SegmentTemplate) Format(com.google.android.exoplayer2.Format)

Example 5 with BaseUrl

use of com.google.android.exoplayer2.source.dash.manifest.BaseUrl in project ExoPlayer by google.

the class DefaultDashChunkSource method onChunkLoadError.

@Override
public boolean onChunkLoadError(Chunk chunk, boolean cancelable, LoadErrorHandlingPolicy.LoadErrorInfo loadErrorInfo, LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
    if (!cancelable) {
        return false;
    }
    if (playerTrackEmsgHandler != null && playerTrackEmsgHandler.onChunkLoadError(chunk)) {
        return true;
    }
    // Workaround for missing segment at the end of the period
    if (!manifest.dynamic && chunk instanceof MediaChunk && loadErrorInfo.exception instanceof InvalidResponseCodeException && ((InvalidResponseCodeException) loadErrorInfo.exception).responseCode == 404) {
        RepresentationHolder representationHolder = representationHolders[trackSelection.indexOf(chunk.trackFormat)];
        long segmentCount = representationHolder.getSegmentCount();
        if (segmentCount != DashSegmentIndex.INDEX_UNBOUNDED && segmentCount != 0) {
            long lastAvailableSegmentNum = representationHolder.getFirstSegmentNum() + segmentCount - 1;
            if (((MediaChunk) chunk).getNextChunkIndex() > lastAvailableSegmentNum) {
                missingLastSegment = true;
                return true;
            }
        }
    }
    int trackIndex = trackSelection.indexOf(chunk.trackFormat);
    RepresentationHolder representationHolder = representationHolders[trackIndex];
    @Nullable BaseUrl newBaseUrl = baseUrlExclusionList.selectBaseUrl(representationHolder.representation.baseUrls);
    if (newBaseUrl != null && !representationHolder.selectedBaseUrl.equals(newBaseUrl)) {
        // which will use the new base URL.
        return true;
    }
    LoadErrorHandlingPolicy.FallbackOptions fallbackOptions = createFallbackOptions(trackSelection, representationHolder.representation.baseUrls);
    if (!fallbackOptions.isFallbackAvailable(LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK) && !fallbackOptions.isFallbackAvailable(LoadErrorHandlingPolicy.FALLBACK_TYPE_LOCATION)) {
        return false;
    }
    @Nullable LoadErrorHandlingPolicy.FallbackSelection fallbackSelection = loadErrorHandlingPolicy.getFallbackSelectionFor(fallbackOptions, loadErrorInfo);
    if (fallbackSelection == null || !fallbackOptions.isFallbackAvailable(fallbackSelection.type)) {
        // Policy indicated to not use any fallback or a fallback type that is not available.
        return false;
    }
    boolean cancelLoad = false;
    if (fallbackSelection.type == LoadErrorHandlingPolicy.FALLBACK_TYPE_TRACK) {
        cancelLoad = trackSelection.blacklist(trackSelection.indexOf(chunk.trackFormat), fallbackSelection.exclusionDurationMs);
    } else if (fallbackSelection.type == LoadErrorHandlingPolicy.FALLBACK_TYPE_LOCATION) {
        baseUrlExclusionList.exclude(representationHolder.selectedBaseUrl, fallbackSelection.exclusionDurationMs);
        cancelLoad = true;
    }
    return cancelLoad;
}
Also used : ContainerMediaChunk(com.google.android.exoplayer2.source.chunk.ContainerMediaChunk) MediaChunk(com.google.android.exoplayer2.source.chunk.MediaChunk) SingleSampleMediaChunk(com.google.android.exoplayer2.source.chunk.SingleSampleMediaChunk) BaseUrl(com.google.android.exoplayer2.source.dash.manifest.BaseUrl) LoadErrorHandlingPolicy(com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy) InvalidResponseCodeException(com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCodeException) Nullable(androidx.annotation.Nullable)

Aggregations

BaseUrl (com.google.android.exoplayer2.source.dash.manifest.BaseUrl)17 Test (org.junit.Test)14 ArrayList (java.util.ArrayList)9 Nullable (androidx.annotation.Nullable)7 SingleSegmentBase (com.google.android.exoplayer2.source.dash.manifest.SegmentBase.SingleSegmentBase)6 Random (java.util.Random)5 Format (com.google.android.exoplayer2.Format)4 RangedUri (com.google.android.exoplayer2.source.dash.manifest.RangedUri)4 Representation (com.google.android.exoplayer2.source.dash.manifest.Representation)4 Uri (android.net.Uri)3 Pair (android.util.Pair)3 DataSpec (com.google.android.exoplayer2.upstream.DataSpec)3 LoadErrorHandlingPolicy (com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy)3 SystemClock (android.os.SystemClock)2 ApplicationProvider (androidx.test.core.app.ApplicationProvider)2 AndroidJUnit4 (androidx.test.ext.junit.runners.AndroidJUnit4)2 C (com.google.android.exoplayer2.C)2 PlayerId (com.google.android.exoplayer2.analytics.PlayerId)2 SchemeData (com.google.android.exoplayer2.drm.DrmInitData.SchemeData)2 LoadEventInfo (com.google.android.exoplayer2.source.LoadEventInfo)2