GenericSource.cpp revision e31eeb4cc65e6b0c98d8476cb89f746ddb79a1b0
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 43NuPlayer::GenericSource::GenericSource( 44 const sp<AMessage> ¬ify, 45 bool uidValid, 46 uid_t uid) 47 : Source(notify), 48 mFetchSubtitleDataGeneration(0), 49 mFetchTimedTextDataGeneration(0), 50 mDurationUs(0ll), 51 mAudioIsVorbis(false), 52 mIsWidevine(false), 53 mUIDValid(uidValid), 54 mUID(uid), 55 mDrmManagerClient(NULL), 56 mMetaDataSize(-1ll), 57 mBitrate(-1ll), 58 mPollBufferingGeneration(0), 59 mPendingReadBufferTypes(0) { 60 resetDataSource(); 61 DataSource::RegisterDefaultSniffers(); 62} 63 64void NuPlayer::GenericSource::resetDataSource() { 65 mAudioTimeUs = 0; 66 mVideoTimeUs = 0; 67 mHTTPService.clear(); 68 mHttpSource.clear(); 69 mUri.clear(); 70 mUriHeaders.clear(); 71 mFd = -1; 72 mOffset = 0; 73 mLength = 0; 74 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0); 75 mDecryptHandle = NULL; 76 mDrmManagerClient = NULL; 77 mStarted = false; 78 mStopRead = true; 79} 80 81status_t NuPlayer::GenericSource::setDataSource( 82 const sp<IMediaHTTPService> &httpService, 83 const char *url, 84 const KeyedVector<String8, String8> *headers) { 85 resetDataSource(); 86 87 mHTTPService = httpService; 88 mUri = url; 89 90 if (headers) { 91 mUriHeaders = *headers; 92 } 93 94 // delay data source creation to prepareAsync() to avoid blocking 95 // the calling thread in setDataSource for any significant time. 96 return OK; 97} 98 99status_t NuPlayer::GenericSource::setDataSource( 100 int fd, int64_t offset, int64_t length) { 101 resetDataSource(); 102 103 mFd = dup(fd); 104 mOffset = offset; 105 mLength = length; 106 107 // delay data source creation to prepareAsync() to avoid blocking 108 // the calling thread in setDataSource for any significant time. 109 return OK; 110} 111 112sp<MetaData> NuPlayer::GenericSource::getFileFormatMeta() const { 113 return mFileMeta; 114} 115 116status_t NuPlayer::GenericSource::initFromDataSource() { 117 sp<MediaExtractor> extractor; 118 119 CHECK(mDataSource != NULL); 120 121 if (mIsWidevine) { 122 String8 mimeType; 123 float confidence; 124 sp<AMessage> dummy; 125 bool success; 126 127 success = SniffWVM(mDataSource, &mimeType, &confidence, &dummy); 128 if (!success 129 || strcasecmp( 130 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) { 131 ALOGE("unsupported widevine mime: %s", mimeType.string()); 132 return UNKNOWN_ERROR; 133 } 134 135 mWVMExtractor = new WVMExtractor(mDataSource); 136 mWVMExtractor->setAdaptiveStreamingMode(true); 137 if (mUIDValid) { 138 mWVMExtractor->setUID(mUID); 139 } 140 extractor = mWVMExtractor; 141 } else { 142 extractor = MediaExtractor::Create(mDataSource, 143 mSniffedMIME.empty() ? NULL: mSniffedMIME.c_str()); 144 } 145 146 if (extractor == NULL) { 147 return UNKNOWN_ERROR; 148 } 149 150 if (extractor->getDrmFlag()) { 151 checkDrmStatus(mDataSource); 152 } 153 154 mFileMeta = extractor->getMetaData(); 155 if (mFileMeta != NULL) { 156 int64_t duration; 157 if (mFileMeta->findInt64(kKeyDuration, &duration)) { 158 mDurationUs = duration; 159 } 160 } 161 162 int32_t totalBitrate = 0; 163 164 size_t numtracks = extractor->countTracks(); 165 if (numtracks == 0) { 166 return UNKNOWN_ERROR; 167 } 168 169 for (size_t i = 0; i < numtracks; ++i) { 170 sp<MediaSource> track = extractor->getTrack(i); 171 if (track == NULL) { 172 continue; 173 } 174 175 sp<MetaData> meta = extractor->getTrackMetaData(i); 176 177 const char *mime; 178 CHECK(meta->findCString(kKeyMIMEType, &mime)); 179 180 // Do the string compare immediately with "mime", 181 // we can't assume "mime" would stay valid after another 182 // extractor operation, some extractors might modify meta 183 // during getTrack() and make it invalid. 184 if (!strncasecmp(mime, "audio/", 6)) { 185 if (mAudioTrack.mSource == NULL) { 186 mAudioTrack.mIndex = i; 187 mAudioTrack.mSource = track; 188 mAudioTrack.mPackets = 189 new AnotherPacketSource(mAudioTrack.mSource->getFormat()); 190 191 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { 192 mAudioIsVorbis = true; 193 } else { 194 mAudioIsVorbis = false; 195 } 196 } 197 } else if (!strncasecmp(mime, "video/", 6)) { 198 if (mVideoTrack.mSource == NULL) { 199 mVideoTrack.mIndex = i; 200 mVideoTrack.mSource = track; 201 mVideoTrack.mPackets = 202 new AnotherPacketSource(mVideoTrack.mSource->getFormat()); 203 204 // check if the source requires secure buffers 205 int32_t secure; 206 if (meta->findInt32(kKeyRequiresSecureBuffers, &secure) 207 && secure) { 208 mIsWidevine = true; 209 if (mUIDValid) { 210 extractor->setUID(mUID); 211 } 212 } 213 } 214 } 215 216 mSources.push(track); 217 int64_t durationUs; 218 if (meta->findInt64(kKeyDuration, &durationUs)) { 219 if (durationUs > mDurationUs) { 220 mDurationUs = durationUs; 221 } 222 } 223 224 int32_t bitrate; 225 if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) { 226 totalBitrate += bitrate; 227 } else { 228 totalBitrate = -1; 229 } 230 } 231 232 if (mSources.size() == 0) { 233 ALOGE("b/23705695"); 234 return UNKNOWN_ERROR; 235 } 236 237 mBitrate = totalBitrate; 238 239 return OK; 240} 241 242void NuPlayer::GenericSource::checkDrmStatus(const sp<DataSource>& dataSource) { 243 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient); 244 if (mDecryptHandle != NULL) { 245 CHECK(mDrmManagerClient); 246 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) { 247 sp<AMessage> msg = dupNotify(); 248 msg->setInt32("what", kWhatDrmNoLicense); 249 msg->post(); 250 } 251 } 252} 253 254int64_t NuPlayer::GenericSource::getLastReadPosition() { 255 if (mAudioTrack.mSource != NULL) { 256 return mAudioTimeUs; 257 } else if (mVideoTrack.mSource != NULL) { 258 return mVideoTimeUs; 259 } else { 260 return 0; 261 } 262} 263 264status_t NuPlayer::GenericSource::setBuffers( 265 bool audio, Vector<MediaBuffer *> &buffers) { 266 if (mIsWidevine && !audio && mVideoTrack.mSource != NULL) { 267 return mVideoTrack.mSource->setBuffers(buffers); 268 } 269 return INVALID_OPERATION; 270} 271 272NuPlayer::GenericSource::~GenericSource() { 273 if (mLooper != NULL) { 274 mLooper->unregisterHandler(id()); 275 mLooper->stop(); 276 } 277} 278 279void NuPlayer::GenericSource::prepareAsync() { 280 if (mLooper == NULL) { 281 mLooper = new ALooper; 282 mLooper->setName("generic"); 283 mLooper->start(); 284 285 mLooper->registerHandler(this); 286 } 287 288 sp<AMessage> msg = new AMessage(kWhatPrepareAsync, id()); 289 msg->post(); 290} 291 292void NuPlayer::GenericSource::onPrepareAsync() { 293 // delayed data source creation 294 if (mDataSource == NULL) { 295 if (!mUri.empty()) { 296 const char* uri = mUri.c_str(); 297 mIsWidevine = !strncasecmp(uri, "widevine://", 11); 298 299 if (!strncasecmp("http://", uri, 7) 300 || !strncasecmp("https://", uri, 8) 301 || mIsWidevine) { 302 mHttpSource = DataSource::CreateMediaHTTP(mHTTPService); 303 if (mHttpSource == NULL) { 304 ALOGE("Failed to create http source!"); 305 notifyPreparedAndCleanup(UNKNOWN_ERROR); 306 return; 307 } 308 } 309 310 mDataSource = DataSource::CreateFromURI( 311 mHTTPService, uri, &mUriHeaders, &mContentType, 312 static_cast<HTTPBase *>(mHttpSource.get())); 313 } else { 314 // set to false first, if the extractor 315 // comes back as secure, set it to true then. 316 mIsWidevine = false; 317 318 mDataSource = new FileSource(mFd, mOffset, mLength); 319 } 320 321 if (mDataSource == NULL) { 322 ALOGE("Failed to create data source!"); 323 notifyPreparedAndCleanup(UNKNOWN_ERROR); 324 return; 325 } 326 327 if (mDataSource->flags() & DataSource::kIsCachingDataSource) { 328 mCachedSource = static_cast<NuCachedSource2 *>(mDataSource.get()); 329 } 330 331 if (mIsWidevine || mCachedSource != NULL) { 332 schedulePollBuffering(); 333 } 334 } 335 336 // check initial caching status 337 status_t err = prefillCacheIfNecessary(); 338 if (err != OK) { 339 if (err == -EAGAIN) { 340 (new AMessage(kWhatPrepareAsync, id()))->post(200000); 341 } else { 342 ALOGE("Failed to prefill data cache!"); 343 notifyPreparedAndCleanup(UNKNOWN_ERROR); 344 } 345 return; 346 } 347 348 // init extrator from data source 349 err = initFromDataSource(); 350 351 if (err != OK) { 352 ALOGE("Failed to init from data source!"); 353 notifyPreparedAndCleanup(err); 354 return; 355 } 356 357 if (mVideoTrack.mSource != NULL) { 358 sp<MetaData> meta = doGetFormatMeta(false /* audio */); 359 sp<AMessage> msg = new AMessage; 360 err = convertMetaDataToMessage(meta, &msg); 361 if(err != OK) { 362 notifyPreparedAndCleanup(err); 363 return; 364 } 365 notifyVideoSizeChanged(msg); 366 } 367 368 notifyFlagsChanged( 369 (mIsWidevine ? FLAG_SECURE : 0) 370 | FLAG_CAN_PAUSE 371 | FLAG_CAN_SEEK_BACKWARD 372 | FLAG_CAN_SEEK_FORWARD 373 | FLAG_CAN_SEEK); 374 375 notifyPrepared(); 376} 377 378void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) { 379 if (err != OK) { 380 mMetaDataSize = -1ll; 381 mContentType = ""; 382 mSniffedMIME = ""; 383 { 384 sp<DataSource> dataSource = mDataSource; 385 sp<NuCachedSource2> cachedSource = mCachedSource; 386 sp<DataSource> httpSource = mHttpSource; 387 { 388 Mutex::Autolock _l(mDisconnectLock); 389 mDataSource.clear(); 390 mDecryptHandle = NULL; 391 mDrmManagerClient = NULL; 392 mCachedSource.clear(); 393 mHttpSource.clear(); 394 } 395 } 396 397 cancelPollBuffering(); 398 } 399 notifyPrepared(err); 400} 401 402status_t NuPlayer::GenericSource::prefillCacheIfNecessary() { 403 CHECK(mDataSource != NULL); 404 405 if (mCachedSource == NULL) { 406 // no prefill if the data source is not cached 407 return OK; 408 } 409 410 // We're not doing this for streams that appear to be audio-only 411 // streams to ensure that even low bandwidth streams start 412 // playing back fairly instantly. 413 if (!strncasecmp(mContentType.string(), "audio/", 6)) { 414 return OK; 415 } 416 417 // We're going to prefill the cache before trying to instantiate 418 // the extractor below, as the latter is an operation that otherwise 419 // could block on the datasource for a significant amount of time. 420 // During that time we'd be unable to abort the preparation phase 421 // without this prefill. 422 423 // Initially make sure we have at least 192 KB for the sniff 424 // to complete without blocking. 425 static const size_t kMinBytesForSniffing = 192 * 1024; 426 static const size_t kDefaultMetaSize = 200000; 427 428 status_t finalStatus; 429 430 size_t cachedDataRemaining = 431 mCachedSource->approxDataRemaining(&finalStatus); 432 433 if (finalStatus != OK || (mMetaDataSize >= 0 434 && (off64_t)cachedDataRemaining >= mMetaDataSize)) { 435 ALOGV("stop caching, status %d, " 436 "metaDataSize %lld, cachedDataRemaining %zu", 437 finalStatus, mMetaDataSize, cachedDataRemaining); 438 return OK; 439 } 440 441 ALOGV("now cached %zu bytes of data", cachedDataRemaining); 442 443 if (mMetaDataSize < 0 444 && cachedDataRemaining >= kMinBytesForSniffing) { 445 String8 tmp; 446 float confidence; 447 sp<AMessage> meta; 448 if (!mCachedSource->sniff(&tmp, &confidence, &meta)) { 449 return UNKNOWN_ERROR; 450 } 451 452 // We successfully identified the file's extractor to 453 // be, remember this mime type so we don't have to 454 // sniff it again when we call MediaExtractor::Create() 455 mSniffedMIME = tmp.string(); 456 457 if (meta == NULL 458 || !meta->findInt64("meta-data-size", 459 reinterpret_cast<int64_t*>(&mMetaDataSize))) { 460 mMetaDataSize = kDefaultMetaSize; 461 } 462 463 if (mMetaDataSize < 0ll) { 464 ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize); 465 return UNKNOWN_ERROR; 466 } 467 } 468 469 return -EAGAIN; 470} 471 472void NuPlayer::GenericSource::start() { 473 ALOGI("start"); 474 475 mStopRead = false; 476 if (mAudioTrack.mSource != NULL) { 477 CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK); 478 479 postReadBuffer(MEDIA_TRACK_TYPE_AUDIO); 480 } 481 482 if (mVideoTrack.mSource != NULL) { 483 CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK); 484 485 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO); 486 } 487 488 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000); 489 mStarted = true; 490} 491 492void NuPlayer::GenericSource::stop() { 493 // nothing to do, just account for DRM playback status 494 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0); 495 mStarted = false; 496 if (mIsWidevine) { 497 // For a widevine source we need to prevent any further reads. 498 sp<AMessage> msg = new AMessage(kWhatStopWidevine, id()); 499 sp<AMessage> response; 500 (void) msg->postAndAwaitResponse(&response); 501 } 502} 503 504void NuPlayer::GenericSource::pause() { 505 // nothing to do, just account for DRM playback status 506 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0); 507 mStarted = false; 508} 509 510void NuPlayer::GenericSource::resume() { 511 // nothing to do, just account for DRM playback status 512 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000); 513 mStarted = true; 514} 515 516void NuPlayer::GenericSource::disconnect() { 517 sp<DataSource> dataSource, httpSource; 518 { 519 Mutex::Autolock _l(mDisconnectLock); 520 dataSource = mDataSource; 521 httpSource = mHttpSource; 522 } 523 524 if (dataSource != NULL) { 525 // disconnect data source 526 if (dataSource->flags() & DataSource::kIsCachingDataSource) { 527 static_cast<NuCachedSource2 *>(dataSource.get())->disconnect(); 528 } 529 } else if (httpSource != NULL) { 530 static_cast<HTTPBase *>(httpSource.get())->disconnect(); 531 } 532} 533 534void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) { 535 if (mDecryptHandle != NULL) { 536 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position); 537 } 538 mSubtitleTrack.mPackets = new AnotherPacketSource(NULL); 539 mTimedTextTrack.mPackets = new AnotherPacketSource(NULL); 540} 541 542status_t NuPlayer::GenericSource::feedMoreTSData() { 543 return OK; 544} 545 546void NuPlayer::GenericSource::schedulePollBuffering() { 547 sp<AMessage> msg = new AMessage(kWhatPollBuffering, id()); 548 msg->setInt32("generation", mPollBufferingGeneration); 549 msg->post(1000000ll); 550} 551 552void NuPlayer::GenericSource::cancelPollBuffering() { 553 ++mPollBufferingGeneration; 554} 555 556void NuPlayer::GenericSource::notifyBufferingUpdate(int percentage) { 557 sp<AMessage> msg = dupNotify(); 558 msg->setInt32("what", kWhatBufferingUpdate); 559 msg->setInt32("percentage", percentage); 560 msg->post(); 561} 562 563void NuPlayer::GenericSource::onPollBuffering() { 564 status_t finalStatus = UNKNOWN_ERROR; 565 int64_t cachedDurationUs = 0ll; 566 567 if (mCachedSource != NULL) { 568 size_t cachedDataRemaining = 569 mCachedSource->approxDataRemaining(&finalStatus); 570 571 if (finalStatus == OK) { 572 off64_t size; 573 int64_t bitrate = 0ll; 574 if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) { 575 bitrate = size * 8000000ll / mDurationUs; 576 } else if (mBitrate > 0) { 577 bitrate = mBitrate; 578 } 579 if (bitrate > 0) { 580 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate; 581 } 582 } 583 } else if (mWVMExtractor != NULL) { 584 cachedDurationUs 585 = mWVMExtractor->getCachedDurationUs(&finalStatus); 586 } 587 588 if (finalStatus == ERROR_END_OF_STREAM) { 589 notifyBufferingUpdate(100); 590 cancelPollBuffering(); 591 return; 592 } else if (cachedDurationUs > 0ll && mDurationUs > 0ll) { 593 int percentage = 100.0 * cachedDurationUs / mDurationUs; 594 if (percentage > 100) { 595 percentage = 100; 596 } 597 598 notifyBufferingUpdate(percentage); 599 } 600 601 schedulePollBuffering(); 602} 603 604 605void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) { 606 switch (msg->what()) { 607 case kWhatPrepareAsync: 608 { 609 onPrepareAsync(); 610 break; 611 } 612 case kWhatFetchSubtitleData: 613 { 614 fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, 615 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); 616 break; 617 } 618 619 case kWhatFetchTimedTextData: 620 { 621 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, 622 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); 623 break; 624 } 625 626 case kWhatSendSubtitleData: 627 { 628 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, 629 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); 630 break; 631 } 632 633 case kWhatSendTimedTextData: 634 { 635 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, 636 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); 637 break; 638 } 639 640 case kWhatChangeAVSource: 641 { 642 int32_t trackIndex; 643 CHECK(msg->findInt32("trackIndex", &trackIndex)); 644 const sp<MediaSource> source = mSources.itemAt(trackIndex); 645 646 Track* track; 647 const char *mime; 648 media_track_type trackType, counterpartType; 649 sp<MetaData> meta = source->getFormat(); 650 meta->findCString(kKeyMIMEType, &mime); 651 if (!strncasecmp(mime, "audio/", 6)) { 652 track = &mAudioTrack; 653 trackType = MEDIA_TRACK_TYPE_AUDIO; 654 counterpartType = MEDIA_TRACK_TYPE_VIDEO;; 655 } else { 656 CHECK(!strncasecmp(mime, "video/", 6)); 657 track = &mVideoTrack; 658 trackType = MEDIA_TRACK_TYPE_VIDEO; 659 counterpartType = MEDIA_TRACK_TYPE_AUDIO;; 660 } 661 662 663 if (track->mSource != NULL) { 664 track->mSource->stop(); 665 } 666 track->mSource = source; 667 track->mSource->start(); 668 track->mIndex = trackIndex; 669 670 status_t avail; 671 if (!track->mPackets->hasBufferAvailable(&avail)) { 672 // sync from other source 673 TRESPASS(); 674 break; 675 } 676 677 int64_t timeUs, actualTimeUs; 678 const bool formatChange = true; 679 sp<AMessage> latestMeta = track->mPackets->getLatestEnqueuedMeta(); 680 CHECK(latestMeta != NULL && latestMeta->findInt64("timeUs", &timeUs)); 681 readBuffer(trackType, timeUs, &actualTimeUs, formatChange); 682 readBuffer(counterpartType, -1, NULL, formatChange); 683 ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs); 684 685 break; 686 } 687 case kWhatPollBuffering: 688 { 689 int32_t generation; 690 CHECK(msg->findInt32("generation", &generation)); 691 if (generation == mPollBufferingGeneration) { 692 onPollBuffering(); 693 } 694 break; 695 } 696 697 case kWhatGetFormat: 698 { 699 onGetFormatMeta(msg); 700 break; 701 } 702 703 case kWhatGetSelectedTrack: 704 { 705 onGetSelectedTrack(msg); 706 break; 707 } 708 709 case kWhatSelectTrack: 710 { 711 onSelectTrack(msg); 712 break; 713 } 714 715 case kWhatSeek: 716 { 717 onSeek(msg); 718 break; 719 } 720 721 case kWhatReadBuffer: 722 { 723 onReadBuffer(msg); 724 break; 725 } 726 727 case kWhatStopWidevine: 728 { 729 // mStopRead is only used for Widevine to prevent the video source 730 // from being read while the associated video decoder is shutting down. 731 mStopRead = true; 732 if (mVideoTrack.mSource != NULL) { 733 mVideoTrack.mPackets->clear(); 734 } 735 sp<AMessage> response = new AMessage; 736 uint32_t replyID; 737 CHECK(msg->senderAwaitsResponse(&replyID)); 738 response->postReply(replyID); 739 break; 740 } 741 default: 742 Source::onMessageReceived(msg); 743 break; 744 } 745} 746 747void NuPlayer::GenericSource::fetchTextData( 748 uint32_t sendWhat, 749 media_track_type type, 750 int32_t curGen, 751 sp<AnotherPacketSource> packets, 752 sp<AMessage> msg) { 753 int32_t msgGeneration; 754 CHECK(msg->findInt32("generation", &msgGeneration)); 755 if (msgGeneration != curGen) { 756 // stale 757 return; 758 } 759 760 int32_t avail; 761 if (packets->hasBufferAvailable(&avail)) { 762 return; 763 } 764 765 int64_t timeUs; 766 CHECK(msg->findInt64("timeUs", &timeUs)); 767 768 int64_t subTimeUs; 769 readBuffer(type, timeUs, &subTimeUs); 770 771 int64_t delayUs = subTimeUs - timeUs; 772 if (msg->what() == kWhatFetchSubtitleData) { 773 const int64_t oneSecUs = 1000000ll; 774 delayUs -= oneSecUs; 775 } 776 sp<AMessage> msg2 = new AMessage(sendWhat, id()); 777 msg2->setInt32("generation", msgGeneration); 778 msg2->post(delayUs < 0 ? 0 : delayUs); 779} 780 781void NuPlayer::GenericSource::sendTextData( 782 uint32_t what, 783 media_track_type type, 784 int32_t curGen, 785 sp<AnotherPacketSource> packets, 786 sp<AMessage> msg) { 787 int32_t msgGeneration; 788 CHECK(msg->findInt32("generation", &msgGeneration)); 789 if (msgGeneration != curGen) { 790 // stale 791 return; 792 } 793 794 int64_t subTimeUs; 795 if (packets->nextBufferTime(&subTimeUs) != OK) { 796 return; 797 } 798 799 int64_t nextSubTimeUs; 800 readBuffer(type, -1, &nextSubTimeUs); 801 802 sp<ABuffer> buffer; 803 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer); 804 if (dequeueStatus == OK) { 805 sp<AMessage> notify = dupNotify(); 806 notify->setInt32("what", what); 807 notify->setBuffer("buffer", buffer); 808 notify->post(); 809 810 const int64_t delayUs = nextSubTimeUs - subTimeUs; 811 msg->post(delayUs < 0 ? 0 : delayUs); 812 } 813} 814 815sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) { 816 sp<AMessage> msg = new AMessage(kWhatGetFormat, id()); 817 msg->setInt32("audio", audio); 818 819 sp<AMessage> response; 820 void *format; 821 status_t err = msg->postAndAwaitResponse(&response); 822 if (err == OK && response != NULL) { 823 CHECK(response->findPointer("format", &format)); 824 return (MetaData *)format; 825 } else { 826 return NULL; 827 } 828} 829 830void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const { 831 int32_t audio; 832 CHECK(msg->findInt32("audio", &audio)); 833 834 sp<AMessage> response = new AMessage; 835 sp<MetaData> format = doGetFormatMeta(audio); 836 response->setPointer("format", format.get()); 837 838 uint32_t replyID; 839 CHECK(msg->senderAwaitsResponse(&replyID)); 840 response->postReply(replyID); 841} 842 843sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const { 844 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource; 845 846 if (source == NULL) { 847 return NULL; 848 } 849 850 return source->getFormat(); 851} 852 853status_t NuPlayer::GenericSource::dequeueAccessUnit( 854 bool audio, sp<ABuffer> *accessUnit) { 855 Track *track = audio ? &mAudioTrack : &mVideoTrack; 856 857 if (track->mSource == NULL) { 858 return -EWOULDBLOCK; 859 } 860 861 if (mIsWidevine && !audio) { 862 // try to read a buffer as we may not have been able to the last time 863 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO); 864 } 865 866 status_t finalResult; 867 if (!track->mPackets->hasBufferAvailable(&finalResult)) { 868 return (finalResult == OK ? -EWOULDBLOCK : finalResult); 869 } 870 871 status_t result = track->mPackets->dequeueAccessUnit(accessUnit); 872 873 if (!track->mPackets->hasBufferAvailable(&finalResult)) { 874 postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO); 875 } 876 877 if (result != OK) { 878 if (mSubtitleTrack.mSource != NULL) { 879 mSubtitleTrack.mPackets->clear(); 880 mFetchSubtitleDataGeneration++; 881 } 882 if (mTimedTextTrack.mSource != NULL) { 883 mTimedTextTrack.mPackets->clear(); 884 mFetchTimedTextDataGeneration++; 885 } 886 return result; 887 } 888 889 int64_t timeUs; 890 status_t eosResult; // ignored 891 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); 892 893 if (mSubtitleTrack.mSource != NULL 894 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { 895 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id()); 896 msg->setInt64("timeUs", timeUs); 897 msg->setInt32("generation", mFetchSubtitleDataGeneration); 898 msg->post(); 899 } 900 901 if (mTimedTextTrack.mSource != NULL 902 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) { 903 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id()); 904 msg->setInt64("timeUs", timeUs); 905 msg->setInt32("generation", mFetchTimedTextDataGeneration); 906 msg->post(); 907 } 908 909 return result; 910} 911 912status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) { 913 *durationUs = mDurationUs; 914 return OK; 915} 916 917size_t NuPlayer::GenericSource::getTrackCount() const { 918 return mSources.size(); 919} 920 921sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const { 922 size_t trackCount = mSources.size(); 923 if (trackIndex >= trackCount) { 924 return NULL; 925 } 926 927 sp<AMessage> format = new AMessage(); 928 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat(); 929 930 const char *mime; 931 CHECK(meta->findCString(kKeyMIMEType, &mime)); 932 933 int32_t trackType; 934 if (!strncasecmp(mime, "video/", 6)) { 935 trackType = MEDIA_TRACK_TYPE_VIDEO; 936 } else if (!strncasecmp(mime, "audio/", 6)) { 937 trackType = MEDIA_TRACK_TYPE_AUDIO; 938 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { 939 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT; 940 } else { 941 trackType = MEDIA_TRACK_TYPE_UNKNOWN; 942 } 943 format->setInt32("type", trackType); 944 945 const char *lang; 946 if (!meta->findCString(kKeyMediaLanguage, &lang)) { 947 lang = "und"; 948 } 949 format->setString("language", lang); 950 951 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 952 format->setString("mime", mime); 953 954 int32_t isAutoselect = 1, isDefault = 0, isForced = 0; 955 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect); 956 meta->findInt32(kKeyTrackIsDefault, &isDefault); 957 meta->findInt32(kKeyTrackIsForced, &isForced); 958 959 format->setInt32("auto", !!isAutoselect); 960 format->setInt32("default", !!isDefault); 961 format->setInt32("forced", !!isForced); 962 } 963 964 return format; 965} 966 967ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const { 968 sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id()); 969 msg->setInt32("type", type); 970 971 sp<AMessage> response; 972 int32_t index; 973 status_t err = msg->postAndAwaitResponse(&response); 974 if (err == OK && response != NULL) { 975 CHECK(response->findInt32("index", &index)); 976 return index; 977 } else { 978 return -1; 979 } 980} 981 982void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const { 983 int32_t tmpType; 984 CHECK(msg->findInt32("type", &tmpType)); 985 media_track_type type = (media_track_type)tmpType; 986 987 sp<AMessage> response = new AMessage; 988 ssize_t index = doGetSelectedTrack(type); 989 response->setInt32("index", index); 990 991 uint32_t replyID; 992 CHECK(msg->senderAwaitsResponse(&replyID)); 993 response->postReply(replyID); 994} 995 996ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const { 997 const Track *track = NULL; 998 switch (type) { 999 case MEDIA_TRACK_TYPE_VIDEO: 1000 track = &mVideoTrack; 1001 break; 1002 case MEDIA_TRACK_TYPE_AUDIO: 1003 track = &mAudioTrack; 1004 break; 1005 case MEDIA_TRACK_TYPE_TIMEDTEXT: 1006 track = &mTimedTextTrack; 1007 break; 1008 case MEDIA_TRACK_TYPE_SUBTITLE: 1009 track = &mSubtitleTrack; 1010 break; 1011 default: 1012 break; 1013 } 1014 1015 if (track != NULL && track->mSource != NULL) { 1016 return track->mIndex; 1017 } 1018 1019 return -1; 1020} 1021 1022status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { 1023 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex); 1024 sp<AMessage> msg = new AMessage(kWhatSelectTrack, id()); 1025 msg->setInt32("trackIndex", trackIndex); 1026 msg->setInt32("select", select); 1027 1028 sp<AMessage> response; 1029 status_t err = msg->postAndAwaitResponse(&response); 1030 if (err == OK && response != NULL) { 1031 CHECK(response->findInt32("err", &err)); 1032 } 1033 1034 return err; 1035} 1036 1037void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) { 1038 int32_t trackIndex, select; 1039 CHECK(msg->findInt32("trackIndex", &trackIndex)); 1040 CHECK(msg->findInt32("select", &select)); 1041 1042 sp<AMessage> response = new AMessage; 1043 status_t err = doSelectTrack(trackIndex, select); 1044 response->setInt32("err", err); 1045 1046 uint32_t replyID; 1047 CHECK(msg->senderAwaitsResponse(&replyID)); 1048 response->postReply(replyID); 1049} 1050 1051status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select) { 1052 if (trackIndex >= mSources.size()) { 1053 return BAD_INDEX; 1054 } 1055 1056 if (!select) { 1057 Track* track = NULL; 1058 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) { 1059 track = &mSubtitleTrack; 1060 mFetchSubtitleDataGeneration++; 1061 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) { 1062 track = &mTimedTextTrack; 1063 mFetchTimedTextDataGeneration++; 1064 } 1065 if (track == NULL) { 1066 return INVALID_OPERATION; 1067 } 1068 track->mSource->stop(); 1069 track->mSource = NULL; 1070 track->mPackets->clear(); 1071 return OK; 1072 } 1073 1074 const sp<MediaSource> source = mSources.itemAt(trackIndex); 1075 sp<MetaData> meta = source->getFormat(); 1076 const char *mime; 1077 CHECK(meta->findCString(kKeyMIMEType, &mime)); 1078 if (!strncasecmp(mime, "text/", 5)) { 1079 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP); 1080 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack; 1081 if (track->mSource != NULL && track->mIndex == trackIndex) { 1082 return OK; 1083 } 1084 track->mIndex = trackIndex; 1085 if (track->mSource != NULL) { 1086 track->mSource->stop(); 1087 } 1088 track->mSource = mSources.itemAt(trackIndex); 1089 track->mSource->start(); 1090 if (track->mPackets == NULL) { 1091 track->mPackets = new AnotherPacketSource(track->mSource->getFormat()); 1092 } else { 1093 track->mPackets->clear(); 1094 track->mPackets->setFormat(track->mSource->getFormat()); 1095 1096 } 1097 1098 if (isSubtitle) { 1099 mFetchSubtitleDataGeneration++; 1100 } else { 1101 mFetchTimedTextDataGeneration++; 1102 } 1103 1104 return OK; 1105 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) { 1106 bool audio = !strncasecmp(mime, "audio/", 6); 1107 Track *track = audio ? &mAudioTrack : &mVideoTrack; 1108 if (track->mSource != NULL && track->mIndex == trackIndex) { 1109 return OK; 1110 } 1111 1112 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id()); 1113 msg->setInt32("trackIndex", trackIndex); 1114 msg->post(); 1115 return OK; 1116 } 1117 1118 return INVALID_OPERATION; 1119} 1120 1121status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) { 1122 sp<AMessage> msg = new AMessage(kWhatSeek, id()); 1123 msg->setInt64("seekTimeUs", seekTimeUs); 1124 1125 sp<AMessage> response; 1126 status_t err = msg->postAndAwaitResponse(&response); 1127 if (err == OK && response != NULL) { 1128 CHECK(response->findInt32("err", &err)); 1129 } 1130 1131 return err; 1132} 1133 1134void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) { 1135 int64_t seekTimeUs; 1136 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs)); 1137 1138 sp<AMessage> response = new AMessage; 1139 status_t err = doSeek(seekTimeUs); 1140 response->setInt32("err", err); 1141 1142 uint32_t replyID; 1143 CHECK(msg->senderAwaitsResponse(&replyID)); 1144 response->postReply(replyID); 1145} 1146 1147status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) { 1148 // If the Widevine source is stopped, do not attempt to read any 1149 // more buffers. 1150 if (mStopRead) { 1151 return INVALID_OPERATION; 1152 } 1153 if (mVideoTrack.mSource != NULL) { 1154 int64_t actualTimeUs; 1155 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs); 1156 1157 seekTimeUs = actualTimeUs; 1158 } 1159 1160 if (mAudioTrack.mSource != NULL) { 1161 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs); 1162 } 1163 1164 setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000); 1165 if (!mStarted) { 1166 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0); 1167 } 1168 return OK; 1169} 1170 1171sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer( 1172 MediaBuffer* mb, 1173 media_track_type trackType, 1174 int64_t *actualTimeUs) { 1175 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO; 1176 size_t outLength = mb->range_length(); 1177 1178 if (audio && mAudioIsVorbis) { 1179 outLength += sizeof(int32_t); 1180 } 1181 1182 sp<ABuffer> ab; 1183 if (mIsWidevine && !audio) { 1184 // data is already provided in the buffer 1185 ab = new ABuffer(NULL, mb->range_length()); 1186 mb->add_ref(); 1187 ab->setMediaBufferBase(mb); 1188 } else { 1189 ab = new ABuffer(outLength); 1190 memcpy(ab->data(), 1191 (const uint8_t *)mb->data() + mb->range_offset(), 1192 mb->range_length()); 1193 } 1194 1195 if (audio && mAudioIsVorbis) { 1196 int32_t numPageSamples; 1197 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) { 1198 numPageSamples = -1; 1199 } 1200 1201 uint8_t* abEnd = ab->data() + mb->range_length(); 1202 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples)); 1203 } 1204 1205 sp<AMessage> meta = ab->meta(); 1206 1207 int64_t timeUs; 1208 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs)); 1209 meta->setInt64("timeUs", timeUs); 1210 1211 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) { 1212 const char *mime; 1213 CHECK(mTimedTextTrack.mSource != NULL 1214 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime)); 1215 meta->setString("mime", mime); 1216 } 1217 1218 int64_t durationUs; 1219 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) { 1220 meta->setInt64("durationUs", durationUs); 1221 } 1222 1223 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 1224 meta->setInt32("trackIndex", mSubtitleTrack.mIndex); 1225 } 1226 1227 if (actualTimeUs) { 1228 *actualTimeUs = timeUs; 1229 } 1230 1231 mb->release(); 1232 mb = NULL; 1233 1234 return ab; 1235} 1236 1237void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) { 1238 Mutex::Autolock _l(mReadBufferLock); 1239 1240 if ((mPendingReadBufferTypes & (1 << trackType)) == 0) { 1241 mPendingReadBufferTypes |= (1 << trackType); 1242 sp<AMessage> msg = new AMessage(kWhatReadBuffer, id()); 1243 msg->setInt32("trackType", trackType); 1244 msg->post(); 1245 } 1246} 1247 1248void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) { 1249 int32_t tmpType; 1250 CHECK(msg->findInt32("trackType", &tmpType)); 1251 media_track_type trackType = (media_track_type)tmpType; 1252 { 1253 // only protect the variable change, as readBuffer may 1254 // take considerable time. This may result in one extra 1255 // read being processed, but that is benign. 1256 Mutex::Autolock _l(mReadBufferLock); 1257 mPendingReadBufferTypes &= ~(1 << trackType); 1258 } 1259 readBuffer(trackType); 1260} 1261 1262void NuPlayer::GenericSource::readBuffer( 1263 media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) { 1264 // Do not read data if Widevine source is stopped 1265 if (mStopRead) { 1266 return; 1267 } 1268 Track *track; 1269 size_t maxBuffers = 1; 1270 switch (trackType) { 1271 case MEDIA_TRACK_TYPE_VIDEO: 1272 track = &mVideoTrack; 1273 if (mIsWidevine) { 1274 maxBuffers = 2; 1275 } 1276 break; 1277 case MEDIA_TRACK_TYPE_AUDIO: 1278 track = &mAudioTrack; 1279 if (mIsWidevine) { 1280 maxBuffers = 8; 1281 } else { 1282 maxBuffers = 64; 1283 } 1284 break; 1285 case MEDIA_TRACK_TYPE_SUBTITLE: 1286 track = &mSubtitleTrack; 1287 break; 1288 case MEDIA_TRACK_TYPE_TIMEDTEXT: 1289 track = &mTimedTextTrack; 1290 break; 1291 default: 1292 TRESPASS(); 1293 } 1294 1295 if (track->mSource == NULL) { 1296 return; 1297 } 1298 1299 if (actualTimeUs) { 1300 *actualTimeUs = seekTimeUs; 1301 } 1302 1303 MediaSource::ReadOptions options; 1304 1305 bool seeking = false; 1306 1307 if (seekTimeUs >= 0) { 1308 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 1309 seeking = true; 1310 } 1311 1312 if (mIsWidevine && trackType != MEDIA_TRACK_TYPE_AUDIO) { 1313 options.setNonBlocking(); 1314 } 1315 1316 for (size_t numBuffers = 0; numBuffers < maxBuffers; ) { 1317 MediaBuffer *mbuf; 1318 status_t err = track->mSource->read(&mbuf, &options); 1319 1320 options.clearSeekTo(); 1321 1322 if (err == OK) { 1323 int64_t timeUs; 1324 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); 1325 if (trackType == MEDIA_TRACK_TYPE_AUDIO) { 1326 mAudioTimeUs = timeUs; 1327 } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) { 1328 mVideoTimeUs = timeUs; 1329 } 1330 1331 // formatChange && seeking: track whose source is changed during selection 1332 // formatChange && !seeking: track whose source is not changed during selection 1333 // !formatChange: normal seek 1334 if ((seeking || formatChange) 1335 && (trackType == MEDIA_TRACK_TYPE_AUDIO 1336 || trackType == MEDIA_TRACK_TYPE_VIDEO)) { 1337 ATSParser::DiscontinuityType type = formatChange 1338 ? (seeking 1339 ? ATSParser::DISCONTINUITY_FORMATCHANGE 1340 : ATSParser::DISCONTINUITY_NONE) 1341 : ATSParser::DISCONTINUITY_SEEK; 1342 track->mPackets->queueDiscontinuity( type, NULL, true /* discard */); 1343 } 1344 1345 sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs); 1346 track->mPackets->queueAccessUnit(buffer); 1347 formatChange = false; 1348 seeking = false; 1349 ++numBuffers; 1350 } else if (err == WOULD_BLOCK) { 1351 break; 1352 } else if (err == INFO_FORMAT_CHANGED) { 1353#if 0 1354 track->mPackets->queueDiscontinuity( 1355 ATSParser::DISCONTINUITY_FORMATCHANGE, 1356 NULL, 1357 false /* discard */); 1358#endif 1359 } else { 1360 track->mPackets->signalEOS(err); 1361 break; 1362 } 1363 } 1364} 1365 1366} // namespace android 1367