/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.android.exoplayer.dash.mpd; import com.google.android.exoplayer.chunk.Format; import com.google.android.exoplayer.dash.DashSegmentIndex; import com.google.android.exoplayer.dash.mpd.SegmentBase.MultiSegmentBase; import com.google.android.exoplayer.dash.mpd.SegmentBase.SingleSegmentBase; import android.net.Uri; /** * A DASH representation. */ public abstract class Representation { /** * Identifies the piece of content to which this {@link Representation} belongs. * <p> * For example, all {@link Representation}s belonging to a video should have the same * {@link #contentId}, which should uniquely identify that video. */ public final String contentId; /** * Identifies the revision of the content. * <p> * If the media for a given ({@link #contentId} can change over time without a change to the * {@link #format}'s {@link Format#id} (e.g. as a result of re-encoding the media with an * updated encoder), then this identifier must uniquely identify the revision of the media. The * timestamp at which the media was encoded is often a suitable. */ public final long revisionId; /** * The format of the representation. */ public final Format format; /** * The start time of the enclosing period in milliseconds since the epoch. */ public final long periodStartMs; /** * The duration of the enclosing period in milliseconds. */ public final long periodDurationMs; /** * The offset of the presentation timestamps in the media stream relative to media time. */ public final long presentationTimeOffsetMs; private final RangedUri initializationUri; /** * Constructs a new instance. * * @param periodStartMs The start time of the enclosing period in milliseconds. * @param periodDurationMs The duration of the enclosing period in milliseconds, or -1 if the * duration is unknown. * @param contentId Identifies the piece of content to which this representation belongs. * @param revisionId Identifies the revision of the content. * @param format The format of the representation. * @param segmentBase A segment base element for the representation. * @return The constructed instance. */ public static Representation newInstance(long periodStartMs, long periodDurationMs, String contentId, long revisionId, Format format, SegmentBase segmentBase) { if (segmentBase instanceof SingleSegmentBase) { return new SingleSegmentRepresentation(periodStartMs, periodDurationMs, contentId, revisionId, format, (SingleSegmentBase) segmentBase, -1); } else if (segmentBase instanceof MultiSegmentBase) { return new MultiSegmentRepresentation(periodStartMs, periodDurationMs, contentId, revisionId, format, (MultiSegmentBase) segmentBase); } else { throw new IllegalArgumentException("segmentBase must be of type SingleSegmentBase or " + "MultiSegmentBase"); } } private Representation(long periodStartMs, long periodDurationMs, String contentId, long revisionId, Format format, SegmentBase segmentBase) { this.periodStartMs = periodStartMs; this.periodDurationMs = periodDurationMs; this.contentId = contentId; this.revisionId = revisionId; this.format = format; initializationUri = segmentBase.getInitialization(this); presentationTimeOffsetMs = (segmentBase.presentationTimeOffset * 1000) / segmentBase.timescale; } /** * Gets a {@link RangedUri} defining the location of the representation's initialization data. * May be null if no initialization data exists. * * @return A {@link RangedUri} defining the location of the initialization data, or null. */ public RangedUri getInitializationUri() { return initializationUri; } /** * Gets a {@link RangedUri} defining the location of the representation's segment index. Null if * the representation provides an index directly. * * @return The location of the segment index, or null. */ public abstract RangedUri getIndexUri(); /** * Gets a segment index, if the representation is able to provide one directly. Null if the * segment index is defined externally. * * @return The segment index, or null. */ public abstract DashSegmentIndex getIndex(); /** * Generates a cache key for the {@link Representation}, in the format * {@code contentId + "." + format.id + "." + revisionId}. * * @return A cache key. */ public String getCacheKey() { return contentId + "." + format.id + "." + revisionId; } /** * A DASH representation consisting of a single segment. */ public static class SingleSegmentRepresentation extends Representation { /** * The {@link Uri} of the single segment. */ public final Uri uri; /** * The content length, or -1 if unknown. */ public final long contentLength; private final RangedUri indexUri; /** * @param periodStartMs The start time of the enclosing period in milliseconds. * @param periodDurationMs The duration of the enclosing period in milliseconds, or -1 if the * duration is unknown. * @param contentId Identifies the piece of content to which this representation belongs. * @param revisionId Identifies the revision of the content. * @param format The format of the representation. * @param uri The uri of the media. * @param initializationStart The offset of the first byte of initialization data. * @param initializationEnd The offset of the last byte of initialization data. * @param indexStart The offset of the first byte of index data. * @param indexEnd The offset of the last byte of index data. * @param contentLength The content length, or -1 if unknown. */ public static SingleSegmentRepresentation newInstance(long periodStartMs, long periodDurationMs, String contentId, long revisionId, Format format, Uri uri, long initializationStart, long initializationEnd, long indexStart, long indexEnd, long contentLength) { RangedUri rangedUri = new RangedUri(uri, null, initializationStart, initializationEnd - initializationStart + 1); SingleSegmentBase segmentBase = new SingleSegmentBase(rangedUri, 1, 0, uri, indexStart, indexEnd - indexStart + 1); return new SingleSegmentRepresentation(periodStartMs, periodDurationMs, contentId, revisionId, format, segmentBase, contentLength); } /** * @param periodStartMs The start time of the enclosing period in milliseconds. * @param periodDurationMs The duration of the enclosing period in milliseconds, or -1 if the * duration is unknown. * @param contentId Identifies the piece of content to which this representation belongs. * @param revisionId Identifies the revision of the content. * @param format The format of the representation. * @param segmentBase The segment base underlying the representation. * @param contentLength The content length, or -1 if unknown. */ public SingleSegmentRepresentation(long periodStartMs, long periodDurationMs, String contentId, long revisionId, Format format, SingleSegmentBase segmentBase, long contentLength) { super(periodStartMs, periodDurationMs, contentId, revisionId, format, segmentBase); this.uri = segmentBase.uri; this.indexUri = segmentBase.getIndex(); this.contentLength = contentLength; } @Override public RangedUri getIndexUri() { return indexUri; } @Override public DashSegmentIndex getIndex() { return null; } } /** * A DASH representation consisting of multiple segments. */ public static class MultiSegmentRepresentation extends Representation implements DashSegmentIndex { private final MultiSegmentBase segmentBase; /** * @param periodStartMs The start time of the enclosing period in milliseconds. * @param periodDurationMs The duration of the enclosing period in milliseconds, or -1 if the * duration is unknown. * @param contentId Identifies the piece of content to which this representation belongs. * @param revisionId Identifies the revision of the content. * @param format The format of the representation. * @param segmentBase The segment base underlying the representation. */ public MultiSegmentRepresentation(long periodStartMs, long periodDurationMs, String contentId, long revisionId, Format format, MultiSegmentBase segmentBase) { super(periodStartMs, periodDurationMs, contentId, revisionId, format, segmentBase); this.segmentBase = segmentBase; } @Override public RangedUri getIndexUri() { return null; } @Override public DashSegmentIndex getIndex() { return this; } // DashSegmentIndex implementation. @Override public RangedUri getSegmentUrl(int segmentIndex) { return segmentBase.getSegmentUrl(this, segmentIndex); } @Override public int getSegmentNum(long timeUs) { return segmentBase.getSegmentNum(timeUs); } @Override public long getTimeUs(int segmentIndex) { return segmentBase.getSegmentTimeUs(segmentIndex); } @Override public long getDurationUs(int segmentIndex) { return segmentBase.getSegmentDurationUs(segmentIndex); } @Override public int getFirstSegmentNum() { return segmentBase.getFirstSegmentNum(); } @Override public int getLastSegmentNum() { return segmentBase.getLastSegmentNum(); } } }