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