GenericSource.cpp revision 360d6d0924f99b82ebacb5cfb6f7bca95e11b4ee
1/* 2 * Copyright (C) 2012 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 "GenericSource" 19 20#include "GenericSource.h" 21 22#include "AnotherPacketSource.h" 23 24#include <media/IMediaHTTPService.h> 25#include <media/stagefright/foundation/ABuffer.h> 26#include <media/stagefright/foundation/ADebug.h> 27#include <media/stagefright/foundation/AMessage.h> 28#include <media/stagefright/DataSource.h> 29#include <media/stagefright/FileSource.h> 30#include <media/stagefright/MediaBuffer.h> 31#include <media/stagefright/MediaDefs.h> 32#include <media/stagefright/MediaExtractor.h> 33#include <media/stagefright/MediaSource.h> 34#include <media/stagefright/MetaData.h> 35#include <media/stagefright/Utils.h> 36#include "../../libstagefright/include/DRMExtractor.h" 37#include "../../libstagefright/include/NuCachedSource2.h" 38#include "../../libstagefright/include/WVMExtractor.h" 39#include "../../libstagefright/include/HTTPBase.h" 40 41namespace android { 42 43NuPlayer::GenericSource::GenericSource( 44 const sp<AMessage> ¬ify, 45 bool uidValid, 46 uid_t uid) 47 : Source(notify), 48 mFetchSubtitleDataGeneration(0), 49 mFetchTimedTextDataGeneration(0), 50 mDurationUs(0ll), 51 mAudioIsVorbis(false), 52 mIsWidevine(false), 53 mUIDValid(uidValid), 54 mUID(uid), 55 mDrmManagerClient(NULL), 56 mMetaDataSize(-1ll), 57 mBitrate(-1ll), 58 mPollBufferingGeneration(0), 59 mPendingReadBufferTypes(0) { 60 resetDataSource(); 61 DataSource::RegisterDefaultSniffers(); 62} 63 64void NuPlayer::GenericSource::resetDataSource() { 65 mAudioTimeUs = 0; 66 mVideoTimeUs = 0; 67 mHTTPService.clear(); 68 mHttpSource.clear(); 69 mUri.clear(); 70 mUriHeaders.clear(); 71 mFd = -1; 72 mOffset = 0; 73 mLength = 0; 74 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0); 75 mDecryptHandle = NULL; 76 mDrmManagerClient = NULL; 77 mStarted = false; 78} 79 80status_t NuPlayer::GenericSource::setDataSource( 81 const sp<IMediaHTTPService> &httpService, 82 const char *url, 83 const KeyedVector<String8, String8> *headers) { 84 resetDataSource(); 85 86 mHTTPService = httpService; 87 mUri = url; 88 89 if (headers) { 90 mUriHeaders = *headers; 91 } 92 93 // delay data source creation to prepareAsync() to avoid blocking 94 // the calling thread in setDataSource for any significant time. 95 return OK; 96} 97 98status_t NuPlayer::GenericSource::setDataSource( 99 int fd, int64_t offset, int64_t length) { 100 resetDataSource(); 101 102 mFd = dup(fd); 103 mOffset = offset; 104 mLength = length; 105 106 // delay data source creation to prepareAsync() to avoid blocking 107 // the calling thread in setDataSource for any significant time. 108 return OK; 109} 110 111sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const { 112 return mFileMeta; 113} 114 115status_t NuPlayer::GenericSource::initFromDataSource() { 116 sp<MediaExtractor> extractor; 117 118 CHECK(mDataSource != NULL); 119 120 if (mIsWidevine) { 121 String8 mimeType; 122 float confidence; 123 sp<AMessage> dummy; 124 bool success; 125 126 success = SniffWVM(mDataSource, &mimeType, &confidence, &dummy); 127 if (!success 128 || strcasecmp( 129 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) { 130 ALOGE("unsupported widevine mime: %s", mimeType.string()); 131 return UNKNOWN_ERROR; 132 } 133 134 mWVMExtractor = new WVMExtractor(mDataSource); 135 mWVMExtractor->setAdaptiveStreamingMode(true); 136 if (mUIDValid) { 137 mWVMExtractor->setUID(mUID); 138 } 139 extractor = mWVMExtractor; 140 } else { 141 extractor = MediaExtractor::Create(mDataSource, 142 mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str()); 143 } 144 145 if (extractor == NULL) { 146 return UNKNOWN_ERROR; 147 } 148 149 if (extractor->getDrmFlag()) { 150 checkDrmStatus(mDataSource); 151 } 152 153 mFileMeta = extractor->getMetaData(); 154 if (mFileMeta != NULL) { 155 int64_t duration; 156 if (mFileMeta->findInt64(kKeyDuration, &duration)) { 157 mDurationUs = duration; 158 } 159 } 160 161 int32_t totalBitrate = 0; 162 163 size_t numtracks = extractor->countTracks(); 164 if (numtracks == 0) { 165 return UNKNOWN_ERROR; 166 } 167 168 for (size_t i = 0; i < numtracks; ++i) { 169 sp<MediaSource> track = extractor->getTrack(i); 170 171 sp<MetaData> meta = extractor->getTrackMetaData(i); 172 173 const char *mime; 174 CHECK(meta->findCString(kKeyMIMEType, &mime)); 175 176 // Do the string compare immediately with "mime", 177 // we can't assume "mime" would stay valid after another 178 // extractor operation, some extractors might modify meta 179 // during getTrack() and make it invalid. 180 if (!strncasecmp(mime, "audio/", 6)) { 181 if (mAudioTrack.mSource == NULL) { 182 mAudioTrack.mIndex = i; 183 mAudioTrack.mSource = track; 184 mAudioTrack.mPackets = 185 new AnotherPacketSource(mAudioTrack.mSource->getFormat()); 186 187 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { 188 mAudioIsVorbis = true; 189 } else { 190 mAudioIsVorbis = false; 191 } 192 } 193 } else if (!strncasecmp(mime, "video/", 6)) { 194 if (mVideoTrack.mSource == NULL) { 195 mVideoTrack.mIndex = i; 196 mVideoTrack.mSource = track; 197 mVideoTrack.mPackets = 198 new AnotherPacketSource(mVideoTrack.mSource->getFormat()); 199 200 // check if the source requires secure buffers 201 int32_t secure; 202 if (meta->findInt32(kKeyRequiresSecureBuffers, &secure) 203 && secure) { 204 mIsWidevine = true; 205 if (mUIDValid) { 206 extractor->setUID(mUID); 207 } 208 } 209 } 210 } 211 212 if (track != NULL) { 213 mSources.push(track); 214 int64_t durationUs; 215 if (meta->findInt64(kKeyDuration, &durationUs)) { 216 if (durationUs > mDurationUs) { 217 mDurationUs = durationUs; 218 } 219 } 220 221 int32_t bitrate; 222 if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) { 223 totalBitrate += bitrate; 224 } else { 225 totalBitrate = -1; 226 } 227 } 228 } 229 230 mBitrate = totalBitrate; 231 232 return OK; 233} 234 235void NuPlayer::GenericSource::checkDrmStatus(const sp<DataSource>& dataSource) { 236 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient); 237 if (mDecryptHandle != NULL) { 238 CHECK(mDrmManagerClient); 239 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) { 240 sp<AMessage> msg = dupNotify(); 241 msg->setInt32("what", kWhatDrmNoLicense); 242 msg->post(); 243 } 244 } 245} 246 247int64_t NuPlayer::GenericSource::getLastReadPosition() { 248 if (mAudioTrack.mSource != NULL) { 249 return mAudioTimeUs; 250 } else if (mVideoTrack.mSource != NULL) { 251 return mVideoTimeUs; 252 } else { 253 return 0; 254 } 255} 256 257status_t NuPlayer::GenericSource::setBuffers( 258 bool audio, Vector<MediaBuffer *> &buffers) { 259 if (mIsWidevine && !audio) { 260 return mVideoTrack.mSource->setBuffers(buffers); 261 } 262 return INVALID_OPERATION; 263} 264 265NuPlayer::GenericSource::~GenericSource() { 266 if (mLooper != NULL) { 267 mLooper->unregisterHandler(id()); 268 mLooper->stop(); 269 } 270} 271 272void NuPlayer::GenericSource::prepareAsync() { 273 if (mLooper == NULL) { 274 mLooper = new ALooper; 275 mLooper->setName("generic"); 276 mLooper->start(); 277 278 mLooper->registerHandler(this); 279 } 280 281 sp<AMessage> msg = new AMessage(kWhatPrepareAsync, id()); 282 msg->post(); 283} 284 285void NuPlayer::GenericSource::onPrepareAsync() { 286 // delayed data source creation 287 if (mDataSource == NULL) { 288 if (!mUri.empty()) { 289 const char* uri = mUri.c_str(); 290 mIsWidevine = !strncasecmp(uri, "widevine://", 11); 291 292 if (!strncasecmp("http://", uri, 7) 293 || !strncasecmp("https://", uri, 8) 294 || mIsWidevine) { 295 mHttpSource = DataSource::CreateMediaHTTP(mHTTPService); 296 if (mHttpSource == NULL) { 297 ALOGE("Failed to create http source!"); 298 notifyPreparedAndCleanup(UNKNOWN_ERROR); 299 return; 300 } 301 } 302 303 mDataSource = DataSource::CreateFromURI( 304 mHTTPService, uri, &mUriHeaders, &mContentType, 305 static_cast<HTTPBase *>(mHttpSource.get())); 306 } else { 307 // set to false first, if the extractor 308 // comes back as secure, set it to true then. 309 mIsWidevine = false; 310 311 mDataSource = new FileSource(mFd, mOffset, mLength); 312 } 313 314 if (mDataSource == NULL) { 315 ALOGE("Failed to create data source!"); 316 notifyPreparedAndCleanup(UNKNOWN_ERROR); 317 return; 318 } 319 320 if (mDataSource->flags() & DataSource::kIsCachingDataSource) { 321 mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get()); 322 } 323 324 if (mIsWidevine || mCachedSource != NULL) { 325 schedulePollBuffering(); 326 } 327 } 328 329 // check initial caching status 330 status_t err = prefillCacheIfNecessary(); 331 if (err != OK) { 332 if (err == -EAGAIN) { 333 (new AMessage(kWhatPrepareAsync, id()))->post(200000); 334 } else { 335 ALOGE("Failed to prefill data cache!"); 336 notifyPreparedAndCleanup(UNKNOWN_ERROR); 337 } 338 return; 339 } 340 341 // init extrator from data source 342 err = initFromDataSource(); 343 344 if (err != OK) { 345 ALOGE("Failed to init from data source!"); 346 notifyPreparedAndCleanup(err); 347 return; 348 } 349 350 if (mVideoTrack.mSource != NULL) { 351 sp<MetaData> meta = doGetFormatMeta(false /* audio */); 352 sp<AMessage> msg = new AMessage; 353 err = convertMetaDataToMessage(meta, &msg); 354 if(err != OK) { 355 notifyPreparedAndCleanup(err); 356 return; 357 } 358 notifyVideoSizeChanged(msg); 359 } 360 361 notifyFlagsChanged( 362 (mIsWidevine ? FLAG_SECURE : 0) 363 | FLAG_CAN_PAUSE 364 | FLAG_CAN_SEEK_BACKWARD 365 | FLAG_CAN_SEEK_FORWARD 366 | FLAG_CAN_SEEK); 367 368 notifyPrepared(); 369} 370 371void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) { 372 if (err != OK) { 373 mMetaDataSize = -1ll; 374 mContentType = ""; 375 mSniffedMIME = ""; 376 mDataSource.clear(); 377 mCachedSource.clear(); 378 mHttpSource.clear(); 379 380 cancelPollBuffering(); 381 } 382 notifyPrepared(err); 383} 384 385status_t NuPlayer::GenericSource::prefillCacheIfNecessary() { 386 CHECK(mDataSource != NULL); 387 388 if (mCachedSource == NULL) { 389 // no prefill if the data source is not cached 390 return OK; 391 } 392 393 // We're not doing this for streams that appear to be audio-only 394 // streams to ensure that even low bandwidth streams start 395 // playing back fairly instantly. 396 if (!strncasecmp(mContentType.string(), "audio/", 6)) { 397 return OK; 398 } 399 400 // We're going to prefill the cache before trying to instantiate 401 // the extractor below, as the latter is an operation that otherwise 402 // could block on the datasource for a significant amount of time. 403 // During that time we'd be unable to abort the preparation phase 404 // without this prefill. 405 406 // Initially make sure we have at least 192 KB for the sniff 407 // to complete without blocking. 408 static const size_t kMinBytesForSniffing = 192 * 1024; 409 static const size_t kDefaultMetaSize = 200000; 410 411 status_t finalStatus; 412 413 size_t cachedDataRemaining = 414 mCachedSource->approxDataRemaining(&finalStatus); 415 416 if (finalStatus != OK || (mMetaDataSize >= 0 417 && (off64_t)cachedDataRemaining >= mMetaDataSize)) { 418 ALOGV("stop caching, status %d, " 419 "metaDataSize %lld, cachedDataRemaining %zu", 420 finalStatus, mMetaDataSize, cachedDataRemaining); 421 return OK; 422 } 423 424 ALOGV("now cached %zu bytes of data", cachedDataRemaining); 425 426 if (mMetaDataSize < 0 427 && cachedDataRemaining >= kMinBytesForSniffing) { 428 String8 tmp; 429 float confidence; 430 sp<AMessage> meta; 431 if (!mCachedSource->sniff(&tmp, &confidence, &meta)) { 432 return UNKNOWN_ERROR; 433 } 434 435 // We successfully identified the file's extractor to 436 // be, remember this mime type so we don't have to 437 // sniff it again when we call MediaExtractor::Create() 438 mSniffedMIME = tmp.string(); 439 440 if (meta == NULL 441 || !meta->findInt64("meta-data-size", 442 reinterpret_cast<int64_t*>(&mMetaDataSize))) { 443 mMetaDataSize = kDefaultMetaSize; 444 } 445 446 if (mMetaDataSize < 0ll) { 447 ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize); 448 return UNKNOWN_ERROR; 449 } 450 } 451 452 return -EAGAIN; 453} 454 455void NuPlayer::GenericSource::start() { 456 ALOGI("start"); 457 458 if (mAudioTrack.mSource != NULL) { 459 CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK); 460 461 postReadBuffer(MEDIA_TRACK_TYPE_AUDIO); 462 } 463 464 if (mVideoTrack.mSource != NULL) { 465 CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK); 466 467 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO); 468 } 469 470 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000); 471 mStarted = true; 472} 473 474void NuPlayer::GenericSource::stop() { 475 // nothing to do, just account for DRM playback status 476 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0); 477 mStarted = false; 478} 479 480void NuPlayer::GenericSource::pause() { 481 // nothing to do, just account for DRM playback status 482 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0); 483 mStarted = false; 484} 485 486void NuPlayer::GenericSource::resume() { 487 // nothing to do, just account for DRM playback status 488 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000); 489 mStarted = true; 490} 491 492void NuPlayer::GenericSource::disconnect() { 493 if (mDataSource != NULL) { 494 // disconnect data source 495 if (mDataSource->flags() & DataSource::kIsCachingDataSource) { 496 static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect(); 497 } 498 } else if (mHttpSource != NULL) { 499 static_cast<HTTPBase *>(mHttpSource.get())->disconnect(); 500 } 501} 502 503void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) { 504 if (mDecryptHandle != NULL) { 505 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position); 506 } 507 mSubtitleTrack.mPackets = new AnotherPacketSource(NULL); 508 mTimedTextTrack.mPackets = new AnotherPacketSource(NULL); 509} 510 511status_t NuPlayer::GenericSource::feedMoreTSData() { 512 return OK; 513} 514 515void NuPlayer::GenericSource::schedulePollBuffering() { 516 sp<AMessage> msg = new AMessage(kWhatPollBuffering, id()); 517 msg->setInt32("generation", mPollBufferingGeneration); 518 msg->post(1000000ll); 519} 520 521void NuPlayer::GenericSource::cancelPollBuffering() { 522 ++mPollBufferingGeneration; 523} 524 525void NuPlayer::GenericSource::notifyBufferingUpdate(int percentage) { 526 sp<AMessage> msg = dupNotify(); 527 msg->setInt32("what", kWhatBufferingUpdate); 528 msg->setInt32("percentage", percentage); 529 msg->post(); 530} 531 532void NuPlayer::GenericSource::onPollBuffering() { 533 status_t finalStatus = UNKNOWN_ERROR; 534 int64_t cachedDurationUs = 0ll; 535 536 if (mCachedSource != NULL) { 537 size_t cachedDataRemaining = 538 mCachedSource->approxDataRemaining(&finalStatus); 539 540 if (finalStatus == OK) { 541 off64_t size; 542 int64_t bitrate = 0ll; 543 if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) { 544 bitrate = size * 8000000ll / mDurationUs; 545 } else if (mBitrate > 0) { 546 bitrate = mBitrate; 547 } 548 if (bitrate > 0) { 549 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate; 550 } 551 } 552 } else if (mWVMExtractor != NULL) { 553 cachedDurationUs 554 = mWVMExtractor->getCachedDurationUs(&finalStatus); 555 } 556 557 if (finalStatus == ERROR_END_OF_STREAM) { 558 notifyBufferingUpdate(100); 559 cancelPollBuffering(); 560 return; 561 } else if (cachedDurationUs > 0ll && mDurationUs > 0ll) { 562 int percentage = 100.0 * cachedDurationUs / mDurationUs; 563 if (percentage > 100) { 564 percentage = 100; 565 } 566 567 notifyBufferingUpdate(percentage); 568 } 569 570 schedulePollBuffering(); 571} 572 573 574void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) { 575 switch (msg->what()) { 576 case kWhatPrepareAsync: 577 { 578 onPrepareAsync(); 579 break; 580 } 581 case kWhatFetchSubtitleData: 582 { 583 fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, 584 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); 585 break; 586 } 587 588 case kWhatFetchTimedTextData: 589 { 590 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, 591 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); 592 break; 593 } 594 595 case kWhatSendSubtitleData: 596 { 597 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, 598 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); 599 break; 600 } 601 602 case kWhatSendTimedTextData: 603 { 604 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, 605 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); 606 break; 607 } 608 609 case kWhatChangeAVSource: 610 { 611 int32_t trackIndex; 612 CHECK(msg->findInt32("trackIndex", &trackIndex)); 613 const sp<MediaSource> source = mSources.itemAt(trackIndex); 614 615 Track* track; 616 const char *mime; 617 media_track_type trackType, counterpartType; 618 sp<MetaData> meta = source->getFormat(); 619 meta->findCString(kKeyMIMEType, &mime); 620 if (!strncasecmp(mime, "audio/", 6)) { 621 track = &mAudioTrack; 622 trackType = MEDIA_TRACK_TYPE_AUDIO; 623 counterpartType = MEDIA_TRACK_TYPE_VIDEO;; 624 } else { 625 CHECK(!strncasecmp(mime, "video/", 6)); 626 track = &mVideoTrack; 627 trackType = MEDIA_TRACK_TYPE_VIDEO; 628 counterpartType = MEDIA_TRACK_TYPE_AUDIO;; 629 } 630 631 632 if (track->mSource != NULL) { 633 track->mSource->stop(); 634 } 635 track->mSource = source; 636 track->mSource->start(); 637 track->mIndex = trackIndex; 638 639 status_t avail; 640 if (!track->mPackets->hasBufferAvailable(&avail)) { 641 // sync from other source 642 TRESPASS(); 643 break; 644 } 645 646 int64_t timeUs, actualTimeUs; 647 const bool formatChange = true; 648 sp<AMessage> latestMeta = track->mPackets->getLatestEnqueuedMeta(); 649 CHECK(latestMeta != NULL && latestMeta->findInt64("timeUs", &timeUs)); 650 readBuffer(trackType, timeUs, &actualTimeUs, formatChange); 651 readBuffer(counterpartType, -1, NULL, formatChange); 652 ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs); 653 654 break; 655 } 656 case kWhatPollBuffering: 657 { 658 int32_t generation; 659 CHECK(msg->findInt32("generation", &generation)); 660 if (generation == mPollBufferingGeneration) { 661 onPollBuffering(); 662 } 663 break; 664 } 665 666 case kWhatGetFormat: 667 { 668 onGetFormatMeta(msg); 669 break; 670 } 671 672 case kWhatGetSelectedTrack: 673 { 674 onGetSelectedTrack(msg); 675 break; 676 } 677 678 case kWhatSelectTrack: 679 { 680 onSelectTrack(msg); 681 break; 682 } 683 684 case kWhatSeek: 685 { 686 onSeek(msg); 687 break; 688 } 689 690 case kWhatReadBuffer: 691 { 692 onReadBuffer(msg); 693 break; 694 } 695 696 default: 697 Source::onMessageReceived(msg); 698 break; 699 } 700} 701 702void NuPlayer::GenericSource::fetchTextData( 703 uint32_t sendWhat, 704 media_track_type type, 705 int32_t curGen, 706 sp<AnotherPacketSource> packets, 707 sp<AMessage> msg) { 708 int32_t msgGeneration; 709 CHECK(msg->findInt32("generation", &msgGeneration)); 710 if (msgGeneration != curGen) { 711 // stale 712 return; 713 } 714 715 int32_t avail; 716 if (packets->hasBufferAvailable(&avail)) { 717 return; 718 } 719 720 int64_t timeUs; 721 CHECK(msg->findInt64("timeUs", &timeUs)); 722 723 int64_t subTimeUs; 724 readBuffer(type, timeUs, &subTimeUs); 725 726 int64_t delayUs = subTimeUs - timeUs; 727 if (msg->what() == kWhatFetchSubtitleData) { 728 const int64_t oneSecUs = 1000000ll; 729 delayUs -= oneSecUs; 730 } 731 sp<AMessage> msg2 = new AMessage(sendWhat, id()); 732 msg2->setInt32("generation", msgGeneration); 733 msg2->post(delayUs < 0 ? 0 : delayUs); 734} 735 736void NuPlayer::GenericSource::sendTextData( 737 uint32_t what, 738 media_track_type type, 739 int32_t curGen, 740 sp<AnotherPacketSource> packets, 741 sp<AMessage> msg) { 742 int32_t msgGeneration; 743 CHECK(msg->findInt32("generation", &msgGeneration)); 744 if (msgGeneration != curGen) { 745 // stale 746 return; 747 } 748 749 int64_t subTimeUs; 750 if (packets->nextBufferTime(&subTimeUs) != OK) { 751 return; 752 } 753 754 int64_t nextSubTimeUs; 755 readBuffer(type, -1, &nextSubTimeUs); 756 757 sp<ABuffer> buffer; 758 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer); 759 if (dequeueStatus == OK) { 760 sp<AMessage> notify = dupNotify(); 761 notify->setInt32("what", what); 762 notify->setBuffer("buffer", buffer); 763 notify->post(); 764 765 const int64_t delayUs = nextSubTimeUs - subTimeUs; 766 msg->post(delayUs < 0 ? 0 : delayUs); 767 } 768} 769 770sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) { 771 sp<AMessage> msg = new AMessage(kWhatGetFormat, id()); 772 msg->setInt32("audio", audio); 773 774 sp<AMessage> response; 775 void *format; 776 status_t err = msg->postAndAwaitResponse(&response); 777 if (err == OK && response != NULL) { 778 CHECK(response->findPointer("format", &format)); 779 return (MetaData *)format; 780 } else { 781 return NULL; 782 } 783} 784 785void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const { 786 int32_t audio; 787 CHECK(msg->findInt32("audio", &audio)); 788 789 sp<AMessage> response = new AMessage; 790 sp<MetaData> format = doGetFormatMeta(audio); 791 response->setPointer("format", format.get()); 792 793 uint32_t replyID; 794 CHECK(msg->senderAwaitsResponse(&replyID)); 795 response->postReply(replyID); 796} 797 798sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const { 799 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource; 800 801 if (source == NULL) { 802 return NULL; 803 } 804 805 return source->getFormat(); 806} 807 808status_t NuPlayer::GenericSource::dequeueAccessUnit( 809 bool audio, sp<ABuffer> *accessUnit) { 810 Track *track = audio ? &mAudioTrack : &mVideoTrack; 811 812 if (track->mSource == NULL) { 813 return -EWOULDBLOCK; 814 } 815 816 if (mIsWidevine && !audio) { 817 // try to read a buffer as we may not have been able to the last time 818 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO); 819 } 820 821 status_t finalResult; 822 if (!track->mPackets->hasBufferAvailable(&finalResult)) { 823 return (finalResult == OK ? -EWOULDBLOCK : finalResult); 824 } 825 826 status_t result = track->mPackets->dequeueAccessUnit(accessUnit); 827 828 if (!track->mPackets->hasBufferAvailable(&finalResult)) { 829 postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO); 830 } 831 832 if (result != OK) { 833 if (mSubtitleTrack.mSource != NULL) { 834 mSubtitleTrack.mPackets->clear(); 835 mFetchSubtitleDataGeneration++; 836 } 837 if (mTimedTextTrack.mSource != NULL) { 838 mTimedTextTrack.mPackets->clear(); 839 mFetchTimedTextDataGeneration++; 840 } 841 return result; 842 } 843 844 int64_t timeUs; 845 status_t eosResult; // ignored 846 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); 847 848 if (mSubtitleTrack.mSource != NULL 849 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { 850 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id()); 851 msg->setInt64("timeUs", timeUs); 852 msg->setInt32("generation", mFetchSubtitleDataGeneration); 853 msg->post(); 854 } 855 856 if (mTimedTextTrack.mSource != NULL 857 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) { 858 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id()); 859 msg->setInt64("timeUs", timeUs); 860 msg->setInt32("generation", mFetchTimedTextDataGeneration); 861 msg->post(); 862 } 863 864 return result; 865} 866 867status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) { 868 *durationUs = mDurationUs; 869 return OK; 870} 871 872size_t NuPlayer::GenericSource::getTrackCount() const { 873 return mSources.size(); 874} 875 876sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const { 877 size_t trackCount = mSources.size(); 878 if (trackIndex >= trackCount) { 879 return NULL; 880 } 881 882 sp<AMessage> format = new AMessage(); 883 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat(); 884 885 const char *mime; 886 CHECK(meta->findCString(kKeyMIMEType, &mime)); 887 888 int32_t trackType; 889 if (!strncasecmp(mime, "video/", 6)) { 890 trackType = MEDIA_TRACK_TYPE_VIDEO; 891 } else if (!strncasecmp(mime, "audio/", 6)) { 892 trackType = MEDIA_TRACK_TYPE_AUDIO; 893 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { 894 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT; 895 } else { 896 trackType = MEDIA_TRACK_TYPE_UNKNOWN; 897 } 898 format->setInt32("type", trackType); 899 900 const char *lang; 901 if (!meta->findCString(kKeyMediaLanguage, &lang)) { 902 lang = "und"; 903 } 904 format->setString("language", lang); 905 906 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 907 format->setString("mime", mime); 908 909 int32_t isAutoselect = 1, isDefault = 0, isForced = 0; 910 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect); 911 meta->findInt32(kKeyTrackIsDefault, &isDefault); 912 meta->findInt32(kKeyTrackIsForced, &isForced); 913 914 format->setInt32("auto", !!isAutoselect); 915 format->setInt32("default", !!isDefault); 916 format->setInt32("forced", !!isForced); 917 } 918 919 return format; 920} 921 922ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const { 923 sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id()); 924 msg->setInt32("type", type); 925 926 sp<AMessage> response; 927 int32_t index; 928 status_t err = msg->postAndAwaitResponse(&response); 929 if (err == OK && response != NULL) { 930 CHECK(response->findInt32("index", &index)); 931 return index; 932 } else { 933 return -1; 934 } 935} 936 937void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const { 938 int32_t tmpType; 939 CHECK(msg->findInt32("type", &tmpType)); 940 media_track_type type = (media_track_type)tmpType; 941 942 sp<AMessage> response = new AMessage; 943 ssize_t index = doGetSelectedTrack(type); 944 response->setInt32("index", index); 945 946 uint32_t replyID; 947 CHECK(msg->senderAwaitsResponse(&replyID)); 948 response->postReply(replyID); 949} 950 951ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const { 952 const Track *track = NULL; 953 switch (type) { 954 case MEDIA_TRACK_TYPE_VIDEO: 955 track = &mVideoTrack; 956 break; 957 case MEDIA_TRACK_TYPE_AUDIO: 958 track = &mAudioTrack; 959 break; 960 case MEDIA_TRACK_TYPE_TIMEDTEXT: 961 track = &mTimedTextTrack; 962 break; 963 case MEDIA_TRACK_TYPE_SUBTITLE: 964 track = &mSubtitleTrack; 965 break; 966 default: 967 break; 968 } 969 970 if (track != NULL && track->mSource != NULL) { 971 return track->mIndex; 972 } 973 974 return -1; 975} 976 977status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { 978 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex); 979 sp<AMessage> msg = new AMessage(kWhatSelectTrack, id()); 980 msg->setInt32("trackIndex", trackIndex); 981 msg->setInt32("select", select); 982 983 sp<AMessage> response; 984 status_t err = msg->postAndAwaitResponse(&response); 985 if (err == OK && response != NULL) { 986 CHECK(response->findInt32("err", &err)); 987 } 988 989 return err; 990} 991 992void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) { 993 int32_t trackIndex, select; 994 CHECK(msg->findInt32("trackIndex", &trackIndex)); 995 CHECK(msg->findInt32("select", &select)); 996 997 sp<AMessage> response = new AMessage; 998 status_t err = doSelectTrack(trackIndex, select); 999 response->setInt32("err", err); 1000 1001 uint32_t replyID; 1002 CHECK(msg->senderAwaitsResponse(&replyID)); 1003 response->postReply(replyID); 1004} 1005 1006status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select) { 1007 if (trackIndex >= mSources.size()) { 1008 return BAD_INDEX; 1009 } 1010 1011 if (!select) { 1012 Track* track = NULL; 1013 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) { 1014 track = &mSubtitleTrack; 1015 mFetchSubtitleDataGeneration++; 1016 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) { 1017 track = &mTimedTextTrack; 1018 mFetchTimedTextDataGeneration++; 1019 } 1020 if (track == NULL) { 1021 return INVALID_OPERATION; 1022 } 1023 track->mSource->stop(); 1024 track->mSource = NULL; 1025 track->mPackets->clear(); 1026 return OK; 1027 } 1028 1029 const sp<MediaSource> source = mSources.itemAt(trackIndex); 1030 sp<MetaData> meta = source->getFormat(); 1031 const char *mime; 1032 CHECK(meta->findCString(kKeyMIMEType, &mime)); 1033 if (!strncasecmp(mime, "text/", 5)) { 1034 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP); 1035 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack; 1036 if (track->mSource != NULL && track->mIndex == trackIndex) { 1037 return OK; 1038 } 1039 track->mIndex = trackIndex; 1040 if (track->mSource != NULL) { 1041 track->mSource->stop(); 1042 } 1043 track->mSource = mSources.itemAt(trackIndex); 1044 track->mSource->start(); 1045 if (track->mPackets == NULL) { 1046 track->mPackets = new AnotherPacketSource(track->mSource->getFormat()); 1047 } else { 1048 track->mPackets->clear(); 1049 track->mPackets->setFormat(track->mSource->getFormat()); 1050 1051 } 1052 1053 if (isSubtitle) { 1054 mFetchSubtitleDataGeneration++; 1055 } else { 1056 mFetchTimedTextDataGeneration++; 1057 } 1058 1059 return OK; 1060 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) { 1061 bool audio = !strncasecmp(mime, "audio/", 6); 1062 Track *track = audio ? &mAudioTrack : &mVideoTrack; 1063 if (track->mSource != NULL && track->mIndex == trackIndex) { 1064 return OK; 1065 } 1066 1067 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id()); 1068 msg->setInt32("trackIndex", trackIndex); 1069 msg->post(); 1070 return OK; 1071 } 1072 1073 return INVALID_OPERATION; 1074} 1075 1076status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) { 1077 sp<AMessage> msg = new AMessage(kWhatSeek, id()); 1078 msg->setInt64("seekTimeUs", seekTimeUs); 1079 1080 sp<AMessage> response; 1081 status_t err = msg->postAndAwaitResponse(&response); 1082 if (err == OK && response != NULL) { 1083 CHECK(response->findInt32("err", &err)); 1084 } 1085 1086 return err; 1087} 1088 1089void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) { 1090 int64_t seekTimeUs; 1091 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs)); 1092 1093 sp<AMessage> response = new AMessage; 1094 status_t err = doSeek(seekTimeUs); 1095 response->setInt32("err", err); 1096 1097 uint32_t replyID; 1098 CHECK(msg->senderAwaitsResponse(&replyID)); 1099 response->postReply(replyID); 1100} 1101 1102status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) { 1103 if (mVideoTrack.mSource != NULL) { 1104 int64_t actualTimeUs; 1105 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs); 1106 1107 seekTimeUs = actualTimeUs; 1108 } 1109 1110 if (mAudioTrack.mSource != NULL) { 1111 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs); 1112 } 1113 1114 setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000); 1115 if (!mStarted) { 1116 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0); 1117 } 1118 return OK; 1119} 1120 1121sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer( 1122 MediaBuffer* mb, 1123 media_track_type trackType, 1124 int64_t *actualTimeUs) { 1125 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO; 1126 size_t outLength = mb->range_length(); 1127 1128 if (audio && mAudioIsVorbis) { 1129 outLength += sizeof(int32_t); 1130 } 1131 1132 sp<ABuffer> ab; 1133 if (mIsWidevine && !audio) { 1134 // data is already provided in the buffer 1135 ab = new ABuffer(NULL, mb->range_length()); 1136 mb->add_ref(); 1137 ab->setMediaBufferBase(mb); 1138 } else { 1139 ab = new ABuffer(outLength); 1140 memcpy(ab->data(), 1141 (const uint8_t *)mb->data() + mb->range_offset(), 1142 mb->range_length()); 1143 } 1144 1145 if (audio && mAudioIsVorbis) { 1146 int32_t numPageSamples; 1147 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) { 1148 numPageSamples = -1; 1149 } 1150 1151 uint8_t* abEnd = ab->data() + mb->range_length(); 1152 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples)); 1153 } 1154 1155 sp<AMessage> meta = ab->meta(); 1156 1157 int64_t timeUs; 1158 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs)); 1159 meta->setInt64("timeUs", timeUs); 1160 1161 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) { 1162 const char *mime; 1163 CHECK(mTimedTextTrack.mSource != NULL 1164 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime)); 1165 meta->setString("mime", mime); 1166 } 1167 1168 int64_t durationUs; 1169 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) { 1170 meta->setInt64("durationUs", durationUs); 1171 } 1172 1173 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 1174 meta->setInt32("trackIndex", mSubtitleTrack.mIndex); 1175 } 1176 1177 if (actualTimeUs) { 1178 *actualTimeUs = timeUs; 1179 } 1180 1181 mb->release(); 1182 mb = NULL; 1183 1184 return ab; 1185} 1186 1187void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) { 1188 Mutex::Autolock _l(mReadBufferLock); 1189 1190 if ((mPendingReadBufferTypes & (1 << trackType)) == 0) { 1191 mPendingReadBufferTypes |= (1 << trackType); 1192 sp<AMessage> msg = new AMessage(kWhatReadBuffer, id()); 1193 msg->setInt32("trackType", trackType); 1194 msg->post(); 1195 } 1196} 1197 1198void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) { 1199 int32_t tmpType; 1200 CHECK(msg->findInt32("trackType", &tmpType)); 1201 media_track_type trackType = (media_track_type)tmpType; 1202 { 1203 // only protect the variable change, as readBuffer may 1204 // take considerable time. This may result in one extra 1205 // read being processed, but that is benign. 1206 Mutex::Autolock _l(mReadBufferLock); 1207 mPendingReadBufferTypes &= ~(1 << trackType); 1208 } 1209 readBuffer(trackType); 1210} 1211 1212void NuPlayer::GenericSource::readBuffer( 1213 media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) { 1214 Track *track; 1215 size_t maxBuffers = 1; 1216 switch (trackType) { 1217 case MEDIA_TRACK_TYPE_VIDEO: 1218 track = &mVideoTrack; 1219 if (mIsWidevine) { 1220 maxBuffers = 2; 1221 } 1222 break; 1223 case MEDIA_TRACK_TYPE_AUDIO: 1224 track = &mAudioTrack; 1225 if (mIsWidevine) { 1226 maxBuffers = 8; 1227 } else { 1228 maxBuffers = 64; 1229 } 1230 break; 1231 case MEDIA_TRACK_TYPE_SUBTITLE: 1232 track = &mSubtitleTrack; 1233 break; 1234 case MEDIA_TRACK_TYPE_TIMEDTEXT: 1235 track = &mTimedTextTrack; 1236 break; 1237 default: 1238 TRESPASS(); 1239 } 1240 1241 if (track->mSource == NULL) { 1242 return; 1243 } 1244 1245 if (actualTimeUs) { 1246 *actualTimeUs = seekTimeUs; 1247 } 1248 1249 MediaSource::ReadOptions options; 1250 1251 bool seeking = false; 1252 1253 if (seekTimeUs >= 0) { 1254 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 1255 seeking = true; 1256 } 1257 1258 if (mIsWidevine && trackType != MEDIA_TRACK_TYPE_AUDIO) { 1259 options.setNonBlocking(); 1260 } 1261 1262 for (size_t numBuffers = 0; numBuffers < maxBuffers; ) { 1263 MediaBuffer *mbuf; 1264 status_t err = track->mSource->read(&mbuf, &options); 1265 1266 options.clearSeekTo(); 1267 1268 if (err == OK) { 1269 int64_t timeUs; 1270 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); 1271 if (trackType == MEDIA_TRACK_TYPE_AUDIO) { 1272 mAudioTimeUs = timeUs; 1273 } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) { 1274 mVideoTimeUs = timeUs; 1275 } 1276 1277 // formatChange && seeking: track whose source is changed during selection 1278 // formatChange && !seeking: track whose source is not changed during selection 1279 // !formatChange: normal seek 1280 if ((seeking || formatChange) 1281 && (trackType == MEDIA_TRACK_TYPE_AUDIO 1282 || trackType == MEDIA_TRACK_TYPE_VIDEO)) { 1283 ATSParser::DiscontinuityType type = formatChange 1284 ? (seeking 1285 ? ATSParser::DISCONTINUITY_FORMATCHANGE 1286 : ATSParser::DISCONTINUITY_NONE) 1287 : ATSParser::DISCONTINUITY_SEEK; 1288 track->mPackets->queueDiscontinuity( type, NULL, true /* discard */); 1289 } 1290 1291 sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs); 1292 track->mPackets->queueAccessUnit(buffer); 1293 formatChange = false; 1294 seeking = false; 1295 ++numBuffers; 1296 } else if (err == WOULD_BLOCK) { 1297 break; 1298 } else if (err == INFO_FORMAT_CHANGED) { 1299#if 0 1300 track->mPackets->queueDiscontinuity( 1301 ATSParser::DISCONTINUITY_FORMATCHANGE, 1302 NULL, 1303 false /* discard */); 1304#endif 1305 } else { 1306 track->mPackets->signalEOS(err); 1307 break; 1308 } 1309 } 1310} 1311 1312} // namespace android 1313