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#include "NuPlayerDrm.h" 22 23#include "AnotherPacketSource.h" 24#include <binder/IServiceManager.h> 25#include <cutils/properties.h> 26#include <media/IMediaExtractorService.h> 27#include <media/IMediaHTTPService.h> 28#include <media/stagefright/foundation/ABuffer.h> 29#include <media/stagefright/foundation/ADebug.h> 30#include <media/stagefright/foundation/AMessage.h> 31#include <media/stagefright/DataSource.h> 32#include <media/stagefright/FileSource.h> 33#include <media/stagefright/MediaBuffer.h> 34#include <media/stagefright/MediaDefs.h> 35#include <media/stagefright/MediaExtractor.h> 36#include <media/stagefright/MediaSource.h> 37#include <media/stagefright/MetaData.h> 38#include <media/stagefright/Utils.h> 39#include "../../libstagefright/include/NuCachedSource2.h" 40#include "../../libstagefright/include/HTTPBase.h" 41 42namespace android { 43 44static const int kLowWaterMarkMs = 2000; // 2secs 45static const int kHighWaterMarkMs = 5000; // 5secs 46static const int kHighWaterMarkRebufferMs = 15000; // 15secs 47 48static const int kLowWaterMarkKB = 40; 49static const int kHighWaterMarkKB = 200; 50 51NuPlayer::GenericSource::GenericSource( 52 const sp<AMessage> ¬ify, 53 bool uidValid, 54 uid_t uid) 55 : Source(notify), 56 mAudioTimeUs(0), 57 mAudioLastDequeueTimeUs(0), 58 mVideoTimeUs(0), 59 mVideoLastDequeueTimeUs(0), 60 mFetchSubtitleDataGeneration(0), 61 mFetchTimedTextDataGeneration(0), 62 mDurationUs(-1ll), 63 mAudioIsVorbis(false), 64 mIsSecure(false), 65 mIsStreaming(false), 66 mUIDValid(uidValid), 67 mUID(uid), 68 mFd(-1), 69 mBitrate(-1ll), 70 mPendingReadBufferTypes(0) { 71 ALOGV("GenericSource"); 72 73 mBufferingMonitor = new BufferingMonitor(notify); 74 resetDataSource(); 75} 76 77void NuPlayer::GenericSource::resetDataSource() { 78 ALOGV("resetDataSource"); 79 80 mHTTPService.clear(); 81 mHttpSource.clear(); 82 mUri.clear(); 83 mUriHeaders.clear(); 84 if (mFd >= 0) { 85 close(mFd); 86 mFd = -1; 87 } 88 mOffset = 0; 89 mLength = 0; 90 mStarted = false; 91 mStopRead = true; 92 93 if (mBufferingMonitorLooper != NULL) { 94 mBufferingMonitorLooper->unregisterHandler(mBufferingMonitor->id()); 95 mBufferingMonitorLooper->stop(); 96 mBufferingMonitorLooper = NULL; 97 } 98 mBufferingMonitor->stop(); 99 100 mIsDrmProtected = false; 101 mIsDrmReleased = false; 102 mIsSecure = false; 103 mMimes.clear(); 104} 105 106status_t NuPlayer::GenericSource::setDataSource( 107 const sp<IMediaHTTPService> &httpService, 108 const char *url, 109 const KeyedVector<String8, String8> *headers) { 110 ALOGV("setDataSource url: %s", url); 111 112 resetDataSource(); 113 114 mHTTPService = httpService; 115 mUri = url; 116 117 if (headers) { 118 mUriHeaders = *headers; 119 } 120 121 // delay data source creation to prepareAsync() to avoid blocking 122 // the calling thread in setDataSource for any significant time. 123 return OK; 124} 125 126status_t NuPlayer::GenericSource::setDataSource( 127 int fd, int64_t offset, int64_t length) { 128 ALOGV("setDataSource %d/%lld/%lld", fd, (long long)offset, (long long)length); 129 130 resetDataSource(); 131 132 mFd = dup(fd); 133 mOffset = offset; 134 mLength = length; 135 136 // delay data source creation to prepareAsync() to avoid blocking 137 // the calling thread in setDataSource for any significant time. 138 return OK; 139} 140 141status_t NuPlayer::GenericSource::setDataSource(const sp<DataSource>& source) { 142 ALOGV("setDataSource (source: %p)", source.get()); 143 144 resetDataSource(); 145 mDataSource = source; 146 return OK; 147} 148 149sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const { 150 return mFileMeta; 151} 152 153status_t NuPlayer::GenericSource::initFromDataSource() { 154 sp<IMediaExtractor> extractor; 155 CHECK(mDataSource != NULL); 156 157 extractor = MediaExtractor::Create(mDataSource, NULL); 158 159 if (extractor == NULL) { 160 ALOGE("initFromDataSource, cannot create extractor!"); 161 return UNKNOWN_ERROR; 162 } 163 164 mFileMeta = extractor->getMetaData(); 165 if (mFileMeta != NULL) { 166 int64_t duration; 167 if (mFileMeta->findInt64(kKeyDuration, &duration)) { 168 mDurationUs = duration; 169 } 170 } 171 172 int32_t totalBitrate = 0; 173 174 size_t numtracks = extractor->countTracks(); 175 if (numtracks == 0) { 176 ALOGE("initFromDataSource, source has no track!"); 177 return UNKNOWN_ERROR; 178 } 179 180 mMimes.clear(); 181 182 for (size_t i = 0; i < numtracks; ++i) { 183 sp<IMediaSource> track = extractor->getTrack(i); 184 if (track == NULL) { 185 continue; 186 } 187 188 sp<MetaData> meta = extractor->getTrackMetaData(i); 189 if (meta == NULL) { 190 ALOGE("no metadata for track %zu", i); 191 return UNKNOWN_ERROR; 192 } 193 194 const char *mime; 195 CHECK(meta->findCString(kKeyMIMEType, &mime)); 196 197 ALOGV("initFromDataSource track[%zu]: %s", i, mime); 198 199 // Do the string compare immediately with "mime", 200 // we can't assume "mime" would stay valid after another 201 // extractor operation, some extractors might modify meta 202 // during getTrack() and make it invalid. 203 if (!strncasecmp(mime, "audio/", 6)) { 204 if (mAudioTrack.mSource == NULL) { 205 mAudioTrack.mIndex = i; 206 mAudioTrack.mSource = track; 207 mAudioTrack.mPackets = 208 new AnotherPacketSource(mAudioTrack.mSource->getFormat()); 209 210 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { 211 mAudioIsVorbis = true; 212 } else { 213 mAudioIsVorbis = false; 214 } 215 216 mMimes.add(String8(mime)); 217 } 218 } else if (!strncasecmp(mime, "video/", 6)) { 219 if (mVideoTrack.mSource == NULL) { 220 mVideoTrack.mIndex = i; 221 mVideoTrack.mSource = track; 222 mVideoTrack.mPackets = 223 new AnotherPacketSource(mVideoTrack.mSource->getFormat()); 224 225 // video always at the beginning 226 mMimes.insertAt(String8(mime), 0); 227 } 228 } 229 230 mSources.push(track); 231 int64_t durationUs; 232 if (meta->findInt64(kKeyDuration, &durationUs)) { 233 if (durationUs > mDurationUs) { 234 mDurationUs = durationUs; 235 } 236 } 237 238 int32_t bitrate; 239 if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) { 240 totalBitrate += bitrate; 241 } else { 242 totalBitrate = -1; 243 } 244 } 245 246 ALOGV("initFromDataSource mSources.size(): %zu mIsSecure: %d mime[0]: %s", mSources.size(), 247 mIsSecure, (mMimes.isEmpty() ? "NONE" : mMimes[0].string())); 248 249 if (mSources.size() == 0) { 250 ALOGE("b/23705695"); 251 return UNKNOWN_ERROR; 252 } 253 254 // Modular DRM: The return value doesn't affect source initialization. 255 (void)checkDrmInfo(); 256 257 mBitrate = totalBitrate; 258 259 return OK; 260} 261 262status_t NuPlayer::GenericSource::getDefaultBufferingSettings( 263 BufferingSettings* buffering /* nonnull */) { 264 mBufferingMonitor->getDefaultBufferingSettings(buffering); 265 return OK; 266} 267 268status_t NuPlayer::GenericSource::setBufferingSettings(const BufferingSettings& buffering) { 269 return mBufferingMonitor->setBufferingSettings(buffering); 270} 271 272status_t NuPlayer::GenericSource::startSources() { 273 // Start the selected A/V tracks now before we start buffering. 274 // Widevine sources might re-initialize crypto when starting, if we delay 275 // this to start(), all data buffered during prepare would be wasted. 276 // (We don't actually start reading until start().) 277 // 278 // TODO: this logic may no longer be relevant after the removal of widevine 279 // support 280 if (mAudioTrack.mSource != NULL && mAudioTrack.mSource->start() != OK) { 281 ALOGE("failed to start audio track!"); 282 return UNKNOWN_ERROR; 283 } 284 285 if (mVideoTrack.mSource != NULL && mVideoTrack.mSource->start() != OK) { 286 ALOGE("failed to start video track!"); 287 return UNKNOWN_ERROR; 288 } 289 290 return OK; 291} 292 293int64_t NuPlayer::GenericSource::getLastReadPosition() { 294 if (mAudioTrack.mSource != NULL) { 295 return mAudioTimeUs; 296 } else if (mVideoTrack.mSource != NULL) { 297 return mVideoTimeUs; 298 } else { 299 return 0; 300 } 301} 302 303status_t NuPlayer::GenericSource::setBuffers( 304 bool audio, Vector<MediaBuffer *> &buffers) { 305 if (mIsSecure && !audio && mVideoTrack.mSource != NULL) { 306 return mVideoTrack.mSource->setBuffers(buffers); 307 } 308 return INVALID_OPERATION; 309} 310 311bool NuPlayer::GenericSource::isStreaming() const { 312 return mIsStreaming; 313} 314 315void NuPlayer::GenericSource::setOffloadAudio(bool offload) { 316 mBufferingMonitor->setOffloadAudio(offload); 317} 318 319NuPlayer::GenericSource::~GenericSource() { 320 ALOGV("~GenericSource"); 321 if (mLooper != NULL) { 322 mLooper->unregisterHandler(id()); 323 mLooper->stop(); 324 } 325 resetDataSource(); 326} 327 328void NuPlayer::GenericSource::prepareAsync() { 329 ALOGV("prepareAsync: (looper: %d)", (mLooper != NULL)); 330 331 if (mLooper == NULL) { 332 mLooper = new ALooper; 333 mLooper->setName("generic"); 334 mLooper->start(); 335 336 mLooper->registerHandler(this); 337 } 338 339 sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this); 340 msg->post(); 341} 342 343void NuPlayer::GenericSource::onPrepareAsync() { 344 ALOGV("onPrepareAsync: mDataSource: %d", (mDataSource != NULL)); 345 346 // delayed data source creation 347 if (mDataSource == NULL) { 348 // set to false first, if the extractor 349 // comes back as secure, set it to true then. 350 mIsSecure = false; 351 352 if (!mUri.empty()) { 353 const char* uri = mUri.c_str(); 354 String8 contentType; 355 356 if (!strncasecmp("http://", uri, 7) || !strncasecmp("https://", uri, 8)) { 357 mHttpSource = DataSource::CreateMediaHTTP(mHTTPService); 358 if (mHttpSource == NULL) { 359 ALOGE("Failed to create http source!"); 360 notifyPreparedAndCleanup(UNKNOWN_ERROR); 361 return; 362 } 363 } 364 365 mDataSource = DataSource::CreateFromURI( 366 mHTTPService, uri, &mUriHeaders, &contentType, 367 static_cast<HTTPBase *>(mHttpSource.get())); 368 } else { 369 if (property_get_bool("media.stagefright.extractremote", true) && 370 !FileSource::requiresDrm(mFd, mOffset, mLength, nullptr /* mime */)) { 371 sp<IBinder> binder = 372 defaultServiceManager()->getService(String16("media.extractor")); 373 if (binder != nullptr) { 374 ALOGD("FileSource remote"); 375 sp<IMediaExtractorService> mediaExService( 376 interface_cast<IMediaExtractorService>(binder)); 377 sp<IDataSource> source = 378 mediaExService->makeIDataSource(mFd, mOffset, mLength); 379 ALOGV("IDataSource(FileSource): %p %d %lld %lld", 380 source.get(), mFd, (long long)mOffset, (long long)mLength); 381 if (source.get() != nullptr) { 382 mDataSource = DataSource::CreateFromIDataSource(source); 383 if (mDataSource != nullptr) { 384 // Close the local file descriptor as it is not needed anymore. 385 close(mFd); 386 mFd = -1; 387 } 388 } else { 389 ALOGW("extractor service cannot make data source"); 390 } 391 } else { 392 ALOGW("extractor service not running"); 393 } 394 } 395 if (mDataSource == nullptr) { 396 ALOGD("FileSource local"); 397 mDataSource = new FileSource(mFd, mOffset, mLength); 398 } 399 // TODO: close should always be done on mFd, see the lines following 400 // DataSource::CreateFromIDataSource above, 401 // and the FileSource constructor should dup the mFd argument as needed. 402 mFd = -1; 403 } 404 405 if (mDataSource == NULL) { 406 ALOGE("Failed to create data source!"); 407 notifyPreparedAndCleanup(UNKNOWN_ERROR); 408 return; 409 } 410 } 411 412 if (mDataSource->flags() & DataSource::kIsCachingDataSource) { 413 mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get()); 414 } 415 416 // For cached streaming cases, we need to wait for enough 417 // buffering before reporting prepared. 418 mIsStreaming = (mCachedSource != NULL); 419 420 // init extractor from data source 421 status_t err = initFromDataSource(); 422 423 if (err != OK) { 424 ALOGE("Failed to init from data source!"); 425 notifyPreparedAndCleanup(err); 426 return; 427 } 428 429 if (mVideoTrack.mSource != NULL) { 430 sp<MetaData> meta = doGetFormatMeta(false /* audio */); 431 sp<AMessage> msg = new AMessage; 432 err = convertMetaDataToMessage(meta, &msg); 433 if(err != OK) { 434 notifyPreparedAndCleanup(err); 435 return; 436 } 437 notifyVideoSizeChanged(msg); 438 } 439 440 notifyFlagsChanged( 441 // FLAG_SECURE will be known if/when prepareDrm is called by the app 442 // FLAG_PROTECTED will be known if/when prepareDrm is called by the app 443 FLAG_CAN_PAUSE | 444 FLAG_CAN_SEEK_BACKWARD | 445 FLAG_CAN_SEEK_FORWARD | 446 FLAG_CAN_SEEK); 447 448 finishPrepareAsync(); 449 450 ALOGV("onPrepareAsync: Done"); 451} 452 453void NuPlayer::GenericSource::finishPrepareAsync() { 454 ALOGV("finishPrepareAsync"); 455 456 status_t err = startSources(); 457 if (err != OK) { 458 ALOGE("Failed to init start data source!"); 459 notifyPreparedAndCleanup(err); 460 return; 461 } 462 463 if (mIsStreaming) { 464 if (mBufferingMonitorLooper == NULL) { 465 mBufferingMonitor->prepare(mCachedSource, mDurationUs, mBitrate, 466 mIsStreaming); 467 468 mBufferingMonitorLooper = new ALooper; 469 mBufferingMonitorLooper->setName("GSBMonitor"); 470 mBufferingMonitorLooper->start(); 471 mBufferingMonitorLooper->registerHandler(mBufferingMonitor); 472 } 473 474 mBufferingMonitor->ensureCacheIsFetching(); 475 mBufferingMonitor->restartPollBuffering(); 476 } else { 477 notifyPrepared(); 478 } 479} 480 481void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) { 482 if (err != OK) { 483 { 484 sp<DataSource> dataSource = mDataSource; 485 sp<NuCachedSource2> cachedSource = mCachedSource; 486 sp<DataSource> httpSource = mHttpSource; 487 { 488 Mutex::Autolock _l(mDisconnectLock); 489 mDataSource.clear(); 490 mCachedSource.clear(); 491 mHttpSource.clear(); 492 } 493 } 494 mBitrate = -1; 495 496 mBufferingMonitor->cancelPollBuffering(); 497 } 498 notifyPrepared(err); 499} 500 501void NuPlayer::GenericSource::start() { 502 ALOGI("start"); 503 504 mStopRead = false; 505 if (mAudioTrack.mSource != NULL) { 506 postReadBuffer(MEDIA_TRACK_TYPE_AUDIO); 507 } 508 509 if (mVideoTrack.mSource != NULL) { 510 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO); 511 } 512 513 mStarted = true; 514 515 (new AMessage(kWhatStart, this))->post(); 516} 517 518void NuPlayer::GenericSource::stop() { 519 mStarted = false; 520} 521 522void NuPlayer::GenericSource::pause() { 523 mStarted = false; 524} 525 526void NuPlayer::GenericSource::resume() { 527 mStarted = true; 528 529 (new AMessage(kWhatResume, this))->post(); 530} 531 532void NuPlayer::GenericSource::disconnect() { 533 sp<DataSource> dataSource, httpSource; 534 { 535 Mutex::Autolock _l(mDisconnectLock); 536 dataSource = mDataSource; 537 httpSource = mHttpSource; 538 } 539 540 if (dataSource != NULL) { 541 // disconnect data source 542 if (dataSource->flags() & DataSource::kIsCachingDataSource) { 543 static_cast<NuCachedSource2 *>(dataSource.get())->disconnect(); 544 } 545 } else if (httpSource != NULL) { 546 static_cast<HTTPBase *>(httpSource.get())->disconnect(); 547 } 548} 549 550status_t NuPlayer::GenericSource::feedMoreTSData() { 551 return OK; 552} 553 554void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) { 555 switch (msg->what()) { 556 case kWhatPrepareAsync: 557 { 558 onPrepareAsync(); 559 break; 560 } 561 case kWhatFetchSubtitleData: 562 { 563 fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, 564 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); 565 break; 566 } 567 568 case kWhatFetchTimedTextData: 569 { 570 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, 571 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); 572 break; 573 } 574 575 case kWhatSendSubtitleData: 576 { 577 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, 578 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); 579 break; 580 } 581 582 case kWhatSendGlobalTimedTextData: 583 { 584 sendGlobalTextData(kWhatTimedTextData, mFetchTimedTextDataGeneration, msg); 585 break; 586 } 587 case kWhatSendTimedTextData: 588 { 589 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, 590 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); 591 break; 592 } 593 594 case kWhatChangeAVSource: 595 { 596 int32_t trackIndex; 597 CHECK(msg->findInt32("trackIndex", &trackIndex)); 598 const sp<IMediaSource> source = mSources.itemAt(trackIndex); 599 600 Track* track; 601 const char *mime; 602 media_track_type trackType, counterpartType; 603 sp<MetaData> meta = source->getFormat(); 604 meta->findCString(kKeyMIMEType, &mime); 605 if (!strncasecmp(mime, "audio/", 6)) { 606 track = &mAudioTrack; 607 trackType = MEDIA_TRACK_TYPE_AUDIO; 608 counterpartType = MEDIA_TRACK_TYPE_VIDEO;; 609 } else { 610 CHECK(!strncasecmp(mime, "video/", 6)); 611 track = &mVideoTrack; 612 trackType = MEDIA_TRACK_TYPE_VIDEO; 613 counterpartType = MEDIA_TRACK_TYPE_AUDIO;; 614 } 615 616 617 if (track->mSource != NULL) { 618 track->mSource->stop(); 619 } 620 track->mSource = source; 621 track->mSource->start(); 622 track->mIndex = trackIndex; 623 624 int64_t timeUs, actualTimeUs; 625 const bool formatChange = true; 626 if (trackType == MEDIA_TRACK_TYPE_AUDIO) { 627 timeUs = mAudioLastDequeueTimeUs; 628 } else { 629 timeUs = mVideoLastDequeueTimeUs; 630 } 631 readBuffer(trackType, timeUs, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */, 632 &actualTimeUs, formatChange); 633 readBuffer(counterpartType, -1, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */, 634 NULL, !formatChange); 635 ALOGV("timeUs %lld actualTimeUs %lld", (long long)timeUs, (long long)actualTimeUs); 636 637 break; 638 } 639 640 case kWhatStart: 641 case kWhatResume: 642 { 643 mBufferingMonitor->restartPollBuffering(); 644 break; 645 } 646 647 case kWhatGetFormat: 648 { 649 onGetFormatMeta(msg); 650 break; 651 } 652 653 case kWhatGetSelectedTrack: 654 { 655 onGetSelectedTrack(msg); 656 break; 657 } 658 659 case kWhatGetTrackInfo: 660 { 661 onGetTrackInfo(msg); 662 break; 663 } 664 665 case kWhatSelectTrack: 666 { 667 onSelectTrack(msg); 668 break; 669 } 670 671 case kWhatSeek: 672 { 673 onSeek(msg); 674 break; 675 } 676 677 case kWhatReadBuffer: 678 { 679 onReadBuffer(msg); 680 break; 681 } 682 683 case kWhatPrepareDrm: 684 { 685 status_t status = onPrepareDrm(msg); 686 sp<AMessage> response = new AMessage; 687 response->setInt32("status", status); 688 sp<AReplyToken> replyID; 689 CHECK(msg->senderAwaitsResponse(&replyID)); 690 response->postReply(replyID); 691 break; 692 } 693 694 case kWhatReleaseDrm: 695 { 696 status_t status = onReleaseDrm(); 697 sp<AMessage> response = new AMessage; 698 response->setInt32("status", status); 699 sp<AReplyToken> replyID; 700 CHECK(msg->senderAwaitsResponse(&replyID)); 701 response->postReply(replyID); 702 break; 703 } 704 705 default: 706 Source::onMessageReceived(msg); 707 break; 708 } 709} 710 711void NuPlayer::GenericSource::fetchTextData( 712 uint32_t sendWhat, 713 media_track_type type, 714 int32_t curGen, 715 const sp<AnotherPacketSource>& packets, 716 const sp<AMessage>& msg) { 717 int32_t msgGeneration; 718 CHECK(msg->findInt32("generation", &msgGeneration)); 719 if (msgGeneration != curGen) { 720 // stale 721 return; 722 } 723 724 int32_t avail; 725 if (packets->hasBufferAvailable(&avail)) { 726 return; 727 } 728 729 int64_t timeUs; 730 CHECK(msg->findInt64("timeUs", &timeUs)); 731 732 int64_t subTimeUs; 733 readBuffer(type, timeUs, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */, &subTimeUs); 734 735 int64_t delayUs = subTimeUs - timeUs; 736 if (msg->what() == kWhatFetchSubtitleData) { 737 const int64_t oneSecUs = 1000000ll; 738 delayUs -= oneSecUs; 739 } 740 sp<AMessage> msg2 = new AMessage(sendWhat, this); 741 msg2->setInt32("generation", msgGeneration); 742 msg2->post(delayUs < 0 ? 0 : delayUs); 743} 744 745void NuPlayer::GenericSource::sendTextData( 746 uint32_t what, 747 media_track_type type, 748 int32_t curGen, 749 const sp<AnotherPacketSource>& packets, 750 const sp<AMessage>& msg) { 751 int32_t msgGeneration; 752 CHECK(msg->findInt32("generation", &msgGeneration)); 753 if (msgGeneration != curGen) { 754 // stale 755 return; 756 } 757 758 int64_t subTimeUs; 759 if (packets->nextBufferTime(&subTimeUs) != OK) { 760 return; 761 } 762 763 int64_t nextSubTimeUs; 764 readBuffer(type, -1, MediaPlayerSeekMode::SEEK_PREVIOUS_SYNC /* mode */, &nextSubTimeUs); 765 766 sp<ABuffer> buffer; 767 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer); 768 if (dequeueStatus == OK) { 769 sp<AMessage> notify = dupNotify(); 770 notify->setInt32("what", what); 771 notify->setBuffer("buffer", buffer); 772 notify->post(); 773 774 const int64_t delayUs = nextSubTimeUs - subTimeUs; 775 msg->post(delayUs < 0 ? 0 : delayUs); 776 } 777} 778 779void NuPlayer::GenericSource::sendGlobalTextData( 780 uint32_t what, 781 int32_t curGen, 782 sp<AMessage> msg) { 783 int32_t msgGeneration; 784 CHECK(msg->findInt32("generation", &msgGeneration)); 785 if (msgGeneration != curGen) { 786 // stale 787 return; 788 } 789 790 uint32_t textType; 791 const void *data; 792 size_t size = 0; 793 if (mTimedTextTrack.mSource->getFormat()->findData( 794 kKeyTextFormatData, &textType, &data, &size)) { 795 mGlobalTimedText = new ABuffer(size); 796 if (mGlobalTimedText->data()) { 797 memcpy(mGlobalTimedText->data(), data, size); 798 sp<AMessage> globalMeta = mGlobalTimedText->meta(); 799 globalMeta->setInt64("timeUs", 0); 800 globalMeta->setString("mime", MEDIA_MIMETYPE_TEXT_3GPP); 801 globalMeta->setInt32("global", 1); 802 sp<AMessage> notify = dupNotify(); 803 notify->setInt32("what", what); 804 notify->setBuffer("buffer", mGlobalTimedText); 805 notify->post(); 806 } 807 } 808} 809 810sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) { 811 sp<AMessage> msg = new AMessage(kWhatGetFormat, this); 812 msg->setInt32("audio", audio); 813 814 sp<AMessage> response; 815 sp<RefBase> format; 816 status_t err = msg->postAndAwaitResponse(&response); 817 if (err == OK && response != NULL) { 818 CHECK(response->findObject("format", &format)); 819 return static_cast<MetaData*>(format.get()); 820 } else { 821 return NULL; 822 } 823} 824 825void NuPlayer::GenericSource::onGetFormatMeta(const sp<AMessage>& msg) const { 826 int32_t audio; 827 CHECK(msg->findInt32("audio", &audio)); 828 829 sp<AMessage> response = new AMessage; 830 sp<MetaData> format = doGetFormatMeta(audio); 831 response->setObject("format", format); 832 833 sp<AReplyToken> replyID; 834 CHECK(msg->senderAwaitsResponse(&replyID)); 835 response->postReply(replyID); 836} 837 838sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const { 839 sp<IMediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource; 840 841 if (source == NULL) { 842 return NULL; 843 } 844 845 return source->getFormat(); 846} 847 848status_t NuPlayer::GenericSource::dequeueAccessUnit( 849 bool audio, sp<ABuffer> *accessUnit) { 850 if (audio && !mStarted) { 851 return -EWOULDBLOCK; 852 } 853 854 // If has gone through stop/releaseDrm sequence, we no longer send down any buffer b/c 855 // the codec's crypto object has gone away (b/37960096). 856 // Note: This will be unnecessary when stop() changes behavior and releases codec (b/35248283). 857 if (!mStarted && mIsDrmReleased) { 858 return -EWOULDBLOCK; 859 } 860 861 Track *track = audio ? &mAudioTrack : &mVideoTrack; 862 863 if (track->mSource == NULL) { 864 return -EWOULDBLOCK; 865 } 866 867 status_t finalResult; 868 if (!track->mPackets->hasBufferAvailable(&finalResult)) { 869 if (finalResult == OK) { 870 postReadBuffer( 871 audio ? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO); 872 return -EWOULDBLOCK; 873 } 874 return finalResult; 875 } 876 877 status_t result = track->mPackets->dequeueAccessUnit(accessUnit); 878 879 // start pulling in more buffers if we only have one (or no) buffer left 880 // so that decoder has less chance of being starved 881 if (track->mPackets->getAvailableBufferCount(&finalResult) < 2) { 882 postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO); 883 } 884 885 if (result != OK) { 886 if (mSubtitleTrack.mSource != NULL) { 887 mSubtitleTrack.mPackets->clear(); 888 mFetchSubtitleDataGeneration++; 889 } 890 if (mTimedTextTrack.mSource != NULL) { 891 mTimedTextTrack.mPackets->clear(); 892 mFetchTimedTextDataGeneration++; 893 } 894 return result; 895 } 896 897 int64_t timeUs; 898 status_t eosResult; // ignored 899 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); 900 if (audio) { 901 mAudioLastDequeueTimeUs = timeUs; 902 mBufferingMonitor->updateDequeuedBufferTime(timeUs); 903 } else { 904 mVideoLastDequeueTimeUs = timeUs; 905 } 906 907 if (mSubtitleTrack.mSource != NULL 908 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { 909 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this); 910 msg->setInt64("timeUs", timeUs); 911 msg->setInt32("generation", mFetchSubtitleDataGeneration); 912 msg->post(); 913 } 914 915 if (mTimedTextTrack.mSource != NULL 916 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) { 917 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this); 918 msg->setInt64("timeUs", timeUs); 919 msg->setInt32("generation", mFetchTimedTextDataGeneration); 920 msg->post(); 921 } 922 923 return result; 924} 925 926status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) { 927 *durationUs = mDurationUs; 928 return OK; 929} 930 931size_t NuPlayer::GenericSource::getTrackCount() const { 932 return mSources.size(); 933} 934 935sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const { 936 sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, this); 937 msg->setSize("trackIndex", trackIndex); 938 939 sp<AMessage> response; 940 sp<RefBase> format; 941 status_t err = msg->postAndAwaitResponse(&response); 942 if (err == OK && response != NULL) { 943 CHECK(response->findObject("format", &format)); 944 return static_cast<AMessage*>(format.get()); 945 } else { 946 return NULL; 947 } 948} 949 950void NuPlayer::GenericSource::onGetTrackInfo(const sp<AMessage>& msg) const { 951 size_t trackIndex; 952 CHECK(msg->findSize("trackIndex", &trackIndex)); 953 954 sp<AMessage> response = new AMessage; 955 sp<AMessage> format = doGetTrackInfo(trackIndex); 956 response->setObject("format", format); 957 958 sp<AReplyToken> replyID; 959 CHECK(msg->senderAwaitsResponse(&replyID)); 960 response->postReply(replyID); 961} 962 963sp<AMessage> NuPlayer::GenericSource::doGetTrackInfo(size_t trackIndex) const { 964 size_t trackCount = mSources.size(); 965 if (trackIndex >= trackCount) { 966 return NULL; 967 } 968 969 sp<AMessage> format = new AMessage(); 970 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat(); 971 if (meta == NULL) { 972 ALOGE("no metadata for track %zu", trackIndex); 973 return NULL; 974 } 975 976 const char *mime; 977 CHECK(meta->findCString(kKeyMIMEType, &mime)); 978 format->setString("mime", mime); 979 980 int32_t trackType; 981 if (!strncasecmp(mime, "video/", 6)) { 982 trackType = MEDIA_TRACK_TYPE_VIDEO; 983 } else if (!strncasecmp(mime, "audio/", 6)) { 984 trackType = MEDIA_TRACK_TYPE_AUDIO; 985 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { 986 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT; 987 } else { 988 trackType = MEDIA_TRACK_TYPE_UNKNOWN; 989 } 990 format->setInt32("type", trackType); 991 992 const char *lang; 993 if (!meta->findCString(kKeyMediaLanguage, &lang)) { 994 lang = "und"; 995 } 996 format->setString("language", lang); 997 998 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 999 int32_t isAutoselect = 1, isDefault = 0, isForced = 0; 1000 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect); 1001 meta->findInt32(kKeyTrackIsDefault, &isDefault); 1002 meta->findInt32(kKeyTrackIsForced, &isForced); 1003 1004 format->setInt32("auto", !!isAutoselect); 1005 format->setInt32("default", !!isDefault); 1006 format->setInt32("forced", !!isForced); 1007 } 1008 1009 return format; 1010} 1011 1012ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const { 1013 sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, this); 1014 msg->setInt32("type", type); 1015 1016 sp<AMessage> response; 1017 int32_t index; 1018 status_t err = msg->postAndAwaitResponse(&response); 1019 if (err == OK && response != NULL) { 1020 CHECK(response->findInt32("index", &index)); 1021 return index; 1022 } else { 1023 return -1; 1024 } 1025} 1026 1027void NuPlayer::GenericSource::onGetSelectedTrack(const sp<AMessage>& msg) const { 1028 int32_t tmpType; 1029 CHECK(msg->findInt32("type", &tmpType)); 1030 media_track_type type = (media_track_type)tmpType; 1031 1032 sp<AMessage> response = new AMessage; 1033 ssize_t index = doGetSelectedTrack(type); 1034 response->setInt32("index", index); 1035 1036 sp<AReplyToken> replyID; 1037 CHECK(msg->senderAwaitsResponse(&replyID)); 1038 response->postReply(replyID); 1039} 1040 1041ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const { 1042 const Track *track = NULL; 1043 switch (type) { 1044 case MEDIA_TRACK_TYPE_VIDEO: 1045 track = &mVideoTrack; 1046 break; 1047 case MEDIA_TRACK_TYPE_AUDIO: 1048 track = &mAudioTrack; 1049 break; 1050 case MEDIA_TRACK_TYPE_TIMEDTEXT: 1051 track = &mTimedTextTrack; 1052 break; 1053 case MEDIA_TRACK_TYPE_SUBTITLE: 1054 track = &mSubtitleTrack; 1055 break; 1056 default: 1057 break; 1058 } 1059 1060 if (track != NULL && track->mSource != NULL) { 1061 return track->mIndex; 1062 } 1063 1064 return -1; 1065} 1066 1067status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) { 1068 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex); 1069 sp<AMessage> msg = new AMessage(kWhatSelectTrack, this); 1070 msg->setInt32("trackIndex", trackIndex); 1071 msg->setInt32("select", select); 1072 msg->setInt64("timeUs", timeUs); 1073 1074 sp<AMessage> response; 1075 status_t err = msg->postAndAwaitResponse(&response); 1076 if (err == OK && response != NULL) { 1077 CHECK(response->findInt32("err", &err)); 1078 } 1079 1080 return err; 1081} 1082 1083void NuPlayer::GenericSource::onSelectTrack(const sp<AMessage>& msg) { 1084 int32_t trackIndex, select; 1085 int64_t timeUs; 1086 CHECK(msg->findInt32("trackIndex", &trackIndex)); 1087 CHECK(msg->findInt32("select", &select)); 1088 CHECK(msg->findInt64("timeUs", &timeUs)); 1089 1090 sp<AMessage> response = new AMessage; 1091 status_t err = doSelectTrack(trackIndex, select, timeUs); 1092 response->setInt32("err", err); 1093 1094 sp<AReplyToken> replyID; 1095 CHECK(msg->senderAwaitsResponse(&replyID)); 1096 response->postReply(replyID); 1097} 1098 1099status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select, int64_t timeUs) { 1100 if (trackIndex >= mSources.size()) { 1101 return BAD_INDEX; 1102 } 1103 1104 if (!select) { 1105 Track* track = NULL; 1106 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) { 1107 track = &mSubtitleTrack; 1108 mFetchSubtitleDataGeneration++; 1109 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) { 1110 track = &mTimedTextTrack; 1111 mFetchTimedTextDataGeneration++; 1112 } 1113 if (track == NULL) { 1114 return INVALID_OPERATION; 1115 } 1116 track->mSource->stop(); 1117 track->mSource = NULL; 1118 track->mPackets->clear(); 1119 return OK; 1120 } 1121 1122 const sp<IMediaSource> source = mSources.itemAt(trackIndex); 1123 sp<MetaData> meta = source->getFormat(); 1124 const char *mime; 1125 CHECK(meta->findCString(kKeyMIMEType, &mime)); 1126 if (!strncasecmp(mime, "text/", 5)) { 1127 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP); 1128 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack; 1129 if (track->mSource != NULL && track->mIndex == trackIndex) { 1130 return OK; 1131 } 1132 track->mIndex = trackIndex; 1133 if (track->mSource != NULL) { 1134 track->mSource->stop(); 1135 } 1136 track->mSource = mSources.itemAt(trackIndex); 1137 track->mSource->start(); 1138 if (track->mPackets == NULL) { 1139 track->mPackets = new AnotherPacketSource(track->mSource->getFormat()); 1140 } else { 1141 track->mPackets->clear(); 1142 track->mPackets->setFormat(track->mSource->getFormat()); 1143 1144 } 1145 1146 if (isSubtitle) { 1147 mFetchSubtitleDataGeneration++; 1148 } else { 1149 mFetchTimedTextDataGeneration++; 1150 } 1151 1152 status_t eosResult; // ignored 1153 if (mSubtitleTrack.mSource != NULL 1154 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { 1155 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this); 1156 msg->setInt64("timeUs", timeUs); 1157 msg->setInt32("generation", mFetchSubtitleDataGeneration); 1158 msg->post(); 1159 } 1160 1161 sp<AMessage> msg2 = new AMessage(kWhatSendGlobalTimedTextData, this); 1162 msg2->setInt32("generation", mFetchTimedTextDataGeneration); 1163 msg2->post(); 1164 1165 if (mTimedTextTrack.mSource != NULL 1166 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) { 1167 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this); 1168 msg->setInt64("timeUs", timeUs); 1169 msg->setInt32("generation", mFetchTimedTextDataGeneration); 1170 msg->post(); 1171 } 1172 1173 return OK; 1174 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) { 1175 bool audio = !strncasecmp(mime, "audio/", 6); 1176 Track *track = audio ? &mAudioTrack : &mVideoTrack; 1177 if (track->mSource != NULL && track->mIndex == trackIndex) { 1178 return OK; 1179 } 1180 1181 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, this); 1182 msg->setInt32("trackIndex", trackIndex); 1183 msg->post(); 1184 return OK; 1185 } 1186 1187 return INVALID_OPERATION; 1188} 1189 1190status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs, MediaPlayerSeekMode mode) { 1191 sp<AMessage> msg = new AMessage(kWhatSeek, this); 1192 msg->setInt64("seekTimeUs", seekTimeUs); 1193 msg->setInt32("mode", mode); 1194 1195 sp<AMessage> response; 1196 status_t err = msg->postAndAwaitResponse(&response); 1197 if (err == OK && response != NULL) { 1198 CHECK(response->findInt32("err", &err)); 1199 } 1200 1201 return err; 1202} 1203 1204void NuPlayer::GenericSource::onSeek(const sp<AMessage>& msg) { 1205 int64_t seekTimeUs; 1206 int32_t mode; 1207 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs)); 1208 CHECK(msg->findInt32("mode", &mode)); 1209 1210 sp<AMessage> response = new AMessage; 1211 status_t err = doSeek(seekTimeUs, (MediaPlayerSeekMode)mode); 1212 response->setInt32("err", err); 1213 1214 sp<AReplyToken> replyID; 1215 CHECK(msg->senderAwaitsResponse(&replyID)); 1216 response->postReply(replyID); 1217} 1218 1219status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs, MediaPlayerSeekMode mode) { 1220 mBufferingMonitor->updateDequeuedBufferTime(-1ll); 1221 1222 // If the Widevine source is stopped, do not attempt to read any 1223 // more buffers. 1224 // 1225 // TODO: revisit after widevine is removed. May be able to 1226 // combine mStopRead with mStarted. 1227 if (mStopRead) { 1228 return INVALID_OPERATION; 1229 } 1230 if (mVideoTrack.mSource != NULL) { 1231 int64_t actualTimeUs; 1232 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, mode, &actualTimeUs); 1233 1234 if (mode != MediaPlayerSeekMode::SEEK_CLOSEST) { 1235 seekTimeUs = actualTimeUs; 1236 } 1237 mVideoLastDequeueTimeUs = actualTimeUs; 1238 } 1239 1240 if (mAudioTrack.mSource != NULL) { 1241 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs); 1242 mAudioLastDequeueTimeUs = seekTimeUs; 1243 } 1244 1245 // If currently buffering, post kWhatBufferingEnd first, so that 1246 // NuPlayer resumes. Otherwise, if cache hits high watermark 1247 // before new polling happens, no one will resume the playback. 1248 mBufferingMonitor->stopBufferingIfNecessary(); 1249 mBufferingMonitor->restartPollBuffering(); 1250 1251 return OK; 1252} 1253 1254sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer( 1255 MediaBuffer* mb, 1256 media_track_type trackType) { 1257 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO; 1258 size_t outLength = mb->range_length(); 1259 1260 if (audio && mAudioIsVorbis) { 1261 outLength += sizeof(int32_t); 1262 } 1263 1264 sp<ABuffer> ab; 1265 1266 if (mIsDrmProtected) { 1267 // Modular DRM 1268 // Enabled for both video/audio so 1) media buffer is reused without extra copying 1269 // 2) meta data can be retrieved in onInputBufferFetched for calling queueSecureInputBuffer. 1270 1271 // data is already provided in the buffer 1272 ab = new ABuffer(NULL, mb->range_length()); 1273 mb->add_ref(); 1274 ab->setMediaBufferBase(mb); 1275 1276 // Modular DRM: Required b/c of the above add_ref. 1277 // If ref>0, there must be an observer, or it'll crash at release(). 1278 // TODO: MediaBuffer might need to be revised to ease such need. 1279 mb->setObserver(this); 1280 // setMediaBufferBase() interestingly doesn't increment the ref count on its own. 1281 // Extra increment (since we want to keep mb alive and attached to ab beyond this function 1282 // call. This is to counter the effect of mb->release() towards the end. 1283 mb->add_ref(); 1284 1285 } else { 1286 ab = new ABuffer(outLength); 1287 memcpy(ab->data(), 1288 (const uint8_t *)mb->data() + mb->range_offset(), 1289 mb->range_length()); 1290 } 1291 1292 if (audio && mAudioIsVorbis) { 1293 int32_t numPageSamples; 1294 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) { 1295 numPageSamples = -1; 1296 } 1297 1298 uint8_t* abEnd = ab->data() + mb->range_length(); 1299 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples)); 1300 } 1301 1302 sp<AMessage> meta = ab->meta(); 1303 1304 int64_t timeUs; 1305 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs)); 1306 meta->setInt64("timeUs", timeUs); 1307 1308 if (trackType == MEDIA_TRACK_TYPE_VIDEO) { 1309 int32_t layerId; 1310 if (mb->meta_data()->findInt32(kKeyTemporalLayerId, &layerId)) { 1311 meta->setInt32("temporal-layer-id", layerId); 1312 } 1313 } 1314 1315 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) { 1316 const char *mime; 1317 CHECK(mTimedTextTrack.mSource != NULL 1318 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime)); 1319 meta->setString("mime", mime); 1320 } 1321 1322 int64_t durationUs; 1323 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) { 1324 meta->setInt64("durationUs", durationUs); 1325 } 1326 1327 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 1328 meta->setInt32("trackIndex", mSubtitleTrack.mIndex); 1329 } 1330 1331 uint32_t dataType; // unused 1332 const void *seiData; 1333 size_t seiLength; 1334 if (mb->meta_data()->findData(kKeySEI, &dataType, &seiData, &seiLength)) { 1335 sp<ABuffer> sei = ABuffer::CreateAsCopy(seiData, seiLength);; 1336 meta->setBuffer("sei", sei); 1337 } 1338 1339 const void *mpegUserDataPointer; 1340 size_t mpegUserDataLength; 1341 if (mb->meta_data()->findData( 1342 kKeyMpegUserData, &dataType, &mpegUserDataPointer, &mpegUserDataLength)) { 1343 sp<ABuffer> mpegUserData = ABuffer::CreateAsCopy(mpegUserDataPointer, mpegUserDataLength); 1344 meta->setBuffer("mpegUserData", mpegUserData); 1345 } 1346 1347 mb->release(); 1348 mb = NULL; 1349 1350 return ab; 1351} 1352 1353void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) { 1354 Mutex::Autolock _l(mReadBufferLock); 1355 1356 if ((mPendingReadBufferTypes & (1 << trackType)) == 0) { 1357 mPendingReadBufferTypes |= (1 << trackType); 1358 sp<AMessage> msg = new AMessage(kWhatReadBuffer, this); 1359 msg->setInt32("trackType", trackType); 1360 msg->post(); 1361 } 1362} 1363 1364void NuPlayer::GenericSource::onReadBuffer(const sp<AMessage>& msg) { 1365 int32_t tmpType; 1366 CHECK(msg->findInt32("trackType", &tmpType)); 1367 media_track_type trackType = (media_track_type)tmpType; 1368 readBuffer(trackType); 1369 { 1370 // only protect the variable change, as readBuffer may 1371 // take considerable time. 1372 Mutex::Autolock _l(mReadBufferLock); 1373 mPendingReadBufferTypes &= ~(1 << trackType); 1374 } 1375} 1376 1377void NuPlayer::GenericSource::readBuffer( 1378 media_track_type trackType, int64_t seekTimeUs, MediaPlayerSeekMode mode, 1379 int64_t *actualTimeUs, bool formatChange) { 1380 // Do not read data if Widevine source is stopped 1381 // 1382 // TODO: revisit after widevine is removed. May be able to 1383 // combine mStopRead with mStarted. 1384 if (mStopRead) { 1385 return; 1386 } 1387 Track *track; 1388 size_t maxBuffers = 1; 1389 switch (trackType) { 1390 case MEDIA_TRACK_TYPE_VIDEO: 1391 track = &mVideoTrack; 1392 maxBuffers = 8; // too large of a number may influence seeks 1393 break; 1394 case MEDIA_TRACK_TYPE_AUDIO: 1395 track = &mAudioTrack; 1396 maxBuffers = 64; 1397 break; 1398 case MEDIA_TRACK_TYPE_SUBTITLE: 1399 track = &mSubtitleTrack; 1400 break; 1401 case MEDIA_TRACK_TYPE_TIMEDTEXT: 1402 track = &mTimedTextTrack; 1403 break; 1404 default: 1405 TRESPASS(); 1406 } 1407 1408 if (track->mSource == NULL) { 1409 return; 1410 } 1411 1412 if (actualTimeUs) { 1413 *actualTimeUs = seekTimeUs; 1414 } 1415 1416 MediaSource::ReadOptions options; 1417 1418 bool seeking = false; 1419 if (seekTimeUs >= 0) { 1420 options.setSeekTo(seekTimeUs, mode); 1421 seeking = true; 1422 } 1423 1424 const bool couldReadMultiple = (track->mSource->supportReadMultiple()); 1425 1426 if (couldReadMultiple) { 1427 options.setNonBlocking(); 1428 } 1429 1430 for (size_t numBuffers = 0; numBuffers < maxBuffers; ) { 1431 Vector<MediaBuffer *> mediaBuffers; 1432 status_t err = NO_ERROR; 1433 1434 if (couldReadMultiple) { 1435 err = track->mSource->readMultiple( 1436 &mediaBuffers, maxBuffers - numBuffers, &options); 1437 } else { 1438 MediaBuffer *mbuf = NULL; 1439 err = track->mSource->read(&mbuf, &options); 1440 if (err == OK && mbuf != NULL) { 1441 mediaBuffers.push_back(mbuf); 1442 } 1443 } 1444 1445 options.clearNonPersistent(); 1446 1447 size_t id = 0; 1448 size_t count = mediaBuffers.size(); 1449 for (; id < count; ++id) { 1450 int64_t timeUs; 1451 MediaBuffer *mbuf = mediaBuffers[id]; 1452 if (!mbuf->meta_data()->findInt64(kKeyTime, &timeUs)) { 1453 mbuf->meta_data()->dumpToLog(); 1454 track->mPackets->signalEOS(ERROR_MALFORMED); 1455 break; 1456 } 1457 if (trackType == MEDIA_TRACK_TYPE_AUDIO) { 1458 mAudioTimeUs = timeUs; 1459 mBufferingMonitor->updateQueuedTime(true /* isAudio */, timeUs); 1460 } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) { 1461 mVideoTimeUs = timeUs; 1462 mBufferingMonitor->updateQueuedTime(false /* isAudio */, timeUs); 1463 } 1464 1465 queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track); 1466 1467 sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType); 1468 if (numBuffers == 0 && actualTimeUs != nullptr) { 1469 *actualTimeUs = timeUs; 1470 } 1471 if (seeking && buffer != nullptr) { 1472 sp<AMessage> meta = buffer->meta(); 1473 if (meta != nullptr && mode == MediaPlayerSeekMode::SEEK_CLOSEST 1474 && seekTimeUs > timeUs) { 1475 sp<AMessage> extra = new AMessage; 1476 extra->setInt64("resume-at-mediaTimeUs", seekTimeUs); 1477 meta->setMessage("extra", extra); 1478 } 1479 } 1480 1481 track->mPackets->queueAccessUnit(buffer); 1482 formatChange = false; 1483 seeking = false; 1484 ++numBuffers; 1485 } 1486 if (id < count) { 1487 // Error, some mediaBuffer doesn't have kKeyTime. 1488 for (; id < count; ++id) { 1489 mediaBuffers[id]->release(); 1490 } 1491 break; 1492 } 1493 1494 if (err == WOULD_BLOCK) { 1495 break; 1496 } else if (err == INFO_FORMAT_CHANGED) { 1497#if 0 1498 track->mPackets->queueDiscontinuity( 1499 ATSParser::DISCONTINUITY_FORMATCHANGE, 1500 NULL, 1501 false /* discard */); 1502#endif 1503 } else if (err != OK) { 1504 queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track); 1505 track->mPackets->signalEOS(err); 1506 break; 1507 } 1508 } 1509} 1510 1511void NuPlayer::GenericSource::queueDiscontinuityIfNeeded( 1512 bool seeking, bool formatChange, media_track_type trackType, Track *track) { 1513 // formatChange && seeking: track whose source is changed during selection 1514 // formatChange && !seeking: track whose source is not changed during selection 1515 // !formatChange: normal seek 1516 if ((seeking || formatChange) 1517 && (trackType == MEDIA_TRACK_TYPE_AUDIO 1518 || trackType == MEDIA_TRACK_TYPE_VIDEO)) { 1519 ATSParser::DiscontinuityType type = (formatChange && seeking) 1520 ? ATSParser::DISCONTINUITY_FORMATCHANGE 1521 : ATSParser::DISCONTINUITY_NONE; 1522 track->mPackets->queueDiscontinuity(type, NULL /* extra */, true /* discard */); 1523 } 1524} 1525 1526NuPlayer::GenericSource::BufferingMonitor::BufferingMonitor(const sp<AMessage> ¬ify) 1527 : mNotify(notify), 1528 mDurationUs(-1ll), 1529 mBitrate(-1ll), 1530 mIsStreaming(false), 1531 mAudioTimeUs(0), 1532 mVideoTimeUs(0), 1533 mPollBufferingGeneration(0), 1534 mPrepareBuffering(false), 1535 mBuffering(false), 1536 mPrevBufferPercentage(-1), 1537 mOffloadAudio(false), 1538 mFirstDequeuedBufferRealUs(-1ll), 1539 mFirstDequeuedBufferMediaUs(-1ll), 1540 mlastDequeuedBufferMediaUs(-1ll) { 1541 getDefaultBufferingSettings(&mSettings); 1542} 1543 1544NuPlayer::GenericSource::BufferingMonitor::~BufferingMonitor() { 1545} 1546 1547void NuPlayer::GenericSource::BufferingMonitor::getDefaultBufferingSettings( 1548 BufferingSettings *buffering /* nonnull */) { 1549 buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY; 1550 buffering->mRebufferingMode = BUFFERING_MODE_TIME_THEN_SIZE; 1551 buffering->mInitialWatermarkMs = kHighWaterMarkMs; 1552 buffering->mRebufferingWatermarkLowMs = kLowWaterMarkMs; 1553 buffering->mRebufferingWatermarkHighMs = kHighWaterMarkRebufferMs; 1554 buffering->mRebufferingWatermarkLowKB = kLowWaterMarkKB; 1555 buffering->mRebufferingWatermarkHighKB = kHighWaterMarkKB; 1556 1557 ALOGV("BufferingMonitor::getDefaultBufferingSettings{%s}", 1558 buffering->toString().string()); 1559} 1560 1561status_t NuPlayer::GenericSource::BufferingMonitor::setBufferingSettings( 1562 const BufferingSettings &buffering) { 1563 ALOGV("BufferingMonitor::setBufferingSettings{%s}", 1564 buffering.toString().string()); 1565 1566 Mutex::Autolock _l(mLock); 1567 if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode) 1568 || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode) 1569 && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs) 1570 || (buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode) 1571 && buffering.mRebufferingWatermarkLowKB > buffering.mRebufferingWatermarkHighKB)) { 1572 return BAD_VALUE; 1573 } 1574 mSettings = buffering; 1575 if (mSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) { 1576 mSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark; 1577 } 1578 if (!mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) { 1579 mSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark; 1580 mSettings.mRebufferingWatermarkHighMs = INT32_MAX; 1581 } 1582 if (!mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) { 1583 mSettings.mRebufferingWatermarkLowKB = BufferingSettings::kNoWatermark; 1584 mSettings.mRebufferingWatermarkHighKB = INT32_MAX; 1585 } 1586 return OK; 1587} 1588 1589void NuPlayer::GenericSource::BufferingMonitor::prepare( 1590 const sp<NuCachedSource2> &cachedSource, 1591 int64_t durationUs, 1592 int64_t bitrate, 1593 bool isStreaming) { 1594 Mutex::Autolock _l(mLock); 1595 prepare_l(cachedSource, durationUs, bitrate, isStreaming); 1596} 1597 1598void NuPlayer::GenericSource::BufferingMonitor::stop() { 1599 Mutex::Autolock _l(mLock); 1600 prepare_l(NULL /* cachedSource */, -1 /* durationUs */, 1601 -1 /* bitrate */, false /* isStreaming */); 1602} 1603 1604void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering() { 1605 Mutex::Autolock _l(mLock); 1606 cancelPollBuffering_l(); 1607} 1608 1609void NuPlayer::GenericSource::BufferingMonitor::restartPollBuffering() { 1610 Mutex::Autolock _l(mLock); 1611 if (mIsStreaming) { 1612 cancelPollBuffering_l(); 1613 onPollBuffering_l(); 1614 } 1615} 1616 1617void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary() { 1618 Mutex::Autolock _l(mLock); 1619 stopBufferingIfNecessary_l(); 1620} 1621 1622void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching() { 1623 Mutex::Autolock _l(mLock); 1624 ensureCacheIsFetching_l(); 1625} 1626 1627void NuPlayer::GenericSource::BufferingMonitor::updateQueuedTime(bool isAudio, int64_t timeUs) { 1628 Mutex::Autolock _l(mLock); 1629 if (isAudio) { 1630 mAudioTimeUs = timeUs; 1631 } else { 1632 mVideoTimeUs = timeUs; 1633 } 1634} 1635 1636void NuPlayer::GenericSource::BufferingMonitor::setOffloadAudio(bool offload) { 1637 Mutex::Autolock _l(mLock); 1638 mOffloadAudio = offload; 1639} 1640 1641void NuPlayer::GenericSource::BufferingMonitor::updateDequeuedBufferTime(int64_t mediaUs) { 1642 Mutex::Autolock _l(mLock); 1643 if (mediaUs < 0) { 1644 mFirstDequeuedBufferRealUs = -1ll; 1645 mFirstDequeuedBufferMediaUs = -1ll; 1646 } else if (mFirstDequeuedBufferRealUs < 0) { 1647 mFirstDequeuedBufferRealUs = ALooper::GetNowUs(); 1648 mFirstDequeuedBufferMediaUs = mediaUs; 1649 } 1650 mlastDequeuedBufferMediaUs = mediaUs; 1651} 1652 1653void NuPlayer::GenericSource::BufferingMonitor::prepare_l( 1654 const sp<NuCachedSource2> &cachedSource, 1655 int64_t durationUs, 1656 int64_t bitrate, 1657 bool isStreaming) { 1658 1659 mCachedSource = cachedSource; 1660 mDurationUs = durationUs; 1661 mBitrate = bitrate; 1662 mIsStreaming = isStreaming; 1663 mAudioTimeUs = 0; 1664 mVideoTimeUs = 0; 1665 mPrepareBuffering = (cachedSource != NULL); 1666 cancelPollBuffering_l(); 1667 mOffloadAudio = false; 1668 mFirstDequeuedBufferRealUs = -1ll; 1669 mFirstDequeuedBufferMediaUs = -1ll; 1670 mlastDequeuedBufferMediaUs = -1ll; 1671} 1672 1673void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering_l() { 1674 mBuffering = false; 1675 ++mPollBufferingGeneration; 1676 mPrevBufferPercentage = -1; 1677} 1678 1679void NuPlayer::GenericSource::BufferingMonitor::notifyBufferingUpdate_l(int32_t percentage) { 1680 // Buffering percent could go backward as it's estimated from remaining 1681 // data and last access time. This could cause the buffering position 1682 // drawn on media control to jitter slightly. Remember previously reported 1683 // percentage and don't allow it to go backward. 1684 if (percentage < mPrevBufferPercentage) { 1685 percentage = mPrevBufferPercentage; 1686 } else if (percentage > 100) { 1687 percentage = 100; 1688 } 1689 1690 mPrevBufferPercentage = percentage; 1691 1692 ALOGV("notifyBufferingUpdate_l: buffering %d%%", percentage); 1693 1694 sp<AMessage> msg = mNotify->dup(); 1695 msg->setInt32("what", kWhatBufferingUpdate); 1696 msg->setInt32("percentage", percentage); 1697 msg->post(); 1698} 1699 1700void NuPlayer::GenericSource::BufferingMonitor::startBufferingIfNecessary_l() { 1701 if (mPrepareBuffering) { 1702 return; 1703 } 1704 1705 if (!mBuffering) { 1706 ALOGD("startBufferingIfNecessary_l"); 1707 1708 mBuffering = true; 1709 1710 ensureCacheIsFetching_l(); 1711 sendCacheStats_l(); 1712 1713 sp<AMessage> notify = mNotify->dup(); 1714 notify->setInt32("what", kWhatPauseOnBufferingStart); 1715 notify->post(); 1716 } 1717} 1718 1719void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary_l() { 1720 if (mPrepareBuffering) { 1721 ALOGD("stopBufferingIfNecessary_l, mBuffering=%d", mBuffering); 1722 1723 mPrepareBuffering = false; 1724 1725 sp<AMessage> notify = mNotify->dup(); 1726 notify->setInt32("what", kWhatPrepared); 1727 notify->setInt32("err", OK); 1728 notify->post(); 1729 1730 return; 1731 } 1732 1733 if (mBuffering) { 1734 ALOGD("stopBufferingIfNecessary_l"); 1735 mBuffering = false; 1736 1737 sendCacheStats_l(); 1738 1739 sp<AMessage> notify = mNotify->dup(); 1740 notify->setInt32("what", kWhatResumeOnBufferingEnd); 1741 notify->post(); 1742 } 1743} 1744 1745void NuPlayer::GenericSource::BufferingMonitor::sendCacheStats_l() { 1746 int32_t kbps = 0; 1747 status_t err = UNKNOWN_ERROR; 1748 1749 if (mCachedSource != NULL) { 1750 err = mCachedSource->getEstimatedBandwidthKbps(&kbps); 1751 } 1752 1753 if (err == OK) { 1754 sp<AMessage> notify = mNotify->dup(); 1755 notify->setInt32("what", kWhatCacheStats); 1756 notify->setInt32("bandwidth", kbps); 1757 notify->post(); 1758 } 1759} 1760 1761void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching_l() { 1762 if (mCachedSource != NULL) { 1763 mCachedSource->resumeFetchingIfNecessary(); 1764 } 1765} 1766 1767void NuPlayer::GenericSource::BufferingMonitor::schedulePollBuffering_l() { 1768 sp<AMessage> msg = new AMessage(kWhatPollBuffering, this); 1769 msg->setInt32("generation", mPollBufferingGeneration); 1770 // Enquires buffering status every second. 1771 msg->post(1000000ll); 1772} 1773 1774int64_t NuPlayer::GenericSource::BufferingMonitor::getLastReadPosition_l() { 1775 if (mAudioTimeUs > 0) { 1776 return mAudioTimeUs; 1777 } else if (mVideoTimeUs > 0) { 1778 return mVideoTimeUs; 1779 } else { 1780 return 0; 1781 } 1782} 1783 1784void NuPlayer::GenericSource::BufferingMonitor::onPollBuffering_l() { 1785 status_t finalStatus = UNKNOWN_ERROR; 1786 int64_t cachedDurationUs = -1ll; 1787 ssize_t cachedDataRemaining = -1; 1788 1789 if (mCachedSource != NULL) { 1790 cachedDataRemaining = 1791 mCachedSource->approxDataRemaining(&finalStatus); 1792 1793 if (finalStatus == OK) { 1794 off64_t size; 1795 int64_t bitrate = 0ll; 1796 if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) { 1797 // |bitrate| uses bits/second unit, while size is number of bytes. 1798 bitrate = size * 8000000ll / mDurationUs; 1799 } else if (mBitrate > 0) { 1800 bitrate = mBitrate; 1801 } 1802 if (bitrate > 0) { 1803 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate; 1804 } 1805 } 1806 } 1807 1808 if (finalStatus != OK) { 1809 ALOGV("onPollBuffering_l: EOS (finalStatus = %d)", finalStatus); 1810 1811 if (finalStatus == ERROR_END_OF_STREAM) { 1812 notifyBufferingUpdate_l(100); 1813 } 1814 1815 stopBufferingIfNecessary_l(); 1816 return; 1817 } 1818 1819 if (cachedDurationUs >= 0ll) { 1820 if (mDurationUs > 0ll) { 1821 int64_t cachedPosUs = getLastReadPosition_l() + cachedDurationUs; 1822 int percentage = 100.0 * cachedPosUs / mDurationUs; 1823 if (percentage > 100) { 1824 percentage = 100; 1825 } 1826 1827 notifyBufferingUpdate_l(percentage); 1828 } 1829 1830 ALOGV("onPollBuffering_l: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f); 1831 1832 if (mPrepareBuffering) { 1833 if (cachedDurationUs > mSettings.mInitialWatermarkMs * 1000) { 1834 stopBufferingIfNecessary_l(); 1835 } 1836 } else if (mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) { 1837 if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) { 1838 // Take into account the data cached in downstream components to try to avoid 1839 // unnecessary pause. 1840 if (mOffloadAudio && mFirstDequeuedBufferRealUs >= 0) { 1841 int64_t downStreamCacheUs = 1842 mlastDequeuedBufferMediaUs - mFirstDequeuedBufferMediaUs 1843 - (ALooper::GetNowUs() - mFirstDequeuedBufferRealUs); 1844 if (downStreamCacheUs > 0) { 1845 cachedDurationUs += downStreamCacheUs; 1846 } 1847 } 1848 1849 if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) { 1850 startBufferingIfNecessary_l(); 1851 } 1852 } else if (cachedDurationUs > mSettings.mRebufferingWatermarkHighMs * 1000) { 1853 stopBufferingIfNecessary_l(); 1854 } 1855 } 1856 } else if (cachedDataRemaining >= 0 1857 && mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) { 1858 ALOGV("onPollBuffering_l: cachedDataRemaining %zd bytes", 1859 cachedDataRemaining); 1860 1861 if (cachedDataRemaining < (mSettings.mRebufferingWatermarkLowKB << 10)) { 1862 startBufferingIfNecessary_l(); 1863 } else if (cachedDataRemaining > (mSettings.mRebufferingWatermarkHighKB << 10)) { 1864 stopBufferingIfNecessary_l(); 1865 } 1866 } 1867 1868 schedulePollBuffering_l(); 1869} 1870 1871void NuPlayer::GenericSource::BufferingMonitor::onMessageReceived(const sp<AMessage> &msg) { 1872 switch (msg->what()) { 1873 case kWhatPollBuffering: 1874 { 1875 int32_t generation; 1876 CHECK(msg->findInt32("generation", &generation)); 1877 Mutex::Autolock _l(mLock); 1878 if (generation == mPollBufferingGeneration) { 1879 onPollBuffering_l(); 1880 } 1881 break; 1882 } 1883 default: 1884 TRESPASS(); 1885 break; 1886 } 1887} 1888 1889// Modular DRM 1890status_t NuPlayer::GenericSource::prepareDrm( 1891 const uint8_t uuid[16], const Vector<uint8_t> &drmSessionId, sp<ICrypto> *crypto) 1892{ 1893 ALOGV("prepareDrm"); 1894 1895 sp<AMessage> msg = new AMessage(kWhatPrepareDrm, this); 1896 // synchronous call so just passing the address but with local copies of "const" args 1897 uint8_t UUID[16]; 1898 memcpy(UUID, uuid, sizeof(UUID)); 1899 Vector<uint8_t> sessionId = drmSessionId; 1900 msg->setPointer("uuid", (void*)UUID); 1901 msg->setPointer("drmSessionId", (void*)&sessionId); 1902 msg->setPointer("crypto", (void*)crypto); 1903 1904 sp<AMessage> response; 1905 status_t status = msg->postAndAwaitResponse(&response); 1906 1907 if (status == OK && response != NULL) { 1908 CHECK(response->findInt32("status", &status)); 1909 ALOGV_IF(status == OK, "prepareDrm: mCrypto: %p (%d)", crypto->get(), 1910 (*crypto != NULL ? (*crypto)->getStrongCount() : 0)); 1911 ALOGD("prepareDrm ret: %d ", status); 1912 } else { 1913 ALOGE("prepareDrm err: %d", status); 1914 } 1915 1916 return status; 1917} 1918 1919status_t NuPlayer::GenericSource::releaseDrm() 1920{ 1921 ALOGV("releaseDrm"); 1922 1923 sp<AMessage> msg = new AMessage(kWhatReleaseDrm, this); 1924 1925 // synchronous call to update the source states before the player proceedes with crypto cleanup 1926 sp<AMessage> response; 1927 status_t status = msg->postAndAwaitResponse(&response); 1928 1929 if (status == OK && response != NULL) { 1930 ALOGD("releaseDrm ret: OK "); 1931 } else { 1932 ALOGE("releaseDrm err: %d", status); 1933 } 1934 1935 return status; 1936} 1937 1938status_t NuPlayer::GenericSource::onPrepareDrm(const sp<AMessage> &msg) 1939{ 1940 ALOGV("onPrepareDrm "); 1941 1942 mIsDrmProtected = false; 1943 mIsDrmReleased = false; 1944 mIsSecure = false; 1945 1946 uint8_t *uuid; 1947 Vector<uint8_t> *drmSessionId; 1948 sp<ICrypto> *outCrypto; 1949 CHECK(msg->findPointer("uuid", (void**)&uuid)); 1950 CHECK(msg->findPointer("drmSessionId", (void**)&drmSessionId)); 1951 CHECK(msg->findPointer("crypto", (void**)&outCrypto)); 1952 1953 status_t status = OK; 1954 sp<ICrypto> crypto = NuPlayerDrm::createCryptoAndPlugin(uuid, *drmSessionId, status); 1955 if (crypto == NULL) { 1956 ALOGE("onPrepareDrm: createCrypto failed. status: %d", status); 1957 return status; 1958 } 1959 ALOGV("onPrepareDrm: createCryptoAndPlugin succeeded for uuid: %s", 1960 DrmUUID::toHexString(uuid).string()); 1961 1962 *outCrypto = crypto; 1963 // as long a there is an active crypto 1964 mIsDrmProtected = true; 1965 1966 if (mMimes.size() == 0) { 1967 status = UNKNOWN_ERROR; 1968 ALOGE("onPrepareDrm: Unexpected. Must have at least one track. status: %d", status); 1969 return status; 1970 } 1971 1972 // first mime in this list is either the video track, or the first audio track 1973 const char *mime = mMimes[0].string(); 1974 mIsSecure = crypto->requiresSecureDecoderComponent(mime); 1975 ALOGV("onPrepareDrm: requiresSecureDecoderComponent mime: %s isSecure: %d", 1976 mime, mIsSecure); 1977 1978 // Checking the member flags while in the looper to send out the notification. 1979 // The legacy mDecryptHandle!=NULL check (for FLAG_PROTECTED) is equivalent to mIsDrmProtected. 1980 notifyFlagsChanged( 1981 (mIsSecure ? FLAG_SECURE : 0) | 1982 // Setting "protected screen" only for L1: b/38390836 1983 (mIsSecure ? FLAG_PROTECTED : 0) | 1984 FLAG_CAN_PAUSE | 1985 FLAG_CAN_SEEK_BACKWARD | 1986 FLAG_CAN_SEEK_FORWARD | 1987 FLAG_CAN_SEEK); 1988 1989 return status; 1990} 1991 1992status_t NuPlayer::GenericSource::onReleaseDrm() 1993{ 1994 if (mIsDrmProtected) { 1995 mIsDrmProtected = false; 1996 // to prevent returning any more buffer after stop/releaseDrm (b/37960096) 1997 mIsDrmReleased = true; 1998 ALOGV("onReleaseDrm: mIsDrmProtected is reset."); 1999 } else { 2000 ALOGE("onReleaseDrm: mIsDrmProtected is already false."); 2001 } 2002 2003 return OK; 2004} 2005 2006status_t NuPlayer::GenericSource::checkDrmInfo() 2007{ 2008 // clearing the flag at prepare in case the player is reused after stop/releaseDrm with the 2009 // same source without being reset (called by prepareAsync/initFromDataSource) 2010 mIsDrmReleased = false; 2011 2012 if (mFileMeta == NULL) { 2013 ALOGI("checkDrmInfo: No metadata"); 2014 return OK; // letting the caller responds accordingly 2015 } 2016 2017 uint32_t type; 2018 const void *pssh; 2019 size_t psshsize; 2020 2021 if (!mFileMeta->findData(kKeyPssh, &type, &pssh, &psshsize)) { 2022 ALOGV("checkDrmInfo: No PSSH"); 2023 return OK; // source without DRM info 2024 } 2025 2026 Parcel parcel; 2027 NuPlayerDrm::retrieveDrmInfo(pssh, psshsize, &parcel); 2028 ALOGV("checkDrmInfo: MEDIA_DRM_INFO PSSH size: %d Parcel size: %d objects#: %d", 2029 (int)psshsize, (int)parcel.dataSize(), (int)parcel.objectsCount()); 2030 2031 if (parcel.dataSize() == 0) { 2032 ALOGE("checkDrmInfo: Unexpected parcel size: 0"); 2033 return UNKNOWN_ERROR; 2034 } 2035 2036 // Can't pass parcel as a message to the player. Converting Parcel->ABuffer to pass it 2037 // to the Player's onSourceNotify then back to Parcel for calling driver's notifyListener. 2038 sp<ABuffer> drmInfoBuffer = ABuffer::CreateAsCopy(parcel.data(), parcel.dataSize()); 2039 notifyDrmInfo(drmInfoBuffer); 2040 2041 return OK; 2042} 2043 2044void NuPlayer::GenericSource::signalBufferReturned(MediaBuffer *buffer) 2045{ 2046 //ALOGV("signalBufferReturned %p refCount: %d", buffer, buffer->localRefcount()); 2047 2048 buffer->setObserver(NULL); 2049 buffer->release(); // this leads to delete since that there is no observor 2050} 2051 2052} // namespace android 2053