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