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