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