GenericSource.cpp revision 661a5270303392bbf22eaa459961e6ab7b26b529
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 | FLAG_CAN_PAUSE 395 | FLAG_CAN_SEEK_BACKWARD 396 | FLAG_CAN_SEEK_FORWARD 397 | FLAG_CAN_SEEK); 398 399 notifyPrepared(); 400} 401 402void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) { 403 if (err != OK) { 404 mMetaDataSize = -1ll; 405 mContentType = ""; 406 mSniffedMIME = ""; 407 mDataSource.clear(); 408 mCachedSource.clear(); 409 mHttpSource.clear(); 410 411 cancelPollBuffering(); 412 } 413 notifyPrepared(err); 414} 415 416status_t NuPlayer::GenericSource::prefillCacheIfNecessary() { 417 CHECK(mDataSource != NULL); 418 419 if (mCachedSource == NULL) { 420 // no prefill if the data source is not cached 421 return OK; 422 } 423 424 // We're not doing this for streams that appear to be audio-only 425 // streams to ensure that even low bandwidth streams start 426 // playing back fairly instantly. 427 if (!strncasecmp(mContentType.string(), "audio/", 6)) { 428 return OK; 429 } 430 431 // We're going to prefill the cache before trying to instantiate 432 // the extractor below, as the latter is an operation that otherwise 433 // could block on the datasource for a significant amount of time. 434 // During that time we'd be unable to abort the preparation phase 435 // without this prefill. 436 437 // Initially make sure we have at least 192 KB for the sniff 438 // to complete without blocking. 439 static const size_t kMinBytesForSniffing = 192 * 1024; 440 static const size_t kDefaultMetaSize = 200000; 441 442 status_t finalStatus; 443 444 size_t cachedDataRemaining = 445 mCachedSource->approxDataRemaining(&finalStatus); 446 447 if (finalStatus != OK || (mMetaDataSize >= 0 448 && (off64_t)cachedDataRemaining >= mMetaDataSize)) { 449 ALOGV("stop caching, status %d, " 450 "metaDataSize %lld, cachedDataRemaining %zu", 451 finalStatus, mMetaDataSize, cachedDataRemaining); 452 return OK; 453 } 454 455 ALOGV("now cached %zu bytes of data", cachedDataRemaining); 456 457 if (mMetaDataSize < 0 458 && cachedDataRemaining >= kMinBytesForSniffing) { 459 String8 tmp; 460 float confidence; 461 sp<AMessage> meta; 462 if (!mCachedSource->sniff(&tmp, &confidence, &meta)) { 463 return UNKNOWN_ERROR; 464 } 465 466 // We successfully identified the file's extractor to 467 // be, remember this mime type so we don't have to 468 // sniff it again when we call MediaExtractor::Create() 469 mSniffedMIME = tmp.string(); 470 471 if (meta == NULL 472 || !meta->findInt64("meta-data-size", 473 reinterpret_cast<int64_t*>(&mMetaDataSize))) { 474 mMetaDataSize = kDefaultMetaSize; 475 } 476 477 if (mMetaDataSize < 0ll) { 478 ALOGE("invalid metaDataSize = %lld bytes", mMetaDataSize); 479 return UNKNOWN_ERROR; 480 } 481 } 482 483 return -EAGAIN; 484} 485 486void NuPlayer::GenericSource::start() { 487 ALOGI("start"); 488 489 mStopRead = false; 490 if (mAudioTrack.mSource != NULL) { 491 CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK); 492 493 postReadBuffer(MEDIA_TRACK_TYPE_AUDIO); 494 } 495 496 if (mVideoTrack.mSource != NULL) { 497 CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK); 498 499 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO); 500 } 501 502 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000); 503 mStarted = true; 504} 505 506void NuPlayer::GenericSource::stop() { 507 // nothing to do, just account for DRM playback status 508 setDrmPlaybackStatusIfNeeded(Playback::STOP, 0); 509 mStarted = false; 510 if (mIsWidevine || mIsSecure) { 511 // For widevine or secure sources we need to prevent any further reads. 512 sp<AMessage> msg = new AMessage(kWhatStopWidevine, id()); 513 sp<AMessage> response; 514 (void) msg->postAndAwaitResponse(&response); 515 } 516} 517 518void NuPlayer::GenericSource::pause() { 519 // nothing to do, just account for DRM playback status 520 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0); 521 mStarted = false; 522} 523 524void NuPlayer::GenericSource::resume() { 525 // nothing to do, just account for DRM playback status 526 setDrmPlaybackStatusIfNeeded(Playback::START, getLastReadPosition() / 1000); 527 mStarted = true; 528} 529 530void NuPlayer::GenericSource::disconnect() { 531 if (mDataSource != NULL) { 532 // disconnect data source 533 if (mDataSource->flags() & DataSource::kIsCachingDataSource) { 534 static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect(); 535 } 536 } else if (mHttpSource != NULL) { 537 static_cast<HTTPBase *>(mHttpSource.get())->disconnect(); 538 } 539} 540 541void NuPlayer::GenericSource::setDrmPlaybackStatusIfNeeded(int playbackStatus, int64_t position) { 542 if (mDecryptHandle != NULL) { 543 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, playbackStatus, position); 544 } 545 mSubtitleTrack.mPackets = new AnotherPacketSource(NULL); 546 mTimedTextTrack.mPackets = new AnotherPacketSource(NULL); 547} 548 549status_t NuPlayer::GenericSource::feedMoreTSData() { 550 return OK; 551} 552 553void NuPlayer::GenericSource::schedulePollBuffering() { 554 sp<AMessage> msg = new AMessage(kWhatPollBuffering, id()); 555 msg->setInt32("generation", mPollBufferingGeneration); 556 msg->post(1000000ll); 557} 558 559void NuPlayer::GenericSource::cancelPollBuffering() { 560 ++mPollBufferingGeneration; 561} 562 563void NuPlayer::GenericSource::notifyBufferingUpdate(int percentage) { 564 sp<AMessage> msg = dupNotify(); 565 msg->setInt32("what", kWhatBufferingUpdate); 566 msg->setInt32("percentage", percentage); 567 msg->post(); 568} 569 570void NuPlayer::GenericSource::onPollBuffering() { 571 status_t finalStatus = UNKNOWN_ERROR; 572 int64_t cachedDurationUs = 0ll; 573 574 if (mCachedSource != NULL) { 575 size_t cachedDataRemaining = 576 mCachedSource->approxDataRemaining(&finalStatus); 577 578 if (finalStatus == OK) { 579 off64_t size; 580 int64_t bitrate = 0ll; 581 if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) { 582 bitrate = size * 8000000ll / mDurationUs; 583 } else if (mBitrate > 0) { 584 bitrate = mBitrate; 585 } 586 if (bitrate > 0) { 587 cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate; 588 } 589 } 590 } else if (mWVMExtractor != NULL) { 591 cachedDurationUs 592 = mWVMExtractor->getCachedDurationUs(&finalStatus); 593 } 594 595 if (finalStatus == ERROR_END_OF_STREAM) { 596 notifyBufferingUpdate(100); 597 cancelPollBuffering(); 598 return; 599 } else if (cachedDurationUs > 0ll && mDurationUs > 0ll) { 600 int percentage = 100.0 * cachedDurationUs / mDurationUs; 601 if (percentage > 100) { 602 percentage = 100; 603 } 604 605 notifyBufferingUpdate(percentage); 606 } 607 608 schedulePollBuffering(); 609} 610 611 612void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) { 613 switch (msg->what()) { 614 case kWhatPrepareAsync: 615 { 616 onPrepareAsync(); 617 break; 618 } 619 case kWhatFetchSubtitleData: 620 { 621 fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, 622 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); 623 break; 624 } 625 626 case kWhatFetchTimedTextData: 627 { 628 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, 629 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); 630 break; 631 } 632 633 case kWhatSendSubtitleData: 634 { 635 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, 636 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); 637 break; 638 } 639 640 case kWhatSendTimedTextData: 641 { 642 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, 643 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); 644 break; 645 } 646 647 case kWhatChangeAVSource: 648 { 649 int32_t trackIndex; 650 CHECK(msg->findInt32("trackIndex", &trackIndex)); 651 const sp<MediaSource> source = mSources.itemAt(trackIndex); 652 653 Track* track; 654 const char *mime; 655 media_track_type trackType, counterpartType; 656 sp<MetaData> meta = source->getFormat(); 657 meta->findCString(kKeyMIMEType, &mime); 658 if (!strncasecmp(mime, "audio/", 6)) { 659 track = &mAudioTrack; 660 trackType = MEDIA_TRACK_TYPE_AUDIO; 661 counterpartType = MEDIA_TRACK_TYPE_VIDEO;; 662 } else { 663 CHECK(!strncasecmp(mime, "video/", 6)); 664 track = &mVideoTrack; 665 trackType = MEDIA_TRACK_TYPE_VIDEO; 666 counterpartType = MEDIA_TRACK_TYPE_AUDIO;; 667 } 668 669 670 if (track->mSource != NULL) { 671 track->mSource->stop(); 672 } 673 track->mSource = source; 674 track->mSource->start(); 675 track->mIndex = trackIndex; 676 677 int64_t timeUs, actualTimeUs; 678 const bool formatChange = true; 679 if (trackType == MEDIA_TRACK_TYPE_AUDIO) { 680 timeUs = mAudioLastDequeueTimeUs; 681 } else { 682 timeUs = mVideoLastDequeueTimeUs; 683 } 684 readBuffer(trackType, timeUs, &actualTimeUs, formatChange); 685 readBuffer(counterpartType, -1, NULL, formatChange); 686 ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs); 687 688 break; 689 } 690 case kWhatPollBuffering: 691 { 692 int32_t generation; 693 CHECK(msg->findInt32("generation", &generation)); 694 if (generation == mPollBufferingGeneration) { 695 onPollBuffering(); 696 } 697 break; 698 } 699 700 case kWhatGetFormat: 701 { 702 onGetFormatMeta(msg); 703 break; 704 } 705 706 case kWhatGetSelectedTrack: 707 { 708 onGetSelectedTrack(msg); 709 break; 710 } 711 712 case kWhatSelectTrack: 713 { 714 onSelectTrack(msg); 715 break; 716 } 717 718 case kWhatSeek: 719 { 720 onSeek(msg); 721 break; 722 } 723 724 case kWhatReadBuffer: 725 { 726 onReadBuffer(msg); 727 break; 728 } 729 730 case kWhatStopWidevine: 731 { 732 // mStopRead is only used for Widevine to prevent the video source 733 // from being read while the associated video decoder is shutting down. 734 mStopRead = true; 735 if (mVideoTrack.mSource != NULL) { 736 mVideoTrack.mPackets->clear(); 737 } 738 sp<AMessage> response = new AMessage; 739 uint32_t replyID; 740 CHECK(msg->senderAwaitsResponse(&replyID)); 741 response->postReply(replyID); 742 break; 743 } 744 default: 745 Source::onMessageReceived(msg); 746 break; 747 } 748} 749 750void NuPlayer::GenericSource::fetchTextData( 751 uint32_t sendWhat, 752 media_track_type type, 753 int32_t curGen, 754 sp<AnotherPacketSource> packets, 755 sp<AMessage> msg) { 756 int32_t msgGeneration; 757 CHECK(msg->findInt32("generation", &msgGeneration)); 758 if (msgGeneration != curGen) { 759 // stale 760 return; 761 } 762 763 int32_t avail; 764 if (packets->hasBufferAvailable(&avail)) { 765 return; 766 } 767 768 int64_t timeUs; 769 CHECK(msg->findInt64("timeUs", &timeUs)); 770 771 int64_t subTimeUs; 772 readBuffer(type, timeUs, &subTimeUs); 773 774 int64_t delayUs = subTimeUs - timeUs; 775 if (msg->what() == kWhatFetchSubtitleData) { 776 const int64_t oneSecUs = 1000000ll; 777 delayUs -= oneSecUs; 778 } 779 sp<AMessage> msg2 = new AMessage(sendWhat, id()); 780 msg2->setInt32("generation", msgGeneration); 781 msg2->post(delayUs < 0 ? 0 : delayUs); 782} 783 784void NuPlayer::GenericSource::sendTextData( 785 uint32_t what, 786 media_track_type type, 787 int32_t curGen, 788 sp<AnotherPacketSource> packets, 789 sp<AMessage> msg) { 790 int32_t msgGeneration; 791 CHECK(msg->findInt32("generation", &msgGeneration)); 792 if (msgGeneration != curGen) { 793 // stale 794 return; 795 } 796 797 int64_t subTimeUs; 798 if (packets->nextBufferTime(&subTimeUs) != OK) { 799 return; 800 } 801 802 int64_t nextSubTimeUs; 803 readBuffer(type, -1, &nextSubTimeUs); 804 805 sp<ABuffer> buffer; 806 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer); 807 if (dequeueStatus == OK) { 808 sp<AMessage> notify = dupNotify(); 809 notify->setInt32("what", what); 810 notify->setBuffer("buffer", buffer); 811 notify->post(); 812 813 const int64_t delayUs = nextSubTimeUs - subTimeUs; 814 msg->post(delayUs < 0 ? 0 : delayUs); 815 } 816} 817 818sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) { 819 sp<AMessage> msg = new AMessage(kWhatGetFormat, id()); 820 msg->setInt32("audio", audio); 821 822 sp<AMessage> response; 823 void *format; 824 status_t err = msg->postAndAwaitResponse(&response); 825 if (err == OK && response != NULL) { 826 CHECK(response->findPointer("format", &format)); 827 return (MetaData *)format; 828 } else { 829 return NULL; 830 } 831} 832 833void NuPlayer::GenericSource::onGetFormatMeta(sp<AMessage> msg) const { 834 int32_t audio; 835 CHECK(msg->findInt32("audio", &audio)); 836 837 sp<AMessage> response = new AMessage; 838 sp<MetaData> format = doGetFormatMeta(audio); 839 response->setPointer("format", format.get()); 840 841 uint32_t replyID; 842 CHECK(msg->senderAwaitsResponse(&replyID)); 843 response->postReply(replyID); 844} 845 846sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const { 847 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource; 848 849 if (source == NULL) { 850 return NULL; 851 } 852 853 return source->getFormat(); 854} 855 856status_t NuPlayer::GenericSource::dequeueAccessUnit( 857 bool audio, sp<ABuffer> *accessUnit) { 858 Track *track = audio ? &mAudioTrack : &mVideoTrack; 859 860 if (track->mSource == NULL) { 861 return -EWOULDBLOCK; 862 } 863 864 if (mIsWidevine && !audio) { 865 // try to read a buffer as we may not have been able to the last time 866 postReadBuffer(MEDIA_TRACK_TYPE_VIDEO); 867 } 868 869 status_t finalResult; 870 if (!track->mPackets->hasBufferAvailable(&finalResult)) { 871 if (finalResult == OK) { 872 postReadBuffer( 873 audio ? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO); 874 return -EWOULDBLOCK; 875 } 876 return finalResult; 877 } 878 879 status_t result = track->mPackets->dequeueAccessUnit(accessUnit); 880 881 if (!track->mPackets->hasBufferAvailable(&finalResult)) { 882 postReadBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO); 883 } 884 885 if (result != OK) { 886 if (mSubtitleTrack.mSource != NULL) { 887 mSubtitleTrack.mPackets->clear(); 888 mFetchSubtitleDataGeneration++; 889 } 890 if (mTimedTextTrack.mSource != NULL) { 891 mTimedTextTrack.mPackets->clear(); 892 mFetchTimedTextDataGeneration++; 893 } 894 return result; 895 } 896 897 int64_t timeUs; 898 status_t eosResult; // ignored 899 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); 900 if (audio) { 901 mAudioLastDequeueTimeUs = timeUs; 902 } else { 903 mVideoLastDequeueTimeUs = timeUs; 904 } 905 906 if (mSubtitleTrack.mSource != NULL 907 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { 908 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id()); 909 msg->setInt64("timeUs", timeUs); 910 msg->setInt32("generation", mFetchSubtitleDataGeneration); 911 msg->post(); 912 } 913 914 if (mTimedTextTrack.mSource != NULL 915 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) { 916 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id()); 917 msg->setInt64("timeUs", timeUs); 918 msg->setInt32("generation", mFetchTimedTextDataGeneration); 919 msg->post(); 920 } 921 922 return result; 923} 924 925status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) { 926 *durationUs = mDurationUs; 927 return OK; 928} 929 930size_t NuPlayer::GenericSource::getTrackCount() const { 931 return mSources.size(); 932} 933 934sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const { 935 size_t trackCount = mSources.size(); 936 if (trackIndex >= trackCount) { 937 return NULL; 938 } 939 940 sp<AMessage> format = new AMessage(); 941 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat(); 942 943 const char *mime; 944 CHECK(meta->findCString(kKeyMIMEType, &mime)); 945 946 int32_t trackType; 947 if (!strncasecmp(mime, "video/", 6)) { 948 trackType = MEDIA_TRACK_TYPE_VIDEO; 949 } else if (!strncasecmp(mime, "audio/", 6)) { 950 trackType = MEDIA_TRACK_TYPE_AUDIO; 951 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { 952 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT; 953 } else { 954 trackType = MEDIA_TRACK_TYPE_UNKNOWN; 955 } 956 format->setInt32("type", trackType); 957 958 const char *lang; 959 if (!meta->findCString(kKeyMediaLanguage, &lang)) { 960 lang = "und"; 961 } 962 format->setString("language", lang); 963 964 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 965 format->setString("mime", mime); 966 967 int32_t isAutoselect = 1, isDefault = 0, isForced = 0; 968 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect); 969 meta->findInt32(kKeyTrackIsDefault, &isDefault); 970 meta->findInt32(kKeyTrackIsForced, &isForced); 971 972 format->setInt32("auto", !!isAutoselect); 973 format->setInt32("default", !!isDefault); 974 format->setInt32("forced", !!isForced); 975 } 976 977 return format; 978} 979 980ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const { 981 sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id()); 982 msg->setInt32("type", type); 983 984 sp<AMessage> response; 985 int32_t index; 986 status_t err = msg->postAndAwaitResponse(&response); 987 if (err == OK && response != NULL) { 988 CHECK(response->findInt32("index", &index)); 989 return index; 990 } else { 991 return -1; 992 } 993} 994 995void NuPlayer::GenericSource::onGetSelectedTrack(sp<AMessage> msg) const { 996 int32_t tmpType; 997 CHECK(msg->findInt32("type", &tmpType)); 998 media_track_type type = (media_track_type)tmpType; 999 1000 sp<AMessage> response = new AMessage; 1001 ssize_t index = doGetSelectedTrack(type); 1002 response->setInt32("index", index); 1003 1004 uint32_t replyID; 1005 CHECK(msg->senderAwaitsResponse(&replyID)); 1006 response->postReply(replyID); 1007} 1008 1009ssize_t NuPlayer::GenericSource::doGetSelectedTrack(media_track_type type) const { 1010 const Track *track = NULL; 1011 switch (type) { 1012 case MEDIA_TRACK_TYPE_VIDEO: 1013 track = &mVideoTrack; 1014 break; 1015 case MEDIA_TRACK_TYPE_AUDIO: 1016 track = &mAudioTrack; 1017 break; 1018 case MEDIA_TRACK_TYPE_TIMEDTEXT: 1019 track = &mTimedTextTrack; 1020 break; 1021 case MEDIA_TRACK_TYPE_SUBTITLE: 1022 track = &mSubtitleTrack; 1023 break; 1024 default: 1025 break; 1026 } 1027 1028 if (track != NULL && track->mSource != NULL) { 1029 return track->mIndex; 1030 } 1031 1032 return -1; 1033} 1034 1035status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select, int64_t timeUs) { 1036 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex); 1037 sp<AMessage> msg = new AMessage(kWhatSelectTrack, id()); 1038 msg->setInt32("trackIndex", trackIndex); 1039 msg->setInt32("select", select); 1040 msg->setInt64("timeUs", timeUs); 1041 1042 sp<AMessage> response; 1043 status_t err = msg->postAndAwaitResponse(&response); 1044 if (err == OK && response != NULL) { 1045 CHECK(response->findInt32("err", &err)); 1046 } 1047 1048 return err; 1049} 1050 1051void NuPlayer::GenericSource::onSelectTrack(sp<AMessage> msg) { 1052 int32_t trackIndex, select; 1053 int64_t timeUs; 1054 CHECK(msg->findInt32("trackIndex", &trackIndex)); 1055 CHECK(msg->findInt32("select", &select)); 1056 CHECK(msg->findInt64("timeUs", &timeUs)); 1057 1058 sp<AMessage> response = new AMessage; 1059 status_t err = doSelectTrack(trackIndex, select, timeUs); 1060 response->setInt32("err", err); 1061 1062 uint32_t replyID; 1063 CHECK(msg->senderAwaitsResponse(&replyID)); 1064 response->postReply(replyID); 1065} 1066 1067status_t NuPlayer::GenericSource::doSelectTrack(size_t trackIndex, bool select, int64_t timeUs) { 1068 if (trackIndex >= mSources.size()) { 1069 return BAD_INDEX; 1070 } 1071 1072 if (!select) { 1073 Track* track = NULL; 1074 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) { 1075 track = &mSubtitleTrack; 1076 mFetchSubtitleDataGeneration++; 1077 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) { 1078 track = &mTimedTextTrack; 1079 mFetchTimedTextDataGeneration++; 1080 } 1081 if (track == NULL) { 1082 return INVALID_OPERATION; 1083 } 1084 track->mSource->stop(); 1085 track->mSource = NULL; 1086 track->mPackets->clear(); 1087 return OK; 1088 } 1089 1090 const sp<MediaSource> source = mSources.itemAt(trackIndex); 1091 sp<MetaData> meta = source->getFormat(); 1092 const char *mime; 1093 CHECK(meta->findCString(kKeyMIMEType, &mime)); 1094 if (!strncasecmp(mime, "text/", 5)) { 1095 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP); 1096 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack; 1097 if (track->mSource != NULL && track->mIndex == trackIndex) { 1098 return OK; 1099 } 1100 track->mIndex = trackIndex; 1101 if (track->mSource != NULL) { 1102 track->mSource->stop(); 1103 } 1104 track->mSource = mSources.itemAt(trackIndex); 1105 track->mSource->start(); 1106 if (track->mPackets == NULL) { 1107 track->mPackets = new AnotherPacketSource(track->mSource->getFormat()); 1108 } else { 1109 track->mPackets->clear(); 1110 track->mPackets->setFormat(track->mSource->getFormat()); 1111 1112 } 1113 1114 if (isSubtitle) { 1115 mFetchSubtitleDataGeneration++; 1116 } else { 1117 mFetchTimedTextDataGeneration++; 1118 } 1119 1120 status_t eosResult; // ignored 1121 if (mSubtitleTrack.mSource != NULL 1122 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { 1123 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id()); 1124 msg->setInt64("timeUs", timeUs); 1125 msg->setInt32("generation", mFetchSubtitleDataGeneration); 1126 msg->post(); 1127 } 1128 1129 if (mTimedTextTrack.mSource != NULL 1130 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) { 1131 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id()); 1132 msg->setInt64("timeUs", timeUs); 1133 msg->setInt32("generation", mFetchTimedTextDataGeneration); 1134 msg->post(); 1135 } 1136 1137 return OK; 1138 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) { 1139 bool audio = !strncasecmp(mime, "audio/", 6); 1140 Track *track = audio ? &mAudioTrack : &mVideoTrack; 1141 if (track->mSource != NULL && track->mIndex == trackIndex) { 1142 return OK; 1143 } 1144 1145 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id()); 1146 msg->setInt32("trackIndex", trackIndex); 1147 msg->post(); 1148 return OK; 1149 } 1150 1151 return INVALID_OPERATION; 1152} 1153 1154status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) { 1155 sp<AMessage> msg = new AMessage(kWhatSeek, id()); 1156 msg->setInt64("seekTimeUs", seekTimeUs); 1157 1158 sp<AMessage> response; 1159 status_t err = msg->postAndAwaitResponse(&response); 1160 if (err == OK && response != NULL) { 1161 CHECK(response->findInt32("err", &err)); 1162 } 1163 1164 return err; 1165} 1166 1167void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) { 1168 int64_t seekTimeUs; 1169 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs)); 1170 1171 sp<AMessage> response = new AMessage; 1172 status_t err = doSeek(seekTimeUs); 1173 response->setInt32("err", err); 1174 1175 uint32_t replyID; 1176 CHECK(msg->senderAwaitsResponse(&replyID)); 1177 response->postReply(replyID); 1178} 1179 1180status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) { 1181 // If the Widevine source is stopped, do not attempt to read any 1182 // more buffers. 1183 if (mStopRead) { 1184 return INVALID_OPERATION; 1185 } 1186 if (mVideoTrack.mSource != NULL) { 1187 int64_t actualTimeUs; 1188 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs); 1189 1190 seekTimeUs = actualTimeUs; 1191 mVideoLastDequeueTimeUs = seekTimeUs; 1192 } 1193 1194 if (mAudioTrack.mSource != NULL) { 1195 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs); 1196 mAudioLastDequeueTimeUs = seekTimeUs; 1197 } 1198 1199 setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000); 1200 if (!mStarted) { 1201 setDrmPlaybackStatusIfNeeded(Playback::PAUSE, 0); 1202 } 1203 return OK; 1204} 1205 1206sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer( 1207 MediaBuffer* mb, 1208 media_track_type trackType, 1209 int64_t /* seekTimeUs */, 1210 int64_t *actualTimeUs) { 1211 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO; 1212 size_t outLength = mb->range_length(); 1213 1214 if (audio && mAudioIsVorbis) { 1215 outLength += sizeof(int32_t); 1216 } 1217 1218 sp<ABuffer> ab; 1219 if (mIsSecure && !audio) { 1220 // data is already provided in the buffer 1221 ab = new ABuffer(NULL, mb->range_length()); 1222 mb->add_ref(); 1223 ab->setMediaBufferBase(mb); 1224 } else { 1225 ab = new ABuffer(outLength); 1226 memcpy(ab->data(), 1227 (const uint8_t *)mb->data() + mb->range_offset(), 1228 mb->range_length()); 1229 } 1230 1231 if (audio && mAudioIsVorbis) { 1232 int32_t numPageSamples; 1233 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) { 1234 numPageSamples = -1; 1235 } 1236 1237 uint8_t* abEnd = ab->data() + mb->range_length(); 1238 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples)); 1239 } 1240 1241 sp<AMessage> meta = ab->meta(); 1242 1243 int64_t timeUs; 1244 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs)); 1245 meta->setInt64("timeUs", timeUs); 1246 1247#if 0 1248 // Temporarily disable pre-roll till we have a full solution to handle 1249 // both single seek and continous seek gracefully. 1250 if (seekTimeUs > timeUs) { 1251 sp<AMessage> extra = new AMessage; 1252 extra->setInt64("resume-at-mediaTimeUs", seekTimeUs); 1253 meta->setMessage("extra", extra); 1254 } 1255#endif 1256 1257 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) { 1258 const char *mime; 1259 CHECK(mTimedTextTrack.mSource != NULL 1260 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime)); 1261 meta->setString("mime", mime); 1262 } 1263 1264 int64_t durationUs; 1265 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) { 1266 meta->setInt64("durationUs", durationUs); 1267 } 1268 1269 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 1270 meta->setInt32("trackIndex", mSubtitleTrack.mIndex); 1271 } 1272 1273 if (actualTimeUs) { 1274 *actualTimeUs = timeUs; 1275 } 1276 1277 mb->release(); 1278 mb = NULL; 1279 1280 return ab; 1281} 1282 1283void NuPlayer::GenericSource::postReadBuffer(media_track_type trackType) { 1284 Mutex::Autolock _l(mReadBufferLock); 1285 1286 if ((mPendingReadBufferTypes & (1 << trackType)) == 0) { 1287 mPendingReadBufferTypes |= (1 << trackType); 1288 sp<AMessage> msg = new AMessage(kWhatReadBuffer, id()); 1289 msg->setInt32("trackType", trackType); 1290 msg->post(); 1291 } 1292} 1293 1294void NuPlayer::GenericSource::onReadBuffer(sp<AMessage> msg) { 1295 int32_t tmpType; 1296 CHECK(msg->findInt32("trackType", &tmpType)); 1297 media_track_type trackType = (media_track_type)tmpType; 1298 readBuffer(trackType); 1299 { 1300 // only protect the variable change, as readBuffer may 1301 // take considerable time. 1302 Mutex::Autolock _l(mReadBufferLock); 1303 mPendingReadBufferTypes &= ~(1 << trackType); 1304 } 1305} 1306 1307void NuPlayer::GenericSource::readBuffer( 1308 media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) { 1309 // Do not read data if Widevine source is stopped 1310 if (mStopRead) { 1311 return; 1312 } 1313 Track *track; 1314 size_t maxBuffers = 1; 1315 switch (trackType) { 1316 case MEDIA_TRACK_TYPE_VIDEO: 1317 track = &mVideoTrack; 1318 if (mIsWidevine) { 1319 maxBuffers = 2; 1320 } 1321 break; 1322 case MEDIA_TRACK_TYPE_AUDIO: 1323 track = &mAudioTrack; 1324 if (mIsWidevine) { 1325 maxBuffers = 8; 1326 } else { 1327 maxBuffers = 64; 1328 } 1329 break; 1330 case MEDIA_TRACK_TYPE_SUBTITLE: 1331 track = &mSubtitleTrack; 1332 break; 1333 case MEDIA_TRACK_TYPE_TIMEDTEXT: 1334 track = &mTimedTextTrack; 1335 break; 1336 default: 1337 TRESPASS(); 1338 } 1339 1340 if (track->mSource == NULL) { 1341 return; 1342 } 1343 1344 if (actualTimeUs) { 1345 *actualTimeUs = seekTimeUs; 1346 } 1347 1348 MediaSource::ReadOptions options; 1349 1350 bool seeking = false; 1351 1352 if (seekTimeUs >= 0) { 1353 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 1354 seeking = true; 1355 } 1356 1357 if (mIsWidevine) { 1358 options.setNonBlocking(); 1359 } 1360 1361 for (size_t numBuffers = 0; numBuffers < maxBuffers; ) { 1362 MediaBuffer *mbuf; 1363 status_t err = track->mSource->read(&mbuf, &options); 1364 1365 options.clearSeekTo(); 1366 1367 if (err == OK) { 1368 int64_t timeUs; 1369 CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); 1370 if (trackType == MEDIA_TRACK_TYPE_AUDIO) { 1371 mAudioTimeUs = timeUs; 1372 } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) { 1373 mVideoTimeUs = timeUs; 1374 } 1375 1376 // formatChange && seeking: track whose source is changed during selection 1377 // formatChange && !seeking: track whose source is not changed during selection 1378 // !formatChange: normal seek 1379 if ((seeking || formatChange) 1380 && (trackType == MEDIA_TRACK_TYPE_AUDIO 1381 || trackType == MEDIA_TRACK_TYPE_VIDEO)) { 1382 ATSParser::DiscontinuityType type = (formatChange && seeking) 1383 ? ATSParser::DISCONTINUITY_FORMATCHANGE 1384 : ATSParser::DISCONTINUITY_NONE; 1385 track->mPackets->queueDiscontinuity( type, NULL, true /* discard */); 1386 } 1387 1388 sp<ABuffer> buffer = mediaBufferToABuffer( 1389 mbuf, trackType, seekTimeUs, actualTimeUs); 1390 track->mPackets->queueAccessUnit(buffer); 1391 formatChange = false; 1392 seeking = false; 1393 ++numBuffers; 1394 } else if (err == WOULD_BLOCK) { 1395 break; 1396 } else if (err == INFO_FORMAT_CHANGED) { 1397#if 0 1398 track->mPackets->queueDiscontinuity( 1399 ATSParser::DISCONTINUITY_FORMATCHANGE, 1400 NULL, 1401 false /* discard */); 1402#endif 1403 } else { 1404 track->mPackets->signalEOS(err); 1405 break; 1406 } 1407 } 1408} 1409 1410} // namespace android 1411