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