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