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