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