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