• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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;
17 
18 import com.google.android.exoplayer2.C;
19 import com.google.android.exoplayer2.Format;
20 import com.google.android.exoplayer2.FormatHolder;
21 import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
22 import com.google.android.exoplayer2.metadata.emsg.EventMessage;
23 import com.google.android.exoplayer2.metadata.emsg.EventMessageEncoder;
24 import com.google.android.exoplayer2.source.SampleStream;
25 import com.google.android.exoplayer2.source.dash.manifest.EventStream;
26 import com.google.android.exoplayer2.util.Util;
27 import java.io.IOException;
28 
29 /**
30  * A {@link SampleStream} consisting of serialized {@link EventMessage}s read from an
31  * {@link EventStream}.
32  */
33 /* package */ final class EventSampleStream implements SampleStream {
34 
35   private final Format upstreamFormat;
36   private final EventMessageEncoder eventMessageEncoder;
37 
38   private long[] eventTimesUs;
39   private boolean eventStreamAppendable;
40   private EventStream eventStream;
41 
42   private boolean isFormatSentDownstream;
43   private int currentIndex;
44   private long pendingSeekPositionUs;
45 
EventSampleStream( EventStream eventStream, Format upstreamFormat, boolean eventStreamAppendable)46   public EventSampleStream(
47       EventStream eventStream, Format upstreamFormat, boolean eventStreamAppendable) {
48     this.upstreamFormat = upstreamFormat;
49     this.eventStream = eventStream;
50     eventMessageEncoder = new EventMessageEncoder();
51     pendingSeekPositionUs = C.TIME_UNSET;
52     eventTimesUs = eventStream.presentationTimesUs;
53     updateEventStream(eventStream, eventStreamAppendable);
54   }
55 
eventStreamId()56   public String eventStreamId() {
57     return eventStream.id();
58   }
59 
updateEventStream(EventStream eventStream, boolean eventStreamAppendable)60   public void updateEventStream(EventStream eventStream, boolean eventStreamAppendable) {
61     long lastReadPositionUs = currentIndex == 0 ? C.TIME_UNSET : eventTimesUs[currentIndex - 1];
62 
63     this.eventStreamAppendable = eventStreamAppendable;
64     this.eventStream = eventStream;
65     this.eventTimesUs = eventStream.presentationTimesUs;
66     if (pendingSeekPositionUs != C.TIME_UNSET) {
67       seekToUs(pendingSeekPositionUs);
68     } else if (lastReadPositionUs != C.TIME_UNSET) {
69       currentIndex =
70           Util.binarySearchCeil(
71               eventTimesUs, lastReadPositionUs, /* inclusive= */ false, /* stayInBounds= */ false);
72     }
73   }
74 
75   /**
76    * Seeks to the specified position in microseconds.
77    *
78    * @param positionUs The seek position in microseconds.
79    */
seekToUs(long positionUs)80   public void seekToUs(long positionUs) {
81     currentIndex =
82         Util.binarySearchCeil(
83             eventTimesUs, positionUs, /* inclusive= */ true, /* stayInBounds= */ false);
84     boolean isPendingSeek = eventStreamAppendable && currentIndex == eventTimesUs.length;
85     pendingSeekPositionUs = isPendingSeek ? positionUs : C.TIME_UNSET;
86   }
87 
88   @Override
isReady()89   public boolean isReady() {
90     return true;
91   }
92 
93   @Override
maybeThrowError()94   public void maybeThrowError() throws IOException {
95     // Do nothing.
96   }
97 
98   @Override
readData(FormatHolder formatHolder, DecoderInputBuffer buffer, boolean formatRequired)99   public int readData(FormatHolder formatHolder, DecoderInputBuffer buffer,
100       boolean formatRequired) {
101     if (formatRequired || !isFormatSentDownstream) {
102       formatHolder.format = upstreamFormat;
103       isFormatSentDownstream = true;
104       return C.RESULT_FORMAT_READ;
105     }
106     if (currentIndex == eventTimesUs.length) {
107       if (!eventStreamAppendable) {
108         buffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM);
109         return C.RESULT_BUFFER_READ;
110       } else {
111         return C.RESULT_NOTHING_READ;
112       }
113     }
114     int sampleIndex = currentIndex++;
115     byte[] serializedEvent = eventMessageEncoder.encode(eventStream.events[sampleIndex]);
116     if (serializedEvent != null) {
117       buffer.ensureSpaceForWrite(serializedEvent.length);
118       buffer.data.put(serializedEvent);
119       buffer.timeUs = eventTimesUs[sampleIndex];
120       buffer.setFlags(C.BUFFER_FLAG_KEY_FRAME);
121       return C.RESULT_BUFFER_READ;
122     } else {
123       return C.RESULT_NOTHING_READ;
124     }
125   }
126 
127   @Override
skipData(long positionUs)128   public int skipData(long positionUs) {
129     int newIndex =
130         Math.max(currentIndex, Util.binarySearchCeil(eventTimesUs, positionUs, true, false));
131     int skipped = newIndex - currentIndex;
132     currentIndex = newIndex;
133     return skipped;
134   }
135 
136 }
137