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