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