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