MPEG2TSExtractor.cpp revision 15d02f84351eaca14099bde11cfbf6f124bea71f
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 "MPEG2TSExtractor.h" 24 25#include <media/DataSource.h> 26#include <media/IStreamSource.h> 27#include <media/MediaSource.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/MediaDefs.h> 34#include <media/stagefright/MediaErrors.h> 35#include <media/stagefright/MetaData.h> 36#include <utils/String8.h> 37 38#include "mpeg2ts/AnotherPacketSource.h" 39#include "mpeg2ts/ATSParser.h" 40 41#include <hidl/HybridInterface.h> 42#include <android/hardware/cas/1.0/ICas.h> 43 44namespace android { 45 46using hardware::cas::V1_0::ICas; 47 48static const size_t kTSPacketSize = 188; 49static const int kMaxDurationReadSize = 250000LL; 50static const int kMaxDurationRetry = 6; 51 52struct MPEG2TSSource : public MediaSource { 53 MPEG2TSSource( 54 const sp<MPEG2TSExtractor> &extractor, 55 const sp<AnotherPacketSource> &impl, 56 bool doesSeek); 57 58 virtual status_t start(MetaData *params = NULL); 59 virtual status_t stop(); 60 virtual sp<MetaData> getFormat(); 61 62 virtual status_t read( 63 MediaBuffer **buffer, const ReadOptions *options = NULL); 64 65private: 66 sp<MPEG2TSExtractor> mExtractor; 67 sp<AnotherPacketSource> mImpl; 68 69 // If there are both audio and video streams, only the video stream 70 // will signal seek on the extractor; otherwise the single stream will seek. 71 bool mDoesSeek; 72 73 DISALLOW_EVIL_CONSTRUCTORS(MPEG2TSSource); 74}; 75 76MPEG2TSSource::MPEG2TSSource( 77 const sp<MPEG2TSExtractor> &extractor, 78 const sp<AnotherPacketSource> &impl, 79 bool doesSeek) 80 : mExtractor(extractor), 81 mImpl(impl), 82 mDoesSeek(doesSeek) { 83} 84 85status_t MPEG2TSSource::start(MetaData *params) { 86 return mImpl->start(params); 87} 88 89status_t MPEG2TSSource::stop() { 90 return mImpl->stop(); 91} 92 93sp<MetaData> MPEG2TSSource::getFormat() { 94 return mImpl->getFormat(); 95} 96 97status_t MPEG2TSSource::read( 98 MediaBuffer **out, const ReadOptions *options) { 99 *out = NULL; 100 101 int64_t seekTimeUs; 102 ReadOptions::SeekMode seekMode; 103 if (mDoesSeek && options && options->getSeekTo(&seekTimeUs, &seekMode)) { 104 // seek is needed 105 status_t err = mExtractor->seek(seekTimeUs, seekMode); 106 if (err != OK) { 107 return err; 108 } 109 } 110 111 if (mExtractor->feedUntilBufferAvailable(mImpl) != OK) { 112 return ERROR_END_OF_STREAM; 113 } 114 115 return mImpl->read(out, options); 116} 117 118//////////////////////////////////////////////////////////////////////////////// 119 120MPEG2TSExtractor::MPEG2TSExtractor(const sp<DataSource> &source) 121 : mDataSource(source), 122 mParser(new ATSParser), 123 mLastSyncEvent(0), 124 mOffset(0) { 125 init(); 126} 127 128size_t MPEG2TSExtractor::countTracks() { 129 return mSourceImpls.size(); 130} 131 132sp<MediaSource> MPEG2TSExtractor::getTrack(size_t index) { 133 if (index >= mSourceImpls.size()) { 134 return NULL; 135 } 136 137 // The seek reference track (video if present; audio otherwise) performs 138 // seek requests, while other tracks ignore requests. 139 return new MPEG2TSSource(this, mSourceImpls.editItemAt(index), 140 (mSeekSyncPoints == &mSyncPoints.editItemAt(index))); 141} 142 143sp<MetaData> MPEG2TSExtractor::getTrackMetaData( 144 size_t index, uint32_t /* flags */) { 145 return index < mSourceImpls.size() 146 ? mSourceImpls.editItemAt(index)->getFormat() : NULL; 147} 148 149sp<MetaData> MPEG2TSExtractor::getMetaData() { 150 sp<MetaData> meta = new MetaData; 151 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG2TS); 152 153 return meta; 154} 155 156//static 157bool MPEG2TSExtractor::isScrambledFormat(const sp<MetaData> &format) { 158 const char *mime; 159 return format->findCString(kKeyMIMEType, &mime) 160 && (!strcasecmp(MEDIA_MIMETYPE_VIDEO_SCRAMBLED, mime) 161 || !strcasecmp(MEDIA_MIMETYPE_AUDIO_SCRAMBLED, mime)); 162} 163 164status_t MPEG2TSExtractor::setMediaCas(const HInterfaceToken &casToken) { 165 HalToken halToken; 166 halToken.setToExternal((uint8_t*)casToken.data(), casToken.size()); 167 sp<ICas> cas = ICas::castFrom(retrieveHalInterface(halToken)); 168 ALOGD("setMediaCas: %p", cas.get()); 169 170 status_t err = mParser->setMediaCas(cas); 171 if (err == OK) { 172 ALOGI("All tracks now have descramblers"); 173 init(); 174 } 175 return err; 176} 177 178void MPEG2TSExtractor::addSource(const sp<AnotherPacketSource> &impl) { 179 bool found = false; 180 for (size_t i = 0; i < mSourceImpls.size(); i++) { 181 if (mSourceImpls[i] == impl) { 182 found = true; 183 break; 184 } 185 } 186 if (!found) { 187 mSourceImpls.push(impl); 188 } 189} 190 191void MPEG2TSExtractor::init() { 192 bool haveAudio = false; 193 bool haveVideo = false; 194 int64_t startTime = ALooper::GetNowUs(); 195 196 status_t err; 197 while ((err = feedMore(true /* isInit */)) == OK 198 || err == ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED) { 199 if (haveAudio && haveVideo) { 200 addSyncPoint_l(mLastSyncEvent); 201 mLastSyncEvent.reset(); 202 break; 203 } 204 if (!haveVideo) { 205 sp<AnotherPacketSource> impl = 206 (AnotherPacketSource *)mParser->getSource( 207 ATSParser::VIDEO).get(); 208 209 if (impl != NULL) { 210 sp<MetaData> format = impl->getFormat(); 211 if (format != NULL) { 212 haveVideo = true; 213 addSource(impl); 214 if (!isScrambledFormat(format)) { 215 mSyncPoints.push(); 216 mSeekSyncPoints = &mSyncPoints.editTop(); 217 } 218 } 219 } 220 } 221 222 if (!haveAudio) { 223 sp<AnotherPacketSource> impl = 224 (AnotherPacketSource *)mParser->getSource( 225 ATSParser::AUDIO).get(); 226 227 if (impl != NULL) { 228 sp<MetaData> format = impl->getFormat(); 229 if (format != NULL) { 230 haveAudio = true; 231 addSource(impl); 232 if (!isScrambledFormat(format)) { 233 mSyncPoints.push(); 234 if (!haveVideo) { 235 mSeekSyncPoints = &mSyncPoints.editTop(); 236 } 237 } 238 } 239 } 240 } 241 242 addSyncPoint_l(mLastSyncEvent); 243 mLastSyncEvent.reset(); 244 245 // ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED is returned when the mpeg2ts 246 // is scrambled but we don't have a MediaCas object set. The extraction 247 // will only continue when setMediaCas() is called successfully. 248 if (err == ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED) { 249 ALOGI("stopped parsing scrambled content, " 250 "haveAudio=%d, haveVideo=%d, elaspedTime=%" PRId64, 251 haveAudio, haveVideo, ALooper::GetNowUs() - startTime); 252 return; 253 } 254 255 // Wait only for 2 seconds to detect audio/video streams. 256 if (ALooper::GetNowUs() - startTime > 2000000ll) { 257 break; 258 } 259 } 260 261 off64_t size; 262 if (mDataSource->getSize(&size) == OK && (haveAudio || haveVideo)) { 263 sp<AnotherPacketSource> impl = haveVideo 264 ? (AnotherPacketSource *)mParser->getSource( 265 ATSParser::VIDEO).get() 266 : (AnotherPacketSource *)mParser->getSource( 267 ATSParser::AUDIO).get(); 268 size_t prevSyncSize = 1; 269 int64_t durationUs = -1; 270 List<int64_t> durations; 271 // Estimate duration --- stabilize until you get <500ms deviation. 272 while (feedMore() == OK 273 && ALooper::GetNowUs() - startTime <= 2000000ll) { 274 if (mSeekSyncPoints->size() > prevSyncSize) { 275 prevSyncSize = mSeekSyncPoints->size(); 276 int64_t diffUs = mSeekSyncPoints->keyAt(prevSyncSize - 1) 277 - mSeekSyncPoints->keyAt(0); 278 off64_t diffOffset = mSeekSyncPoints->valueAt(prevSyncSize - 1) 279 - mSeekSyncPoints->valueAt(0); 280 int64_t currentDurationUs = size * diffUs / diffOffset; 281 durations.push_back(currentDurationUs); 282 if (durations.size() > 5) { 283 durations.erase(durations.begin()); 284 int64_t min = *durations.begin(); 285 int64_t max = *durations.begin(); 286 for (auto duration : durations) { 287 if (min > duration) { 288 min = duration; 289 } 290 if (max < duration) { 291 max = duration; 292 } 293 } 294 if (max - min < 500 * 1000) { 295 durationUs = currentDurationUs; 296 break; 297 } 298 } 299 } 300 } 301 status_t err; 302 int64_t bufferedDurationUs; 303 bufferedDurationUs = impl->getBufferedDurationUs(&err); 304 if (err == ERROR_END_OF_STREAM) { 305 durationUs = bufferedDurationUs; 306 } 307 if (durationUs > 0) { 308 const sp<MetaData> meta = impl->getFormat(); 309 meta->setInt64(kKeyDuration, durationUs); 310 impl->setFormat(meta); 311 } else { 312 estimateDurationsFromTimesUsAtEnd(); 313 } 314 } 315 316 ALOGI("haveAudio=%d, haveVideo=%d, elaspedTime=%" PRId64, 317 haveAudio, haveVideo, ALooper::GetNowUs() - startTime); 318} 319 320status_t MPEG2TSExtractor::feedMore(bool isInit) { 321 Mutex::Autolock autoLock(mLock); 322 323 uint8_t packet[kTSPacketSize]; 324 ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize); 325 326 if (n < (ssize_t)kTSPacketSize) { 327 if (n >= 0) { 328 mParser->signalEOS(ERROR_END_OF_STREAM); 329 } 330 return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM; 331 } 332 333 ATSParser::SyncEvent event(mOffset); 334 mOffset += n; 335 status_t err = mParser->feedTSPacket(packet, kTSPacketSize, &event); 336 if (event.hasReturnedData()) { 337 if (isInit) { 338 mLastSyncEvent = event; 339 } else { 340 addSyncPoint_l(event); 341 } 342 } 343 return err; 344} 345 346void MPEG2TSExtractor::addSyncPoint_l(const ATSParser::SyncEvent &event) { 347 if (!event.hasReturnedData()) { 348 return; 349 } 350 351 for (size_t i = 0; i < mSourceImpls.size(); ++i) { 352 if (mSourceImpls[i].get() == event.getMediaSource().get()) { 353 KeyedVector<int64_t, off64_t> *syncPoints = &mSyncPoints.editItemAt(i); 354 syncPoints->add(event.getTimeUs(), event.getOffset()); 355 // We're keeping the size of the sync points at most 5mb per a track. 356 size_t size = syncPoints->size(); 357 if (size >= 327680) { 358 int64_t firstTimeUs = syncPoints->keyAt(0); 359 int64_t lastTimeUs = syncPoints->keyAt(size - 1); 360 if (event.getTimeUs() - firstTimeUs > lastTimeUs - event.getTimeUs()) { 361 syncPoints->removeItemsAt(0, 4096); 362 } else { 363 syncPoints->removeItemsAt(size - 4096, 4096); 364 } 365 } 366 break; 367 } 368 } 369} 370 371status_t MPEG2TSExtractor::estimateDurationsFromTimesUsAtEnd() { 372 if (!(mDataSource->flags() & DataSource::kIsLocalFileSource)) { 373 return ERROR_UNSUPPORTED; 374 } 375 376 off64_t size = 0; 377 status_t err = mDataSource->getSize(&size); 378 if (err != OK) { 379 return err; 380 } 381 382 uint8_t packet[kTSPacketSize]; 383 const off64_t zero = 0; 384 off64_t offset = max(zero, size - kMaxDurationReadSize); 385 if (mDataSource->readAt(offset, &packet, 0) < 0) { 386 return ERROR_IO; 387 } 388 389 int retry = 0; 390 bool allDurationsFound = false; 391 int64_t timeAnchorUs = mParser->getFirstPTSTimeUs(); 392 do { 393 int bytesRead = 0; 394 sp<ATSParser> parser = new ATSParser(ATSParser::TS_TIMESTAMPS_ARE_ABSOLUTE); 395 ATSParser::SyncEvent ev(0); 396 offset = max(zero, size - (kMaxDurationReadSize << retry)); 397 offset = (offset / kTSPacketSize) * kTSPacketSize; 398 for (;;) { 399 if (bytesRead >= kMaxDurationReadSize << max(0, retry - 1)) { 400 break; 401 } 402 403 ssize_t n = mDataSource->readAt(offset, packet, kTSPacketSize); 404 if (n < 0) { 405 return n; 406 } else if (n < (ssize_t)kTSPacketSize) { 407 break; 408 } 409 410 offset += kTSPacketSize; 411 bytesRead += kTSPacketSize; 412 err = parser->feedTSPacket(packet, kTSPacketSize, &ev); 413 if (err != OK) { 414 return err; 415 } 416 417 if (ev.hasReturnedData()) { 418 int64_t durationUs = ev.getTimeUs(); 419 ATSParser::SourceType type = ev.getType(); 420 ev.reset(); 421 422 int64_t firstTimeUs; 423 sp<AnotherPacketSource> src = 424 (AnotherPacketSource *)mParser->getSource(type).get(); 425 if (src == NULL || src->nextBufferTime(&firstTimeUs) != OK) { 426 continue; 427 } 428 durationUs += src->getEstimatedBufferDurationUs(); 429 durationUs -= timeAnchorUs; 430 durationUs -= firstTimeUs; 431 if (durationUs > 0) { 432 int64_t origDurationUs, lastDurationUs; 433 const sp<MetaData> meta = src->getFormat(); 434 const uint32_t kKeyLastDuration = 'ldur'; 435 // Require two consecutive duration calculations to be within 1 sec before 436 // updating; use MetaData to store previous duration estimate in per-stream 437 // context. 438 if (!meta->findInt64(kKeyDuration, &origDurationUs) 439 || !meta->findInt64(kKeyLastDuration, &lastDurationUs) 440 || (origDurationUs < durationUs 441 && abs(durationUs - lastDurationUs) < 60000000)) { 442 meta->setInt64(kKeyDuration, durationUs); 443 } 444 meta->setInt64(kKeyLastDuration, durationUs); 445 } 446 } 447 } 448 449 if (!allDurationsFound) { 450 allDurationsFound = true; 451 for (auto t: {ATSParser::VIDEO, ATSParser::AUDIO}) { 452 sp<AnotherPacketSource> src = (AnotherPacketSource *)mParser->getSource(t).get(); 453 if (src == NULL) { 454 continue; 455 } 456 int64_t durationUs; 457 const sp<MetaData> meta = src->getFormat(); 458 if (!meta->findInt64(kKeyDuration, &durationUs)) { 459 allDurationsFound = false; 460 break; 461 } 462 } 463 } 464 465 ++retry; 466 } while(!allDurationsFound && offset > 0 && retry <= kMaxDurationRetry); 467 468 return allDurationsFound? OK : ERROR_UNSUPPORTED; 469} 470 471uint32_t MPEG2TSExtractor::flags() const { 472 return CAN_PAUSE | CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD; 473} 474 475status_t MPEG2TSExtractor::seek(int64_t seekTimeUs, 476 const MediaSource::ReadOptions::SeekMode &seekMode) { 477 if (mSeekSyncPoints == NULL || mSeekSyncPoints->isEmpty()) { 478 ALOGW("No sync point to seek to."); 479 // ... and therefore we have nothing useful to do here. 480 return OK; 481 } 482 483 // Determine whether we're seeking beyond the known area. 484 bool shouldSeekBeyond = 485 (seekTimeUs > mSeekSyncPoints->keyAt(mSeekSyncPoints->size() - 1)); 486 487 // Determine the sync point to seek. 488 size_t index = 0; 489 for (; index < mSeekSyncPoints->size(); ++index) { 490 int64_t timeUs = mSeekSyncPoints->keyAt(index); 491 if (timeUs > seekTimeUs) { 492 break; 493 } 494 } 495 496 switch (seekMode) { 497 case MediaSource::ReadOptions::SEEK_NEXT_SYNC: 498 if (index == mSeekSyncPoints->size()) { 499 ALOGW("Next sync not found; starting from the latest sync."); 500 --index; 501 } 502 break; 503 case MediaSource::ReadOptions::SEEK_CLOSEST_SYNC: 504 case MediaSource::ReadOptions::SEEK_CLOSEST: 505 ALOGW("seekMode not supported: %d; falling back to PREVIOUS_SYNC", 506 seekMode); 507 // fall-through 508 case MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC: 509 if (index == 0) { 510 ALOGW("Previous sync not found; starting from the earliest " 511 "sync."); 512 } else { 513 --index; 514 } 515 break; 516 default: 517 return ERROR_UNSUPPORTED; 518 } 519 if (!shouldSeekBeyond || mOffset <= mSeekSyncPoints->valueAt(index)) { 520 int64_t actualSeekTimeUs = mSeekSyncPoints->keyAt(index); 521 mOffset = mSeekSyncPoints->valueAt(index); 522 status_t err = queueDiscontinuityForSeek(actualSeekTimeUs); 523 if (err != OK) { 524 return err; 525 } 526 } 527 528 if (shouldSeekBeyond) { 529 status_t err = seekBeyond(seekTimeUs); 530 if (err != OK) { 531 return err; 532 } 533 } 534 535 // Fast-forward to sync frame. 536 for (size_t i = 0; i < mSourceImpls.size(); ++i) { 537 const sp<AnotherPacketSource> &impl = mSourceImpls[i]; 538 status_t err; 539 feedUntilBufferAvailable(impl); 540 while (impl->hasBufferAvailable(&err)) { 541 sp<AMessage> meta = impl->getMetaAfterLastDequeued(0); 542 sp<ABuffer> buffer; 543 if (meta == NULL) { 544 return UNKNOWN_ERROR; 545 } 546 int32_t sync; 547 if (meta->findInt32("isSync", &sync) && sync) { 548 break; 549 } 550 err = impl->dequeueAccessUnit(&buffer); 551 if (err != OK) { 552 return err; 553 } 554 feedUntilBufferAvailable(impl); 555 } 556 } 557 558 return OK; 559} 560 561status_t MPEG2TSExtractor::queueDiscontinuityForSeek(int64_t actualSeekTimeUs) { 562 // Signal discontinuity 563 sp<AMessage> extra(new AMessage); 564 extra->setInt64(kATSParserKeyMediaTimeUs, actualSeekTimeUs); 565 mParser->signalDiscontinuity(ATSParser::DISCONTINUITY_TIME, extra); 566 567 // After discontinuity, impl should only have discontinuities 568 // with the last being what we queued. Dequeue them all here. 569 for (size_t i = 0; i < mSourceImpls.size(); ++i) { 570 const sp<AnotherPacketSource> &impl = mSourceImpls.itemAt(i); 571 sp<ABuffer> buffer; 572 status_t err; 573 while (impl->hasBufferAvailable(&err)) { 574 if (err != OK) { 575 return err; 576 } 577 err = impl->dequeueAccessUnit(&buffer); 578 // If the source contains anything but discontinuity, that's 579 // a programming mistake. 580 CHECK(err == INFO_DISCONTINUITY); 581 } 582 } 583 584 // Feed until we have a buffer for each source. 585 for (size_t i = 0; i < mSourceImpls.size(); ++i) { 586 const sp<AnotherPacketSource> &impl = mSourceImpls.itemAt(i); 587 sp<ABuffer> buffer; 588 status_t err = feedUntilBufferAvailable(impl); 589 if (err != OK) { 590 return err; 591 } 592 } 593 594 return OK; 595} 596 597status_t MPEG2TSExtractor::seekBeyond(int64_t seekTimeUs) { 598 // If we're seeking beyond where we know --- read until we reach there. 599 size_t syncPointsSize = mSeekSyncPoints->size(); 600 601 while (seekTimeUs > mSeekSyncPoints->keyAt( 602 mSeekSyncPoints->size() - 1)) { 603 status_t err; 604 if (syncPointsSize < mSeekSyncPoints->size()) { 605 syncPointsSize = mSeekSyncPoints->size(); 606 int64_t syncTimeUs = mSeekSyncPoints->keyAt(syncPointsSize - 1); 607 // Dequeue buffers before sync point in order to avoid too much 608 // cache building up. 609 sp<ABuffer> buffer; 610 for (size_t i = 0; i < mSourceImpls.size(); ++i) { 611 const sp<AnotherPacketSource> &impl = mSourceImpls[i]; 612 int64_t timeUs; 613 while ((err = impl->nextBufferTime(&timeUs)) == OK) { 614 if (timeUs < syncTimeUs) { 615 impl->dequeueAccessUnit(&buffer); 616 } else { 617 break; 618 } 619 } 620 if (err != OK && err != -EWOULDBLOCK) { 621 return err; 622 } 623 } 624 } 625 if (feedMore() != OK) { 626 return ERROR_END_OF_STREAM; 627 } 628 } 629 630 return OK; 631} 632 633status_t MPEG2TSExtractor::feedUntilBufferAvailable( 634 const sp<AnotherPacketSource> &impl) { 635 status_t finalResult; 636 while (!impl->hasBufferAvailable(&finalResult)) { 637 if (finalResult != OK) { 638 return finalResult; 639 } 640 641 status_t err = feedMore(); 642 if (err != OK) { 643 impl->signalEOS(err); 644 } 645 } 646 return OK; 647} 648 649//////////////////////////////////////////////////////////////////////////////// 650 651bool SniffMPEG2TS( 652 const sp<DataSource> &source, String8 *mimeType, float *confidence, 653 sp<AMessage> *) { 654 for (int i = 0; i < 5; ++i) { 655 char header; 656 if (source->readAt(kTSPacketSize * i, &header, 1) != 1 657 || header != 0x47) { 658 return false; 659 } 660 } 661 662 *confidence = 0.1f; 663 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2TS); 664 665 return true; 666} 667 668} // namespace android 669