• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.android.usbtuner.exoplayer;
17 
18 import com.google.android.exoplayer.C;
19 import com.google.android.exoplayer.MediaFormat;
20 import com.google.android.exoplayer.MediaFormatHolder;
21 import com.google.android.exoplayer.SampleHolder;
22 import com.google.android.exoplayer.SampleSource;
23 import com.google.android.exoplayer.SampleSource.SampleSourceReader;
24 import com.google.android.exoplayer.util.Assertions;
25 
26 import java.io.IOException;
27 
28 /** {@link SampleSource} that extracts sample data using a {@link SampleExtractor}. */
29 public final class MpegTsSampleSource implements SampleSource, SampleSourceReader {
30 
31     private static final int TRACK_STATE_DISABLED = 0;
32     private static final int TRACK_STATE_ENABLED = 1;
33     private static final int TRACK_STATE_FORMAT_SENT = 2;
34 
35     private final SampleExtractor mSampleExtractor;
36 
37     private MediaFormat[] mTrackFormats;
38     private boolean mPrepared;
39     private IOException mPreparationError;
40     private int mRemainingReleaseCount;
41     private int[] mTrackStates;
42     private boolean[] mPendingDiscontinuities;
43 
44     private long mLastSeekPositionUs;
45     private long mPendingSeekPositionUs;
46 
47     /**
48      * Creates a new sample source that extracts samples using {@code mSampleExtractor}.
49      *
50      * @param sampleExtractor a sample extractor for accessing media samples
51      */
MpegTsSampleSource(SampleExtractor sampleExtractor)52     public MpegTsSampleSource(SampleExtractor sampleExtractor) {
53         mSampleExtractor = Assertions.checkNotNull(sampleExtractor);
54     }
55 
56     @Override
register()57     public SampleSourceReader register() {
58         mRemainingReleaseCount++;
59         return this;
60     }
61 
62     @Override
prepare(long positionUs)63     public boolean prepare(long positionUs) {
64         if (!mPrepared) {
65             if (mPreparationError != null) {
66                 return false;
67             }
68             try {
69                 if (mSampleExtractor.prepare()) {
70                     mTrackFormats = mSampleExtractor.getTrackFormats();
71                     mTrackStates = new int[mTrackFormats.length];
72                     mPendingDiscontinuities = new boolean[mTrackStates.length];
73                     mPrepared = true;
74                 }
75             } catch (IOException e) {
76                 mPreparationError = e;
77                 return false;
78             }
79         }
80         return true;
81     }
82 
83     @Override
getTrackCount()84     public int getTrackCount() {
85         Assertions.checkState(mPrepared);
86         return mTrackFormats.length;
87     }
88 
89     @Override
getFormat(int track)90     public MediaFormat getFormat(int track) {
91         Assertions.checkState(mPrepared);
92         return mTrackFormats[track];
93     }
94 
95     @Override
enable(int track, long positionUs)96     public void enable(int track, long positionUs) {
97         Assertions.checkState(mPrepared);
98         Assertions.checkState(mTrackStates[track] == TRACK_STATE_DISABLED);
99         mTrackStates[track] = TRACK_STATE_ENABLED;
100         mSampleExtractor.selectTrack(track);
101         seekToUsInternal(positionUs, positionUs != 0);
102     }
103 
104     @Override
disable(int track)105     public void disable(int track) {
106         Assertions.checkState(mPrepared);
107         Assertions.checkState(mTrackStates[track] != TRACK_STATE_DISABLED);
108         mSampleExtractor.deselectTrack(track);
109         mPendingDiscontinuities[track] = false;
110         mTrackStates[track] = TRACK_STATE_DISABLED;
111     }
112 
113     @Override
continueBuffering(int track, long positionUs)114     public boolean continueBuffering(int track, long positionUs) {
115         return mSampleExtractor.continueBuffering(positionUs);
116     }
117 
118     @Override
readDiscontinuity(int track)119     public long readDiscontinuity(int track) {
120         if (mPendingDiscontinuities[track]) {
121             mPendingDiscontinuities[track] = false;
122             return mLastSeekPositionUs;
123         }
124         return NO_DISCONTINUITY;
125     }
126 
127     @Override
readData(int track, long positionUs, MediaFormatHolder formatHolder, SampleHolder sampleHolder)128     public int readData(int track, long positionUs, MediaFormatHolder formatHolder,
129       SampleHolder sampleHolder) {
130         Assertions.checkState(mPrepared);
131         Assertions.checkState(mTrackStates[track] != TRACK_STATE_DISABLED);
132         if (mPendingDiscontinuities[track]) {
133             return NOTHING_READ;
134         }
135         if (mTrackStates[track] != TRACK_STATE_FORMAT_SENT) {
136             mSampleExtractor.getTrackMediaFormat(track, formatHolder);
137             mTrackStates[track] = TRACK_STATE_FORMAT_SENT;
138             return FORMAT_READ;
139         }
140 
141         mPendingSeekPositionUs = C.UNKNOWN_TIME_US;
142         return mSampleExtractor.readSample(track, sampleHolder);
143     }
144 
145     @Override
maybeThrowError()146     public void maybeThrowError() throws IOException {
147         if (mPreparationError != null) {
148             throw mPreparationError;
149         }
150     }
151 
152     @Override
seekToUs(long positionUs)153     public void seekToUs(long positionUs) {
154         Assertions.checkState(mPrepared);
155         seekToUsInternal(positionUs, false);
156     }
157 
158     @Override
getBufferedPositionUs()159     public long getBufferedPositionUs() {
160         Assertions.checkState(mPrepared);
161         return mSampleExtractor.getBufferedPositionUs();
162     }
163 
164     @Override
release()165     public void release() {
166         Assertions.checkState(mRemainingReleaseCount > 0);
167         if (--mRemainingReleaseCount == 0) {
168             mSampleExtractor.release();
169         }
170     }
171 
seekToUsInternal(long positionUs, boolean force)172     private void seekToUsInternal(long positionUs, boolean force) {
173         // Unless forced, avoid duplicate calls to the underlying extractor's seek method
174         // in the case that there have been no interleaving calls to readSample.
175         if (force || mPendingSeekPositionUs != positionUs) {
176             mLastSeekPositionUs = positionUs;
177             mPendingSeekPositionUs = positionUs;
178             mSampleExtractor.seekTo(positionUs);
179             for (int i = 0; i < mTrackStates.length; ++i) {
180                 if (mTrackStates[i] != TRACK_STATE_DISABLED) {
181                     mPendingDiscontinuities[i] = true;
182                 }
183             }
184         }
185     }
186 }
187