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