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