1 /*
2 * Copyright (C) 2010 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
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "MPEG2TSExtractor"
19
20 #include <inttypes.h>
21 #include <utils/Log.h>
22
23 #include "include/MPEG2TSExtractor.h"
24 #include "include/NuCachedSource2.h"
25
26 #include <media/stagefright/foundation/ABuffer.h>
27 #include <media/stagefright/foundation/ADebug.h>
28 #include <media/stagefright/foundation/ALooper.h>
29 #include <media/stagefright/DataSource.h>
30 #include <media/stagefright/MediaDefs.h>
31 #include <media/stagefright/MediaErrors.h>
32 #include <media/stagefright/MediaSource.h>
33 #include <media/stagefright/MetaData.h>
34 #include <media/IStreamSource.h>
35 #include <utils/String8.h>
36
37 #include "AnotherPacketSource.h"
38 #include "ATSParser.h"
39
40 namespace android {
41
42 static const size_t kTSPacketSize = 188;
43
44 struct MPEG2TSSource : public MediaSource {
45 MPEG2TSSource(
46 const sp<MPEG2TSExtractor> &extractor,
47 const sp<AnotherPacketSource> &impl,
48 bool doesSeek);
49
50 virtual status_t start(MetaData *params = NULL);
51 virtual status_t stop();
52 virtual sp<MetaData> getFormat();
53
54 virtual status_t read(
55 MediaBuffer **buffer, const ReadOptions *options = NULL);
56
57 private:
58 sp<MPEG2TSExtractor> mExtractor;
59 sp<AnotherPacketSource> mImpl;
60
61 // If there are both audio and video streams, only the video stream
62 // will signal seek on the extractor; otherwise the single stream will seek.
63 bool mDoesSeek;
64
65 DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSSource);
66 };
67
MPEG2TSSource(const sp<MPEG2TSExtractor> & extractor,const sp<AnotherPacketSource> & impl,bool doesSeek)68 MPEG2TSSource::MPEG2TSSource(
69 const sp<MPEG2TSExtractor> &extractor,
70 const sp<AnotherPacketSource> &impl,
71 bool doesSeek)
72 : mExtractor(extractor),
73 mImpl(impl),
74 mDoesSeek(doesSeek) {
75 }
76
start(MetaData * params)77 status_t MPEG2TSSource::start(MetaData *params) {
78 return mImpl->start(params);
79 }
80
stop()81 status_t MPEG2TSSource::stop() {
82 return mImpl->stop();
83 }
84
getFormat()85 sp<MetaData> MPEG2TSSource::getFormat() {
86 return mImpl->getFormat();
87 }
88
read(MediaBuffer ** out,const ReadOptions * options)89 status_t MPEG2TSSource::read(
90 MediaBuffer **out, const ReadOptions *options) {
91 *out = NULL;
92
93 int64_t seekTimeUs;
94 ReadOptions::SeekMode seekMode;
95 if (mDoesSeek && options && options->getSeekTo(&seekTimeUs, &seekMode)) {
96 // seek is needed
97 status_t err = mExtractor->seek(seekTimeUs, seekMode);
98 if (err != OK) {
99 return err;
100 }
101 }
102
103 if (mExtractor->feedUntilBufferAvailable(mImpl) != OK) {
104 return ERROR_END_OF_STREAM;
105 }
106
107 return mImpl->read(out, options);
108 }
109
110 ////////////////////////////////////////////////////////////////////////////////
111
MPEG2TSExtractor(const sp<DataSource> & source)112 MPEG2TSExtractor::MPEG2TSExtractor(const sp<DataSource> &source)
113 : mDataSource(source),
114 mParser(new ATSParser),
115 mOffset(0) {
116 init();
117 }
118
countTracks()119 size_t MPEG2TSExtractor::countTracks() {
120 return mSourceImpls.size();
121 }
122
getTrack(size_t index)123 sp<MediaSource> MPEG2TSExtractor::getTrack(size_t index) {
124 if (index >= mSourceImpls.size()) {
125 return NULL;
126 }
127
128 // The seek reference track (video if present; audio otherwise) performs
129 // seek requests, while other tracks ignore requests.
130 return new MPEG2TSSource(this, mSourceImpls.editItemAt(index),
131 (mSeekSyncPoints == &mSyncPoints.editItemAt(index)));
132 }
133
getTrackMetaData(size_t index,uint32_t)134 sp<MetaData> MPEG2TSExtractor::getTrackMetaData(
135 size_t index, uint32_t /* flags */) {
136 return index < mSourceImpls.size()
137 ? mSourceImpls.editItemAt(index)->getFormat() : NULL;
138 }
139
getMetaData()140 sp<MetaData> MPEG2TSExtractor::getMetaData() {
141 sp<MetaData> meta = new MetaData;
142 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
143
144 return meta;
145 }
146
init()147 void MPEG2TSExtractor::init() {
148 bool haveAudio = false;
149 bool haveVideo = false;
150 int64_t startTime = ALooper::GetNowUs();
151
152 while (feedMore() == OK) {
153 if (haveAudio && haveVideo) {
154 break;
155 }
156 if (!haveVideo) {
157 sp<AnotherPacketSource> impl =
158 (AnotherPacketSource *)mParser->getSource(
159 ATSParser::VIDEO).get();
160
161 if (impl != NULL) {
162 haveVideo = true;
163 mSourceImpls.push(impl);
164 mSyncPoints.push();
165 mSeekSyncPoints = &mSyncPoints.editTop();
166 }
167 }
168
169 if (!haveAudio) {
170 sp<AnotherPacketSource> impl =
171 (AnotherPacketSource *)mParser->getSource(
172 ATSParser::AUDIO).get();
173
174 if (impl != NULL) {
175 haveAudio = true;
176 mSourceImpls.push(impl);
177 mSyncPoints.push();
178 if (!haveVideo) {
179 mSeekSyncPoints = &mSyncPoints.editTop();
180 }
181 }
182 }
183
184 // Wait only for 2 seconds to detect audio/video streams.
185 if (ALooper::GetNowUs() - startTime > 2000000ll) {
186 break;
187 }
188 }
189
190 off64_t size;
191 if (mDataSource->getSize(&size) == OK && (haveAudio || haveVideo)) {
192 sp<AnotherPacketSource> impl = haveVideo
193 ? (AnotherPacketSource *)mParser->getSource(
194 ATSParser::VIDEO).get()
195 : (AnotherPacketSource *)mParser->getSource(
196 ATSParser::AUDIO).get();
197 size_t prevSyncSize = 1;
198 int64_t durationUs = -1;
199 List<int64_t> durations;
200 // Estimate duration --- stabilize until you get <500ms deviation.
201 while (feedMore() == OK
202 && ALooper::GetNowUs() - startTime <= 2000000ll) {
203 if (mSeekSyncPoints->size() > prevSyncSize) {
204 prevSyncSize = mSeekSyncPoints->size();
205 int64_t diffUs = mSeekSyncPoints->keyAt(prevSyncSize - 1)
206 - mSeekSyncPoints->keyAt(0);
207 off64_t diffOffset = mSeekSyncPoints->valueAt(prevSyncSize - 1)
208 - mSeekSyncPoints->valueAt(0);
209 durationUs = size * diffUs / diffOffset;
210 durations.push_back(durationUs);
211 if (durations.size() > 5) {
212 durations.erase(durations.begin());
213 int64_t min = *durations.begin();
214 int64_t max = *durations.begin();
215 for (List<int64_t>::iterator i = durations.begin();
216 i != durations.end();
217 ++i) {
218 if (min > *i) {
219 min = *i;
220 }
221 if (max < *i) {
222 max = *i;
223 }
224 }
225 if (max - min < 500 * 1000) {
226 break;
227 }
228 }
229 }
230 }
231 status_t err;
232 int64_t bufferedDurationUs;
233 bufferedDurationUs = impl->getBufferedDurationUs(&err);
234 if (err == ERROR_END_OF_STREAM) {
235 durationUs = bufferedDurationUs;
236 }
237 if (durationUs > 0) {
238 const sp<MetaData> meta = impl->getFormat();
239 meta->setInt64(kKeyDuration, durationUs);
240 impl->setFormat(meta);
241 }
242 }
243
244 ALOGI("haveAudio=%d, haveVideo=%d, elaspedTime=%" PRId64,
245 haveAudio, haveVideo, ALooper::GetNowUs() - startTime);
246 }
247
feedMore()248 status_t MPEG2TSExtractor::feedMore() {
249 Mutex::Autolock autoLock(mLock);
250
251 uint8_t packet[kTSPacketSize];
252 ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize);
253
254 if (n < (ssize_t)kTSPacketSize) {
255 if (n >= 0) {
256 mParser->signalEOS(ERROR_END_OF_STREAM);
257 }
258 return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM;
259 }
260
261 ATSParser::SyncEvent event(mOffset);
262 mOffset += n;
263 status_t err = mParser->feedTSPacket(packet, kTSPacketSize, &event);
264 if (event.isInit()) {
265 for (size_t i = 0; i < mSourceImpls.size(); ++i) {
266 if (mSourceImpls[i].get() == event.getMediaSource().get()) {
267 KeyedVector<int64_t, off64_t> *syncPoints = &mSyncPoints.editItemAt(i);
268 syncPoints->add(event.getTimeUs(), event.getOffset());
269 // We're keeping the size of the sync points at most 5mb per a track.
270 size_t size = syncPoints->size();
271 if (size >= 327680) {
272 int64_t firstTimeUs = syncPoints->keyAt(0);
273 int64_t lastTimeUs = syncPoints->keyAt(size - 1);
274 if (event.getTimeUs() - firstTimeUs > lastTimeUs - event.getTimeUs()) {
275 syncPoints->removeItemsAt(0, 4096);
276 } else {
277 syncPoints->removeItemsAt(size - 4096, 4096);
278 }
279 }
280 break;
281 }
282 }
283 }
284 return err;
285 }
286
flags() const287 uint32_t MPEG2TSExtractor::flags() const {
288 return CAN_PAUSE | CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD;
289 }
290
seek(int64_t seekTimeUs,const MediaSource::ReadOptions::SeekMode & seekMode)291 status_t MPEG2TSExtractor::seek(int64_t seekTimeUs,
292 const MediaSource::ReadOptions::SeekMode &seekMode) {
293 if (mSeekSyncPoints == NULL || mSeekSyncPoints->isEmpty()) {
294 ALOGW("No sync point to seek to.");
295 // ... and therefore we have nothing useful to do here.
296 return OK;
297 }
298
299 // Determine whether we're seeking beyond the known area.
300 bool shouldSeekBeyond =
301 (seekTimeUs > mSeekSyncPoints->keyAt(mSeekSyncPoints->size() - 1));
302
303 // Determine the sync point to seek.
304 size_t index = 0;
305 for (; index < mSeekSyncPoints->size(); ++index) {
306 int64_t timeUs = mSeekSyncPoints->keyAt(index);
307 if (timeUs > seekTimeUs) {
308 break;
309 }
310 }
311
312 switch (seekMode) {
313 case MediaSource::ReadOptions::SEEK_NEXT_SYNC:
314 if (index == mSeekSyncPoints->size()) {
315 ALOGW("Next sync not found; starting from the latest sync.");
316 --index;
317 }
318 break;
319 case MediaSource::ReadOptions::SEEK_CLOSEST_SYNC:
320 case MediaSource::ReadOptions::SEEK_CLOSEST:
321 ALOGW("seekMode not supported: %d; falling back to PREVIOUS_SYNC",
322 seekMode);
323 // fall-through
324 case MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC:
325 if (index == 0) {
326 ALOGW("Previous sync not found; starting from the earliest "
327 "sync.");
328 } else {
329 --index;
330 }
331 break;
332 }
333 if (!shouldSeekBeyond || mOffset <= mSeekSyncPoints->valueAt(index)) {
334 int64_t actualSeekTimeUs = mSeekSyncPoints->keyAt(index);
335 mOffset = mSeekSyncPoints->valueAt(index);
336 status_t err = queueDiscontinuityForSeek(actualSeekTimeUs);
337 if (err != OK) {
338 return err;
339 }
340 }
341
342 if (shouldSeekBeyond) {
343 status_t err = seekBeyond(seekTimeUs);
344 if (err != OK) {
345 return err;
346 }
347 }
348
349 // Fast-forward to sync frame.
350 for (size_t i = 0; i < mSourceImpls.size(); ++i) {
351 const sp<AnotherPacketSource> &impl = mSourceImpls[i];
352 status_t err;
353 feedUntilBufferAvailable(impl);
354 while (impl->hasBufferAvailable(&err)) {
355 sp<AMessage> meta = impl->getMetaAfterLastDequeued(0);
356 sp<ABuffer> buffer;
357 if (meta == NULL) {
358 return UNKNOWN_ERROR;
359 }
360 int32_t sync;
361 if (meta->findInt32("isSync", &sync) && sync) {
362 break;
363 }
364 err = impl->dequeueAccessUnit(&buffer);
365 if (err != OK) {
366 return err;
367 }
368 feedUntilBufferAvailable(impl);
369 }
370 }
371
372 return OK;
373 }
374
queueDiscontinuityForSeek(int64_t actualSeekTimeUs)375 status_t MPEG2TSExtractor::queueDiscontinuityForSeek(int64_t actualSeekTimeUs) {
376 // Signal discontinuity
377 sp<AMessage> extra(new AMessage);
378 extra->setInt64(IStreamListener::kKeyMediaTimeUs, actualSeekTimeUs);
379 mParser->signalDiscontinuity(ATSParser::DISCONTINUITY_TIME, extra);
380
381 // After discontinuity, impl should only have discontinuities
382 // with the last being what we queued. Dequeue them all here.
383 for (size_t i = 0; i < mSourceImpls.size(); ++i) {
384 const sp<AnotherPacketSource> &impl = mSourceImpls.itemAt(i);
385 sp<ABuffer> buffer;
386 status_t err;
387 while (impl->hasBufferAvailable(&err)) {
388 if (err != OK) {
389 return err;
390 }
391 err = impl->dequeueAccessUnit(&buffer);
392 // If the source contains anything but discontinuity, that's
393 // a programming mistake.
394 CHECK(err == INFO_DISCONTINUITY);
395 }
396 }
397
398 // Feed until we have a buffer for each source.
399 for (size_t i = 0; i < mSourceImpls.size(); ++i) {
400 const sp<AnotherPacketSource> &impl = mSourceImpls.itemAt(i);
401 sp<ABuffer> buffer;
402 status_t err = feedUntilBufferAvailable(impl);
403 if (err != OK) {
404 return err;
405 }
406 }
407
408 return OK;
409 }
410
seekBeyond(int64_t seekTimeUs)411 status_t MPEG2TSExtractor::seekBeyond(int64_t seekTimeUs) {
412 // If we're seeking beyond where we know --- read until we reach there.
413 size_t syncPointsSize = mSeekSyncPoints->size();
414
415 while (seekTimeUs > mSeekSyncPoints->keyAt(
416 mSeekSyncPoints->size() - 1)) {
417 status_t err;
418 if (syncPointsSize < mSeekSyncPoints->size()) {
419 syncPointsSize = mSeekSyncPoints->size();
420 int64_t syncTimeUs = mSeekSyncPoints->keyAt(syncPointsSize - 1);
421 // Dequeue buffers before sync point in order to avoid too much
422 // cache building up.
423 sp<ABuffer> buffer;
424 for (size_t i = 0; i < mSourceImpls.size(); ++i) {
425 const sp<AnotherPacketSource> &impl = mSourceImpls[i];
426 int64_t timeUs;
427 while ((err = impl->nextBufferTime(&timeUs)) == OK) {
428 if (timeUs < syncTimeUs) {
429 impl->dequeueAccessUnit(&buffer);
430 } else {
431 break;
432 }
433 }
434 if (err != OK && err != -EWOULDBLOCK) {
435 return err;
436 }
437 }
438 }
439 if (feedMore() != OK) {
440 return ERROR_END_OF_STREAM;
441 }
442 }
443
444 return OK;
445 }
446
feedUntilBufferAvailable(const sp<AnotherPacketSource> & impl)447 status_t MPEG2TSExtractor::feedUntilBufferAvailable(
448 const sp<AnotherPacketSource> &impl) {
449 status_t finalResult;
450 while (!impl->hasBufferAvailable(&finalResult)) {
451 if (finalResult != OK) {
452 return finalResult;
453 }
454
455 status_t err = feedMore();
456 if (err != OK) {
457 impl->signalEOS(err);
458 }
459 }
460 return OK;
461 }
462
463 ////////////////////////////////////////////////////////////////////////////////
464
SniffMPEG2TS(const sp<DataSource> & source,String8 * mimeType,float * confidence,sp<AMessage> *)465 bool SniffMPEG2TS(
466 const sp<DataSource> &source, String8 *mimeType, float *confidence,
467 sp<AMessage> *) {
468 for (int i = 0; i < 5; ++i) {
469 char header;
470 if (source->readAt(kTSPacketSize * i, &header, 1) != 1
471 || header != 0x47) {
472 return false;
473 }
474 }
475
476 *confidence = 0.1f;
477 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
478
479 return true;
480 }
481
482 } // namespace android
483