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