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