GenericSource.cpp revision 55e2f4ca5bb23ce32fbdd627b0f648c27106b98e
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 mDataSource.clear(); 471 mCachedSource.clear(); 472 mHttpSource.clear(); 473 mBitrate = -1; 474 475 cancelPollBuffering(); 476 } 477 notifyPrepared(err); 478} 479 480void NuPlayer::GenericSource::start() { 481 ALOGI("start"); 482 483 mStopRead = false; 484 if (mAudioTrack.mSource != NULL) { 485 postReadBuffer(MEDIA_TRACK_TYPE_AUDIO); 486 } 487 488 if (mVideoTrack.mSource != NULL) { 489 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO); 490 } 491 492 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000); 493 mStarted = true; 494 495 (new AMessage(kWhatStart, this))->post(); 496} 497 498void NuPlayer::GenericSource::stop() { 499 // nothing to do, just account for DRM playback status 500 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0); 501 mStarted = false; 502 if (mIsWidevine || mIsSecure) { 503 // For widevine or secure sources we need to prevent any further reads. 504 sp<AMessage> msg = new AMessage(kWhatStopWidevine, this); 505 sp<AMessage> response; 506 (void) msg->postAndAwaitResponse(&response); 507 } 508} 509 510void NuPlayer::GenericSource::pause() { 511 // nothing to do, just account for DRM playback status 512 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0); 513 mStarted = false; 514} 515 516void NuPlayer::GenericSource::resume() { 517 // nothing to do, just account for DRM playback status 518 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000); 519 mStarted = true; 520 521 (new AMessage(kWhatResume, this))->post(); 522} 523 524void NuPlayer::GenericSource::disconnect() { 525 if (mDataSource != NULL) { 526 // disconnect data source 527 if (mDataSource->flags() & DataSource::kIsCachingDataSource) { 528 static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect(); 529 } 530 } else if (mHttpSource != NULL) { 531 static_cast<HTTPBase *>(mHttpSource.get())->disconnect(); 532 } 533} 534 535void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) { 536 if (mDecryptHandle != NULL) { 537 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position); 538 } 539 mSubtitleTrack.mPackets = new AnotherPacketSource(NULL); 540 mTimedTextTrack.mPackets = new AnotherPacketSource(NULL); 541} 542 543status_t NuPlayer::GenericSource::feedMoreTSData() { 544 return OK; 545} 546 547void NuPlayer::GenericSource::schedulePollBuffering() { 548 sp<AMessage> msg = new AMessage(kWhatPollBuffering, this); 549 msg->setInt32("generation", mPollBufferingGeneration); 550 msg->post(1000000ll); 551} 552 553void NuPlayer::GenericSource::cancelPollBuffering() { 554 mBuffering = false; 555 ++mPollBufferingGeneration; 556 mPrevBufferPercentage = -1; 557} 558 559void NuPlayer::GenericSource::restartPollBuffering() { 560 if (mIsStreaming) { 561 cancelPollBuffering(); 562 onPollBuffering(); 563 } 564} 565 566void NuPlayer::GenericSource::notifyBufferingUpdate(int32_t percentage) { 567 // Buffering percent could go backward as it's estimated from remaining 568 // data and last access time. This could cause the buffering position 569 // drawn on media control to jitter slightly. Remember previously reported 570 // percentage and don't allow it to go backward. 571 if (percentage < mPrevBufferPercentage) { 572 percentage = mPrevBufferPercentage; 573 } else if (percentage > 100) { 574 percentage = 100; 575 } 576 577 mPrevBufferPercentage = percentage; 578 579 ALOGV("notifyBufferingUpdate: buffering %d%%", percentage); 580 581 sp<AMessage> msg = dupNotify(); 582 msg->setInt32("what", kWhatBufferingUpdate); 583 msg->setInt32("percentage", percentage); 584 msg->post(); 585} 586 587void NuPlayer::GenericSource::startBufferingIfNecessary() { 588 ALOGV("startBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d", 589 mPrepareBuffering, mBuffering); 590 591 if (mPrepareBuffering) { 592 return; 593 } 594 595 if (!mBuffering) { 596 mBuffering = true; 597 598 ensureCacheIsFetching(); 599 sendCacheStats(); 600 601 sp<AMessage> notify = dupNotify(); 602 notify->setInt32("what", kWhatPauseOnBufferingStart); 603 notify->post(); 604 } 605} 606 607void NuPlayer::GenericSource::stopBufferingIfNecessary() { 608 ALOGV("stopBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d", 609 mPrepareBuffering, mBuffering); 610 611 if (mPrepareBuffering) { 612 mPrepareBuffering = false; 613 notifyPrepared(); 614 return; 615 } 616 617 if (mBuffering) { 618 mBuffering = false; 619 620 sendCacheStats(); 621 622 sp<AMessage> notify = dupNotify(); 623 notify->setInt32("what", kWhatResumeOnBufferingEnd); 624 notify->post(); 625 } 626} 627 628void NuPlayer::GenericSource::sendCacheStats() { 629 int32_t kbps = 0; 630 status_t err = UNKNOWN_ERROR; 631 632 if (mWVMExtractor != NULL) { 633 err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps); 634 } else if (mCachedSource != NULL) { 635 err = mCachedSource->getEstimatedBandwidthKbps(&kbps); 636 } 637 638 if (err == OK) { 639 sp<AMessage> notify = dupNotify(); 640 notify->setInt32("what", kWhatCacheStats); 641 notify->setInt32("bandwidth", kbps); 642 notify->post(); 643 } 644} 645 646void NuPlayer::GenericSource::ensureCacheIsFetching() { 647 if (mCachedSource != NULL) { 648 mCachedSource->resumeFetchingIfNecessary(); 649 } 650} 651 652void NuPlayer::GenericSource::onPollBuffering() { 653 status_t finalStatus = UNKNOWN_ERROR; 654 int64_t cachedDurationUs = -1ll; 655 ssize_t cachedDataRemaining = -1; 656 657 ALOGW_IF(mWVMExtractor != NULL && mCachedSource != NULL, 658 "WVMExtractor and NuCachedSource both present"); 659 660 if (mWVMExtractor != NULL) { 661 cachedDurationUs = 662 mWVMExtractor->getCachedDurationUs(&finalStatus); 663 } else if (mCachedSource != NULL) { 664 cachedDataRemaining = 665 mCachedSource->approxDataRemaining(&finalStatus); 666 667 if (finalStatus == OK) { 668 off64_t size; 669 int64_t bitrate = 0ll; 670 if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) { 671 bitrate = size * 8000000ll / mDurationUs; 672 } else if (mBitrate > 0) { 673 bitrate = mBitrate; 674 } 675 if (bitrate > 0) { 676 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate; 677 } 678 } 679 } 680 681 if (finalStatus != OK) { 682 ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus); 683 684 if (finalStatus == ERROR_END_OF_STREAM) { 685 notifyBufferingUpdate(100); 686 } 687 688 stopBufferingIfNecessary(); 689 return; 690 } else if (cachedDurationUs >= 0ll) { 691 if (mDurationUs > 0ll) { 692 int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs; 693 int percentage = 100.0 * cachedPosUs / mDurationUs; 694 if (percentage > 100) { 695 percentage = 100; 696 } 697 698 notifyBufferingUpdate(percentage); 699 } 700 701 ALOGV("onPollBuffering: cachedDurationUs %.1f sec", 702 cachedDurationUs / 1000000.0f); 703 704 if (cachedDurationUs < kLowWaterMarkUs) { 705 startBufferingIfNecessary(); 706 } else if (cachedDurationUs > kHighWaterMarkUs) { 707 stopBufferingIfNecessary(); 708 } 709 } else if (cachedDataRemaining >= 0) { 710 ALOGV("onPollBuffering: cachedDataRemaining %zd bytes", 711 cachedDataRemaining); 712 713 if (cachedDataRemaining < kLowWaterMarkBytes) { 714 startBufferingIfNecessary(); 715 } else if (cachedDataRemaining > kHighWaterMarkBytes) { 716 stopBufferingIfNecessary(); 717 } 718 } 719 720 schedulePollBuffering(); 721} 722 723void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) { 724 switch (msg->what()) { 725 case kWhatPrepareAsync: 726 { 727 onPrepareAsync(); 728 break; 729 } 730 case kWhatFetchSubtitleData: 731 { 732 fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, 733 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); 734 break; 735 } 736 737 case kWhatFetchTimedTextData: 738 { 739 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, 740 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); 741 break; 742 } 743 744 case kWhatSendSubtitleData: 745 { 746 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, 747 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); 748 break; 749 } 750 751 case kWhatSendGlobalTimedTextData: 752 { 753 sendGlobalTextData(kWhatTimedTextData, mFetchTimedTextDataGeneration, msg); 754 break; 755 } 756 case kWhatSendTimedTextData: 757 { 758 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, 759 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); 760 break; 761 } 762 763 case kWhatChangeAVSource: 764 { 765 int32_t trackIndex; 766 CHECK(msg->findInt32("trackIndex", &trackIndex)); 767 const sp<MediaSource> source = mSources.itemAt(trackIndex); 768 769 Track* track; 770 const char *mime; 771 media_track_type trackType, counterpartType; 772 sp<MetaData> meta = source->getFormat(); 773 meta->findCString(kKeyMIMEType, &mime); 774 if (!strncasecmp(mime, "audio/", 6)) { 775 track = &mAudioTrack; 776 trackType = MEDIA_TRACK_TYPE_AUDIO; 777 counterpartType = MEDIA_TRACK_TYPE_VIDEO;; 778 } else { 779 CHECK(!strncasecmp(mime, "video/", 6)); 780 track = &mVideoTrack; 781 trackType = MEDIA_TRACK_TYPE_VIDEO; 782 counterpartType = MEDIA_TRACK_TYPE_AUDIO;; 783 } 784 785 786 if (track->mSource != NULL) { 787 track->mSource->stop(); 788 } 789 track->mSource = source; 790 track->mSource->start(); 791 track->mIndex = trackIndex; 792 793 int64_t timeUs, actualTimeUs; 794 const bool formatChange = true; 795 if (trackType == MEDIA_TRACK_TYPE_AUDIO) { 796 timeUs = mAudioLastDequeueTimeUs; 797 } else { 798 timeUs = mVideoLastDequeueTimeUs; 799 } 800 readBuffer(trackType, timeUs, &actualTimeUs, formatChange); 801 readBuffer(counterpartType, -1, NULL, formatChange); 802 ALOGV("timeUs %lld actualTimeUs %lld", (long long)timeUs, (long long)actualTimeUs); 803 804 break; 805 } 806 807 case kWhatStart: 808 case kWhatResume: 809 { 810 restartPollBuffering(); 811 break; 812 } 813 814 case kWhatPollBuffering: 815 { 816 int32_t generation; 817 CHECK(msg->findInt32("generation", &generation)); 818 if (generation == mPollBufferingGeneration) { 819 onPollBuffering(); 820 } 821 break; 822 } 823 824 case kWhatGetFormat: 825 { 826 onGetFormatMeta(msg); 827 break; 828 } 829 830 case kWhatGetSelectedTrack: 831 { 832 onGetSelectedTrack(msg); 833 break; 834 } 835 836 case kWhatSelectTrack: 837 { 838 onSelectTrack(msg); 839 break; 840 } 841 842 case kWhatSeek: 843 { 844 onSeek(msg); 845 break; 846 } 847 848 case kWhatReadBuffer: 849 { 850 onReadBuffer(msg); 851 break; 852 } 853 854 case kWhatSecureDecodersInstantiated: 855 { 856 int32_t err; 857 CHECK(msg->findInt32("err", &err)); 858 onSecureDecodersInstantiated(err); 859 break; 860 } 861 862 case kWhatStopWidevine: 863 { 864 // mStopRead is only used for Widevine to prevent the video source 865 // from being read while the associated video decoder is shutting down. 866 mStopRead = true; 867 if (mVideoTrack.mSource != NULL) { 868 mVideoTrack.mPackets->clear(); 869 } 870 sp<AMessage> response = new AMessage; 871 sp<AReplyToken> replyID; 872 CHECK(msg->senderAwaitsResponse(&replyID)); 873 response->postReply(replyID); 874 break; 875 } 876 default: 877 Source::onMessageReceived(msg); 878 break; 879 } 880} 881 882void NuPlayer::GenericSource::fetchTextData( 883 uint32_t sendWhat, 884 media_track_type type, 885 int32_t curGen, 886 sp<AnotherPacketSource> packets, 887 sp<AMessage> msg) { 888 int32_t msgGeneration; 889 CHECK(msg->findInt32("generation", &msgGeneration)); 890 if (msgGeneration != curGen) { 891 // stale 892 return; 893 } 894 895 int32_t avail; 896 if (packets->hasBufferAvailable(&avail)) { 897 return; 898 } 899 900 int64_t timeUs; 901 CHECK(msg->findInt64("timeUs", &timeUs)); 902 903 int64_t subTimeUs; 904 readBuffer(type, timeUs, &subTimeUs); 905 906 int64_t delayUs = subTimeUs - timeUs; 907 if (msg->what() == kWhatFetchSubtitleData) { 908 const int64_t oneSecUs = 1000000ll; 909 delayUs -= oneSecUs; 910 } 911 sp<AMessage> msg2 = new AMessage(sendWhat, this); 912 msg2->setInt32("generation", msgGeneration); 913 msg2->post(delayUs < 0 ? 0 : delayUs); 914} 915 916void NuPlayer::GenericSource::sendTextData( 917 uint32_t what, 918 media_track_type type, 919 int32_t curGen, 920 sp<AnotherPacketSource> packets, 921 sp<AMessage> msg) { 922 int32_t msgGeneration; 923 CHECK(msg->findInt32("generation", &msgGeneration)); 924 if (msgGeneration != curGen) { 925 // stale 926 return; 927 } 928 929 int64_t subTimeUs; 930 if (packets->nextBufferTime(&subTimeUs) != OK) { 931 return; 932 } 933 934 int64_t nextSubTimeUs; 935 readBuffer(type, -1, &nextSubTimeUs); 936 937 sp<ABuffer> buffer; 938 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer); 939 if (dequeueStatus == OK) { 940 sp<AMessage> notify = dupNotify(); 941 notify->setInt32("what", what); 942 notify->setBuffer("buffer", buffer); 943 notify->post(); 944 945 const int64_t delayUs = nextSubTimeUs - subTimeUs; 946 msg->post(delayUs < 0 ? 0 : delayUs); 947 } 948} 949 950void NuPlayer::GenericSource::sendGlobalTextData( 951 uint32_t what, 952 int32_t curGen, 953 sp<AMessage> msg) { 954 int32_t msgGeneration; 955 CHECK(msg->findInt32("generation", &msgGeneration)); 956 if (msgGeneration != curGen) { 957 // stale 958 return; 959 } 960 961 uint32_t textType; 962 const void *data; 963 size_t size = 0; 964 if (mTimedTextTrack.mSource->getFormat()->findData( 965 kKeyTextFormatData, &textType, &data, &size)) { 966 mGlobalTimedText = new ABuffer(size); 967 if (mGlobalTimedText->data()) { 968 memcpy(mGlobalTimedText->data(), data, size); 969 sp<AMessage> globalMeta = mGlobalTimedText->meta(); 970 globalMeta->setInt64("timeUs", 0); 971 globalMeta->setString("mime", MEDIA_MIMETYPE_TEXT_3GPP); 972 globalMeta->setInt32("global", 1); 973 sp<AMessage> notify = dupNotify(); 974 notify->setInt32("what", what); 975 notify->setBuffer("buffer", mGlobalTimedText); 976 notify->post(); 977 } 978 } 979} 980 981sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) { 982 sp<AMessage> msg = new AMessage(kWhatGetFormat, this); 983 msg->setInt32("audio", audio); 984 985 sp<AMessage> response; 986 void *format; 987 status_t err = msg->postAndAwaitResponse(&response); 988 if (err == OK && response != NULL) { 989 CHECK(response->findPointer("format", &format)); 990 return (MetaData *)format; 991 } else { 992 return NULL; 993 } 994} 995 996void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const { 997 int32_t audio; 998 CHECK(msg->findInt32("audio", &audio)); 999 1000 sp<AMessage> response = new AMessage; 1001 sp<MetaData> format = doGetFormatMeta(audio); 1002 response->setPointer("format", format.get()); 1003 1004 sp<AReplyToken> replyID; 1005 CHECK(msg->senderAwaitsResponse(&replyID)); 1006 response->postReply(replyID); 1007} 1008 1009sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const { 1010 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource; 1011 1012 if (source == NULL) { 1013 return NULL; 1014 } 1015 1016 return source->getFormat(); 1017} 1018 1019status_t NuPlayer::GenericSource::dequeueAccessUnit( 1020 bool audio, sp<ABuffer> *accessUnit) { 1021 Track *track = audio ? &mAudioTrack : &mVideoTrack; 1022 1023 if (track->mSource == NULL) { 1024 return -EWOULDBLOCK; 1025 } 1026 1027 if (mIsWidevine && !audio) { 1028 // try to read a buffer as we may not have been able to the last time 1029 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO); 1030 } 1031 1032 status_t finalResult; 1033 if (!track->mPackets->hasBufferAvailable(&finalResult)) { 1034 if (finalResult == OK) { 1035 postReadBuffer( 1036 audio ? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO); 1037 return -EWOULDBLOCK; 1038 } 1039 return finalResult; 1040 } 1041 1042 status_t result = track->mPackets->dequeueAccessUnit(accessUnit); 1043 1044 // start pulling in more buffers if we only have one (or no) buffer left 1045 // so that decoder has less chance of being starved 1046 if (track->mPackets->getAvailableBufferCount(&finalResult) < 2) { 1047 postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO); 1048 } 1049 1050 if (result != OK) { 1051 if (mSubtitleTrack.mSource != NULL) { 1052 mSubtitleTrack.mPackets->clear(); 1053 mFetchSubtitleDataGeneration++; 1054 } 1055 if (mTimedTextTrack.mSource != NULL) { 1056 mTimedTextTrack.mPackets->clear(); 1057 mFetchTimedTextDataGeneration++; 1058 } 1059 return result; 1060 } 1061 1062 int64_t timeUs; 1063 status_t eosResult; // ignored 1064 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); 1065 if (audio) { 1066 mAudioLastDequeueTimeUs = timeUs; 1067 } else { 1068 mVideoLastDequeueTimeUs = timeUs; 1069 } 1070 1071 if (mSubtitleTrack.mSource != NULL 1072 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { 1073 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this); 1074 msg->setInt64("timeUs", timeUs); 1075 msg->setInt32("generation", mFetchSubtitleDataGeneration); 1076 msg->post(); 1077 } 1078 1079 if (mTimedTextTrack.mSource != NULL 1080 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) { 1081 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this); 1082 msg->setInt64("timeUs", timeUs); 1083 msg->setInt32("generation", mFetchTimedTextDataGeneration); 1084 msg->post(); 1085 } 1086 1087 return result; 1088} 1089 1090status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) { 1091 *durationUs = mDurationUs; 1092 return OK; 1093} 1094 1095size_t NuPlayer::GenericSource::getTrackCount() const { 1096 return mSources.size(); 1097} 1098 1099sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const { 1100 size_t trackCount = mSources.size(); 1101 if (trackIndex >= trackCount) { 1102 return NULL; 1103 } 1104 1105 sp<AMessage> format = new AMessage(); 1106 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat(); 1107 1108 const char *mime; 1109 CHECK(meta->findCString(kKeyMIMEType, &mime)); 1110 format->setString("mime", mime); 1111 1112 int32_t trackType; 1113 if (!strncasecmp(mime, "video/", 6)) { 1114 trackType = MEDIA_TRACK_TYPE_VIDEO; 1115 } else if (!strncasecmp(mime, "audio/", 6)) { 1116 trackType = MEDIA_TRACK_TYPE_AUDIO; 1117 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { 1118 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT; 1119 } else { 1120 trackType = MEDIA_TRACK_TYPE_UNKNOWN; 1121 } 1122 format->setInt32("type", trackType); 1123 1124 const char *lang; 1125 if (!meta->findCString(kKeyMediaLanguage, &lang)) { 1126 lang = "und"; 1127 } 1128 format->setString("language", lang); 1129 1130 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 1131 int32_t isAutoselect = 1, isDefault = 0, isForced = 0; 1132 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect); 1133 meta->findInt32(kKeyTrackIsDefault, &isDefault); 1134 meta->findInt32(kKeyTrackIsForced, &isForced); 1135 1136 format->setInt32("auto", !!isAutoselect); 1137 format->setInt32("default", !!isDefault); 1138 format->setInt32("forced", !!isForced); 1139 } 1140 1141 return format; 1142} 1143 1144ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const { 1145 sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, this); 1146 msg->setInt32("type", type); 1147 1148 sp<AMessage> response; 1149 int32_t index; 1150 status_t err = msg->postAndAwaitResponse(&response); 1151 if (err == OK && response != NULL) { 1152 CHECK(response->findInt32("index", &index)); 1153 return index; 1154 } else { 1155 return -1; 1156 } 1157} 1158 1159void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const { 1160 int32_t tmpType; 1161 CHECK(msg->findInt32("type", &tmpType)); 1162 media_track_type type = (media_track_type)tmpType; 1163 1164 sp<AMessage> response = new AMessage; 1165 ssize_t index = doGetSelectedTrack(type); 1166 response->setInt32("index", index); 1167 1168 sp<AReplyToken> replyID; 1169 CHECK(msg->senderAwaitsResponse(&replyID)); 1170 response->postReply(replyID); 1171} 1172 1173ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const { 1174 const Track *track = NULL; 1175 switch (type) { 1176 case MEDIA_TRACK_TYPE_VIDEO: 1177 track = &mVideoTrack; 1178 break; 1179 case MEDIA_TRACK_TYPE_AUDIO: 1180 track = &mAudioTrack; 1181 break; 1182 case MEDIA_TRACK_TYPE_TIMEDTEXT: 1183 track = &mTimedTextTrack; 1184 break; 1185 case MEDIA_TRACK_TYPE_SUBTITLE: 1186 track = &mSubtitleTrack; 1187 break; 1188 default: 1189 break; 1190 } 1191 1192 if (track != NULL && track->mSource != NULL) { 1193 return track->mIndex; 1194 } 1195 1196 return -1; 1197} 1198 1199status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) { 1200 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex); 1201 sp<AMessage> msg = new AMessage(kWhatSelectTrack, this); 1202 msg->setInt32("trackIndex", trackIndex); 1203 msg->setInt32("select", select); 1204 msg->setInt64("timeUs", timeUs); 1205 1206 sp<AMessage> response; 1207 status_t err = msg->postAndAwaitResponse(&response); 1208 if (err == OK && response != NULL) { 1209 CHECK(response->findInt32("err", &err)); 1210 } 1211 1212 return err; 1213} 1214 1215void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) { 1216 int32_t trackIndex, select; 1217 int64_t timeUs; 1218 CHECK(msg->findInt32("trackIndex", &trackIndex)); 1219 CHECK(msg->findInt32("select", &select)); 1220 CHECK(msg->findInt64("timeUs", &timeUs)); 1221 1222 sp<AMessage> response = new AMessage; 1223 status_t err = doSelectTrack(trackIndex, select, timeUs); 1224 response->setInt32("err", err); 1225 1226 sp<AReplyToken> replyID; 1227 CHECK(msg->senderAwaitsResponse(&replyID)); 1228 response->postReply(replyID); 1229} 1230 1231status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select, int64_t timeUs) { 1232 if (trackIndex >= mSources.size()) { 1233 return BAD_INDEX; 1234 } 1235 1236 if (!select) { 1237 Track* track = NULL; 1238 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) { 1239 track = &mSubtitleTrack; 1240 mFetchSubtitleDataGeneration++; 1241 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) { 1242 track = &mTimedTextTrack; 1243 mFetchTimedTextDataGeneration++; 1244 } 1245 if (track == NULL) { 1246 return INVALID_OPERATION; 1247 } 1248 track->mSource->stop(); 1249 track->mSource = NULL; 1250 track->mPackets->clear(); 1251 return OK; 1252 } 1253 1254 const sp<MediaSource> source = mSources.itemAt(trackIndex); 1255 sp<MetaData> meta = source->getFormat(); 1256 const char *mime; 1257 CHECK(meta->findCString(kKeyMIMEType, &mime)); 1258 if (!strncasecmp(mime, "text/", 5)) { 1259 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP); 1260 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack; 1261 if (track->mSource != NULL && track->mIndex == trackIndex) { 1262 return OK; 1263 } 1264 track->mIndex = trackIndex; 1265 if (track->mSource != NULL) { 1266 track->mSource->stop(); 1267 } 1268 track->mSource = mSources.itemAt(trackIndex); 1269 track->mSource->start(); 1270 if (track->mPackets == NULL) { 1271 track->mPackets = new AnotherPacketSource(track->mSource->getFormat()); 1272 } else { 1273 track->mPackets->clear(); 1274 track->mPackets->setFormat(track->mSource->getFormat()); 1275 1276 } 1277 1278 if (isSubtitle) { 1279 mFetchSubtitleDataGeneration++; 1280 } else { 1281 mFetchTimedTextDataGeneration++; 1282 } 1283 1284 status_t eosResult; // ignored 1285 if (mSubtitleTrack.mSource != NULL 1286 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { 1287 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, this); 1288 msg->setInt64("timeUs", timeUs); 1289 msg->setInt32("generation", mFetchSubtitleDataGeneration); 1290 msg->post(); 1291 } 1292 1293 sp<AMessage> msg2 = new AMessage(kWhatSendGlobalTimedTextData, this); 1294 msg2->setInt32("generation", mFetchTimedTextDataGeneration); 1295 msg2->post(); 1296 1297 if (mTimedTextTrack.mSource != NULL 1298 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) { 1299 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this); 1300 msg->setInt64("timeUs", timeUs); 1301 msg->setInt32("generation", mFetchTimedTextDataGeneration); 1302 msg->post(); 1303 } 1304 1305 return OK; 1306 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) { 1307 bool audio = !strncasecmp(mime, "audio/", 6); 1308 Track *track = audio ? &mAudioTrack : &mVideoTrack; 1309 if (track->mSource != NULL && track->mIndex == trackIndex) { 1310 return OK; 1311 } 1312 1313 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, this); 1314 msg->setInt32("trackIndex", trackIndex); 1315 msg->post(); 1316 return OK; 1317 } 1318 1319 return INVALID_OPERATION; 1320} 1321 1322status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) { 1323 sp<AMessage> msg = new AMessage(kWhatSeek, this); 1324 msg->setInt64("seekTimeUs", seekTimeUs); 1325 1326 sp<AMessage> response; 1327 status_t err = msg->postAndAwaitResponse(&response); 1328 if (err == OK && response != NULL) { 1329 CHECK(response->findInt32("err", &err)); 1330 } 1331 1332 return err; 1333} 1334 1335void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) { 1336 int64_t seekTimeUs; 1337 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs)); 1338 1339 sp<AMessage> response = new AMessage; 1340 status_t err = doSeek(seekTimeUs); 1341 response->setInt32("err", err); 1342 1343 sp<AReplyToken> replyID; 1344 CHECK(msg->senderAwaitsResponse(&replyID)); 1345 response->postReply(replyID); 1346} 1347 1348status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) { 1349 // If the Widevine source is stopped, do not attempt to read any 1350 // more buffers. 1351 if (mStopRead) { 1352 return INVALID_OPERATION; 1353 } 1354 if (mVideoTrack.mSource != NULL) { 1355 int64_t actualTimeUs; 1356 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs); 1357 1358 seekTimeUs = actualTimeUs; 1359 mVideoLastDequeueTimeUs = seekTimeUs; 1360 } 1361 1362 if (mAudioTrack.mSource != NULL) { 1363 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs); 1364 mAudioLastDequeueTimeUs = seekTimeUs; 1365 } 1366 1367 setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000); 1368 if (!mStarted) { 1369 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0); 1370 } 1371 1372 // If currently buffering, post kWhatBufferingEnd first, so that 1373 // NuPlayer resumes. Otherwise, if cache hits high watermark 1374 // before new polling happens, no one will resume the playback. 1375 stopBufferingIfNecessary(); 1376 restartPollBuffering(); 1377 1378 return OK; 1379} 1380 1381sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer( 1382 MediaBuffer* mb, 1383 media_track_type trackType, 1384 int64_t /* seekTimeUs */, 1385 int64_t *actualTimeUs) { 1386 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO; 1387 size_t outLength = mb->range_length(); 1388 1389 if (audio && mAudioIsVorbis) { 1390 outLength += sizeof(int32_t); 1391 } 1392 1393 sp<ABuffer> ab; 1394 if (mIsSecure && !audio) { 1395 // data is already provided in the buffer 1396 ab = new ABuffer(NULL, mb->range_length()); 1397 mb->add_ref(); 1398 ab->setMediaBufferBase(mb); 1399 } else { 1400 ab = new ABuffer(outLength); 1401 memcpy(ab->data(), 1402 (const uint8_t *)mb->data() + mb->range_offset(), 1403 mb->range_length()); 1404 } 1405 1406 if (audio && mAudioIsVorbis) { 1407 int32_t numPageSamples; 1408 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) { 1409 numPageSamples = -1; 1410 } 1411 1412 uint8_t* abEnd = ab->data() + mb->range_length(); 1413 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples)); 1414 } 1415 1416 sp<AMessage> meta = ab->meta(); 1417 1418 int64_t timeUs; 1419 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs)); 1420 meta->setInt64("timeUs", timeUs); 1421 1422#if 0 1423 // Temporarily disable pre-roll till we have a full solution to handle 1424 // both single seek and continous seek gracefully. 1425 if (seekTimeUs > timeUs) { 1426 sp<AMessage> extra = new AMessage; 1427 extra->setInt64("resume-at-mediaTimeUs", seekTimeUs); 1428 meta->setMessage("extra", extra); 1429 } 1430#endif 1431 1432 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) { 1433 const char *mime; 1434 CHECK(mTimedTextTrack.mSource != NULL 1435 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime)); 1436 meta->setString("mime", mime); 1437 } 1438 1439 int64_t durationUs; 1440 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) { 1441 meta->setInt64("durationUs", durationUs); 1442 } 1443 1444 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 1445 meta->setInt32("trackIndex", mSubtitleTrack.mIndex); 1446 } 1447 1448 uint32_t dataType; // unused 1449 const void *seiData; 1450 size_t seiLength; 1451 if (mb->meta_data()->findData(kKeySEI, &dataType, &seiData, &seiLength)) { 1452 sp<ABuffer> sei = ABuffer::CreateAsCopy(seiData, seiLength);; 1453 meta->setBuffer("sei", sei); 1454 } 1455 1456 if (actualTimeUs) { 1457 *actualTimeUs = timeUs; 1458 } 1459 1460 mb->release(); 1461 mb = NULL; 1462 1463 return ab; 1464} 1465 1466void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) { 1467 Mutex::Autolock _l(mReadBufferLock); 1468 1469 if ((mPendingReadBufferTypes & (1 << trackType)) == 0) { 1470 mPendingReadBufferTypes |= (1 << trackType); 1471 sp<AMessage> msg = new AMessage(kWhatReadBuffer, this); 1472 msg->setInt32("trackType", trackType); 1473 msg->post(); 1474 } 1475} 1476 1477void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) { 1478 int32_t tmpType; 1479 CHECK(msg->findInt32("trackType", &tmpType)); 1480 media_track_type trackType = (media_track_type)tmpType; 1481 readBuffer(trackType); 1482 { 1483 // only protect the variable change, as readBuffer may 1484 // take considerable time. 1485 Mutex::Autolock _l(mReadBufferLock); 1486 mPendingReadBufferTypes &= ~(1 << trackType); 1487 } 1488} 1489 1490void NuPlayer::GenericSource::readBuffer( 1491 media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) { 1492 // Do not read data if Widevine source is stopped 1493 if (mStopRead) { 1494 return; 1495 } 1496 Track *track; 1497 size_t maxBuffers = 1; 1498 switch (trackType) { 1499 case MEDIA_TRACK_TYPE_VIDEO: 1500 track = &mVideoTrack; 1501 if (mIsWidevine) { 1502 maxBuffers = 2; 1503 } else { 1504 maxBuffers = 4; 1505 } 1506 break; 1507 case MEDIA_TRACK_TYPE_AUDIO: 1508 track = &mAudioTrack; 1509 if (mIsWidevine) { 1510 maxBuffers = 8; 1511 } else { 1512 maxBuffers = 64; 1513 } 1514 break; 1515 case MEDIA_TRACK_TYPE_SUBTITLE: 1516 track = &mSubtitleTrack; 1517 break; 1518 case MEDIA_TRACK_TYPE_TIMEDTEXT: 1519 track = &mTimedTextTrack; 1520 break; 1521 default: 1522 TRESPASS(); 1523 } 1524 1525 if (track->mSource == NULL) { 1526 return; 1527 } 1528 1529 if (actualTimeUs) { 1530 *actualTimeUs = seekTimeUs; 1531 } 1532 1533 MediaSource::ReadOptions options; 1534 1535 bool seeking = false; 1536 1537 if (seekTimeUs >= 0) { 1538 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 1539 seeking = true; 1540 } 1541 1542 if (mIsWidevine) { 1543 options.setNonBlocking(); 1544 } 1545 1546 for (size_t numBuffers = 0; numBuffers < maxBuffers; ) { 1547 MediaBuffer *mbuf; 1548 status_t err = track->mSource->read(&mbuf, &options); 1549 1550 options.clearSeekTo(); 1551 1552 if (err == OK) { 1553 int64_t timeUs; 1554 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); 1555 if (trackType == MEDIA_TRACK_TYPE_AUDIO) { 1556 mAudioTimeUs = timeUs; 1557 } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) { 1558 mVideoTimeUs = timeUs; 1559 } 1560 1561 queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track); 1562 1563 sp<ABuffer> buffer = mediaBufferToABuffer( 1564 mbuf, trackType, seekTimeUs, 1565 numBuffers == 0 ? actualTimeUs : NULL); 1566 track->mPackets->queueAccessUnit(buffer); 1567 formatChange = false; 1568 seeking = false; 1569 ++numBuffers; 1570 } else if (err == WOULD_BLOCK) { 1571 break; 1572 } else if (err == INFO_FORMAT_CHANGED) { 1573#if 0 1574 track->mPackets->queueDiscontinuity( 1575 ATSParser::DISCONTINUITY_FORMATCHANGE, 1576 NULL, 1577 false /* discard */); 1578#endif 1579 } else { 1580 queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track); 1581 track->mPackets->signalEOS(err); 1582 break; 1583 } 1584 } 1585} 1586 1587void NuPlayer::GenericSource::queueDiscontinuityIfNeeded( 1588 bool seeking, bool formatChange, media_track_type trackType, Track *track) { 1589 // formatChange && seeking: track whose source is changed during selection 1590 // formatChange && !seeking: track whose source is not changed during selection 1591 // !formatChange: normal seek 1592 if ((seeking || formatChange) 1593 && (trackType == MEDIA_TRACK_TYPE_AUDIO 1594 || trackType == MEDIA_TRACK_TYPE_VIDEO)) { 1595 ATSParser::DiscontinuityType type = (formatChange && seeking) 1596 ? ATSParser::DISCONTINUITY_FORMATCHANGE 1597 : ATSParser::DISCONTINUITY_NONE; 1598 track->mPackets->queueDiscontinuity(type, NULL /* extra */, true /* discard */); 1599 } 1600} 1601 1602} // namespace android 1603