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