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