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