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