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