GenericSource.cpp revision 7e892180f3992c088dc0d44f0b0e54ace4dabe3c
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/stagefright/foundation/ABuffer.h> 25#include <media/stagefright/foundation/ADebug.h> 26#include <media/stagefright/foundation/AMessage.h> 27#include <media/stagefright/DataSource.h> 28#include <media/stagefright/FileSource.h> 29#include <media/stagefright/MediaBuffer.h> 30#include <media/stagefright/MediaDefs.h> 31#include <media/stagefright/MediaExtractor.h> 32#include <media/stagefright/MediaSource.h> 33#include <media/stagefright/MetaData.h> 34#include "../../libstagefright/include/WVMExtractor.h" 35 36namespace android { 37 38NuPlayer::GenericSource::GenericSource( 39 const sp<AMessage> ¬ify, 40 const sp<IMediaHTTPService> &httpService, 41 const char *url, 42 const KeyedVector<String8, String8> *headers, 43 bool isWidevine, 44 bool uidValid, 45 uid_t uid) 46 : Source(notify), 47 mFetchSubtitleDataGeneration(0), 48 mFetchTimedTextDataGeneration(0), 49 mDurationUs(0ll), 50 mAudioIsVorbis(false), 51 mIsWidevine(isWidevine), 52 mUIDValid(uidValid), 53 mUID(uid) { 54 DataSource::RegisterDefaultSniffers(); 55 56 sp<DataSource> dataSource = 57 DataSource::CreateFromURI(httpService, url, headers); 58 CHECK(dataSource != NULL); 59 60 initFromDataSource(dataSource); 61} 62 63NuPlayer::GenericSource::GenericSource( 64 const sp<AMessage> ¬ify, 65 int fd, int64_t offset, int64_t length) 66 : Source(notify), 67 mFetchSubtitleDataGeneration(0), 68 mFetchTimedTextDataGeneration(0), 69 mDurationUs(0ll), 70 mAudioIsVorbis(false), 71 mIsWidevine(false), 72 mUIDValid(false), 73 mUID(0) { 74 DataSource::RegisterDefaultSniffers(); 75 76 sp<DataSource> dataSource = new FileSource(dup(fd), offset, length); 77 78 initFromDataSource(dataSource); 79} 80 81void NuPlayer::GenericSource::initFromDataSource( 82 const sp<DataSource> &dataSource) { 83 sp<MediaExtractor> extractor; 84 85 if (mIsWidevine) { 86 String8 mimeType; 87 float confidence; 88 sp<AMessage> dummy; 89 bool success; 90 91 success = SniffWVM(dataSource, &mimeType, &confidence, &dummy); 92 if (!success 93 || strcasecmp( 94 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) { 95 ALOGE("unsupported widevine mime: %s", mimeType.string()); 96 return; 97 } 98 99 sp<WVMExtractor> wvmExtractor = new WVMExtractor(dataSource); 100 wvmExtractor->setAdaptiveStreamingMode(true); 101 if (mUIDValid) { 102 wvmExtractor->setUID(mUID); 103 } 104 extractor = wvmExtractor; 105 } else { 106 extractor = MediaExtractor::Create(dataSource); 107 } 108 109 CHECK(extractor != NULL); 110 111 sp<MetaData> fileMeta = extractor->getMetaData(); 112 if (fileMeta != NULL) { 113 int64_t duration; 114 if (fileMeta->findInt64(kKeyDuration, &duration)) { 115 mDurationUs = duration; 116 } 117 } 118 119 for (size_t i = 0; i < extractor->countTracks(); ++i) { 120 sp<MetaData> meta = extractor->getTrackMetaData(i); 121 122 const char *mime; 123 CHECK(meta->findCString(kKeyMIMEType, &mime)); 124 125 sp<MediaSource> track = extractor->getTrack(i); 126 127 if (!strncasecmp(mime, "audio/", 6)) { 128 if (mAudioTrack.mSource == NULL) { 129 mAudioTrack.mIndex = i; 130 mAudioTrack.mSource = track; 131 132 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { 133 mAudioIsVorbis = true; 134 } else { 135 mAudioIsVorbis = false; 136 } 137 } 138 } else if (!strncasecmp(mime, "video/", 6)) { 139 if (mVideoTrack.mSource == NULL) { 140 mVideoTrack.mIndex = i; 141 mVideoTrack.mSource = track; 142 143 // check if the source requires secure buffers 144 int32_t secure; 145 if (meta->findInt32(kKeyRequiresSecureBuffers, &secure) && secure) { 146 mIsWidevine = true; 147 } 148 } 149 } 150 151 if (track != NULL) { 152 mSources.push(track); 153 int64_t durationUs; 154 if (meta->findInt64(kKeyDuration, &durationUs)) { 155 if (durationUs > mDurationUs) { 156 mDurationUs = durationUs; 157 } 158 } 159 } 160 } 161} 162 163status_t NuPlayer::GenericSource::setBuffers(bool audio, Vector<MediaBuffer *> &buffers) { 164 if (mIsWidevine && !audio) { 165 return mVideoTrack.mSource->setBuffers(buffers); 166 } 167 return INVALID_OPERATION; 168} 169 170NuPlayer::GenericSource::~GenericSource() { 171} 172 173void NuPlayer::GenericSource::prepareAsync() { 174 if (mVideoTrack.mSource != NULL) { 175 sp<MetaData> meta = mVideoTrack.mSource->getFormat(); 176 177 int32_t width, height; 178 CHECK(meta->findInt32(kKeyWidth, &width)); 179 CHECK(meta->findInt32(kKeyHeight, &height)); 180 181 notifyVideoSizeChanged(width, height); 182 } 183 184 notifyFlagsChanged( 185 (mIsWidevine ? FLAG_SECURE : 0) 186 | FLAG_CAN_PAUSE 187 | FLAG_CAN_SEEK_BACKWARD 188 | FLAG_CAN_SEEK_FORWARD 189 | FLAG_CAN_SEEK); 190 191 notifyPrepared(); 192} 193 194void NuPlayer::GenericSource::start() { 195 ALOGI("start"); 196 197 if (mAudioTrack.mSource != NULL) { 198 CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK); 199 mAudioTrack.mPackets = 200 new AnotherPacketSource(mAudioTrack.mSource->getFormat()); 201 202 readBuffer(MEDIA_TRACK_TYPE_AUDIO); 203 } 204 205 if (mVideoTrack.mSource != NULL) { 206 CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK); 207 mVideoTrack.mPackets = 208 new AnotherPacketSource(mVideoTrack.mSource->getFormat()); 209 210 readBuffer(MEDIA_TRACK_TYPE_VIDEO); 211 } 212} 213 214status_t NuPlayer::GenericSource::feedMoreTSData() { 215 return OK; 216} 217 218void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) { 219 switch (msg->what()) { 220 case kWhatFetchSubtitleData: 221 { 222 fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, 223 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); 224 break; 225 } 226 227 case kWhatFetchTimedTextData: 228 { 229 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, 230 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); 231 break; 232 } 233 234 case kWhatSendSubtitleData: 235 { 236 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, 237 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); 238 break; 239 } 240 241 case kWhatSendTimedTextData: 242 { 243 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, 244 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); 245 break; 246 } 247 248 case kWhatChangeAVSource: 249 { 250 int32_t trackIndex; 251 CHECK(msg->findInt32("trackIndex", &trackIndex)); 252 const sp<MediaSource> source = mSources.itemAt(trackIndex); 253 254 Track* track; 255 const char *mime; 256 media_track_type trackType, counterpartType; 257 sp<MetaData> meta = source->getFormat(); 258 meta->findCString(kKeyMIMEType, &mime); 259 if (!strncasecmp(mime, "audio/", 6)) { 260 track = &mAudioTrack; 261 trackType = MEDIA_TRACK_TYPE_AUDIO; 262 counterpartType = MEDIA_TRACK_TYPE_VIDEO;; 263 } else { 264 CHECK(!strncasecmp(mime, "video/", 6)); 265 track = &mVideoTrack; 266 trackType = MEDIA_TRACK_TYPE_VIDEO; 267 counterpartType = MEDIA_TRACK_TYPE_AUDIO;; 268 } 269 270 271 if (track->mSource != NULL) { 272 track->mSource->stop(); 273 } 274 track->mSource = source; 275 track->mSource->start(); 276 track->mIndex = trackIndex; 277 278 status_t avail; 279 if (!track->mPackets->hasBufferAvailable(&avail)) { 280 // sync from other source 281 TRESPASS(); 282 break; 283 } 284 285 int64_t timeUs, actualTimeUs; 286 const bool formatChange = true; 287 sp<AMessage> latestMeta = track->mPackets->getLatestMeta(); 288 CHECK(latestMeta != NULL && latestMeta->findInt64("timeUs", &timeUs)); 289 readBuffer(trackType, timeUs, &actualTimeUs, formatChange); 290 readBuffer(counterpartType, -1, NULL, formatChange); 291 ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs); 292 293 break; 294 } 295 296 default: 297 Source::onMessageReceived(msg); 298 break; 299 } 300} 301 302void NuPlayer::GenericSource::fetchTextData( 303 uint32_t sendWhat, 304 media_track_type type, 305 int32_t curGen, 306 sp<AnotherPacketSource> packets, 307 sp<AMessage> msg) { 308 int32_t msgGeneration; 309 CHECK(msg->findInt32("generation", &msgGeneration)); 310 if (msgGeneration != curGen) { 311 // stale 312 return; 313 } 314 315 int32_t avail; 316 if (packets->hasBufferAvailable(&avail)) { 317 return; 318 } 319 320 int64_t timeUs; 321 CHECK(msg->findInt64("timeUs", &timeUs)); 322 323 int64_t subTimeUs; 324 readBuffer(type, timeUs, &subTimeUs); 325 326 int64_t delayUs = subTimeUs - timeUs; 327 if (msg->what() == kWhatFetchSubtitleData) { 328 const int64_t oneSecUs = 1000000ll; 329 delayUs -= oneSecUs; 330 } 331 sp<AMessage> msg2 = new AMessage(sendWhat, id()); 332 msg2->setInt32("generation", msgGeneration); 333 msg2->post(delayUs < 0 ? 0 : delayUs); 334} 335 336void NuPlayer::GenericSource::sendTextData( 337 uint32_t what, 338 media_track_type type, 339 int32_t curGen, 340 sp<AnotherPacketSource> packets, 341 sp<AMessage> msg) { 342 int32_t msgGeneration; 343 CHECK(msg->findInt32("generation", &msgGeneration)); 344 if (msgGeneration != curGen) { 345 // stale 346 return; 347 } 348 349 int64_t subTimeUs; 350 if (packets->nextBufferTime(&subTimeUs) != OK) { 351 return; 352 } 353 354 int64_t nextSubTimeUs; 355 readBuffer(type, -1, &nextSubTimeUs); 356 357 sp<ABuffer> buffer; 358 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer); 359 if (dequeueStatus == OK) { 360 sp<AMessage> notify = dupNotify(); 361 notify->setInt32("what", what); 362 notify->setBuffer("buffer", buffer); 363 notify->post(); 364 365 const int64_t delayUs = nextSubTimeUs - subTimeUs; 366 msg->post(delayUs < 0 ? 0 : delayUs); 367 } 368} 369 370sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) { 371 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource; 372 373 if (source == NULL) { 374 return NULL; 375 } 376 377 return source->getFormat(); 378} 379 380status_t NuPlayer::GenericSource::dequeueAccessUnit( 381 bool audio, sp<ABuffer> *accessUnit) { 382 Track *track = audio ? &mAudioTrack : &mVideoTrack; 383 384 if (track->mSource == NULL) { 385 return -EWOULDBLOCK; 386 } 387 388 if (mIsWidevine && !audio) { 389 // try to read a buffer as we may not have been able to the last time 390 readBuffer(MEDIA_TRACK_TYPE_VIDEO, -1ll); 391 } 392 393 status_t finalResult; 394 if (!track->mPackets->hasBufferAvailable(&finalResult)) { 395 return (finalResult == OK ? -EWOULDBLOCK : finalResult); 396 } 397 398 status_t result = track->mPackets->dequeueAccessUnit(accessUnit); 399 400 if (!track->mPackets->hasBufferAvailable(&finalResult)) { 401 readBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO, -1ll); 402 } 403 404 if (mSubtitleTrack.mSource == NULL && mTimedTextTrack.mSource == NULL) { 405 return result; 406 } 407 408 if (mSubtitleTrack.mSource != NULL) { 409 CHECK(mSubtitleTrack.mPackets != NULL); 410 } 411 if (mTimedTextTrack.mSource != NULL) { 412 CHECK(mTimedTextTrack.mPackets != NULL); 413 } 414 415 if (result != OK) { 416 if (mSubtitleTrack.mSource != NULL) { 417 mSubtitleTrack.mPackets->clear(); 418 mFetchSubtitleDataGeneration++; 419 } 420 if (mTimedTextTrack.mSource != NULL) { 421 mTimedTextTrack.mPackets->clear(); 422 mFetchTimedTextDataGeneration++; 423 } 424 return result; 425 } 426 427 int64_t timeUs; 428 status_t eosResult; // ignored 429 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); 430 431 if (mSubtitleTrack.mSource != NULL 432 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { 433 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id()); 434 msg->setInt64("timeUs", timeUs); 435 msg->setInt32("generation", mFetchSubtitleDataGeneration); 436 msg->post(); 437 } 438 439 if (mTimedTextTrack.mSource != NULL 440 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) { 441 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id()); 442 msg->setInt64("timeUs", timeUs); 443 msg->setInt32("generation", mFetchTimedTextDataGeneration); 444 msg->post(); 445 } 446 447 return result; 448} 449 450status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) { 451 *durationUs = mDurationUs; 452 return OK; 453} 454 455size_t NuPlayer::GenericSource::getTrackCount() const { 456 return mSources.size(); 457} 458 459sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const { 460 size_t trackCount = mSources.size(); 461 if (trackIndex >= trackCount) { 462 return NULL; 463 } 464 465 sp<AMessage> format = new AMessage(); 466 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat(); 467 468 const char *mime; 469 CHECK(meta->findCString(kKeyMIMEType, &mime)); 470 471 int32_t trackType; 472 if (!strncasecmp(mime, "video/", 6)) { 473 trackType = MEDIA_TRACK_TYPE_VIDEO; 474 } else if (!strncasecmp(mime, "audio/", 6)) { 475 trackType = MEDIA_TRACK_TYPE_AUDIO; 476 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { 477 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT; 478 } else { 479 trackType = MEDIA_TRACK_TYPE_UNKNOWN; 480 } 481 format->setInt32("type", trackType); 482 483 const char *lang; 484 if (!meta->findCString(kKeyMediaLanguage, &lang)) { 485 lang = "und"; 486 } 487 format->setString("language", lang); 488 489 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 490 format->setString("mime", mime); 491 492 int32_t isAutoselect = 1, isDefault = 0, isForced = 0; 493 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect); 494 meta->findInt32(kKeyTrackIsDefault, &isDefault); 495 meta->findInt32(kKeyTrackIsForced, &isForced); 496 497 format->setInt32("auto", !!isAutoselect); 498 format->setInt32("default", !!isDefault); 499 format->setInt32("forced", !!isForced); 500 } 501 502 return format; 503} 504 505ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const { 506 const Track *track = NULL; 507 switch (type) { 508 case MEDIA_TRACK_TYPE_VIDEO: 509 track = &mVideoTrack; 510 break; 511 case MEDIA_TRACK_TYPE_AUDIO: 512 track = &mAudioTrack; 513 break; 514 case MEDIA_TRACK_TYPE_TIMEDTEXT: 515 track = &mTimedTextTrack; 516 break; 517 case MEDIA_TRACK_TYPE_SUBTITLE: 518 track = &mSubtitleTrack; 519 break; 520 default: 521 break; 522 } 523 524 if (track != NULL && track->mSource != NULL) { 525 return track->mIndex; 526 } 527 528 return -1; 529} 530 531status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { 532 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex); 533 if (trackIndex >= mSources.size()) { 534 return BAD_INDEX; 535 } 536 537 if (!select) { 538 Track* track = NULL; 539 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) { 540 track = &mSubtitleTrack; 541 mFetchSubtitleDataGeneration++; 542 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) { 543 track = &mTimedTextTrack; 544 mFetchTimedTextDataGeneration++; 545 } 546 if (track == NULL) { 547 return INVALID_OPERATION; 548 } 549 track->mSource->stop(); 550 track->mSource = NULL; 551 track->mPackets->clear(); 552 return OK; 553 } 554 555 const sp<MediaSource> source = mSources.itemAt(trackIndex); 556 sp<MetaData> meta = source->getFormat(); 557 const char *mime; 558 CHECK(meta->findCString(kKeyMIMEType, &mime)); 559 if (!strncasecmp(mime, "text/", 5)) { 560 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP); 561 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack; 562 if (track->mSource != NULL && track->mIndex == trackIndex) { 563 return OK; 564 } 565 track->mIndex = trackIndex; 566 if (track->mSource != NULL) { 567 track->mSource->stop(); 568 } 569 track->mSource = mSources.itemAt(trackIndex); 570 track->mSource->start(); 571 if (track->mPackets == NULL) { 572 track->mPackets = new AnotherPacketSource(track->mSource->getFormat()); 573 } else { 574 track->mPackets->clear(); 575 track->mPackets->setFormat(track->mSource->getFormat()); 576 577 } 578 579 if (isSubtitle) { 580 mFetchSubtitleDataGeneration++; 581 } else { 582 mFetchTimedTextDataGeneration++; 583 } 584 585 return OK; 586 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) { 587 bool audio = !strncasecmp(mime, "audio/", 6); 588 Track *track = audio ? &mAudioTrack : &mVideoTrack; 589 if (track->mSource != NULL && track->mIndex == trackIndex) { 590 return OK; 591 } 592 593 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id()); 594 msg->setInt32("trackIndex", trackIndex); 595 msg->post(); 596 return OK; 597 } 598 599 return INVALID_OPERATION; 600} 601 602status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) { 603 if (mVideoTrack.mSource != NULL) { 604 int64_t actualTimeUs; 605 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs); 606 607 seekTimeUs = actualTimeUs; 608 } 609 610 if (mAudioTrack.mSource != NULL) { 611 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs); 612 } 613 614 return OK; 615} 616 617sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer( 618 MediaBuffer* mb, 619 media_track_type trackType, 620 int64_t *actualTimeUs) { 621 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO; 622 size_t outLength = mb->range_length(); 623 624 if (audio && mAudioIsVorbis) { 625 outLength += sizeof(int32_t); 626 } 627 628 sp<ABuffer> ab; 629 if (mIsWidevine && !audio) { 630 // data is already provided in the buffer 631 ab = new ABuffer(NULL, mb->range_length()); 632 ab->meta()->setPointer("mediaBuffer", mb); 633 mb->add_ref(); 634 } else { 635 ab = new ABuffer(outLength); 636 memcpy(ab->data(), 637 (const uint8_t *)mb->data() + mb->range_offset(), 638 mb->range_length()); 639 } 640 641 if (audio && mAudioIsVorbis) { 642 int32_t numPageSamples; 643 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) { 644 numPageSamples = -1; 645 } 646 647 uint8_t* abEnd = ab->data() + mb->range_length(); 648 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples)); 649 } 650 651 sp<AMessage> meta = ab->meta(); 652 653 int64_t timeUs; 654 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs)); 655 meta->setInt64("timeUs", timeUs); 656 657 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) { 658 const char *mime; 659 CHECK(mTimedTextTrack.mSource != NULL 660 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime)); 661 meta->setString("mime", mime); 662 } 663 664 int64_t durationUs; 665 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) { 666 meta->setInt64("durationUs", durationUs); 667 } 668 669 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 670 meta->setInt32("trackIndex", mSubtitleTrack.mIndex); 671 } 672 673 if (actualTimeUs) { 674 *actualTimeUs = timeUs; 675 } 676 677 mb->release(); 678 mb = NULL; 679 680 return ab; 681} 682 683void NuPlayer::GenericSource::readBuffer( 684 media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) { 685 Track *track; 686 switch (trackType) { 687 case MEDIA_TRACK_TYPE_VIDEO: 688 track = &mVideoTrack; 689 break; 690 case MEDIA_TRACK_TYPE_AUDIO: 691 track = &mAudioTrack; 692 break; 693 case MEDIA_TRACK_TYPE_SUBTITLE: 694 track = &mSubtitleTrack; 695 break; 696 case MEDIA_TRACK_TYPE_TIMEDTEXT: 697 track = &mTimedTextTrack; 698 break; 699 default: 700 TRESPASS(); 701 } 702 703 if (track->mSource == NULL) { 704 return; 705 } 706 707 if (actualTimeUs) { 708 *actualTimeUs = seekTimeUs; 709 } 710 711 MediaSource::ReadOptions options; 712 713 bool seeking = false; 714 715 if (seekTimeUs >= 0) { 716 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 717 seeking = true; 718 } 719 720 if (mIsWidevine && trackType != MEDIA_TRACK_TYPE_AUDIO) { 721 options.setNonBlocking(); 722 } 723 724 for (;;) { 725 MediaBuffer *mbuf; 726 status_t err = track->mSource->read(&mbuf, &options); 727 728 options.clearSeekTo(); 729 730 if (err == OK) { 731 // formatChange && seeking: track whose source is changed during selection 732 // formatChange && !seeking: track whose source is not changed during selection 733 // !formatChange: normal seek 734 if ((seeking || formatChange) 735 && (trackType == MEDIA_TRACK_TYPE_AUDIO 736 || trackType == MEDIA_TRACK_TYPE_VIDEO)) { 737 ATSParser::DiscontinuityType type = formatChange 738 ? (seeking 739 ? ATSParser::DISCONTINUITY_FORMATCHANGE 740 : ATSParser::DISCONTINUITY_NONE) 741 : ATSParser::DISCONTINUITY_SEEK; 742 track->mPackets->queueDiscontinuity( type, NULL, true /* discard */); 743 } 744 745 sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs); 746 track->mPackets->queueAccessUnit(buffer); 747 break; 748 } else if (err == WOULD_BLOCK) { 749 break; 750 } else if (err == INFO_FORMAT_CHANGED) { 751#if 0 752 track->mPackets->queueDiscontinuity( 753 ATSParser::DISCONTINUITY_FORMATCHANGE, 754 NULL, 755 false /* discard */); 756#endif 757 } else { 758 track->mPackets->signalEOS(err); 759 break; 760 } 761 } 762} 763 764} // namespace android 765