1 /* 2 * Copyright 2017 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 "GenericSource2" 19 20 #include "GenericSource2.h" 21 #include "NuPlayer2Drm.h" 22 23 #include "AnotherPacketSource.h" 24 #include <binder/IServiceManager.h> 25 #include <cutils/properties.h> 26 #include <media/DataSource.h> 27 #include <media/MediaBufferHolder.h> 28 #include <media/IMediaExtractorService.h> 29 #include <media/IMediaSource.h> 30 #include <media/MediaHTTPService.h> 31 #include <media/MediaExtractor.h> 32 #include <media/MediaSource.h> 33 #include <media/NdkWrapper.h> 34 #include <media/stagefright/foundation/ABuffer.h> 35 #include <media/stagefright/foundation/ADebug.h> 36 #include <media/stagefright/foundation/AMessage.h> 37 #include <media/stagefright/DataSourceFactory.h> 38 #include <media/stagefright/InterfaceUtils.h> 39 #include <media/stagefright/MediaBuffer.h> 40 #include <media/stagefright/MediaClock.h> 41 #include <media/stagefright/MediaDefs.h> 42 #include <media/stagefright/MediaExtractorFactory.h> 43 #include <media/stagefright/MetaData.h> 44 #include <media/stagefright/NdkUtils.h> 45 #include <media/stagefright/Utils.h> 46 #include "../../libstagefright/include/NuCachedSource2.h" 47 #include "../../libstagefright/include/HTTPBase.h" 48 49 namespace android { 50 51 static const int kInitialMarkMs = 5000; // 5secs 52 53 //static const int kPausePlaybackMarkMs = 2000; // 2secs 54 static const int kResumePlaybackMarkMs = 15000; // 15secs 55 56 NuPlayer2::GenericSource2::GenericSource2( 57 const sp<AMessage> ¬ify, 58 uid_t uid, 59 const sp<MediaClock> &mediaClock) 60 : Source(notify), 61 mAudioTimeUs(0), 62 mAudioLastDequeueTimeUs(0), 63 mVideoTimeUs(0), 64 mVideoLastDequeueTimeUs(0), 65 mPrevBufferPercentage(-1), 66 mPollBufferingGeneration(0), 67 mSentPauseOnBuffering(false), 68 mAudioDataGeneration(0), 69 mVideoDataGeneration(0), 70 mFetchSubtitleDataGeneration(0), 71 mFetchTimedTextDataGeneration(0), 72 mDurationUs(-1ll), 73 mAudioIsVorbis(false), 74 mIsSecure(false), 75 mIsStreaming(false), 76 mUID(uid), 77 mMediaClock(mediaClock), 78 mFd(-1), 79 mBitrate(-1ll), 80 mPendingReadBufferTypes(0) { 81 ALOGV("GenericSource2"); 82 CHECK(mediaClock != NULL); 83 84 mBufferingSettings.mInitialMarkMs = kInitialMarkMs; 85 mBufferingSettings.mResumePlaybackMarkMs = kResumePlaybackMarkMs; 86 resetDataSource(); 87 } 88 89 void NuPlayer2::GenericSource2::resetDataSource() { 90 ALOGV("resetDataSource"); 91 92 mHTTPService.clear(); 93 mHttpSource.clear(); 94 mDisconnected = false; 95 mUri.clear(); 96 mUriHeaders.clear(); 97 if (mFd >= 0) { 98 close(mFd); 99 mFd = -1; 100 } 101 mOffset = 0; 102 mLength = 0; 103 mStarted = false; 104 mPreparing = false; 105 106 mIsDrmProtected = false; 107 mIsDrmReleased = false; 108 mIsSecure = false; 109 mMimes.clear(); 110 } 111 112 status_t NuPlayer2::GenericSource2::setDataSource( 113 const sp<MediaHTTPService> &httpService, 114 const char *url, 115 const KeyedVector<String8, String8> *headers) { 116 Mutex::Autolock _l(mLock); 117 ALOGV("setDataSource url: %s", url); 118 119 resetDataSource(); 120 121 mHTTPService = httpService; 122 mUri = url; 123 124 if (headers) { 125 mUriHeaders = *headers; 126 } 127 128 // delay data source creation to prepareAsync() to avoid blocking 129 // the calling thread in setDataSource for any significant time. 130 return OK; 131 } 132 133 status_t NuPlayer2::GenericSource2::setDataSource( 134 int fd, int64_t offset, int64_t length) { 135 Mutex::Autolock _l(mLock); 136 ALOGV("setDataSource %d/%lld/%lld", fd, (long long)offset, (long long)length); 137 138 resetDataSource(); 139 140 mFd = dup(fd); 141 mOffset = offset; 142 mLength = length; 143 144 // delay data source creation to prepareAsync() to avoid blocking 145 // the calling thread in setDataSource for any significant time. 146 return OK; 147 } 148 149 status_t NuPlayer2::GenericSource2::setDataSource(const sp<DataSource>& source) { 150 Mutex::Autolock _l(mLock); 151 ALOGV("setDataSource (source: %p)", source.get()); 152 153 resetDataSource(); 154 mDataSource = source; 155 return OK; 156 } 157 158 sp<MetaData> NuPlayer2::GenericSource2::getFileFormatMeta() const { 159 Mutex::Autolock _l(mLock); 160 return mFileMeta; 161 } 162 163 status_t NuPlayer2::GenericSource2::initFromDataSource() { 164 mExtractor = new AMediaExtractorWrapper(AMediaExtractor_new()); 165 CHECK(mDataSource != NULL || mFd != -1); 166 sp<DataSource> dataSource = mDataSource; 167 const int fd = mFd; 168 const int64_t offset = mOffset; 169 const int64_t length = mLength; 170 171 mLock.unlock(); 172 // This might take long time if data source is not reliable. 173 status_t err; 174 if (dataSource != nullptr) { 175 mDataSourceWrapper = new AMediaDataSourceWrapper(dataSource); 176 err = mExtractor->setDataSource(mDataSourceWrapper->getAMediaDataSource()); 177 } else { 178 err = mExtractor->setDataSource(fd, offset, length); 179 } 180 181 if (err != OK) { 182 ALOGE("initFromDataSource, failed to create data source!"); 183 mLock.lock(); 184 return UNKNOWN_ERROR; 185 } 186 187 size_t numtracks = mExtractor->getTrackCount(); 188 if (numtracks == 0) { 189 ALOGE("initFromDataSource, source has no track!"); 190 mLock.lock(); 191 return UNKNOWN_ERROR; 192 } 193 194 mLock.lock(); 195 mFd = -1; 196 mDataSource = dataSource; 197 mFileMeta = convertMediaFormatWrapperToMetaData(mExtractor->getFormat()); 198 if (mFileMeta != NULL) { 199 int64_t duration; 200 if (mFileMeta->findInt64(kKeyDuration, &duration)) { 201 mDurationUs = duration; 202 } 203 } 204 205 int32_t totalBitrate = 0; 206 207 mMimes.clear(); 208 209 for (size_t i = 0; i < numtracks; ++i) { 210 211 sp<AMediaFormatWrapper> trackFormat = mExtractor->getTrackFormat(i); 212 if (trackFormat == NULL) { 213 ALOGE("no metadata for track %zu", i); 214 return UNKNOWN_ERROR; 215 } 216 217 sp<AMediaExtractorWrapper> trackExtractor = new AMediaExtractorWrapper(AMediaExtractor_new()); 218 if (mDataSourceWrapper != nullptr) { 219 err = trackExtractor->setDataSource(mDataSourceWrapper->getAMediaDataSource()); 220 } else { 221 err = trackExtractor->setDataSource(fd, offset, length); 222 } 223 224 const char *mime; 225 sp<MetaData> meta = convertMediaFormatWrapperToMetaData(trackFormat); 226 CHECK(meta->findCString(kKeyMIMEType, &mime)); 227 228 ALOGV("initFromDataSource track[%zu]: %s", i, mime); 229 230 // Do the string compare immediately with "mime", 231 // we can't assume "mime" would stay valid after another 232 // extractor operation, some extractors might modify meta 233 // during getTrack() and make it invalid. 234 if (!strncasecmp(mime, "audio/", 6)) { 235 if (mAudioTrack.mExtractor == NULL) { 236 mAudioTrack.mIndex = i; 237 mAudioTrack.mExtractor = trackExtractor; 238 mAudioTrack.mExtractor->selectTrack(i); 239 mAudioTrack.mPackets = new AnotherPacketSource(meta); 240 241 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { 242 mAudioIsVorbis = true; 243 } else { 244 mAudioIsVorbis = false; 245 } 246 247 mMimes.add(String8(mime)); 248 } 249 } else if (!strncasecmp(mime, "video/", 6)) { 250 if (mVideoTrack.mExtractor == NULL) { 251 mVideoTrack.mIndex = i; 252 mVideoTrack.mExtractor = trackExtractor; 253 mVideoTrack.mExtractor->selectTrack(i); 254 mVideoTrack.mPackets = new AnotherPacketSource(meta); 255 256 // video always at the beginning 257 mMimes.insertAt(String8(mime), 0); 258 } 259 } 260 261 mExtractors.push(trackExtractor); 262 int64_t durationUs; 263 if (meta->findInt64(kKeyDuration, &durationUs)) { 264 if (durationUs > mDurationUs) { 265 mDurationUs = durationUs; 266 } 267 } 268 269 int32_t bitrate; 270 if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) { 271 totalBitrate += bitrate; 272 } else { 273 totalBitrate = -1; 274 } 275 } 276 277 ALOGV("initFromDataSource mExtractors.size(): %zu mIsSecure: %d mime[0]: %s", mExtractors.size(), 278 mIsSecure, (mMimes.isEmpty() ? "NONE" : mMimes[0].string())); 279 280 if (mExtractors.size() == 0) { 281 ALOGE("b/23705695"); 282 return UNKNOWN_ERROR; 283 } 284 285 // Modular DRM: The return value doesn't affect source initialization. 286 (void)checkDrmInfo(); 287 288 mBitrate = totalBitrate; 289 290 return OK; 291 } 292 293 status_t NuPlayer2::GenericSource2::getBufferingSettings( 294 BufferingSettings* buffering /* nonnull */) { 295 { 296 Mutex::Autolock _l(mLock); 297 *buffering = mBufferingSettings; 298 } 299 300 ALOGV("getBufferingSettings{%s}", buffering->toString().string()); 301 return OK; 302 } 303 304 status_t NuPlayer2::GenericSource2::setBufferingSettings(const BufferingSettings& buffering) { 305 ALOGV("setBufferingSettings{%s}", buffering.toString().string()); 306 307 Mutex::Autolock _l(mLock); 308 mBufferingSettings = buffering; 309 return OK; 310 } 311 312 int64_t NuPlayer2::GenericSource2::getLastReadPosition() { 313 if (mAudioTrack.mExtractor != NULL) { 314 return mAudioTimeUs; 315 } else if (mVideoTrack.mExtractor != NULL) { 316 return mVideoTimeUs; 317 } else { 318 return 0; 319 } 320 } 321 322 bool NuPlayer2::GenericSource2::isStreaming() const { 323 Mutex::Autolock _l(mLock); 324 return mIsStreaming; 325 } 326 327 NuPlayer2::GenericSource2::~GenericSource2() { 328 ALOGV("~GenericSource2"); 329 if (mLooper != NULL) { 330 mLooper->unregisterHandler(id()); 331 mLooper->stop(); 332 } 333 if (mDataSource != NULL) { 334 mDataSource->close(); 335 } 336 resetDataSource(); 337 } 338 339 void NuPlayer2::GenericSource2::prepareAsync() { 340 Mutex::Autolock _l(mLock); 341 ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL)); 342 343 if (mLooper == NULL) { 344 mLooper = new ALooper; 345 mLooper->setName("generic"); 346 mLooper->start(false, /* runOnCallingThread */ 347 true, /* canCallJava */ 348 PRIORITY_DEFAULT); 349 350 mLooper->registerHandler(this); 351 } 352 353 sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this); 354 msg->post(); 355 } 356 357 void NuPlayer2::GenericSource2::onPrepareAsync() { 358 ALOGV("onPrepareAsync: mDataSource: %d", (mDataSource != NULL)); 359 360 // delayed data source creation 361 if (mDataSource == NULL) { 362 // set to false first, if the extractor 363 // comes back as secure, set it to true then. 364 mIsSecure = false; 365 366 if (!mUri.empty()) { 367 const char* uri = mUri.c_str(); 368 String8 contentType; 369 370 if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) { 371 mHttpSource = DataSourceFactory::CreateMediaHTTP(mHTTPService); 372 if (mHttpSource == NULL) { 373 ALOGE("Failed to create http source!"); 374 notifyPreparedAndCleanup(UNKNOWN_ERROR); 375 return; 376 } 377 } 378 379 mLock.unlock(); 380 // This might take long time if connection has some issue. 381 sp<DataSource> dataSource = DataSourceFactory::CreateFromURI( 382 mHTTPService, uri, &mUriHeaders, &contentType, 383 static_cast<HTTPBase *>(mHttpSource.get())); 384 mLock.lock(); 385 if (!mDisconnected) { 386 mDataSource = dataSource; 387 } 388 } 389 390 if (mFd == -1 && mDataSource == NULL) { 391 ALOGE("Failed to create data source!"); 392 notifyPreparedAndCleanup(UNKNOWN_ERROR); 393 return; 394 } 395 } 396 397 if (mDataSource != nullptr && mDataSource->flags() & DataSource::kIsCachingDataSource) { 398 mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get()); 399 } 400 401 // For cached streaming cases, we need to wait for enough 402 // buffering before reporting prepared. 403 mIsStreaming = (mCachedSource != NULL); 404 405 // init extractor from data source 406 status_t err = initFromDataSource(); 407 408 if (err != OK) { 409 ALOGE("Failed to init from data source!"); 410 notifyPreparedAndCleanup(err); 411 return; 412 } 413 414 if (mVideoTrack.mExtractor != NULL) { 415 sp<MetaData> meta = getFormatMeta_l(false /* audio */); 416 sp<AMessage> msg = new AMessage; 417 err = convertMetaDataToMessage(meta, &msg); 418 if(err != OK) { 419 notifyPreparedAndCleanup(err); 420 return; 421 } 422 notifyVideoSizeChanged(msg); 423 } 424 425 notifyFlagsChanged( 426 // FLAG_SECURE will be known if/when prepareDrm is called by the app 427 // FLAG_PROTECTED will be known if/when prepareDrm is called by the app 428 FLAG_CAN_PAUSE | 429 FLAG_CAN_SEEK_BACKWARD | 430 FLAG_CAN_SEEK_FORWARD | 431 FLAG_CAN_SEEK); 432 433 finishPrepareAsync(); 434 435 ALOGV("onPrepareAsync: Done"); 436 } 437 438 void NuPlayer2::GenericSource2::finishPrepareAsync() { 439 ALOGV("finishPrepareAsync"); 440 441 if (mIsStreaming) { 442 mCachedSource->resumeFetchingIfNecessary(); 443 mPreparing = true; 444 schedulePollBuffering(); 445 } else { 446 notifyPrepared(); 447 } 448 449 if (mAudioTrack.mExtractor != NULL) { 450 postReadBuffer(MEDIA_TRACK_TYPE_AUDIO); 451 } 452 453 if (mVideoTrack.mExtractor != NULL) { 454 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO); 455 } 456 } 457 458 void NuPlayer2::GenericSource2::notifyPreparedAndCleanup(status_t err) { 459 if (err != OK) { 460 mDataSource.clear(); 461 mCachedSource.clear(); 462 mHttpSource.clear(); 463 464 mBitrate = -1; 465 mPrevBufferPercentage = -1; 466 ++mPollBufferingGeneration; 467 } 468 notifyPrepared(err); 469 } 470 471 void NuPlayer2::GenericSource2::start() { 472 Mutex::Autolock _l(mLock); 473 ALOGI("start"); 474 475 if (mAudioTrack.mExtractor != NULL) { 476 postReadBuffer(MEDIA_TRACK_TYPE_AUDIO); 477 } 478 479 if (mVideoTrack.mExtractor != NULL) { 480 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO); 481 } 482 483 mStarted = true; 484 } 485 486 void NuPlayer2::GenericSource2::stop() { 487 Mutex::Autolock _l(mLock); 488 mStarted = false; 489 } 490 491 void NuPlayer2::GenericSource2::pause() { 492 Mutex::Autolock _l(mLock); 493 mStarted = false; 494 } 495 496 void NuPlayer2::GenericSource2::resume() { 497 Mutex::Autolock _l(mLock); 498 mStarted = true; 499 } 500 501 void NuPlayer2::GenericSource2::disconnect() { 502 sp<DataSource> dataSource, httpSource; 503 { 504 Mutex::Autolock _l(mLock); 505 dataSource = mDataSource; 506 httpSource = mHttpSource; 507 mDisconnected = true; 508 } 509 510 if (dataSource != NULL) { 511 // disconnect data source 512 if (dataSource->flags() & DataSource::kIsCachingDataSource) { 513 static_cast<NuCachedSource2 *>(dataSource.get())->disconnect(); 514 } 515 } else if (httpSource != NULL) { 516 static_cast<HTTPBase *>(httpSource.get())->disconnect(); 517 } 518 519 mDataSourceWrapper = NULL; 520 521 } 522 523 status_t NuPlayer2::GenericSource2::feedMoreTSData() { 524 return OK; 525 } 526 527 void NuPlayer2::GenericSource2::sendCacheStats() { 528 int32_t kbps = 0; 529 status_t err = UNKNOWN_ERROR; 530 531 if (mCachedSource != NULL) { 532 err = mCachedSource->getEstimatedBandwidthKbps(&kbps); 533 } 534 535 if (err == OK) { 536 sp<AMessage> notify = dupNotify(); 537 notify->setInt32("what", kWhatCacheStats); 538 notify->setInt32("bandwidth", kbps); 539 notify->post(); 540 } 541 } 542 543 void NuPlayer2::GenericSource2::onMessageReceived(const sp<AMessage> &msg) { 544 Mutex::Autolock _l(mLock); 545 switch (msg->what()) { 546 case kWhatPrepareAsync: 547 { 548 onPrepareAsync(); 549 break; 550 } 551 case kWhatFetchSubtitleData: 552 { 553 fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, 554 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); 555 break; 556 } 557 558 case kWhatFetchTimedTextData: 559 { 560 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, 561 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); 562 break; 563 } 564 565 case kWhatSendSubtitleData: 566 { 567 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, 568 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); 569 break; 570 } 571 572 case kWhatSendGlobalTimedTextData: 573 { 574 sendGlobalTextData(kWhatTimedTextData, mFetchTimedTextDataGeneration, msg); 575 break; 576 } 577 case kWhatSendTimedTextData: 578 { 579 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, 580 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); 581 break; 582 } 583 584 case kWhatChangeAVSource: 585 { 586 int32_t trackIndex; 587 CHECK(msg->findInt32("trackIndex", &trackIndex)); 588 const sp<AMediaExtractorWrapper> extractor = mExtractors.itemAt(trackIndex); 589 590 Track* track; 591 AString mime; 592 media_track_type trackType, counterpartType; 593 sp<AMediaFormatWrapper> format = extractor->getTrackFormat(trackIndex); 594 format->getString(AMEDIAFORMAT_KEY_MIME, &mime); 595 if (!strncasecmp(mime.c_str(), "audio/", 6)) { 596 track = &mAudioTrack; 597 trackType = MEDIA_TRACK_TYPE_AUDIO; 598 counterpartType = MEDIA_TRACK_TYPE_VIDEO;; 599 } else { 600 CHECK(!strncasecmp(mime.c_str(), "video/", 6)); 601 track = &mVideoTrack; 602 trackType = MEDIA_TRACK_TYPE_VIDEO; 603 counterpartType = MEDIA_TRACK_TYPE_AUDIO;; 604 } 605 606 607 track->mExtractor = extractor; 608 track->mExtractor->selectSingleTrack(trackIndex); 609 track->mIndex = trackIndex; 610 ++mAudioDataGeneration; 611 ++mVideoDataGeneration; 612 613 int64_t timeUs, actualTimeUs; 614 const bool formatChange = true; 615 if (trackType == MEDIA_TRACK_TYPE_AUDIO) { 616 timeUs = mAudioLastDequeueTimeUs; 617 } else { 618 timeUs = mVideoLastDequeueTimeUs; 619 } 620 readBuffer(trackType, timeUs, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */, 621 &actualTimeUs, formatChange); 622 readBuffer(counterpartType, -1, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */, 623 NULL, !formatChange); 624 ALOGV("timeUs %lld actualTimeUs %lld", (long long)timeUs, (long long)actualTimeUs); 625 626 break; 627 } 628 629 case kWhatSeek: 630 { 631 onSeek(msg); 632 break; 633 } 634 635 case kWhatReadBuffer: 636 { 637 onReadBuffer(msg); 638 break; 639 } 640 641 case kWhatPollBuffering: 642 { 643 int32_t generation; 644 CHECK(msg->findInt32("generation", &generation)); 645 if (generation == mPollBufferingGeneration) { 646 onPollBuffering(); 647 } 648 break; 649 } 650 651 default: 652 Source::onMessageReceived(msg); 653 break; 654 } 655 } 656 657 void NuPlayer2::GenericSource2::fetchTextData( 658 uint32_t sendWhat, 659 media_track_type type, 660 int32_t curGen, 661 const sp<AnotherPacketSource>& packets, 662 const sp<AMessage>& msg) { 663 int32_t msgGeneration; 664 CHECK(msg->findInt32("generation", &msgGeneration)); 665 if (msgGeneration != curGen) { 666 // stale 667 return; 668 } 669 670 int32_t avail; 671 if (packets->hasBufferAvailable(&avail)) { 672 return; 673 } 674 675 int64_t timeUs; 676 CHECK(msg->findInt64("timeUs", &timeUs)); 677 678 int64_t subTimeUs = 0; 679 readBuffer(type, timeUs, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */, &subTimeUs); 680 681 status_t eosResult; 682 if (!packets->hasBufferAvailable(&eosResult)) { 683 return; 684 } 685 686 if (msg->what() == kWhatFetchSubtitleData) { 687 subTimeUs -= 1000000ll; // send subtile data one second earlier 688 } 689 sp<AMessage> msg2 = new AMessage(sendWhat, this); 690 msg2->setInt32("generation", msgGeneration); 691 mMediaClock->addTimer(msg2, subTimeUs); 692 } 693 694 void NuPlayer2::GenericSource2::sendTextData( 695 uint32_t what, 696 media_track_type type, 697 int32_t curGen, 698 const sp<AnotherPacketSource>& packets, 699 const sp<AMessage>& msg) { 700 int32_t msgGeneration; 701 CHECK(msg->findInt32("generation", &msgGeneration)); 702 if (msgGeneration != curGen) { 703 // stale 704 return; 705 } 706 707 int64_t subTimeUs; 708 if (packets->nextBufferTime(&subTimeUs) != OK) { 709 return; 710 } 711 712 int64_t nextSubTimeUs; 713 readBuffer(type, -1, MediaPlayer2SeekMode::SEEK_PREVIOUS_SYNC /* mode */, &nextSubTimeUs); 714 715 sp<ABuffer> buffer; 716 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer); 717 if (dequeueStatus == OK) { 718 sp<AMessage> notify = dupNotify(); 719 notify->setInt32("what", what); 720 notify->setBuffer("buffer", buffer); 721 notify->post(); 722 723 if (msg->what() == kWhatSendSubtitleData) { 724 nextSubTimeUs -= 1000000ll; // send subtile data one second earlier 725 } 726 mMediaClock->addTimer(msg, nextSubTimeUs); 727 } 728 } 729 730 void NuPlayer2::GenericSource2::sendGlobalTextData( 731 uint32_t what, 732 int32_t curGen, 733 sp<AMessage> msg) { 734 int32_t msgGeneration; 735 CHECK(msg->findInt32("generation", &msgGeneration)); 736 if (msgGeneration != curGen) { 737 // stale 738 return; 739 } 740 741 void *data = NULL; 742 size_t size = 0; 743 if (mTimedTextTrack.mExtractor->getTrackFormat(mTimedTextTrack.mIndex)->getBuffer( 744 "text", &data, &size)) { 745 mGlobalTimedText = new ABuffer(size); 746 if (mGlobalTimedText->data()) { 747 memcpy(mGlobalTimedText->data(), data, size); 748 sp<AMessage> globalMeta = mGlobalTimedText->meta(); 749 globalMeta->setInt64("timeUs", 0); 750 globalMeta->setString("mime", MEDIA_MIMETYPE_TEXT_3GPP); 751 globalMeta->setInt32("global", 1); 752 sp<AMessage> notify = dupNotify(); 753 notify->setInt32("what", what); 754 notify->setBuffer("buffer", mGlobalTimedText); 755 notify->post(); 756 } 757 } 758 } 759 760 sp<AMessage> NuPlayer2::GenericSource2::getFormat(bool audio) { 761 Mutex::Autolock _l(mLock); 762 return getFormat_l(audio); 763 } 764 765 sp<MetaData> NuPlayer2::GenericSource2::getFormatMeta(bool audio) { 766 Mutex::Autolock _l(mLock); 767 return getFormatMeta_l(audio); 768 } 769 770 sp<AMessage> NuPlayer2::GenericSource2::getFormat_l(bool audio) { 771 sp<AMediaExtractorWrapper> extractor = audio ? mAudioTrack.mExtractor : mVideoTrack.mExtractor; 772 size_t trackIndex = audio ? mAudioTrack.mIndex : mVideoTrack.mIndex; 773 774 if (extractor == NULL) { 775 return NULL; 776 } 777 778 return extractor->getTrackFormat(trackIndex)->toAMessage(); 779 } 780 781 sp<MetaData> NuPlayer2::GenericSource2::getFormatMeta_l(bool audio) { 782 sp<AMediaExtractorWrapper> extractor = audio ? mAudioTrack.mExtractor : mVideoTrack.mExtractor; 783 size_t trackIndex = audio ? mAudioTrack.mIndex : mVideoTrack.mIndex; 784 785 if (extractor == NULL) { 786 return NULL; 787 } 788 789 return convertMediaFormatWrapperToMetaData(extractor->getTrackFormat(trackIndex)); 790 } 791 792 status_t NuPlayer2::GenericSource2::dequeueAccessUnit( 793 bool audio, sp<ABuffer> *accessUnit) { 794 Mutex::Autolock _l(mLock); 795 // If has gone through stop/releaseDrm sequence, we no longer send down any buffer b/c 796 // the codec's crypto object has gone away (b/37960096). 797 // Note: This will be unnecessary when stop() changes behavior and releases codec (b/35248283). 798 if (!mStarted && mIsDrmReleased) { 799 return -EWOULDBLOCK; 800 } 801 802 Track *track = audio ? &mAudioTrack : &mVideoTrack; 803 804 if (track->mExtractor == NULL) { 805 return -EWOULDBLOCK; 806 } 807 808 status_t finalResult; 809 if (!track->mPackets->hasBufferAvailable(&finalResult)) { 810 if (finalResult == OK) { 811 postReadBuffer( 812 audio ? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO); 813 return -EWOULDBLOCK; 814 } 815 return finalResult; 816 } 817 818 status_t result = track->mPackets->dequeueAccessUnit(accessUnit); 819 820 // start pulling in more buffers if cache is running low 821 // so that decoder has less chance of being starved 822 if (!mIsStreaming) { 823 if (track->mPackets->getAvailableBufferCount(&finalResult) < 2) { 824 postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO); 825 } 826 } else { 827 int64_t durationUs = track->mPackets->getBufferedDurationUs(&finalResult); 828 // TODO: maxRebufferingMarkMs could be larger than 829 // mBufferingSettings.mResumePlaybackMarkMs 830 int64_t restartBufferingMarkUs = 831 mBufferingSettings.mResumePlaybackMarkMs * 1000ll / 2; 832 if (finalResult == OK) { 833 if (durationUs < restartBufferingMarkUs) { 834 postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO); 835 } 836 if (track->mPackets->getAvailableBufferCount(&finalResult) < 2 837 && !mSentPauseOnBuffering && !mPreparing) { 838 mCachedSource->resumeFetchingIfNecessary(); 839 sendCacheStats(); 840 mSentPauseOnBuffering = true; 841 sp<AMessage> notify = dupNotify(); 842 notify->setInt32("what", kWhatPauseOnBufferingStart); 843 notify->post(); 844 } 845 } 846 } 847 848 if (result != OK) { 849 if (mSubtitleTrack.mExtractor != NULL) { 850 mSubtitleTrack.mPackets->clear(); 851 mFetchSubtitleDataGeneration++; 852 } 853 if (mTimedTextTrack.mExtractor != NULL) { 854 mTimedTextTrack.mPackets->clear(); 855 mFetchTimedTextDataGeneration++; 856 } 857 return result; 858 } 859 860 int64_t timeUs; 861 status_t eosResult; // ignored 862 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); 863 if (audio) { 864 mAudioLastDequeueTimeUs = timeUs; 865 } else { 866 mVideoLastDequeueTimeUs = timeUs; 867 } 868 869 if (mSubtitleTrack.mExtractor != NULL 870 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { 871 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this); 872 msg->setInt64("timeUs", timeUs); 873 msg->setInt32("generation", mFetchSubtitleDataGeneration); 874 msg->post(); 875 } 876 877 if (mTimedTextTrack.mExtractor != NULL 878 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) { 879 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this); 880 msg->setInt64("timeUs", timeUs); 881 msg->setInt32("generation", mFetchTimedTextDataGeneration); 882 msg->post(); 883 } 884 885 return result; 886 } 887 888 status_t NuPlayer2::GenericSource2::getDuration(int64_t *durationUs) { 889 Mutex::Autolock _l(mLock); 890 *durationUs = mDurationUs; 891 return OK; 892 } 893 894 size_t NuPlayer2::GenericSource2::getTrackCount() const { 895 Mutex::Autolock _l(mLock); 896 return mExtractors.size(); 897 } 898 899 sp<AMessage> NuPlayer2::GenericSource2::getTrackInfo(size_t trackIndex) const { 900 Mutex::Autolock _l(mLock); 901 size_t trackCount = mExtractors.size(); 902 if (trackIndex >= trackCount) { 903 return NULL; 904 } 905 906 sp<AMessage> format = mExtractors.itemAt(trackIndex)->getTrackFormat(trackIndex)->toAMessage(); 907 if (format == NULL) { 908 ALOGE("no metadata for track %zu", trackIndex); 909 return NULL; 910 } 911 912 AString mime; 913 CHECK(format->findString(AMEDIAFORMAT_KEY_MIME, &mime)); 914 915 int32_t trackType; 916 if (!strncasecmp(mime.c_str(), "video/", 6)) { 917 trackType = MEDIA_TRACK_TYPE_VIDEO; 918 } else if (!strncasecmp(mime.c_str(), "audio/", 6)) { 919 trackType = MEDIA_TRACK_TYPE_AUDIO; 920 } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_TEXT_3GPP)) { 921 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT; 922 } else { 923 trackType = MEDIA_TRACK_TYPE_UNKNOWN; 924 } 925 format->setInt32("type", trackType); 926 927 AString lang; 928 if (!format->findString("language", &lang)) { 929 format->setString("language", "und"); 930 } 931 932 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 933 int32_t isAutoselect = 1, isDefault = 0, isForced = 0; 934 format->findInt32(AMEDIAFORMAT_KEY_IS_AUTOSELECT, &isAutoselect); 935 format->findInt32(AMEDIAFORMAT_KEY_IS_DEFAULT, &isDefault); 936 format->findInt32(AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE, &isForced); 937 938 format->setInt32("auto", !!isAutoselect); 939 format->setInt32("default", !!isDefault); 940 format->setInt32("forced", !!isForced); 941 } 942 943 return format; 944 } 945 946 ssize_t NuPlayer2::GenericSource2::getSelectedTrack(media_track_type type) const { 947 Mutex::Autolock _l(mLock); 948 const Track *track = NULL; 949 switch (type) { 950 case MEDIA_TRACK_TYPE_VIDEO: 951 track = &mVideoTrack; 952 break; 953 case MEDIA_TRACK_TYPE_AUDIO: 954 track = &mAudioTrack; 955 break; 956 case MEDIA_TRACK_TYPE_TIMEDTEXT: 957 track = &mTimedTextTrack; 958 break; 959 case MEDIA_TRACK_TYPE_SUBTITLE: 960 track = &mSubtitleTrack; 961 break; 962 default: 963 break; 964 } 965 966 if (track != NULL && track->mExtractor != NULL) { 967 return track->mIndex; 968 } 969 970 return -1; 971 } 972 973 status_t NuPlayer2::GenericSource2::selectTrack(size_t trackIndex, bool select, int64_t timeUs) { 974 Mutex::Autolock _l(mLock); 975 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex); 976 977 if (trackIndex >= mExtractors.size()) { 978 return BAD_INDEX; 979 } 980 981 if (!select) { 982 Track* track = NULL; 983 if (mSubtitleTrack.mExtractor != NULL && trackIndex == mSubtitleTrack.mIndex) { 984 track = &mSubtitleTrack; 985 mFetchSubtitleDataGeneration++; 986 } else if (mTimedTextTrack.mExtractor != NULL && trackIndex == mTimedTextTrack.mIndex) { 987 track = &mTimedTextTrack; 988 mFetchTimedTextDataGeneration++; 989 } 990 if (track == NULL) { 991 return INVALID_OPERATION; 992 } 993 track->mExtractor = NULL; 994 track->mPackets->clear(); 995 return OK; 996 } 997 998 const sp<AMediaExtractorWrapper> extractor = mExtractors.itemAt(trackIndex); 999 sp<MetaData> meta = convertMediaFormatWrapperToMetaData(extractor->getTrackFormat(trackIndex)); 1000 const char *mime; 1001 CHECK(meta->findCString(kKeyMIMEType, &mime)); 1002 if (!strncasecmp(mime, "text/", 5)) { 1003 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP); 1004 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack; 1005 if (track->mExtractor != NULL && track->mIndex == trackIndex) { 1006 return OK; 1007 } 1008 track->mIndex = trackIndex; 1009 track->mExtractor = mExtractors.itemAt(trackIndex); 1010 track->mExtractor->selectSingleTrack(trackIndex); 1011 if (track->mPackets == NULL) { 1012 track->mPackets = new AnotherPacketSource(meta); 1013 } else { 1014 track->mPackets->clear(); 1015 track->mPackets->setFormat(meta); 1016 1017 } 1018 1019 if (isSubtitle) { 1020 mFetchSubtitleDataGeneration++; 1021 } else { 1022 mFetchTimedTextDataGeneration++; 1023 } 1024 1025 status_t eosResult; // ignored 1026 if (mSubtitleTrack.mExtractor != NULL 1027 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { 1028 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this); 1029 msg->setInt64("timeUs", timeUs); 1030 msg->setInt32("generation", mFetchSubtitleDataGeneration); 1031 msg->post(); 1032 } 1033 1034 sp<AMessage> msg2 = new AMessage(kWhatSendGlobalTimedTextData, this); 1035 msg2->setInt32("generation", mFetchTimedTextDataGeneration); 1036 msg2->post(); 1037 1038 if (mTimedTextTrack.mExtractor != NULL 1039 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) { 1040 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this); 1041 msg->setInt64("timeUs", timeUs); 1042 msg->setInt32("generation", mFetchTimedTextDataGeneration); 1043 msg->post(); 1044 } 1045 1046 return OK; 1047 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) { 1048 bool audio = !strncasecmp(mime, "audio/", 6); 1049 Track *track = audio ? &mAudioTrack : &mVideoTrack; 1050 if (track->mExtractor != NULL && track->mIndex == trackIndex) { 1051 return OK; 1052 } 1053 1054 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, this); 1055 msg->setInt32("trackIndex", trackIndex); 1056 msg->post(); 1057 return OK; 1058 } 1059 1060 return INVALID_OPERATION; 1061 } 1062 1063 status_t NuPlayer2::GenericSource2::seekTo(int64_t seekTimeUs, MediaPlayer2SeekMode mode) { 1064 ALOGV("seekTo: %lld, %d", (long long)seekTimeUs, mode); 1065 sp<AMessage> msg = new AMessage(kWhatSeek, this); 1066 msg->setInt64("seekTimeUs", seekTimeUs); 1067 msg->setInt32("mode", mode); 1068 1069 // Need to call readBuffer on |mLooper| to ensure the calls to 1070 // IMediaSource::read* are serialized. Note that IMediaSource::read* 1071 // is called without |mLock| acquired and MediaSource is not thread safe. 1072 sp<AMessage> response; 1073 status_t err = msg->postAndAwaitResponse(&response); 1074 if (err == OK && response != NULL) { 1075 CHECK(response->findInt32("err", &err)); 1076 } 1077 1078 return err; 1079 } 1080 1081 void NuPlayer2::GenericSource2::onSeek(const sp<AMessage>& msg) { 1082 int64_t seekTimeUs; 1083 int32_t mode; 1084 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs)); 1085 CHECK(msg->findInt32("mode", &mode)); 1086 1087 sp<AMessage> response = new AMessage; 1088 status_t err = doSeek(seekTimeUs, (MediaPlayer2SeekMode)mode); 1089 response->setInt32("err", err); 1090 1091 sp<AReplyToken> replyID; 1092 CHECK(msg->senderAwaitsResponse(&replyID)); 1093 response->postReply(replyID); 1094 } 1095 1096 status_t NuPlayer2::GenericSource2::doSeek(int64_t seekTimeUs, MediaPlayer2SeekMode mode) { 1097 if (mVideoTrack.mExtractor != NULL) { 1098 ++mVideoDataGeneration; 1099 1100 int64_t actualTimeUs; 1101 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, mode, &actualTimeUs); 1102 1103 if (mode != MediaPlayer2SeekMode::SEEK_CLOSEST) { 1104 seekTimeUs = actualTimeUs; 1105 } 1106 mVideoLastDequeueTimeUs = actualTimeUs; 1107 } 1108 1109 if (mAudioTrack.mExtractor != NULL) { 1110 ++mAudioDataGeneration; 1111 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs, MediaPlayer2SeekMode::SEEK_CLOSEST); 1112 mAudioLastDequeueTimeUs = seekTimeUs; 1113 } 1114 1115 if (mSubtitleTrack.mExtractor != NULL) { 1116 mSubtitleTrack.mPackets->clear(); 1117 mFetchSubtitleDataGeneration++; 1118 } 1119 1120 if (mTimedTextTrack.mExtractor != NULL) { 1121 mTimedTextTrack.mPackets->clear(); 1122 mFetchTimedTextDataGeneration++; 1123 } 1124 1125 ++mPollBufferingGeneration; 1126 schedulePollBuffering(); 1127 return OK; 1128 } 1129 1130 sp<ABuffer> NuPlayer2::GenericSource2::mediaBufferToABuffer( 1131 MediaBufferBase* mb, 1132 media_track_type trackType) { 1133 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO; 1134 size_t outLength = mb->range_length(); 1135 1136 if (audio && mAudioIsVorbis) { 1137 outLength += sizeof(int32_t); 1138 } 1139 1140 sp<ABuffer> ab; 1141 1142 if (mIsDrmProtected) { 1143 // Modular DRM 1144 // Enabled for both video/audio so 1) media buffer is reused without extra copying 1145 // 2) meta data can be retrieved in onInputBufferFetched for calling queueSecureInputBuffer. 1146 1147 // data is already provided in the buffer 1148 ab = new ABuffer(NULL, mb->range_length()); 1149 ab->meta()->setObject("mediaBufferHolder", new MediaBufferHolder(mb)); 1150 1151 // Modular DRM: Required b/c of the above add_ref. 1152 // If ref>0, there must be an observer, or it'll crash at release(). 1153 // TODO: MediaBuffer might need to be revised to ease such need. 1154 mb->setObserver(this); 1155 // setMediaBufferBase() interestingly doesn't increment the ref count on its own. 1156 // Extra increment (since we want to keep mb alive and attached to ab beyond this function 1157 // call. This is to counter the effect of mb->release() towards the end. 1158 mb->add_ref(); 1159 1160 } else { 1161 ab = new ABuffer(outLength); 1162 memcpy(ab->data(), 1163 (const uint8_t *)mb->data() + mb->range_offset(), 1164 mb->range_length()); 1165 } 1166 1167 if (audio && mAudioIsVorbis) { 1168 int32_t numPageSamples; 1169 if (!mb->meta_data().findInt32(kKeyValidSamples, &numPageSamples)) { 1170 numPageSamples = -1; 1171 } 1172 1173 uint8_t* abEnd = ab->data() + mb->range_length(); 1174 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples)); 1175 } 1176 1177 sp<AMessage> meta = ab->meta(); 1178 1179 int64_t timeUs; 1180 CHECK(mb->meta_data().findInt64(kKeyTime, &timeUs)); 1181 meta->setInt64("timeUs", timeUs); 1182 1183 if (trackType == MEDIA_TRACK_TYPE_VIDEO) { 1184 int32_t layerId; 1185 if (mb->meta_data().findInt32(kKeyTemporalLayerId, &layerId)) { 1186 meta->setInt32("temporal-layer-id", layerId); 1187 } 1188 } 1189 1190 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) { 1191 AString mime; 1192 sp<AMediaExtractorWrapper> extractor = mTimedTextTrack.mExtractor; 1193 size_t trackIndex = mTimedTextTrack.mIndex; 1194 CHECK(extractor != NULL 1195 && extractor->getTrackFormat(trackIndex)->getString(AMEDIAFORMAT_KEY_MIME, &mime)); 1196 meta->setString("mime", mime.c_str()); 1197 } 1198 1199 int64_t durationUs; 1200 if (mb->meta_data().findInt64(kKeyDuration, &durationUs)) { 1201 meta->setInt64("durationUs", durationUs); 1202 } 1203 1204 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 1205 meta->setInt32(AMEDIAFORMAT_KEY_TRACK_INDEX, mSubtitleTrack.mIndex); 1206 } 1207 1208 uint32_t dataType; // unused 1209 const void *seiData; 1210 size_t seiLength; 1211 if (mb->meta_data().findData(kKeySEI, &dataType, &seiData, &seiLength)) { 1212 sp<ABuffer> sei = ABuffer::CreateAsCopy(seiData, seiLength);; 1213 meta->setBuffer("sei", sei); 1214 } 1215 1216 const void *mpegUserDataPointer; 1217 size_t mpegUserDataLength; 1218 if (mb->meta_data().findData( 1219 kKeyMpegUserData, &dataType, &mpegUserDataPointer, &mpegUserDataLength)) { 1220 sp<ABuffer> mpegUserData = ABuffer::CreateAsCopy(mpegUserDataPointer, mpegUserDataLength); 1221 meta->setBuffer(AMEDIAFORMAT_KEY_MPEG_USER_DATA, mpegUserData); 1222 } 1223 1224 mb->release(); 1225 mb = NULL; 1226 1227 return ab; 1228 } 1229 1230 int32_t NuPlayer2::GenericSource2::getDataGeneration(media_track_type type) const { 1231 int32_t generation = -1; 1232 switch (type) { 1233 case MEDIA_TRACK_TYPE_VIDEO: 1234 generation = mVideoDataGeneration; 1235 break; 1236 case MEDIA_TRACK_TYPE_AUDIO: 1237 generation = mAudioDataGeneration; 1238 break; 1239 case MEDIA_TRACK_TYPE_TIMEDTEXT: 1240 generation = mFetchTimedTextDataGeneration; 1241 break; 1242 case MEDIA_TRACK_TYPE_SUBTITLE: 1243 generation = mFetchSubtitleDataGeneration; 1244 break; 1245 default: 1246 break; 1247 } 1248 1249 return generation; 1250 } 1251 1252 void NuPlayer2::GenericSource2::postReadBuffer(media_track_type trackType) { 1253 if ((mPendingReadBufferTypes & (1 << trackType)) == 0) { 1254 mPendingReadBufferTypes |= (1 << trackType); 1255 sp<AMessage> msg = new AMessage(kWhatReadBuffer, this); 1256 msg->setInt32("trackType", trackType); 1257 msg->post(); 1258 } 1259 } 1260 1261 void NuPlayer2::GenericSource2::onReadBuffer(const sp<AMessage>& msg) { 1262 int32_t tmpType; 1263 CHECK(msg->findInt32("trackType", &tmpType)); 1264 media_track_type trackType = (media_track_type)tmpType; 1265 mPendingReadBufferTypes &= ~(1 << trackType); 1266 readBuffer(trackType); 1267 } 1268 1269 void NuPlayer2::GenericSource2::readBuffer( 1270 media_track_type trackType, int64_t seekTimeUs, MediaPlayer2SeekMode mode, 1271 int64_t *actualTimeUs, bool formatChange) { 1272 Track *track; 1273 size_t maxBuffers = 1; 1274 switch (trackType) { 1275 case MEDIA_TRACK_TYPE_VIDEO: 1276 track = &mVideoTrack; 1277 maxBuffers = 8; // too large of a number may influence seeks 1278 break; 1279 case MEDIA_TRACK_TYPE_AUDIO: 1280 track = &mAudioTrack; 1281 maxBuffers = 64; 1282 break; 1283 case MEDIA_TRACK_TYPE_SUBTITLE: 1284 track = &mSubtitleTrack; 1285 break; 1286 case MEDIA_TRACK_TYPE_TIMEDTEXT: 1287 track = &mTimedTextTrack; 1288 break; 1289 default: 1290 TRESPASS(); 1291 } 1292 1293 if (track->mExtractor == NULL) { 1294 return; 1295 } 1296 1297 if (actualTimeUs) { 1298 *actualTimeUs = seekTimeUs; 1299 } 1300 1301 1302 bool seeking = false; 1303 sp<AMediaExtractorWrapper> extractor = track->mExtractor; 1304 if (seekTimeUs >= 0) { 1305 extractor->seekTo(seekTimeUs, mode); 1306 seeking = true; 1307 } 1308 1309 int32_t generation = getDataGeneration(trackType); 1310 for (size_t numBuffers = 0; numBuffers < maxBuffers; ) { 1311 Vector<sp<ABuffer> > aBuffers; 1312 1313 mLock.unlock(); 1314 1315 sp<AMediaFormatWrapper> format; 1316 ssize_t sampleSize = -1; 1317 status_t err = extractor->getSampleFormat(format); 1318 if (err == OK) { 1319 sampleSize = extractor->getSampleSize(); 1320 } 1321 1322 if (err != OK || sampleSize < 0) { 1323 mLock.lock(); 1324 track->mPackets->signalEOS(err != OK ? err : ERROR_END_OF_STREAM); 1325 break; 1326 } 1327 1328 sp<ABuffer> abuf = new ABuffer(sampleSize); 1329 sampleSize = extractor->readSampleData(abuf); 1330 mLock.lock(); 1331 1332 // in case track has been changed since we don't have lock for some time. 1333 if (generation != getDataGeneration(trackType)) { 1334 break; 1335 } 1336 1337 int64_t timeUs = extractor->getSampleTime(); 1338 if (timeUs < 0) { 1339 track->mPackets->signalEOS(ERROR_MALFORMED); 1340 break; 1341 } 1342 1343 sp<AMessage> meta = abuf->meta(); 1344 format->writeToAMessage(meta); 1345 meta->setInt64("timeUs", timeUs); 1346 if (trackType == MEDIA_TRACK_TYPE_AUDIO) { 1347 mAudioTimeUs = timeUs; 1348 } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) { 1349 mVideoTimeUs = timeUs; 1350 } 1351 1352 queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track); 1353 1354 if (numBuffers == 0 && actualTimeUs != nullptr) { 1355 *actualTimeUs = timeUs; 1356 } 1357 if (seeking) { 1358 if (meta != nullptr && mode == MediaPlayer2SeekMode::SEEK_CLOSEST 1359 && seekTimeUs > timeUs) { 1360 sp<AMessage> extra = new AMessage; 1361 extra->setInt64("resume-at-mediaTimeUs", seekTimeUs); 1362 meta->setMessage("extra", extra); 1363 } 1364 } 1365 1366 track->mPackets->queueAccessUnit(abuf); 1367 formatChange = false; 1368 seeking = false; 1369 ++numBuffers; 1370 extractor->advance(); 1371 1372 } 1373 1374 if (mIsStreaming 1375 && (trackType == MEDIA_TRACK_TYPE_VIDEO || trackType == MEDIA_TRACK_TYPE_AUDIO)) { 1376 status_t finalResult; 1377 int64_t durationUs = track->mPackets->getBufferedDurationUs(&finalResult); 1378 1379 // TODO: maxRebufferingMarkMs could be larger than 1380 // mBufferingSettings.mResumePlaybackMarkMs 1381 int64_t markUs = (mPreparing ? mBufferingSettings.mInitialMarkMs 1382 : mBufferingSettings.mResumePlaybackMarkMs) * 1000ll; 1383 if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) { 1384 if (mPreparing || mSentPauseOnBuffering) { 1385 Track *counterTrack = 1386 (trackType == MEDIA_TRACK_TYPE_VIDEO ? &mAudioTrack : &mVideoTrack); 1387 if (counterTrack->mExtractor != NULL) { 1388 durationUs = counterTrack->mPackets->getBufferedDurationUs(&finalResult); 1389 } 1390 if (finalResult == ERROR_END_OF_STREAM || durationUs >= markUs) { 1391 if (mPreparing) { 1392 notifyPrepared(); 1393 mPreparing = false; 1394 } else { 1395 sendCacheStats(); 1396 mSentPauseOnBuffering = false; 1397 sp<AMessage> notify = dupNotify(); 1398 notify->setInt32("what", kWhatResumeOnBufferingEnd); 1399 notify->post(); 1400 } 1401 } 1402 } 1403 return; 1404 } 1405 1406 postReadBuffer(trackType); 1407 } 1408 } 1409 1410 void NuPlayer2::GenericSource2::queueDiscontinuityIfNeeded( 1411 bool seeking, bool formatChange, media_track_type trackType, Track *track) { 1412 // formatChange && seeking: track whose source is changed during selection 1413 // formatChange && !seeking: track whose source is not changed during selection 1414 // !formatChange: normal seek 1415 if ((seeking || formatChange) 1416 && (trackType == MEDIA_TRACK_TYPE_AUDIO 1417 || trackType == MEDIA_TRACK_TYPE_VIDEO)) { 1418 ATSParser::DiscontinuityType type = (formatChange && seeking) 1419 ? ATSParser::DISCONTINUITY_FORMATCHANGE 1420 : ATSParser::DISCONTINUITY_NONE; 1421 track->mPackets->queueDiscontinuity(type, NULL /* extra */, true /* discard */); 1422 } 1423 } 1424 1425 void NuPlayer2::GenericSource2::notifyBufferingUpdate(int32_t percentage) { 1426 // Buffering percent could go backward as it's estimated from remaining 1427 // data and last access time. This could cause the buffering position 1428 // drawn on media control to jitter slightly. Remember previously reported 1429 // percentage and don't allow it to go backward. 1430 if (percentage < mPrevBufferPercentage) { 1431 percentage = mPrevBufferPercentage; 1432 } else if (percentage > 100) { 1433 percentage = 100; 1434 } 1435 1436 mPrevBufferPercentage = percentage; 1437 1438 ALOGV("notifyBufferingUpdate: buffering %d%%", percentage); 1439 1440 sp<AMessage> notify = dupNotify(); 1441 notify->setInt32("what", kWhatBufferingUpdate); 1442 notify->setInt32("percentage", percentage); 1443 notify->post(); 1444 } 1445 1446 void NuPlayer2::GenericSource2::schedulePollBuffering() { 1447 sp<AMessage> msg = new AMessage(kWhatPollBuffering, this); 1448 msg->setInt32("generation", mPollBufferingGeneration); 1449 // Enquires buffering status every second. 1450 msg->post(1000000ll); 1451 } 1452 1453 void NuPlayer2::GenericSource2::onPollBuffering() { 1454 status_t finalStatus = UNKNOWN_ERROR; 1455 int64_t cachedDurationUs = -1ll; 1456 ssize_t cachedDataRemaining = -1; 1457 1458 if (mCachedSource != NULL) { 1459 cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus); 1460 1461 if (finalStatus == OK) { 1462 off64_t size; 1463 int64_t bitrate = 0ll; 1464 if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) { 1465 // |bitrate| uses bits/second unit, while size is number of bytes. 1466 bitrate = size * 8000000ll / mDurationUs; 1467 } else if (mBitrate > 0) { 1468 bitrate = mBitrate; 1469 } 1470 if (bitrate > 0) { 1471 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate; 1472 } 1473 } 1474 } 1475 1476 if (finalStatus != OK) { 1477 ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus); 1478 1479 if (finalStatus == ERROR_END_OF_STREAM) { 1480 notifyBufferingUpdate(100); 1481 } 1482 1483 return; 1484 } 1485 1486 if (cachedDurationUs >= 0ll) { 1487 if (mDurationUs > 0ll) { 1488 int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs; 1489 int percentage = 100.0 * cachedPosUs / mDurationUs; 1490 if (percentage > 100) { 1491 percentage = 100; 1492 } 1493 1494 notifyBufferingUpdate(percentage); 1495 } 1496 1497 ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f); 1498 } 1499 1500 schedulePollBuffering(); 1501 } 1502 1503 // Modular DRM 1504 status_t NuPlayer2::GenericSource2::prepareDrm( 1505 const uint8_t uuid[16], 1506 const Vector<uint8_t> &drmSessionId, 1507 sp<AMediaCryptoWrapper> *outCrypto) { 1508 Mutex::Autolock _l(mLock); 1509 ALOGV("prepareDrm"); 1510 1511 mIsDrmProtected = false; 1512 mIsDrmReleased = false; 1513 mIsSecure = false; 1514 1515 status_t status = OK; 1516 sp<AMediaCryptoWrapper> crypto = 1517 new AMediaCryptoWrapper(uuid, drmSessionId.array(), drmSessionId.size()); 1518 if (crypto == NULL) { 1519 ALOGE("prepareDrm: failed to create crypto."); 1520 return UNKNOWN_ERROR; 1521 } 1522 ALOGV("prepareDrm: crypto created for uuid: %s", 1523 DrmUUID::toHexString(uuid).string()); 1524 1525 *outCrypto = crypto; 1526 // as long a there is an active crypto 1527 mIsDrmProtected = true; 1528 1529 if (mMimes.size() == 0) { 1530 status = UNKNOWN_ERROR; 1531 ALOGE("prepareDrm: Unexpected. Must have at least one track. status: %d", status); 1532 return status; 1533 } 1534 1535 // first mime in this list is either the video track, or the first audio track 1536 const char *mime = mMimes[0].string(); 1537 mIsSecure = crypto->requiresSecureDecoderComponent(mime); 1538 ALOGV("prepareDrm: requiresSecureDecoderComponent mime: %s isSecure: %d", 1539 mime, mIsSecure); 1540 1541 // Checking the member flags while in the looper to send out the notification. 1542 // The legacy mDecryptHandle!=NULL check (for FLAG_PROTECTED) is equivalent to mIsDrmProtected. 1543 notifyFlagsChanged( 1544 (mIsSecure ? FLAG_SECURE : 0) | 1545 // Setting "protected screen" only for L1: b/38390836 1546 (mIsSecure ? FLAG_PROTECTED : 0) | 1547 FLAG_CAN_PAUSE | 1548 FLAG_CAN_SEEK_BACKWARD | 1549 FLAG_CAN_SEEK_FORWARD | 1550 FLAG_CAN_SEEK); 1551 1552 if (status == OK) { 1553 ALOGV("prepareDrm: mCrypto: %p", outCrypto->get()); 1554 ALOGD("prepareDrm ret: %d ", status); 1555 } else { 1556 ALOGE("prepareDrm err: %d", status); 1557 } 1558 return status; 1559 } 1560 1561 status_t NuPlayer2::GenericSource2::releaseDrm() { 1562 Mutex::Autolock _l(mLock); 1563 ALOGV("releaseDrm"); 1564 1565 if (mIsDrmProtected) { 1566 mIsDrmProtected = false; 1567 // to prevent returning any more buffer after stop/releaseDrm (b/37960096) 1568 mIsDrmReleased = true; 1569 ALOGV("releaseDrm: mIsDrmProtected is reset."); 1570 } else { 1571 ALOGE("releaseDrm: mIsDrmProtected is already false."); 1572 } 1573 1574 return OK; 1575 } 1576 1577 status_t NuPlayer2::GenericSource2::checkDrmInfo() 1578 { 1579 // clearing the flag at prepare in case the player is reused after stop/releaseDrm with the 1580 // same source without being reset (called by prepareAsync/initFromDataSource) 1581 mIsDrmReleased = false; 1582 1583 if (mExtractor == NULL) { 1584 ALOGV("checkDrmInfo: No extractor"); 1585 return OK; // letting the caller responds accordingly 1586 } 1587 1588 PsshInfo *psshInfo = mExtractor->getPsshInfo(); 1589 if (psshInfo == NULL) { 1590 ALOGV("checkDrmInfo: No PSSH"); 1591 return OK; // source without DRM info 1592 } 1593 1594 sp<ABuffer> drmInfoBuffer = NuPlayer2Drm::retrieveDrmInfo(psshInfo); 1595 ALOGV("checkDrmInfo: MEDIA_DRM_INFO PSSH drm info size: %d", (int)drmInfoBuffer->size()); 1596 1597 if (drmInfoBuffer->size() == 0) { 1598 ALOGE("checkDrmInfo: Unexpected parcel size: 0"); 1599 return UNKNOWN_ERROR; 1600 } 1601 1602 notifyDrmInfo(drmInfoBuffer); 1603 1604 return OK; 1605 } 1606 1607 void NuPlayer2::GenericSource2::signalBufferReturned(MediaBufferBase *buffer) 1608 { 1609 //ALOGV("signalBufferReturned %p refCount: %d", buffer, buffer->localRefcount()); 1610 1611 buffer->setObserver(NULL); 1612 buffer->release(); // this leads to delete since that there is no observor 1613 } 1614 1615 } // namespace android 1616