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