• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.android.exoplayer2.source.dash.manifest;
17 
18 import android.net.Uri;
19 import androidx.annotation.Nullable;
20 import com.google.android.exoplayer2.C;
21 import com.google.android.exoplayer2.offline.FilterableManifest;
22 import com.google.android.exoplayer2.offline.StreamKey;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.LinkedList;
26 import java.util.List;
27 
28 /**
29  * Represents a DASH media presentation description (mpd), as defined by ISO/IEC 23009-1:2014
30  * Section 5.3.1.2.
31  */
32 public class DashManifest implements FilterableManifest<DashManifest> {
33 
34   /**
35    * The {@code availabilityStartTime} value in milliseconds since epoch, or {@link C#TIME_UNSET} if
36    * not present.
37    */
38   public final long availabilityStartTimeMs;
39 
40   /**
41    * The duration of the presentation in milliseconds, or {@link C#TIME_UNSET} if not applicable.
42    */
43   public final long durationMs;
44 
45   /**
46    * The {@code minBufferTime} value in milliseconds, or {@link C#TIME_UNSET} if not present.
47    */
48   public final long minBufferTimeMs;
49 
50   /**
51    * Whether the manifest has value "dynamic" for the {@code type} attribute.
52    */
53   public final boolean dynamic;
54 
55   /**
56    * The {@code minimumUpdatePeriod} value in milliseconds, or {@link C#TIME_UNSET} if not
57    * applicable.
58    */
59   public final long minUpdatePeriodMs;
60 
61   /**
62    * The {@code timeShiftBufferDepth} value in milliseconds, or {@link C#TIME_UNSET} if not
63    * present.
64    */
65   public final long timeShiftBufferDepthMs;
66 
67   /**
68    * The {@code suggestedPresentationDelay} value in milliseconds, or {@link C#TIME_UNSET} if not
69    * present.
70    */
71   public final long suggestedPresentationDelayMs;
72 
73   /**
74    * The {@code publishTime} value in milliseconds since epoch, or {@link C#TIME_UNSET} if
75    * not present.
76    */
77   public final long publishTimeMs;
78 
79   /**
80    * The {@link UtcTimingElement}, or null if not present. Defined in DVB A168:7/2016, Section
81    * 4.7.2.
82    */
83   @Nullable public final UtcTimingElement utcTiming;
84 
85   /** The location of this manifest, or null if not present. */
86   @Nullable public final Uri location;
87 
88   /** The {@link ProgramInformation}, or null if not present. */
89   @Nullable public final ProgramInformation programInformation;
90 
91   private final List<Period> periods;
92 
93   /**
94    * @deprecated Use {@link #DashManifest(long, long, long, boolean, long, long, long, long,
95    *     ProgramInformation, UtcTimingElement, Uri, List)}.
96    */
97   @Deprecated
DashManifest( long availabilityStartTimeMs, long durationMs, long minBufferTimeMs, boolean dynamic, long minUpdatePeriodMs, long timeShiftBufferDepthMs, long suggestedPresentationDelayMs, long publishTimeMs, @Nullable UtcTimingElement utcTiming, @Nullable Uri location, List<Period> periods)98   public DashManifest(
99       long availabilityStartTimeMs,
100       long durationMs,
101       long minBufferTimeMs,
102       boolean dynamic,
103       long minUpdatePeriodMs,
104       long timeShiftBufferDepthMs,
105       long suggestedPresentationDelayMs,
106       long publishTimeMs,
107       @Nullable UtcTimingElement utcTiming,
108       @Nullable Uri location,
109       List<Period> periods) {
110     this(
111         availabilityStartTimeMs,
112         durationMs,
113         minBufferTimeMs,
114         dynamic,
115         minUpdatePeriodMs,
116         timeShiftBufferDepthMs,
117         suggestedPresentationDelayMs,
118         publishTimeMs,
119         /* programInformation= */ null,
120         utcTiming,
121         location,
122         periods);
123   }
124 
DashManifest( long availabilityStartTimeMs, long durationMs, long minBufferTimeMs, boolean dynamic, long minUpdatePeriodMs, long timeShiftBufferDepthMs, long suggestedPresentationDelayMs, long publishTimeMs, @Nullable ProgramInformation programInformation, @Nullable UtcTimingElement utcTiming, @Nullable Uri location, List<Period> periods)125   public DashManifest(
126       long availabilityStartTimeMs,
127       long durationMs,
128       long minBufferTimeMs,
129       boolean dynamic,
130       long minUpdatePeriodMs,
131       long timeShiftBufferDepthMs,
132       long suggestedPresentationDelayMs,
133       long publishTimeMs,
134       @Nullable ProgramInformation programInformation,
135       @Nullable UtcTimingElement utcTiming,
136       @Nullable Uri location,
137       List<Period> periods) {
138     this.availabilityStartTimeMs = availabilityStartTimeMs;
139     this.durationMs = durationMs;
140     this.minBufferTimeMs = minBufferTimeMs;
141     this.dynamic = dynamic;
142     this.minUpdatePeriodMs = minUpdatePeriodMs;
143     this.timeShiftBufferDepthMs = timeShiftBufferDepthMs;
144     this.suggestedPresentationDelayMs = suggestedPresentationDelayMs;
145     this.publishTimeMs = publishTimeMs;
146     this.programInformation = programInformation;
147     this.utcTiming = utcTiming;
148     this.location = location;
149     this.periods = periods == null ? Collections.emptyList() : periods;
150   }
151 
getPeriodCount()152   public final int getPeriodCount() {
153     return periods.size();
154   }
155 
getPeriod(int index)156   public final Period getPeriod(int index) {
157     return periods.get(index);
158   }
159 
getPeriodDurationMs(int index)160   public final long getPeriodDurationMs(int index) {
161     return index == periods.size() - 1
162         ? (durationMs == C.TIME_UNSET ? C.TIME_UNSET : (durationMs - periods.get(index).startMs))
163         : (periods.get(index + 1).startMs - periods.get(index).startMs);
164   }
165 
getPeriodDurationUs(int index)166   public final long getPeriodDurationUs(int index) {
167     return C.msToUs(getPeriodDurationMs(index));
168   }
169 
170   @Override
copy(List<StreamKey> streamKeys)171   public final DashManifest copy(List<StreamKey> streamKeys) {
172     LinkedList<StreamKey> keys = new LinkedList<>(streamKeys);
173     Collections.sort(keys);
174     keys.add(new StreamKey(-1, -1, -1)); // Add a stopper key to the end
175 
176     ArrayList<Period> copyPeriods = new ArrayList<>();
177     long shiftMs = 0;
178     for (int periodIndex = 0; periodIndex < getPeriodCount(); periodIndex++) {
179       if (keys.peek().periodIndex != periodIndex) {
180         // No representations selected in this period.
181         long periodDurationMs = getPeriodDurationMs(periodIndex);
182         if (periodDurationMs != C.TIME_UNSET) {
183           shiftMs += periodDurationMs;
184         }
185       } else {
186         Period period = getPeriod(periodIndex);
187         ArrayList<AdaptationSet> copyAdaptationSets =
188             copyAdaptationSets(period.adaptationSets, keys);
189         Period copiedPeriod = new Period(period.id, period.startMs - shiftMs, copyAdaptationSets,
190             period.eventStreams);
191         copyPeriods.add(copiedPeriod);
192       }
193     }
194     long newDuration = durationMs != C.TIME_UNSET ? durationMs - shiftMs : C.TIME_UNSET;
195     return new DashManifest(
196         availabilityStartTimeMs,
197         newDuration,
198         minBufferTimeMs,
199         dynamic,
200         minUpdatePeriodMs,
201         timeShiftBufferDepthMs,
202         suggestedPresentationDelayMs,
203         publishTimeMs,
204         programInformation,
205         utcTiming,
206         location,
207         copyPeriods);
208   }
209 
copyAdaptationSets( List<AdaptationSet> adaptationSets, LinkedList<StreamKey> keys)210   private static ArrayList<AdaptationSet> copyAdaptationSets(
211       List<AdaptationSet> adaptationSets, LinkedList<StreamKey> keys) {
212     StreamKey key = keys.poll();
213     int periodIndex = key.periodIndex;
214     ArrayList<AdaptationSet> copyAdaptationSets = new ArrayList<>();
215     do {
216       int adaptationSetIndex = key.groupIndex;
217       AdaptationSet adaptationSet = adaptationSets.get(adaptationSetIndex);
218 
219       List<Representation> representations = adaptationSet.representations;
220       ArrayList<Representation> copyRepresentations = new ArrayList<>();
221       do {
222         Representation representation = representations.get(key.trackIndex);
223         copyRepresentations.add(representation);
224         key = keys.poll();
225       } while (key.periodIndex == periodIndex && key.groupIndex == adaptationSetIndex);
226 
227       copyAdaptationSets.add(
228           new AdaptationSet(
229               adaptationSet.id,
230               adaptationSet.type,
231               copyRepresentations,
232               adaptationSet.accessibilityDescriptors,
233               adaptationSet.essentialProperties,
234               adaptationSet.supplementalProperties));
235     } while(key.periodIndex == periodIndex);
236     // Add back the last key which doesn't belong to the period being processed
237     keys.addFirst(key);
238     return copyAdaptationSets;
239   }
240 
241 }
242