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