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