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