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 <android-base/macros.h>
24
25 #include "MPEG2TSExtractor.h"
26
27 #include <media/IStreamSource.h>
28 #include <media/stagefright/foundation/ABuffer.h>
29 #include <media/stagefright/foundation/ADebug.h>
30 #include <media/stagefright/foundation/ALooper.h>
31 #include <media/stagefright/foundation/AUtils.h>
32 #include <media/stagefright/foundation/MediaKeys.h>
33 #include <media/stagefright/DataSourceBase.h>
34 #include <media/stagefright/MediaDefs.h>
35 #include <media/stagefright/MediaErrors.h>
36 #include <media/stagefright/MetaData.h>
37 #include <media/stagefright/Utils.h>
38 #include <utils/String8.h>
39
40 #include <AnotherPacketSource.h>
41
42 #include <hidl/HybridInterface.h>
43 #include <android/hardware/cas/1.0/ICas.h>
44
45 namespace android {
46
47 using hardware::cas::V1_0::ICas;
48
49 static const size_t kTSPacketSize = 188;
50 static const int kMaxDurationReadSize = 250000LL;
51 static const int kMaxDurationRetry = 6;
52
53 struct MPEG2TSSource : public MediaTrackHelper {
54 MPEG2TSSource(
55 MPEG2TSExtractor *extractor,
56 const sp<AnotherPacketSource> &impl,
57 bool doesSeek);
58 virtual ~MPEG2TSSource();
59
60 virtual media_status_t start();
61 virtual media_status_t stop();
62 virtual media_status_t getFormat(AMediaFormat *);
63
64 virtual media_status_t read(
65 MediaBufferHelper **buffer, const ReadOptions *options = NULL);
66
67 private:
68 MPEG2TSExtractor *mExtractor;
69 sp<AnotherPacketSource> mImpl;
70
71 // If there are both audio and video streams, only the video stream
72 // will signal seek on the extractor; otherwise the single stream will seek.
73 bool mDoesSeek;
74
75 DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSSource);
76 };
77
MPEG2TSSource(MPEG2TSExtractor * extractor,const sp<AnotherPacketSource> & impl,bool doesSeek)78 MPEG2TSSource::MPEG2TSSource(
79 MPEG2TSExtractor *extractor,
80 const sp<AnotherPacketSource> &impl,
81 bool doesSeek)
82 : mExtractor(extractor),
83 mImpl(impl),
84 mDoesSeek(doesSeek) {
85 }
86
~MPEG2TSSource()87 MPEG2TSSource::~MPEG2TSSource() {
88 }
89
start()90 media_status_t MPEG2TSSource::start() {
91 // initialize with one small buffer, but allow growth
92 mBufferGroup->init(1 /* one buffer */, 256 /* buffer size */, 64 /* max number of buffers */);
93
94 if (!mImpl->start(NULL)) { // AnotherPacketSource::start() doesn't use its argument
95 return AMEDIA_OK;
96 }
97 return AMEDIA_ERROR_UNKNOWN;
98 }
99
stop()100 media_status_t MPEG2TSSource::stop() {
101 if (!mImpl->stop()) {
102 return AMEDIA_OK;
103 }
104 return AMEDIA_ERROR_UNKNOWN;
105 }
106
copyAMessageToAMediaFormat(AMediaFormat * format,sp<AMessage> msg)107 void copyAMessageToAMediaFormat(AMediaFormat *format, sp<AMessage> msg) {
108 size_t numEntries = msg->countEntries();
109 for (size_t i = 0; i < numEntries; i++) {
110 AMessage::Type type;
111 const char *name = msg->getEntryNameAt(i, &type);
112 AMessage::ItemData id = msg->getEntryAt(i);
113
114 switch (type) {
115 case AMessage::kTypeInt32:
116 int32_t val32;
117 if (id.find(&val32)) {
118 AMediaFormat_setInt32(format, name, val32);
119 }
120 break;
121 case AMessage::kTypeInt64:
122 int64_t val64;
123 if (id.find(&val64)) {
124 AMediaFormat_setInt64(format, name, val64);
125 }
126 break;
127 case AMessage::kTypeFloat:
128 float valfloat;
129 if (id.find(&valfloat)) {
130 AMediaFormat_setFloat(format, name, valfloat);
131 }
132 break;
133 case AMessage::kTypeDouble:
134 double valdouble;
135 if (id.find(&valdouble)) {
136 AMediaFormat_setDouble(format, name, valdouble);
137 }
138 break;
139 case AMessage::kTypeString:
140 if (AString s; id.find(&s)) {
141 AMediaFormat_setString(format, name, s.c_str());
142 }
143 break;
144 case AMessage::kTypeBuffer:
145 {
146 sp<ABuffer> buffer;
147 if (id.find(&buffer)) {
148 AMediaFormat_setBuffer(format, name, buffer->data(), buffer->size());
149 }
150 break;
151 }
152 default:
153 ALOGW("ignoring unsupported type %d '%s'", type, name);
154 }
155 }
156 }
157
getFormat(AMediaFormat * meta)158 media_status_t MPEG2TSSource::getFormat(AMediaFormat *meta) {
159 sp<MetaData> implMeta = mImpl->getFormat();
160 sp<AMessage> msg;
161 convertMetaDataToMessage(implMeta, &msg);
162 copyAMessageToAMediaFormat(meta, msg);
163 return AMEDIA_OK;
164 }
165
read(MediaBufferHelper ** out,const ReadOptions * options)166 media_status_t MPEG2TSSource::read(
167 MediaBufferHelper **out, const ReadOptions *options) {
168 *out = NULL;
169
170 int64_t seekTimeUs;
171 ReadOptions::SeekMode seekMode;
172 if (mDoesSeek && options && options->getSeekTo(&seekTimeUs, &seekMode)) {
173 // seek is needed
174 status_t err = mExtractor->seek(seekTimeUs, (ReadOptions::SeekMode)seekMode);
175 if (err == ERROR_END_OF_STREAM) {
176 return AMEDIA_ERROR_END_OF_STREAM;
177 } else if (err != OK) {
178 return AMEDIA_ERROR_UNKNOWN;
179 }
180 }
181
182 if (mExtractor->feedUntilBufferAvailable(mImpl) != OK) {
183 return AMEDIA_ERROR_END_OF_STREAM;
184 }
185
186 MediaBufferBase *mbuf;
187 mImpl->read(&mbuf, (MediaTrack::ReadOptions*) options);
188 size_t length = mbuf->range_length();
189 MediaBufferHelper *outbuf;
190 mBufferGroup->acquire_buffer(&outbuf, false, length);
191 memcpy(outbuf->data(), mbuf->data(), length);
192 outbuf->set_range(0, length);
193 *out = outbuf;
194 MetaDataBase &inMeta = mbuf->meta_data();
195 AMediaFormat *outMeta = outbuf->meta_data();
196 AMediaFormat_clear(outMeta);
197 int64_t val64;
198 if (inMeta.findInt64(kKeyTime, &val64)) {
199 AMediaFormat_setInt64(outMeta, AMEDIAFORMAT_KEY_TIME_US, val64);
200 }
201 int32_t val32;
202 if (inMeta.findInt32(kKeyIsSyncFrame, &val32)) {
203 AMediaFormat_setInt32(outMeta, AMEDIAFORMAT_KEY_IS_SYNC_FRAME, val32);
204 }
205 if (inMeta.findInt32(kKeyCryptoMode, &val32)) {
206 AMediaFormat_setInt32(outMeta, AMEDIAFORMAT_KEY_CRYPTO_MODE, val32);
207 }
208 uint32_t bufType;
209 const void *bufData;
210 size_t bufSize;
211 if (inMeta.findData(kKeyCryptoIV, &bufType, &bufData, &bufSize)) {
212 AMediaFormat_setBuffer(outMeta, AMEDIAFORMAT_KEY_CRYPTO_IV, bufData, bufSize);
213 }
214 if (inMeta.findData(kKeyCryptoKey, &bufType, &bufData, &bufSize)) {
215 AMediaFormat_setBuffer(outMeta, AMEDIAFORMAT_KEY_CRYPTO_KEY, bufData, bufSize);
216 }
217 if (inMeta.findData(kKeyPlainSizes, &bufType, &bufData, &bufSize)) {
218 AMediaFormat_setBuffer(outMeta, AMEDIAFORMAT_KEY_CRYPTO_PLAIN_SIZES, bufData, bufSize);
219 }
220 if (inMeta.findData(kKeyEncryptedSizes, &bufType, &bufData, &bufSize)) {
221 AMediaFormat_setBuffer(outMeta, AMEDIAFORMAT_KEY_CRYPTO_ENCRYPTED_SIZES, bufData, bufSize);
222 }
223 if (inMeta.findData(kKeySEI, &bufType, &bufData, &bufSize)) {
224 AMediaFormat_setBuffer(outMeta, AMEDIAFORMAT_KEY_SEI, bufData, bufSize);
225 }
226 if (inMeta.findData(kKeyAudioPresentationInfo, &bufType, &bufData, &bufSize)) {
227 AMediaFormat_setBuffer(outMeta, AMEDIAFORMAT_KEY_AUDIO_PRESENTATION_INFO, bufData, bufSize);
228 }
229 mbuf->release();
230 return AMEDIA_OK;
231 }
232
233 ////////////////////////////////////////////////////////////////////////////////
234
MPEG2TSExtractor(DataSourceHelper * source)235 MPEG2TSExtractor::MPEG2TSExtractor(DataSourceHelper *source)
236 : mDataSource(source),
237 mParser(new ATSParser),
238 mLastSyncEvent(0),
239 mOffset(0) {
240 char header;
241 if (source->readAt(0, &header, 1) == 1 && header == 0x47) {
242 mHeaderSkip = 0;
243 } else {
244 mHeaderSkip = 4;
245 }
246 init();
247 }
248
~MPEG2TSExtractor()249 MPEG2TSExtractor::~MPEG2TSExtractor() {
250 delete mDataSource;
251 }
252
countTracks()253 size_t MPEG2TSExtractor::countTracks() {
254 return mSourceImpls.size();
255 }
256
getTrack(size_t index)257 MediaTrackHelper *MPEG2TSExtractor::getTrack(size_t index) {
258 if (index >= mSourceImpls.size()) {
259 return NULL;
260 }
261
262 // The seek reference track (video if present; audio otherwise) performs
263 // seek requests, while other tracks ignore requests.
264 return new MPEG2TSSource(this, mSourceImpls.editItemAt(index),
265 (mSeekSyncPoints == &mSyncPoints.editItemAt(index)));
266 }
267
getTrackMetaData(AMediaFormat * meta,size_t index,uint32_t)268 media_status_t MPEG2TSExtractor::getTrackMetaData(
269 AMediaFormat *meta,
270 size_t index, uint32_t /* flags */) {
271 if (meta == nullptr) {
272 return AMEDIA_ERROR_INVALID_PARAMETER;
273 }
274 sp<MetaData> implMeta = index < mSourceImpls.size()
275 ? mSourceImpls.editItemAt(index)->getFormat() : NULL;
276 if (implMeta == NULL) {
277 return AMEDIA_ERROR_UNKNOWN;
278 }
279 sp<AMessage> msg = new AMessage;
280 convertMetaDataToMessage(implMeta, &msg);
281 copyAMessageToAMediaFormat(meta, msg);
282 return AMEDIA_OK;
283 }
284
getMetaData(AMediaFormat * meta)285 media_status_t MPEG2TSExtractor::getMetaData(AMediaFormat *meta) {
286 AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
287 return AMEDIA_OK;
288 }
289
290 //static
isScrambledFormat(MetaDataBase & format)291 bool MPEG2TSExtractor::isScrambledFormat(MetaDataBase &format) {
292 const char *mime;
293 return format.findCString(kKeyMIMEType, &mime)
294 && (!strcasecmp(MEDIA_MIMETYPE_VIDEO_SCRAMBLED, mime)
295 || !strcasecmp(MEDIA_MIMETYPE_AUDIO_SCRAMBLED, mime));
296 }
297
setMediaCas(const uint8_t * casToken,size_t size)298 media_status_t MPEG2TSExtractor::setMediaCas(const uint8_t* casToken, size_t size) {
299 HalToken halToken;
300 halToken.setToExternal((uint8_t*)casToken, size);
301 sp<ICas> cas = ICas::castFrom(retrieveHalInterface(halToken));
302 ALOGD("setMediaCas: %p", cas.get());
303
304 status_t err = mParser->setMediaCas(cas);
305 if (err == OK) {
306 ALOGI("All tracks now have descramblers");
307 init();
308 return AMEDIA_OK;
309 }
310 return AMEDIA_ERROR_UNKNOWN;
311 }
312
findIndexOfSource(const sp<AnotherPacketSource> & impl,size_t * index)313 status_t MPEG2TSExtractor::findIndexOfSource(const sp<AnotherPacketSource> &impl, size_t *index) {
314 for (size_t i = 0; i < mSourceImpls.size(); i++) {
315 if (mSourceImpls[i] == impl) {
316 *index = i;
317 return OK;
318 }
319 }
320 return NAME_NOT_FOUND;
321 }
322
addSource(const sp<AnotherPacketSource> & impl)323 void MPEG2TSExtractor::addSource(const sp<AnotherPacketSource> &impl) {
324 size_t index;
325 if (findIndexOfSource(impl, &index) != OK) {
326 mSourceImpls.push(impl);
327 mSyncPoints.push();
328 }
329 }
330
init()331 void MPEG2TSExtractor::init() {
332 bool haveAudio = false;
333 bool haveVideo = false;
334 int64_t startTime = ALooper::GetNowUs();
335 size_t index;
336
337 status_t err;
338 while ((err = feedMore(true /* isInit */)) == OK
339 || err == ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED) {
340 if (haveAudio && haveVideo) {
341 addSyncPoint_l(mLastSyncEvent);
342 mLastSyncEvent.reset();
343 break;
344 }
345 if (!haveVideo) {
346 sp<AnotherPacketSource> impl = mParser->getSource(ATSParser::VIDEO);
347
348 if (impl != NULL) {
349 sp<MetaData> format = impl->getFormat();
350 if (format != NULL) {
351 haveVideo = true;
352 addSource(impl);
353 if (!isScrambledFormat(*(format.get()))) {
354 if (findIndexOfSource(impl, &index) == OK) {
355 mSeekSyncPoints = &mSyncPoints.editItemAt(index);
356 }
357 }
358 }
359 }
360 }
361
362 if (!haveAudio) {
363 sp<AnotherPacketSource> impl = mParser->getSource(ATSParser::AUDIO);
364
365 if (impl != NULL) {
366 sp<MetaData> format = impl->getFormat();
367 if (format != NULL) {
368 haveAudio = true;
369 addSource(impl);
370 if (!isScrambledFormat(*(format.get())) && !haveVideo) {
371 if (findIndexOfSource(impl, &index) == OK) {
372 mSeekSyncPoints = &mSyncPoints.editItemAt(index);
373 }
374 }
375 }
376 }
377 }
378
379 addSyncPoint_l(mLastSyncEvent);
380 mLastSyncEvent.reset();
381
382 // ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED is returned when the mpeg2ts
383 // is scrambled but we don't have a MediaCas object set. The extraction
384 // will only continue when setMediaCas() is called successfully.
385 if (err == ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED) {
386 ALOGI("stopped parsing scrambled content, "
387 "haveAudio=%d, haveVideo=%d, elaspedTime=%" PRId64,
388 haveAudio, haveVideo, ALooper::GetNowUs() - startTime);
389 return;
390 }
391
392 // Wait only for 2 seconds to detect audio/video streams.
393 if (ALooper::GetNowUs() - startTime > 2000000LL) {
394 break;
395 }
396 }
397
398 off64_t size;
399 if (mDataSource->getSize(&size) == OK && (haveAudio || haveVideo)) {
400 size_t prevSyncSize = 1;
401 int64_t durationUs = -1;
402 List<int64_t> durations;
403 // Estimate duration --- stabilize until you get <500ms deviation.
404 while (feedMore() == OK
405 && ALooper::GetNowUs() - startTime <= 2000000LL) {
406 if (mSeekSyncPoints->size() > prevSyncSize) {
407 prevSyncSize = mSeekSyncPoints->size();
408 int64_t diffUs = mSeekSyncPoints->keyAt(prevSyncSize - 1)
409 - mSeekSyncPoints->keyAt(0);
410 off64_t diffOffset = mSeekSyncPoints->valueAt(prevSyncSize - 1)
411 - mSeekSyncPoints->valueAt(0);
412 int64_t currentDurationUs = size * diffUs / diffOffset;
413 durations.push_back(currentDurationUs);
414 if (durations.size() > 5) {
415 durations.erase(durations.begin());
416 int64_t min = *durations.begin();
417 int64_t max = *durations.begin();
418 for (auto duration : durations) {
419 if (min > duration) {
420 min = duration;
421 }
422 if (max < duration) {
423 max = duration;
424 }
425 }
426 if (max - min < 500 * 1000) {
427 durationUs = currentDurationUs;
428 break;
429 }
430 }
431 }
432 }
433
434 bool found = false;
435 for (int i = 0; i < ATSParser::NUM_SOURCE_TYPES; ++i) {
436 ATSParser::SourceType type = static_cast<ATSParser::SourceType>(i);
437 sp<AnotherPacketSource> impl = mParser->getSource(type);
438 if (impl == NULL) {
439 continue;
440 }
441
442 int64_t trackDurationUs = durationUs;
443
444 status_t err;
445 int64_t bufferedDurationUs = impl->getBufferedDurationUs(&err);
446 if (err == ERROR_END_OF_STREAM) {
447 trackDurationUs = bufferedDurationUs;
448 }
449 if (trackDurationUs > 0) {
450 ALOGV("[SourceType%d] durationUs=%" PRId64 "", type, trackDurationUs);
451 const sp<MetaData> meta = impl->getFormat();
452 meta->setInt64(kKeyDuration, trackDurationUs);
453 impl->setFormat(meta);
454
455 found = true;
456 }
457 }
458 if (!found) {
459 estimateDurationsFromTimesUsAtEnd();
460 }
461 }
462
463 ALOGI("haveAudio=%d, haveVideo=%d, elaspedTime=%" PRId64,
464 haveAudio, haveVideo, ALooper::GetNowUs() - startTime);
465 }
466
feedMore(bool isInit)467 status_t MPEG2TSExtractor::feedMore(bool isInit) {
468 Mutex::Autolock autoLock(mLock);
469
470 uint8_t packet[kTSPacketSize];
471 ssize_t n = mDataSource->readAt(mOffset + mHeaderSkip, packet, kTSPacketSize);
472
473 if (n < (ssize_t)kTSPacketSize) {
474 if (n >= 0) {
475 mParser->signalEOS(ERROR_END_OF_STREAM);
476 }
477 return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM;
478 }
479
480 ATSParser::SyncEvent event(mOffset);
481 mOffset += mHeaderSkip + n;
482 status_t err = mParser->feedTSPacket(packet, kTSPacketSize, &event);
483 if (event.hasReturnedData()) {
484 if (isInit) {
485 mLastSyncEvent = event;
486 } else {
487 addSyncPoint_l(event);
488 }
489 }
490 return err;
491 }
492
addSyncPoint_l(const ATSParser::SyncEvent & event)493 void MPEG2TSExtractor::addSyncPoint_l(const ATSParser::SyncEvent &event) {
494 if (!event.hasReturnedData()) {
495 return;
496 }
497
498 for (size_t i = 0; i < mSourceImpls.size(); ++i) {
499 if (mSourceImpls[i].get() == event.getMediaSource().get()) {
500 KeyedVector<int64_t, off64_t> *syncPoints = &mSyncPoints.editItemAt(i);
501 syncPoints->add(event.getTimeUs(), event.getOffset());
502 // We're keeping the size of the sync points at most 5mb per a track.
503 size_t size = syncPoints->size();
504 if (size >= 327680) {
505 int64_t firstTimeUs = syncPoints->keyAt(0);
506 int64_t lastTimeUs = syncPoints->keyAt(size - 1);
507 if (event.getTimeUs() - firstTimeUs > lastTimeUs - event.getTimeUs()) {
508 syncPoints->removeItemsAt(0, 4096);
509 } else {
510 syncPoints->removeItemsAt(size - 4096, 4096);
511 }
512 }
513 break;
514 }
515 }
516 }
517
estimateDurationsFromTimesUsAtEnd()518 status_t MPEG2TSExtractor::estimateDurationsFromTimesUsAtEnd() {
519 if (!(mDataSource->flags() & DataSourceBase::kIsLocalFileSource)) {
520 return ERROR_UNSUPPORTED;
521 }
522
523 off64_t size = 0;
524 status_t err = mDataSource->getSize(&size);
525 if (err != OK) {
526 return err;
527 }
528
529 uint8_t packet[kTSPacketSize];
530 const off64_t zero = 0;
531 off64_t offset = max(zero, size - kMaxDurationReadSize);
532 if (mDataSource->readAt(offset, &packet, 0) < 0) {
533 return ERROR_IO;
534 }
535
536 int retry = 0;
537 bool allDurationsFound = false;
538 int64_t timeAnchorUs = mParser->getFirstPTSTimeUs();
539 do {
540 int bytesRead = 0;
541 sp<ATSParser> parser = new ATSParser(ATSParser::TS_TIMESTAMPS_ARE_ABSOLUTE);
542 ATSParser::SyncEvent ev(0);
543 offset = max(zero, size - (kMaxDurationReadSize << retry));
544 offset = (offset / kTSPacketSize) * kTSPacketSize;
545 for (;;) {
546 if (bytesRead >= kMaxDurationReadSize << max(0, retry - 1)) {
547 break;
548 }
549
550 ssize_t n = mDataSource->readAt(offset+mHeaderSkip, packet, kTSPacketSize);
551 if (n < 0) {
552 return n;
553 } else if (n < (ssize_t)kTSPacketSize) {
554 break;
555 }
556
557 offset += kTSPacketSize + mHeaderSkip;
558 bytesRead += kTSPacketSize + mHeaderSkip;
559 err = parser->feedTSPacket(packet, kTSPacketSize, &ev);
560 if (err != OK) {
561 return err;
562 }
563
564 if (ev.hasReturnedData()) {
565 int64_t durationUs = ev.getTimeUs();
566 ATSParser::SourceType type = ev.getType();
567 ev.reset();
568
569 int64_t firstTimeUs;
570 sp<AnotherPacketSource> src = mParser->getSource(type);
571 if (src == NULL || src->nextBufferTime(&firstTimeUs) != OK) {
572 continue;
573 }
574 durationUs += src->getEstimatedBufferDurationUs();
575 durationUs -= timeAnchorUs;
576 durationUs -= firstTimeUs;
577 if (durationUs > 0) {
578 int64_t origDurationUs, lastDurationUs;
579 const sp<MetaData> meta = src->getFormat();
580 const uint32_t kKeyLastDuration = 'ldur';
581 // Require two consecutive duration calculations to be within 1 sec before
582 // updating; use MetaData to store previous duration estimate in per-stream
583 // context.
584 if (!meta->findInt64(kKeyDuration, &origDurationUs)
585 || !meta->findInt64(kKeyLastDuration, &lastDurationUs)
586 || (origDurationUs < durationUs
587 && abs(durationUs - lastDurationUs) < 60000000)) {
588 meta->setInt64(kKeyDuration, durationUs);
589 }
590 meta->setInt64(kKeyLastDuration, durationUs);
591 }
592 }
593 }
594
595 if (!allDurationsFound) {
596 allDurationsFound = true;
597 for (auto t: {ATSParser::VIDEO, ATSParser::AUDIO}) {
598 sp<AnotherPacketSource> src = mParser->getSource(t);
599 if (src == NULL) {
600 continue;
601 }
602 int64_t durationUs;
603 const sp<MetaData> meta = src->getFormat();
604 if (!meta->findInt64(kKeyDuration, &durationUs)) {
605 allDurationsFound = false;
606 break;
607 }
608 }
609 }
610
611 ++retry;
612 } while(!allDurationsFound && offset > 0 && retry <= kMaxDurationRetry);
613
614 return allDurationsFound? OK : ERROR_UNSUPPORTED;
615 }
616
flags() const617 uint32_t MPEG2TSExtractor::flags() const {
618 return CAN_PAUSE | CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD;
619 }
620
seek(int64_t seekTimeUs,const MediaTrackHelper::ReadOptions::SeekMode & seekMode)621 status_t MPEG2TSExtractor::seek(int64_t seekTimeUs,
622 const MediaTrackHelper::ReadOptions::SeekMode &seekMode) {
623 if (mSeekSyncPoints == NULL || mSeekSyncPoints->isEmpty()) {
624 ALOGW("No sync point to seek to.");
625 // ... and therefore we have nothing useful to do here.
626 return OK;
627 }
628
629 // Determine whether we're seeking beyond the known area.
630 bool shouldSeekBeyond =
631 (seekTimeUs > mSeekSyncPoints->keyAt(mSeekSyncPoints->size() - 1));
632
633 // Determine the sync point to seek.
634 size_t index = 0;
635 for (; index < mSeekSyncPoints->size(); ++index) {
636 int64_t timeUs = mSeekSyncPoints->keyAt(index);
637 if (timeUs > seekTimeUs) {
638 break;
639 }
640 }
641
642 switch (seekMode) {
643 case MediaTrackHelper::ReadOptions::SEEK_NEXT_SYNC:
644 if (index == mSeekSyncPoints->size()) {
645 ALOGW("Next sync not found; starting from the latest sync.");
646 --index;
647 }
648 break;
649 case MediaTrackHelper::ReadOptions::SEEK_CLOSEST_SYNC:
650 case MediaTrackHelper::ReadOptions::SEEK_CLOSEST:
651 ALOGW("seekMode not supported: %d; falling back to PREVIOUS_SYNC",
652 seekMode);
653 FALLTHROUGH_INTENDED;
654 case MediaTrackHelper::ReadOptions::SEEK_PREVIOUS_SYNC:
655 if (index == 0) {
656 ALOGW("Previous sync not found; starting from the earliest "
657 "sync.");
658 } else {
659 --index;
660 }
661 break;
662 default:
663 return ERROR_UNSUPPORTED;
664 }
665 if (!shouldSeekBeyond || mOffset <= mSeekSyncPoints->valueAt(index)) {
666 int64_t actualSeekTimeUs = mSeekSyncPoints->keyAt(index);
667 mOffset = mSeekSyncPoints->valueAt(index);
668 status_t err = queueDiscontinuityForSeek(actualSeekTimeUs);
669 if (err != OK) {
670 return err;
671 }
672 }
673
674 if (shouldSeekBeyond) {
675 status_t err = seekBeyond(seekTimeUs);
676 if (err != OK) {
677 return err;
678 }
679 }
680
681 // Fast-forward to sync frame.
682 for (size_t i = 0; i < mSourceImpls.size(); ++i) {
683 const sp<AnotherPacketSource> &impl = mSourceImpls[i];
684 status_t err;
685 feedUntilBufferAvailable(impl);
686 while (impl->hasBufferAvailable(&err)) {
687 sp<AMessage> meta = impl->getMetaAfterLastDequeued(0);
688 sp<ABuffer> buffer;
689 if (meta == NULL) {
690 return UNKNOWN_ERROR;
691 }
692 int32_t sync;
693 if (meta->findInt32("isSync", &sync) && sync) {
694 break;
695 }
696 err = impl->dequeueAccessUnit(&buffer);
697 if (err != OK) {
698 return err;
699 }
700 feedUntilBufferAvailable(impl);
701 }
702 }
703
704 return OK;
705 }
706
queueDiscontinuityForSeek(int64_t actualSeekTimeUs)707 status_t MPEG2TSExtractor::queueDiscontinuityForSeek(int64_t actualSeekTimeUs) {
708 // Signal discontinuity
709 sp<AMessage> extra(new AMessage);
710 extra->setInt64(kATSParserKeyMediaTimeUs, actualSeekTimeUs);
711 mParser->signalDiscontinuity(ATSParser::DISCONTINUITY_TIME, extra);
712
713 // After discontinuity, impl should only have discontinuities
714 // with the last being what we queued. Dequeue them all here.
715 for (size_t i = 0; i < mSourceImpls.size(); ++i) {
716 const sp<AnotherPacketSource> &impl = mSourceImpls.itemAt(i);
717 sp<ABuffer> buffer;
718 status_t err;
719 while (impl->hasBufferAvailable(&err)) {
720 if (err != OK) {
721 return err;
722 }
723 err = impl->dequeueAccessUnit(&buffer);
724 // If the source contains anything but discontinuity, that's
725 // a programming mistake.
726 CHECK(err == INFO_DISCONTINUITY);
727 }
728 }
729
730 // Feed until we have a buffer for each source.
731 for (size_t i = 0; i < mSourceImpls.size(); ++i) {
732 const sp<AnotherPacketSource> &impl = mSourceImpls.itemAt(i);
733 sp<ABuffer> buffer;
734 status_t err = feedUntilBufferAvailable(impl);
735 if (err != OK) {
736 return err;
737 }
738 }
739
740 return OK;
741 }
742
seekBeyond(int64_t seekTimeUs)743 status_t MPEG2TSExtractor::seekBeyond(int64_t seekTimeUs) {
744 // If we're seeking beyond where we know --- read until we reach there.
745 size_t syncPointsSize = mSeekSyncPoints->size();
746
747 while (seekTimeUs > mSeekSyncPoints->keyAt(
748 mSeekSyncPoints->size() - 1)) {
749 status_t err;
750 if (syncPointsSize < mSeekSyncPoints->size()) {
751 syncPointsSize = mSeekSyncPoints->size();
752 int64_t syncTimeUs = mSeekSyncPoints->keyAt(syncPointsSize - 1);
753 // Dequeue buffers before sync point in order to avoid too much
754 // cache building up.
755 sp<ABuffer> buffer;
756 for (size_t i = 0; i < mSourceImpls.size(); ++i) {
757 const sp<AnotherPacketSource> &impl = mSourceImpls[i];
758 int64_t timeUs;
759 while ((err = impl->nextBufferTime(&timeUs)) == OK) {
760 if (timeUs < syncTimeUs) {
761 impl->dequeueAccessUnit(&buffer);
762 } else {
763 break;
764 }
765 }
766 if (err != OK && err != -EWOULDBLOCK) {
767 return err;
768 }
769 }
770 }
771 if (feedMore() != OK) {
772 return ERROR_END_OF_STREAM;
773 }
774 }
775
776 return OK;
777 }
778
feedUntilBufferAvailable(const sp<AnotherPacketSource> & impl)779 status_t MPEG2TSExtractor::feedUntilBufferAvailable(
780 const sp<AnotherPacketSource> &impl) {
781 status_t finalResult;
782 while (!impl->hasBufferAvailable(&finalResult)) {
783 if (finalResult != OK) {
784 return finalResult;
785 }
786
787 status_t err = feedMore();
788 if (err != OK) {
789 impl->signalEOS(err);
790 }
791 }
792 return OK;
793 }
794
795 ////////////////////////////////////////////////////////////////////////////////
796
SniffMPEG2TS(DataSourceHelper * source,float * confidence)797 bool SniffMPEG2TS(DataSourceHelper *source, float *confidence) {
798 for (int i = 0; i < 5; ++i) {
799 char header;
800 if (source->readAt(kTSPacketSize * i, &header, 1) != 1
801 || header != 0x47) {
802 // not ts file, check if m2ts file
803 for (int j = 0; j < 5; ++j) {
804 char headers[5];
805 if (source->readAt((kTSPacketSize + 4) * j, &headers, 5) != 5
806 || headers[4] != 0x47) {
807 // not m2ts file too, return
808 return false;
809 }
810 }
811 ALOGV("this is m2ts file\n");
812 break;
813 }
814 }
815
816 *confidence = 0.1f;
817
818 return true;
819 }
820
821 } // namespace android
822