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