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