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