GenericSource.cpp revision a19f33e4e50cda5d5953fa0cc662502262ac9dfd
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 sp<MetaData> meta = mVideoTrack.mSource->getFormat(); 232 233 int32_t width, height; 234 CHECK(meta->findInt32(kKeyWidth, &width)); 235 CHECK(meta->findInt32(kKeyHeight, &height)); 236 237 notifyVideoSizeChanged(width, height); 238 } 239 240 notifyFlagsChanged( 241 (mIsWidevine ? FLAG_SECURE : 0) 242 | FLAG_CAN_PAUSE 243 | FLAG_CAN_SEEK_BACKWARD 244 | FLAG_CAN_SEEK_FORWARD 245 | FLAG_CAN_SEEK); 246 247 notifyPrepared(); 248} 249 250void NuPlayer::GenericSource::start() { 251 ALOGI("start"); 252 253 if (mAudioTrack.mSource != NULL) { 254 CHECK_EQ(mAudioTrack.mSource->start(), (status_t)OK); 255 mAudioTrack.mPackets = 256 new AnotherPacketSource(mAudioTrack.mSource->getFormat()); 257 258 readBuffer(MEDIA_TRACK_TYPE_AUDIO); 259 } 260 261 if (mVideoTrack.mSource != NULL) { 262 CHECK_EQ(mVideoTrack.mSource->start(), (status_t)OK); 263 mVideoTrack.mPackets = 264 new AnotherPacketSource(mVideoTrack.mSource->getFormat()); 265 266 readBuffer(MEDIA_TRACK_TYPE_VIDEO); 267 } 268} 269 270status_t NuPlayer::GenericSource::feedMoreTSData() { 271 return OK; 272} 273 274void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) { 275 switch (msg->what()) { 276 case kWhatFetchSubtitleData: 277 { 278 fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, 279 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); 280 break; 281 } 282 283 case kWhatFetchTimedTextData: 284 { 285 fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, 286 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); 287 break; 288 } 289 290 case kWhatSendSubtitleData: 291 { 292 sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, 293 mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); 294 break; 295 } 296 297 case kWhatSendTimedTextData: 298 { 299 sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, 300 mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); 301 break; 302 } 303 304 case kWhatChangeAVSource: 305 { 306 int32_t trackIndex; 307 CHECK(msg->findInt32("trackIndex", &trackIndex)); 308 const sp<MediaSource> source = mSources.itemAt(trackIndex); 309 310 Track* track; 311 const char *mime; 312 media_track_type trackType, counterpartType; 313 sp<MetaData> meta = source->getFormat(); 314 meta->findCString(kKeyMIMEType, &mime); 315 if (!strncasecmp(mime, "audio/", 6)) { 316 track = &mAudioTrack; 317 trackType = MEDIA_TRACK_TYPE_AUDIO; 318 counterpartType = MEDIA_TRACK_TYPE_VIDEO;; 319 } else { 320 CHECK(!strncasecmp(mime, "video/", 6)); 321 track = &mVideoTrack; 322 trackType = MEDIA_TRACK_TYPE_VIDEO; 323 counterpartType = MEDIA_TRACK_TYPE_AUDIO;; 324 } 325 326 327 if (track->mSource != NULL) { 328 track->mSource->stop(); 329 } 330 track->mSource = source; 331 track->mSource->start(); 332 track->mIndex = trackIndex; 333 334 status_t avail; 335 if (!track->mPackets->hasBufferAvailable(&avail)) { 336 // sync from other source 337 TRESPASS(); 338 break; 339 } 340 341 int64_t timeUs, actualTimeUs; 342 const bool formatChange = true; 343 sp<AMessage> latestMeta = track->mPackets->getLatestEnqueuedMeta(); 344 CHECK(latestMeta != NULL && latestMeta->findInt64("timeUs", &timeUs)); 345 readBuffer(trackType, timeUs, &actualTimeUs, formatChange); 346 readBuffer(counterpartType, -1, NULL, formatChange); 347 ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs); 348 349 break; 350 } 351 352 default: 353 Source::onMessageReceived(msg); 354 break; 355 } 356} 357 358void NuPlayer::GenericSource::fetchTextData( 359 uint32_t sendWhat, 360 media_track_type type, 361 int32_t curGen, 362 sp<AnotherPacketSource> packets, 363 sp<AMessage> msg) { 364 int32_t msgGeneration; 365 CHECK(msg->findInt32("generation", &msgGeneration)); 366 if (msgGeneration != curGen) { 367 // stale 368 return; 369 } 370 371 int32_t avail; 372 if (packets->hasBufferAvailable(&avail)) { 373 return; 374 } 375 376 int64_t timeUs; 377 CHECK(msg->findInt64("timeUs", &timeUs)); 378 379 int64_t subTimeUs; 380 readBuffer(type, timeUs, &subTimeUs); 381 382 int64_t delayUs = subTimeUs - timeUs; 383 if (msg->what() == kWhatFetchSubtitleData) { 384 const int64_t oneSecUs = 1000000ll; 385 delayUs -= oneSecUs; 386 } 387 sp<AMessage> msg2 = new AMessage(sendWhat, id()); 388 msg2->setInt32("generation", msgGeneration); 389 msg2->post(delayUs < 0 ? 0 : delayUs); 390} 391 392void NuPlayer::GenericSource::sendTextData( 393 uint32_t what, 394 media_track_type type, 395 int32_t curGen, 396 sp<AnotherPacketSource> packets, 397 sp<AMessage> msg) { 398 int32_t msgGeneration; 399 CHECK(msg->findInt32("generation", &msgGeneration)); 400 if (msgGeneration != curGen) { 401 // stale 402 return; 403 } 404 405 int64_t subTimeUs; 406 if (packets->nextBufferTime(&subTimeUs) != OK) { 407 return; 408 } 409 410 int64_t nextSubTimeUs; 411 readBuffer(type, -1, &nextSubTimeUs); 412 413 sp<ABuffer> buffer; 414 status_t dequeueStatus = packets->dequeueAccessUnit(&buffer); 415 if (dequeueStatus == OK) { 416 sp<AMessage> notify = dupNotify(); 417 notify->setInt32("what", what); 418 notify->setBuffer("buffer", buffer); 419 notify->post(); 420 421 const int64_t delayUs = nextSubTimeUs - subTimeUs; 422 msg->post(delayUs < 0 ? 0 : delayUs); 423 } 424} 425 426sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) { 427 sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource; 428 429 if (source == NULL) { 430 return NULL; 431 } 432 433 return source->getFormat(); 434} 435 436status_t NuPlayer::GenericSource::dequeueAccessUnit( 437 bool audio, sp<ABuffer> *accessUnit) { 438 Track *track = audio ? &mAudioTrack : &mVideoTrack; 439 440 if (track->mSource == NULL) { 441 return -EWOULDBLOCK; 442 } 443 444 if (mIsWidevine && !audio) { 445 // try to read a buffer as we may not have been able to the last time 446 readBuffer(MEDIA_TRACK_TYPE_VIDEO, -1ll); 447 } 448 449 status_t finalResult; 450 if (!track->mPackets->hasBufferAvailable(&finalResult)) { 451 return (finalResult == OK ? -EWOULDBLOCK : finalResult); 452 } 453 454 status_t result = track->mPackets->dequeueAccessUnit(accessUnit); 455 456 if (!track->mPackets->hasBufferAvailable(&finalResult)) { 457 readBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO, -1ll); 458 } 459 460 if (mSubtitleTrack.mSource == NULL && mTimedTextTrack.mSource == NULL) { 461 return result; 462 } 463 464 if (mSubtitleTrack.mSource != NULL) { 465 CHECK(mSubtitleTrack.mPackets != NULL); 466 } 467 if (mTimedTextTrack.mSource != NULL) { 468 CHECK(mTimedTextTrack.mPackets != NULL); 469 } 470 471 if (result != OK) { 472 if (mSubtitleTrack.mSource != NULL) { 473 mSubtitleTrack.mPackets->clear(); 474 mFetchSubtitleDataGeneration++; 475 } 476 if (mTimedTextTrack.mSource != NULL) { 477 mTimedTextTrack.mPackets->clear(); 478 mFetchTimedTextDataGeneration++; 479 } 480 return result; 481 } 482 483 int64_t timeUs; 484 status_t eosResult; // ignored 485 CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); 486 487 if (mSubtitleTrack.mSource != NULL 488 && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { 489 sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id()); 490 msg->setInt64("timeUs", timeUs); 491 msg->setInt32("generation", mFetchSubtitleDataGeneration); 492 msg->post(); 493 } 494 495 if (mTimedTextTrack.mSource != NULL 496 && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) { 497 sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id()); 498 msg->setInt64("timeUs", timeUs); 499 msg->setInt32("generation", mFetchTimedTextDataGeneration); 500 msg->post(); 501 } 502 503 return result; 504} 505 506status_t NuPlayer::GenericSource::getDuration(int64_t *durationUs) { 507 *durationUs = mDurationUs; 508 return OK; 509} 510 511size_t NuPlayer::GenericSource::getTrackCount() const { 512 return mSources.size(); 513} 514 515sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const { 516 size_t trackCount = mSources.size(); 517 if (trackIndex >= trackCount) { 518 return NULL; 519 } 520 521 sp<AMessage> format = new AMessage(); 522 sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat(); 523 524 const char *mime; 525 CHECK(meta->findCString(kKeyMIMEType, &mime)); 526 527 int32_t trackType; 528 if (!strncasecmp(mime, "video/", 6)) { 529 trackType = MEDIA_TRACK_TYPE_VIDEO; 530 } else if (!strncasecmp(mime, "audio/", 6)) { 531 trackType = MEDIA_TRACK_TYPE_AUDIO; 532 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { 533 trackType = MEDIA_TRACK_TYPE_TIMEDTEXT; 534 } else { 535 trackType = MEDIA_TRACK_TYPE_UNKNOWN; 536 } 537 format->setInt32("type", trackType); 538 539 const char *lang; 540 if (!meta->findCString(kKeyMediaLanguage, &lang)) { 541 lang = "und"; 542 } 543 format->setString("language", lang); 544 545 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 546 format->setString("mime", mime); 547 548 int32_t isAutoselect = 1, isDefault = 0, isForced = 0; 549 meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect); 550 meta->findInt32(kKeyTrackIsDefault, &isDefault); 551 meta->findInt32(kKeyTrackIsForced, &isForced); 552 553 format->setInt32("auto", !!isAutoselect); 554 format->setInt32("default", !!isDefault); 555 format->setInt32("forced", !!isForced); 556 } 557 558 return format; 559} 560 561ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const { 562 const Track *track = NULL; 563 switch (type) { 564 case MEDIA_TRACK_TYPE_VIDEO: 565 track = &mVideoTrack; 566 break; 567 case MEDIA_TRACK_TYPE_AUDIO: 568 track = &mAudioTrack; 569 break; 570 case MEDIA_TRACK_TYPE_TIMEDTEXT: 571 track = &mTimedTextTrack; 572 break; 573 case MEDIA_TRACK_TYPE_SUBTITLE: 574 track = &mSubtitleTrack; 575 break; 576 default: 577 break; 578 } 579 580 if (track != NULL && track->mSource != NULL) { 581 return track->mIndex; 582 } 583 584 return -1; 585} 586 587status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { 588 ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex); 589 if (trackIndex >= mSources.size()) { 590 return BAD_INDEX; 591 } 592 593 if (!select) { 594 Track* track = NULL; 595 if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) { 596 track = &mSubtitleTrack; 597 mFetchSubtitleDataGeneration++; 598 } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) { 599 track = &mTimedTextTrack; 600 mFetchTimedTextDataGeneration++; 601 } 602 if (track == NULL) { 603 return INVALID_OPERATION; 604 } 605 track->mSource->stop(); 606 track->mSource = NULL; 607 track->mPackets->clear(); 608 return OK; 609 } 610 611 const sp<MediaSource> source = mSources.itemAt(trackIndex); 612 sp<MetaData> meta = source->getFormat(); 613 const char *mime; 614 CHECK(meta->findCString(kKeyMIMEType, &mime)); 615 if (!strncasecmp(mime, "text/", 5)) { 616 bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP); 617 Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack; 618 if (track->mSource != NULL && track->mIndex == trackIndex) { 619 return OK; 620 } 621 track->mIndex = trackIndex; 622 if (track->mSource != NULL) { 623 track->mSource->stop(); 624 } 625 track->mSource = mSources.itemAt(trackIndex); 626 track->mSource->start(); 627 if (track->mPackets == NULL) { 628 track->mPackets = new AnotherPacketSource(track->mSource->getFormat()); 629 } else { 630 track->mPackets->clear(); 631 track->mPackets->setFormat(track->mSource->getFormat()); 632 633 } 634 635 if (isSubtitle) { 636 mFetchSubtitleDataGeneration++; 637 } else { 638 mFetchTimedTextDataGeneration++; 639 } 640 641 return OK; 642 } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) { 643 bool audio = !strncasecmp(mime, "audio/", 6); 644 Track *track = audio ? &mAudioTrack : &mVideoTrack; 645 if (track->mSource != NULL && track->mIndex == trackIndex) { 646 return OK; 647 } 648 649 sp<AMessage> msg = new AMessage(kWhatChangeAVSource, id()); 650 msg->setInt32("trackIndex", trackIndex); 651 msg->post(); 652 return OK; 653 } 654 655 return INVALID_OPERATION; 656} 657 658status_t NuPlayer::GenericSource::seekTo(int64_t seekTimeUs) { 659 if (mVideoTrack.mSource != NULL) { 660 int64_t actualTimeUs; 661 readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs); 662 663 seekTimeUs = actualTimeUs; 664 } 665 666 if (mAudioTrack.mSource != NULL) { 667 readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs); 668 } 669 670 return OK; 671} 672 673sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer( 674 MediaBuffer* mb, 675 media_track_type trackType, 676 int64_t *actualTimeUs) { 677 bool audio = trackType == MEDIA_TRACK_TYPE_AUDIO; 678 size_t outLength = mb->range_length(); 679 680 if (audio && mAudioIsVorbis) { 681 outLength += sizeof(int32_t); 682 } 683 684 sp<ABuffer> ab; 685 if (mIsWidevine && !audio) { 686 // data is already provided in the buffer 687 ab = new ABuffer(NULL, mb->range_length()); 688 ab->meta()->setPointer("mediaBuffer", mb); 689 mb->add_ref(); 690 } else { 691 ab = new ABuffer(outLength); 692 memcpy(ab->data(), 693 (const uint8_t *)mb->data() + mb->range_offset(), 694 mb->range_length()); 695 } 696 697 if (audio && mAudioIsVorbis) { 698 int32_t numPageSamples; 699 if (!mb->meta_data()->findInt32(kKeyValidSamples, &numPageSamples)) { 700 numPageSamples = -1; 701 } 702 703 uint8_t* abEnd = ab->data() + mb->range_length(); 704 memcpy(abEnd, &numPageSamples, sizeof(numPageSamples)); 705 } 706 707 sp<AMessage> meta = ab->meta(); 708 709 int64_t timeUs; 710 CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs)); 711 meta->setInt64("timeUs", timeUs); 712 713 if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) { 714 const char *mime; 715 CHECK(mTimedTextTrack.mSource != NULL 716 && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime)); 717 meta->setString("mime", mime); 718 } 719 720 int64_t durationUs; 721 if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) { 722 meta->setInt64("durationUs", durationUs); 723 } 724 725 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 726 meta->setInt32("trackIndex", mSubtitleTrack.mIndex); 727 } 728 729 if (actualTimeUs) { 730 *actualTimeUs = timeUs; 731 } 732 733 mb->release(); 734 mb = NULL; 735 736 return ab; 737} 738 739void NuPlayer::GenericSource::readBuffer( 740 media_track_type trackType, int64_t seekTimeUs, int64_t *actualTimeUs, bool formatChange) { 741 Track *track; 742 switch (trackType) { 743 case MEDIA_TRACK_TYPE_VIDEO: 744 track = &mVideoTrack; 745 break; 746 case MEDIA_TRACK_TYPE_AUDIO: 747 track = &mAudioTrack; 748 break; 749 case MEDIA_TRACK_TYPE_SUBTITLE: 750 track = &mSubtitleTrack; 751 break; 752 case MEDIA_TRACK_TYPE_TIMEDTEXT: 753 track = &mTimedTextTrack; 754 break; 755 default: 756 TRESPASS(); 757 } 758 759 if (track->mSource == NULL) { 760 return; 761 } 762 763 if (actualTimeUs) { 764 *actualTimeUs = seekTimeUs; 765 } 766 767 MediaSource::ReadOptions options; 768 769 bool seeking = false; 770 771 if (seekTimeUs >= 0) { 772 options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 773 seeking = true; 774 } 775 776 if (mIsWidevine && trackType != MEDIA_TRACK_TYPE_AUDIO) { 777 options.setNonBlocking(); 778 } 779 780 for (;;) { 781 MediaBuffer *mbuf; 782 status_t err = track->mSource->read(&mbuf, &options); 783 784 options.clearSeekTo(); 785 786 if (err == OK) { 787 // formatChange && seeking: track whose source is changed during selection 788 // formatChange && !seeking: track whose source is not changed during selection 789 // !formatChange: normal seek 790 if ((seeking || formatChange) 791 && (trackType == MEDIA_TRACK_TYPE_AUDIO 792 || trackType == MEDIA_TRACK_TYPE_VIDEO)) { 793 ATSParser::DiscontinuityType type = formatChange 794 ? (seeking 795 ? ATSParser::DISCONTINUITY_FORMATCHANGE 796 : ATSParser::DISCONTINUITY_NONE) 797 : ATSParser::DISCONTINUITY_SEEK; 798 track->mPackets->queueDiscontinuity( type, NULL, true /* discard */); 799 } 800 801 sp<ABuffer> buffer = mediaBufferToABuffer(mbuf, trackType, actualTimeUs); 802 track->mPackets->queueAccessUnit(buffer); 803 break; 804 } else if (err == WOULD_BLOCK) { 805 break; 806 } else if (err == INFO_FORMAT_CHANGED) { 807#if 0 808 track->mPackets->queueDiscontinuity( 809 ATSParser::DISCONTINUITY_FORMATCHANGE, 810 NULL, 811 false /* discard */); 812#endif 813 } else { 814 track->mPackets->signalEOS(err); 815 break; 816 } 817 } 818} 819 820} // namespace android 821