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