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