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