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