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