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