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