NuMediaExtractor.cpp revision 9d07855aaff8a6b502a3ab058002cdd4a278b965
1/* 2 * Copyright 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 "NuMediaExtractor" 19#include <utils/Log.h> 20 21#include <media/stagefright/NuMediaExtractor.h> 22 23#include "include/ESDS.h" 24#include "include/NuCachedSource2.h" 25#include "include/WVMExtractor.h" 26 27#include <media/stagefright/foundation/ABuffer.h> 28#include <media/stagefright/foundation/ADebug.h> 29#include <media/stagefright/foundation/AMessage.h> 30#include <media/stagefright/DataSource.h> 31#include <media/stagefright/FileSource.h> 32#include <media/stagefright/MediaBuffer.h> 33#include <media/stagefright/MediaDefs.h> 34#include <media/stagefright/MediaErrors.h> 35#include <media/stagefright/MediaExtractor.h> 36#include <media/stagefright/MediaSource.h> 37#include <media/stagefright/MetaData.h> 38#include <media/stagefright/Utils.h> 39 40namespace android { 41 42NuMediaExtractor::NuMediaExtractor() 43 : mIsWidevineExtractor(false), 44 mTotalBitrate(-1ll), 45 mDurationUs(-1ll) { 46} 47 48NuMediaExtractor::~NuMediaExtractor() { 49 releaseTrackSamples(); 50 51 for (size_t i = 0; i < mSelectedTracks.size(); ++i) { 52 TrackInfo *info = &mSelectedTracks.editItemAt(i); 53 54 CHECK_EQ((status_t)OK, info->mSource->stop()); 55 } 56 57 mSelectedTracks.clear(); 58} 59 60status_t NuMediaExtractor::setDataSource( 61 const char *path, const KeyedVector<String8, String8> *headers) { 62 Mutex::Autolock autoLock(mLock); 63 64 if (mImpl != NULL) { 65 return -EINVAL; 66 } 67 68 sp<DataSource> dataSource = 69 DataSource::CreateFromURI(path, headers); 70 71 if (dataSource == NULL) { 72 return -ENOENT; 73 } 74 75 mIsWidevineExtractor = false; 76 if (!strncasecmp("widevine://", path, 11)) { 77 String8 mimeType; 78 float confidence; 79 sp<AMessage> dummy; 80 bool success = SniffWVM(dataSource, &mimeType, &confidence, &dummy); 81 82 if (!success 83 || strcasecmp( 84 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) { 85 return ERROR_UNSUPPORTED; 86 } 87 88 sp<WVMExtractor> extractor = new WVMExtractor(dataSource); 89 extractor->setAdaptiveStreamingMode(true); 90 91 mImpl = extractor; 92 mIsWidevineExtractor = true; 93 } else { 94 mImpl = MediaExtractor::Create(dataSource); 95 } 96 97 if (mImpl == NULL) { 98 return ERROR_UNSUPPORTED; 99 } 100 101 mDataSource = dataSource; 102 103 updateDurationAndBitrate(); 104 105 return OK; 106} 107 108status_t NuMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) { 109 Mutex::Autolock autoLock(mLock); 110 111 if (mImpl != NULL) { 112 return -EINVAL; 113 } 114 115 sp<FileSource> fileSource = new FileSource(dup(fd), offset, size); 116 117 status_t err = fileSource->initCheck(); 118 if (err != OK) { 119 return err; 120 } 121 122 mImpl = MediaExtractor::Create(fileSource); 123 124 if (mImpl == NULL) { 125 return ERROR_UNSUPPORTED; 126 } 127 128 mDataSource = fileSource; 129 130 updateDurationAndBitrate(); 131 132 return OK; 133} 134 135void NuMediaExtractor::updateDurationAndBitrate() { 136 mTotalBitrate = 0ll; 137 mDurationUs = -1ll; 138 139 for (size_t i = 0; i < mImpl->countTracks(); ++i) { 140 sp<MetaData> meta = mImpl->getTrackMetaData(i); 141 142 int32_t bitrate; 143 if (!meta->findInt32(kKeyBitRate, &bitrate)) { 144 const char *mime; 145 CHECK(meta->findCString(kKeyMIMEType, &mime)); 146 ALOGV("track of type '%s' does not publish bitrate", mime); 147 148 mTotalBitrate = -1ll; 149 } else if (mTotalBitrate >= 0ll) { 150 mTotalBitrate += bitrate; 151 } 152 153 int64_t durationUs; 154 if (meta->findInt64(kKeyDuration, &durationUs) 155 && durationUs > mDurationUs) { 156 mDurationUs = durationUs; 157 } 158 } 159} 160 161size_t NuMediaExtractor::countTracks() const { 162 Mutex::Autolock autoLock(mLock); 163 164 return mImpl == NULL ? 0 : mImpl->countTracks(); 165} 166 167status_t NuMediaExtractor::getTrackFormat( 168 size_t index, sp<AMessage> *format) const { 169 Mutex::Autolock autoLock(mLock); 170 171 *format = NULL; 172 173 if (mImpl == NULL) { 174 return -EINVAL; 175 } 176 177 if (index >= mImpl->countTracks()) { 178 return -ERANGE; 179 } 180 181 sp<MetaData> meta = mImpl->getTrackMetaData(index); 182 183 const char *mime; 184 CHECK(meta->findCString(kKeyMIMEType, &mime)); 185 186 sp<AMessage> msg = new AMessage; 187 msg->setString("mime", mime); 188 189 int64_t durationUs; 190 if (meta->findInt64(kKeyDuration, &durationUs)) { 191 msg->setInt64("durationUs", durationUs); 192 } 193 194 if (!strncasecmp("video/", mime, 6)) { 195 int32_t width, height; 196 CHECK(meta->findInt32(kKeyWidth, &width)); 197 CHECK(meta->findInt32(kKeyHeight, &height)); 198 199 msg->setInt32("width", width); 200 msg->setInt32("height", height); 201 } else if (!strncasecmp("audio/", mime, 6)) { 202 int32_t numChannels, sampleRate; 203 CHECK(meta->findInt32(kKeyChannelCount, &numChannels)); 204 CHECK(meta->findInt32(kKeySampleRate, &sampleRate)); 205 206 msg->setInt32("channel-count", numChannels); 207 msg->setInt32("sample-rate", sampleRate); 208 209 int32_t isADTS; 210 if (meta->findInt32(kKeyIsADTS, &isADTS)) { 211 msg->setInt32("is-adts", true); 212 } 213 } 214 215 int32_t maxInputSize; 216 if (meta->findInt32(kKeyMaxInputSize, &maxInputSize)) { 217 msg->setInt32("max-input-size", maxInputSize); 218 } 219 220 uint32_t type; 221 const void *data; 222 size_t size; 223 if (meta->findData(kKeyAVCC, &type, &data, &size)) { 224 // Parse the AVCDecoderConfigurationRecord 225 226 const uint8_t *ptr = (const uint8_t *)data; 227 228 CHECK(size >= 7); 229 CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1 230 uint8_t profile = ptr[1]; 231 uint8_t level = ptr[3]; 232 233 // There is decodable content out there that fails the following 234 // assertion, let's be lenient for now... 235 // CHECK((ptr[4] >> 2) == 0x3f); // reserved 236 237 size_t lengthSize = 1 + (ptr[4] & 3); 238 239 // commented out check below as H264_QVGA_500_NO_AUDIO.3gp 240 // violates it... 241 // CHECK((ptr[5] >> 5) == 7); // reserved 242 243 size_t numSeqParameterSets = ptr[5] & 31; 244 245 ptr += 6; 246 size -= 6; 247 248 sp<ABuffer> buffer = new ABuffer(1024); 249 buffer->setRange(0, 0); 250 251 for (size_t i = 0; i < numSeqParameterSets; ++i) { 252 CHECK(size >= 2); 253 size_t length = U16_AT(ptr); 254 255 ptr += 2; 256 size -= 2; 257 258 CHECK(size >= length); 259 260 memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4); 261 memcpy(buffer->data() + buffer->size() + 4, ptr, length); 262 buffer->setRange(0, buffer->size() + 4 + length); 263 264 ptr += length; 265 size -= length; 266 } 267 268 buffer->meta()->setInt32("csd", true); 269 buffer->meta()->setInt64("timeUs", 0); 270 271 msg->setBuffer("csd-0", buffer); 272 273 buffer = new ABuffer(1024); 274 buffer->setRange(0, 0); 275 276 CHECK(size >= 1); 277 size_t numPictureParameterSets = *ptr; 278 ++ptr; 279 --size; 280 281 for (size_t i = 0; i < numPictureParameterSets; ++i) { 282 CHECK(size >= 2); 283 size_t length = U16_AT(ptr); 284 285 ptr += 2; 286 size -= 2; 287 288 CHECK(size >= length); 289 290 memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4); 291 memcpy(buffer->data() + buffer->size() + 4, ptr, length); 292 buffer->setRange(0, buffer->size() + 4 + length); 293 294 ptr += length; 295 size -= length; 296 } 297 298 buffer->meta()->setInt32("csd", true); 299 buffer->meta()->setInt64("timeUs", 0); 300 msg->setBuffer("csd-1", buffer); 301 } else if (meta->findData(kKeyESDS, &type, &data, &size)) { 302 ESDS esds((const char *)data, size); 303 CHECK_EQ(esds.InitCheck(), (status_t)OK); 304 305 const void *codec_specific_data; 306 size_t codec_specific_data_size; 307 esds.getCodecSpecificInfo( 308 &codec_specific_data, &codec_specific_data_size); 309 310 sp<ABuffer> buffer = new ABuffer(codec_specific_data_size); 311 312 memcpy(buffer->data(), codec_specific_data, 313 codec_specific_data_size); 314 315 buffer->meta()->setInt32("csd", true); 316 buffer->meta()->setInt64("timeUs", 0); 317 msg->setBuffer("csd-0", buffer); 318 } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) { 319 sp<ABuffer> buffer = new ABuffer(size); 320 memcpy(buffer->data(), data, size); 321 322 buffer->meta()->setInt32("csd", true); 323 buffer->meta()->setInt64("timeUs", 0); 324 msg->setBuffer("csd-0", buffer); 325 326 if (!meta->findData(kKeyVorbisBooks, &type, &data, &size)) { 327 return -EINVAL; 328 } 329 330 buffer = new ABuffer(size); 331 memcpy(buffer->data(), data, size); 332 333 buffer->meta()->setInt32("csd", true); 334 buffer->meta()->setInt64("timeUs", 0); 335 msg->setBuffer("csd-1", buffer); 336 } 337 338 *format = msg; 339 340 return OK; 341} 342 343status_t NuMediaExtractor::selectTrack(size_t index) { 344 Mutex::Autolock autoLock(mLock); 345 346 if (mImpl == NULL) { 347 return -EINVAL; 348 } 349 350 if (index >= mImpl->countTracks()) { 351 return -ERANGE; 352 } 353 354 for (size_t i = 0; i < mSelectedTracks.size(); ++i) { 355 TrackInfo *info = &mSelectedTracks.editItemAt(i); 356 357 if (info->mTrackIndex == index) { 358 // This track has already been selected. 359 return OK; 360 } 361 } 362 363 sp<MediaSource> source = mImpl->getTrack(index); 364 365 CHECK_EQ((status_t)OK, source->start()); 366 367 mSelectedTracks.push(); 368 TrackInfo *info = &mSelectedTracks.editItemAt(mSelectedTracks.size() - 1); 369 370 info->mSource = source; 371 info->mTrackIndex = index; 372 info->mFinalResult = OK; 373 info->mSample = NULL; 374 info->mSampleTimeUs = -1ll; 375 info->mTrackFlags = 0; 376 377 const char *mime; 378 CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime)); 379 380 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { 381 info->mTrackFlags |= kIsVorbis; 382 } 383 384 return OK; 385} 386 387status_t NuMediaExtractor::unselectTrack(size_t index) { 388 Mutex::Autolock autoLock(mLock); 389 390 if (mImpl == NULL) { 391 return -EINVAL; 392 } 393 394 if (index >= mImpl->countTracks()) { 395 return -ERANGE; 396 } 397 398 size_t i; 399 for (i = 0; i < mSelectedTracks.size(); ++i) { 400 TrackInfo *info = &mSelectedTracks.editItemAt(i); 401 402 if (info->mTrackIndex == index) { 403 break; 404 } 405 } 406 407 if (i == mSelectedTracks.size()) { 408 // Not selected. 409 return OK; 410 } 411 412 TrackInfo *info = &mSelectedTracks.editItemAt(i); 413 414 if (info->mSample != NULL) { 415 info->mSample->release(); 416 info->mSample = NULL; 417 418 info->mSampleTimeUs = -1ll; 419 } 420 421 CHECK_EQ((status_t)OK, info->mSource->stop()); 422 423 mSelectedTracks.removeAt(i); 424 425 return OK; 426} 427 428void NuMediaExtractor::releaseTrackSamples() { 429 for (size_t i = 0; i < mSelectedTracks.size(); ++i) { 430 TrackInfo *info = &mSelectedTracks.editItemAt(i); 431 432 if (info->mSample != NULL) { 433 info->mSample->release(); 434 info->mSample = NULL; 435 436 info->mSampleTimeUs = -1ll; 437 } 438 } 439} 440 441ssize_t NuMediaExtractor::fetchTrackSamples( 442 int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) { 443 TrackInfo *minInfo = NULL; 444 ssize_t minIndex = -1; 445 446 for (size_t i = 0; i < mSelectedTracks.size(); ++i) { 447 TrackInfo *info = &mSelectedTracks.editItemAt(i); 448 449 if (seekTimeUs >= 0ll) { 450 info->mFinalResult = OK; 451 452 if (info->mSample != NULL) { 453 info->mSample->release(); 454 info->mSample = NULL; 455 info->mSampleTimeUs = -1ll; 456 } 457 } else if (info->mFinalResult != OK) { 458 continue; 459 } 460 461 if (info->mSample == NULL) { 462 MediaSource::ReadOptions options; 463 if (seekTimeUs >= 0ll) { 464 options.setSeekTo(seekTimeUs, mode); 465 } 466 status_t err = info->mSource->read(&info->mSample, &options); 467 468 if (err != OK) { 469 CHECK(info->mSample == NULL); 470 471 info->mFinalResult = err; 472 info->mSampleTimeUs = -1ll; 473 continue; 474 } else { 475 CHECK(info->mSample != NULL); 476 CHECK(info->mSample->meta_data()->findInt64( 477 kKeyTime, &info->mSampleTimeUs)); 478 } 479 } 480 481 if (minInfo == NULL || info->mSampleTimeUs < minInfo->mSampleTimeUs) { 482 minInfo = info; 483 minIndex = i; 484 } 485 } 486 487 return minIndex; 488} 489 490status_t NuMediaExtractor::seekTo( 491 int64_t timeUs, MediaSource::ReadOptions::SeekMode mode) { 492 Mutex::Autolock autoLock(mLock); 493 494 ssize_t minIndex = fetchTrackSamples(timeUs, mode); 495 496 if (minIndex < 0) { 497 return ERROR_END_OF_STREAM; 498 } 499 500 return OK; 501} 502 503status_t NuMediaExtractor::advance() { 504 Mutex::Autolock autoLock(mLock); 505 506 ssize_t minIndex = fetchTrackSamples(); 507 508 if (minIndex < 0) { 509 return ERROR_END_OF_STREAM; 510 } 511 512 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); 513 514 info->mSample->release(); 515 info->mSample = NULL; 516 info->mSampleTimeUs = -1ll; 517 518 return OK; 519} 520 521status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) { 522 Mutex::Autolock autoLock(mLock); 523 524 ssize_t minIndex = fetchTrackSamples(); 525 526 if (minIndex < 0) { 527 return ERROR_END_OF_STREAM; 528 } 529 530 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); 531 532 size_t sampleSize = info->mSample->range_length(); 533 534 if (info->mTrackFlags & kIsVorbis) { 535 // Each sample's data is suffixed by the number of page samples 536 // or -1 if not available. 537 sampleSize += sizeof(int32_t); 538 } 539 540 if (buffer->capacity() < sampleSize) { 541 return -ENOMEM; 542 } 543 544 const uint8_t *src = 545 (const uint8_t *)info->mSample->data() 546 + info->mSample->range_offset(); 547 548 memcpy((uint8_t *)buffer->data(), src, info->mSample->range_length()); 549 550 if (info->mTrackFlags & kIsVorbis) { 551 int32_t numPageSamples; 552 if (!info->mSample->meta_data()->findInt32( 553 kKeyValidSamples, &numPageSamples)) { 554 numPageSamples = -1; 555 } 556 557 memcpy((uint8_t *)buffer->data() + info->mSample->range_length(), 558 &numPageSamples, 559 sizeof(numPageSamples)); 560 } 561 562 buffer->setRange(0, sampleSize); 563 564 return OK; 565} 566 567status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) { 568 Mutex::Autolock autoLock(mLock); 569 570 ssize_t minIndex = fetchTrackSamples(); 571 572 if (minIndex < 0) { 573 return ERROR_END_OF_STREAM; 574 } 575 576 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); 577 *trackIndex = info->mTrackIndex; 578 579 return OK; 580} 581 582status_t NuMediaExtractor::getSampleTime(int64_t *sampleTimeUs) { 583 Mutex::Autolock autoLock(mLock); 584 585 ssize_t minIndex = fetchTrackSamples(); 586 587 if (minIndex < 0) { 588 return ERROR_END_OF_STREAM; 589 } 590 591 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); 592 *sampleTimeUs = info->mSampleTimeUs; 593 594 return OK; 595} 596 597status_t NuMediaExtractor::getSampleMeta(sp<MetaData> *sampleMeta) { 598 Mutex::Autolock autoLock(mLock); 599 600 *sampleMeta = NULL; 601 602 ssize_t minIndex = fetchTrackSamples(); 603 604 if (minIndex < 0) { 605 return ERROR_END_OF_STREAM; 606 } 607 608 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); 609 *sampleMeta = info->mSample->meta_data(); 610 611 return OK; 612} 613 614bool NuMediaExtractor::getTotalBitrate(int64_t *bitrate) const { 615 if (mTotalBitrate >= 0) { 616 *bitrate = mTotalBitrate; 617 return true; 618 } 619 620 off64_t size; 621 if (mDurationUs >= 0 && mDataSource->getSize(&size) == OK) { 622 *bitrate = size * 8000000ll / mDurationUs; // in bits/sec 623 return true; 624 } 625 626 return false; 627} 628 629// Returns true iff cached duration is available/applicable. 630bool NuMediaExtractor::getCachedDuration( 631 int64_t *durationUs, bool *eos) const { 632 Mutex::Autolock autoLock(mLock); 633 634 int64_t bitrate; 635 if (mIsWidevineExtractor) { 636 sp<WVMExtractor> wvmExtractor = 637 static_cast<WVMExtractor *>(mImpl.get()); 638 639 status_t finalStatus; 640 *durationUs = wvmExtractor->getCachedDurationUs(&finalStatus); 641 *eos = (finalStatus != OK); 642 return true; 643 } else if ((mDataSource->flags() & DataSource::kIsCachingDataSource) 644 && getTotalBitrate(&bitrate)) { 645 sp<NuCachedSource2> cachedSource = 646 static_cast<NuCachedSource2 *>(mDataSource.get()); 647 648 status_t finalStatus; 649 size_t cachedDataRemaining = 650 cachedSource->approxDataRemaining(&finalStatus); 651 652 *durationUs = cachedDataRemaining * 8000000ll / bitrate; 653 *eos = (finalStatus != OK); 654 return true; 655 } 656 657 return false; 658} 659 660} // namespace android 661