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