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