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