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 25 #include <media/DataSource.h> 26 #include <media/MediaSource.h> 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/DataSourceFactory.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/MediaExtractorFactory.h> 37 #include <media/stagefright/MetaData.h> 38 #include <media/stagefright/Utils.h> 39 40 namespace android { 41 42 NuMediaExtractor::Sample::Sample() 43 : mBuffer(NULL), 44 mSampleTimeUs(-1LL) { 45 } 46 47 NuMediaExtractor::Sample::Sample(MediaBufferBase *buffer, int64_t timeUs) 48 : mBuffer(buffer), 49 mSampleTimeUs(timeUs) { 50 } 51 52 NuMediaExtractor::NuMediaExtractor() 53 : mTotalBitrate(-1LL), 54 mDurationUs(-1LL) { 55 } 56 57 NuMediaExtractor::~NuMediaExtractor() { 58 releaseAllTrackSamples(); 59 60 for (size_t i = 0; i < mSelectedTracks.size(); ++i) { 61 TrackInfo *info = &mSelectedTracks.editItemAt(i); 62 63 status_t err = info->mSource->stop(); 64 ALOGE_IF(err != OK, "error %d stopping track %zu", err, i); 65 } 66 67 mSelectedTracks.clear(); 68 if (mDataSource != NULL) { 69 mDataSource->close(); 70 } 71 } 72 73 status_t NuMediaExtractor::setDataSource( 74 const sp<MediaHTTPService> &httpService, 75 const char *path, 76 const KeyedVector<String8, String8> *headers) { 77 Mutex::Autolock autoLock(mLock); 78 79 if (mImpl != NULL || path == NULL) { 80 return -EINVAL; 81 } 82 83 sp<DataSource> dataSource = 84 DataSourceFactory::CreateFromURI(httpService, path, headers); 85 86 if (dataSource == NULL) { 87 return -ENOENT; 88 } 89 90 mImpl = MediaExtractorFactory::Create(dataSource); 91 92 if (mImpl == NULL) { 93 return ERROR_UNSUPPORTED; 94 } 95 96 if (!mCasToken.empty()) { 97 mImpl->setMediaCas(mCasToken); 98 } 99 100 status_t err = updateDurationAndBitrate(); 101 if (err == OK) { 102 mDataSource = dataSource; 103 } 104 105 return OK; 106 } 107 108 status_t NuMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) { 109 110 ALOGV("setDataSource fd=%d (%s), offset=%lld, length=%lld", 111 fd, nameForFd(fd).c_str(), (long long) offset, (long long) size); 112 113 Mutex::Autolock autoLock(mLock); 114 115 if (mImpl != NULL) { 116 return -EINVAL; 117 } 118 119 sp<FileSource> fileSource = new FileSource(dup(fd), offset, size); 120 121 status_t err = fileSource->initCheck(); 122 if (err != OK) { 123 return err; 124 } 125 126 mImpl = MediaExtractorFactory::Create(fileSource); 127 128 if (mImpl == NULL) { 129 return ERROR_UNSUPPORTED; 130 } 131 132 if (!mCasToken.empty()) { 133 mImpl->setMediaCas(mCasToken); 134 } 135 136 err = updateDurationAndBitrate(); 137 if (err == OK) { 138 mDataSource = fileSource; 139 } 140 141 return OK; 142 } 143 144 status_t NuMediaExtractor::setDataSource(const sp<DataSource> &source) { 145 Mutex::Autolock autoLock(mLock); 146 147 if (mImpl != NULL) { 148 return -EINVAL; 149 } 150 151 status_t err = source->initCheck(); 152 if (err != OK) { 153 return err; 154 } 155 156 mImpl = MediaExtractorFactory::Create(source); 157 158 if (mImpl == NULL) { 159 return ERROR_UNSUPPORTED; 160 } 161 162 if (!mCasToken.empty()) { 163 mImpl->setMediaCas(mCasToken); 164 } 165 166 err = updateDurationAndBitrate(); 167 if (err == OK) { 168 mDataSource = source; 169 } 170 171 return err; 172 } 173 174 static String8 arrayToString(const std::vector<uint8_t> &array) { 175 String8 result; 176 for (size_t i = 0; i < array.size(); i++) { 177 result.appendFormat("%02x ", array[i]); 178 } 179 if (result.isEmpty()) { 180 result.append("(null)"); 181 } 182 return result; 183 } 184 185 status_t NuMediaExtractor::setMediaCas(const HInterfaceToken &casToken) { 186 ALOGV("setMediaCas: casToken={%s}", arrayToString(casToken).c_str()); 187 188 Mutex::Autolock autoLock(mLock); 189 190 if (casToken.empty()) { 191 return BAD_VALUE; 192 } 193 194 mCasToken = casToken; 195 196 if (mImpl != NULL) { 197 mImpl->setMediaCas(casToken); 198 status_t err = updateDurationAndBitrate(); 199 if (err != OK) { 200 return err; 201 } 202 } 203 204 return OK; 205 } 206 207 status_t NuMediaExtractor::updateDurationAndBitrate() { 208 if (mImpl->countTracks() > kMaxTrackCount) { 209 return ERROR_UNSUPPORTED; 210 } 211 212 mTotalBitrate = 0LL; 213 mDurationUs = -1LL; 214 215 for (size_t i = 0; i < mImpl->countTracks(); ++i) { 216 sp<MetaData> meta = mImpl->getTrackMetaData(i); 217 if (meta == NULL) { 218 ALOGW("no metadata for track %zu", i); 219 continue; 220 } 221 222 int32_t bitrate; 223 if (!meta->findInt32(kKeyBitRate, &bitrate)) { 224 const char *mime; 225 CHECK(meta->findCString(kKeyMIMEType, &mime)); 226 ALOGV("track of type '%s' does not publish bitrate", mime); 227 228 mTotalBitrate = -1LL; 229 } else if (mTotalBitrate >= 0LL) { 230 mTotalBitrate += bitrate; 231 } 232 233 int64_t durationUs; 234 if (meta->findInt64(kKeyDuration, &durationUs) 235 && durationUs > mDurationUs) { 236 mDurationUs = durationUs; 237 } 238 } 239 return OK; 240 } 241 242 size_t NuMediaExtractor::countTracks() const { 243 Mutex::Autolock autoLock(mLock); 244 245 return mImpl == NULL ? 0 : mImpl->countTracks(); 246 } 247 248 status_t NuMediaExtractor::getTrackFormat( 249 size_t index, sp<AMessage> *format, uint32_t flags) const { 250 Mutex::Autolock autoLock(mLock); 251 252 *format = NULL; 253 254 if (mImpl == NULL) { 255 return -EINVAL; 256 } 257 258 if (index >= mImpl->countTracks()) { 259 return -ERANGE; 260 } 261 262 sp<MetaData> meta = mImpl->getTrackMetaData(index, flags); 263 // Extractors either support trackID-s or not, so either all tracks have trackIDs or none. 264 // Generate trackID if missing. 265 int32_t trackID; 266 if (meta != NULL && !meta->findInt32(kKeyTrackID, &trackID)) { 267 meta->setInt32(kKeyTrackID, (int32_t)index + 1); 268 } 269 return convertMetaDataToMessage(meta, format); 270 } 271 272 status_t NuMediaExtractor::getFileFormat(sp<AMessage> *format) const { 273 Mutex::Autolock autoLock(mLock); 274 275 *format = NULL; 276 277 if (mImpl == NULL) { 278 return -EINVAL; 279 } 280 281 sp<MetaData> meta = mImpl->getMetaData(); 282 283 const char *mime; 284 CHECK(meta->findCString(kKeyMIMEType, &mime)); 285 *format = new AMessage(); 286 (*format)->setString("mime", mime); 287 288 uint32_t type; 289 const void *pssh; 290 size_t psshsize; 291 if (meta->findData(kKeyPssh, &type, &pssh, &psshsize)) { 292 sp<ABuffer> buf = new ABuffer(psshsize); 293 memcpy(buf->data(), pssh, psshsize); 294 (*format)->setBuffer("pssh", buf); 295 } 296 297 return OK; 298 } 299 300 status_t NuMediaExtractor::getExifOffsetSize(off64_t *offset, size_t *size) const { 301 Mutex::Autolock autoLock(mLock); 302 303 if (mImpl == NULL) { 304 return -EINVAL; 305 } 306 307 sp<MetaData> meta = mImpl->getMetaData(); 308 309 int64_t exifOffset, exifSize; 310 if (meta->findInt64(kKeyExifOffset, &exifOffset) 311 && meta->findInt64(kKeyExifSize, &exifSize)) { 312 *offset = (off64_t) exifOffset; 313 *size = (size_t) exifSize; 314 315 return OK; 316 } 317 return ERROR_UNSUPPORTED; 318 } 319 320 status_t NuMediaExtractor::selectTrack(size_t index, 321 int64_t startTimeUs, MediaSource::ReadOptions::SeekMode mode) { 322 Mutex::Autolock autoLock(mLock); 323 324 if (mImpl == NULL) { 325 return -EINVAL; 326 } 327 328 if (index >= mImpl->countTracks()) { 329 return -ERANGE; 330 } 331 332 for (size_t i = 0; i < mSelectedTracks.size(); ++i) { 333 TrackInfo *info = &mSelectedTracks.editItemAt(i); 334 335 if (info->mTrackIndex == index) { 336 // This track has already been selected. 337 return OK; 338 } 339 } 340 341 sp<IMediaSource> source = mImpl->getTrack(index); 342 343 if (source == nullptr) { 344 ALOGE("track %zu is empty", index); 345 return ERROR_MALFORMED; 346 } 347 348 status_t ret = source->start(); 349 if (ret != OK) { 350 ALOGE("track %zu failed to start", index); 351 return ret; 352 } 353 354 sp<MetaData> meta = source->getFormat(); 355 if (meta == NULL) { 356 ALOGE("track %zu has no meta data", index); 357 return ERROR_MALFORMED; 358 } 359 360 const char *mime; 361 if (!meta->findCString(kKeyMIMEType, &mime)) { 362 ALOGE("track %zu has no mime type in meta data", index); 363 return ERROR_MALFORMED; 364 } 365 ALOGV("selectTrack, track[%zu]: %s", index, mime); 366 367 mSelectedTracks.push(); 368 TrackInfo *info = &mSelectedTracks.editItemAt(mSelectedTracks.size() - 1); 369 370 info->mSource = source; 371 info->mTrackIndex = index; 372 if (!strncasecmp(mime, "audio/", 6)) { 373 info->mTrackType = MEDIA_TRACK_TYPE_AUDIO; 374 info->mMaxFetchCount = 64; 375 } else if (!strncasecmp(mime, "video/", 6)) { 376 info->mTrackType = MEDIA_TRACK_TYPE_VIDEO; 377 info->mMaxFetchCount = 8; 378 } else { 379 info->mTrackType = MEDIA_TRACK_TYPE_UNKNOWN; 380 info->mMaxFetchCount = 1; 381 } 382 info->mFinalResult = OK; 383 releaseTrackSamples(info); 384 info->mTrackFlags = 0; 385 386 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { 387 info->mTrackFlags |= kIsVorbis; 388 } 389 390 if (startTimeUs >= 0) { 391 fetchTrackSamples(info, startTimeUs, mode); 392 } 393 394 return OK; 395 } 396 397 status_t NuMediaExtractor::unselectTrack(size_t index) { 398 Mutex::Autolock autoLock(mLock); 399 400 if (mImpl == NULL) { 401 return -EINVAL; 402 } 403 404 if (index >= mImpl->countTracks()) { 405 return -ERANGE; 406 } 407 408 size_t i; 409 for (i = 0; i < mSelectedTracks.size(); ++i) { 410 TrackInfo *info = &mSelectedTracks.editItemAt(i); 411 412 if (info->mTrackIndex == index) { 413 break; 414 } 415 } 416 417 if (i == mSelectedTracks.size()) { 418 // Not selected. 419 return OK; 420 } 421 422 TrackInfo *info = &mSelectedTracks.editItemAt(i); 423 424 releaseTrackSamples(info); 425 426 CHECK_EQ((status_t)OK, info->mSource->stop()); 427 428 mSelectedTracks.removeAt(i); 429 430 return OK; 431 } 432 433 void NuMediaExtractor::releaseTrackSamples(TrackInfo *info) { 434 if (info == NULL) { 435 return; 436 } 437 438 auto it = info->mSamples.begin(); 439 while (it != info->mSamples.end()) { 440 if (it->mBuffer != NULL) { 441 it->mBuffer->release(); 442 } 443 it = info->mSamples.erase(it); 444 } 445 } 446 447 void NuMediaExtractor::releaseAllTrackSamples() { 448 for (size_t i = 0; i < mSelectedTracks.size(); ++i) { 449 releaseTrackSamples(&mSelectedTracks.editItemAt(i)); 450 } 451 } 452 453 ssize_t NuMediaExtractor::fetchAllTrackSamples( 454 int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) { 455 TrackInfo *minInfo = NULL; 456 ssize_t minIndex = ERROR_END_OF_STREAM; 457 458 for (size_t i = 0; i < mSelectedTracks.size(); ++i) { 459 TrackInfo *info = &mSelectedTracks.editItemAt(i); 460 fetchTrackSamples(info, seekTimeUs, mode); 461 462 status_t err = info->mFinalResult; 463 if (err != OK && err != ERROR_END_OF_STREAM && info->mSamples.empty()) { 464 return err; 465 } 466 467 if (info->mSamples.empty()) { 468 continue; 469 } 470 471 if (minInfo == NULL) { 472 minInfo = info; 473 minIndex = i; 474 } else { 475 auto it = info->mSamples.begin(); 476 auto itMin = minInfo->mSamples.begin(); 477 if (it->mSampleTimeUs < itMin->mSampleTimeUs) { 478 minInfo = info; 479 minIndex = i; 480 } 481 } 482 } 483 484 return minIndex; 485 } 486 487 void NuMediaExtractor::fetchTrackSamples(TrackInfo *info, 488 int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) { 489 if (info == NULL) { 490 return; 491 } 492 493 MediaSource::ReadOptions options; 494 if (seekTimeUs >= 0LL) { 495 options.setSeekTo(seekTimeUs, mode); 496 info->mFinalResult = OK; 497 releaseTrackSamples(info); 498 } else if (info->mFinalResult != OK || !info->mSamples.empty()) { 499 return; 500 } 501 502 status_t err = OK; 503 Vector<MediaBufferBase *> mediaBuffers; 504 if (info->mSource->supportReadMultiple()) { 505 options.setNonBlocking(); 506 err = info->mSource->readMultiple(&mediaBuffers, info->mMaxFetchCount, &options); 507 } else { 508 MediaBufferBase *mbuf = NULL; 509 err = info->mSource->read(&mbuf, &options); 510 if (err == OK && mbuf != NULL) { 511 mediaBuffers.push_back(mbuf); 512 } 513 } 514 515 info->mFinalResult = err; 516 if (err != OK && err != ERROR_END_OF_STREAM) { 517 ALOGW("read on track %zu failed with error %d", info->mTrackIndex, err); 518 } 519 520 size_t count = mediaBuffers.size(); 521 bool releaseRemaining = false; 522 for (size_t id = 0; id < count; ++id) { 523 int64_t timeUs; 524 MediaBufferBase *mbuf = mediaBuffers[id]; 525 if (mbuf == NULL) { 526 continue; 527 } 528 if (releaseRemaining) { 529 mbuf->release(); 530 continue; 531 } 532 if (mbuf->meta_data().findInt64(kKeyTime, &timeUs)) { 533 info->mSamples.emplace_back(mbuf, timeUs); 534 } else { 535 mbuf->meta_data().dumpToLog(); 536 info->mFinalResult = ERROR_MALFORMED; 537 mbuf->release(); 538 releaseRemaining = true; 539 } 540 } 541 } 542 543 status_t NuMediaExtractor::seekTo( 544 int64_t timeUs, MediaSource::ReadOptions::SeekMode mode) { 545 Mutex::Autolock autoLock(mLock); 546 547 ssize_t minIndex = fetchAllTrackSamples(timeUs, mode); 548 549 if (minIndex < 0) { 550 return ERROR_END_OF_STREAM; 551 } 552 553 return OK; 554 } 555 556 status_t NuMediaExtractor::advance() { 557 Mutex::Autolock autoLock(mLock); 558 559 ssize_t minIndex = fetchAllTrackSamples(); 560 561 if (minIndex < 0) { 562 return ERROR_END_OF_STREAM; 563 } 564 565 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); 566 567 if (info == NULL || info->mSamples.empty()) { 568 return ERROR_END_OF_STREAM; 569 } 570 571 auto it = info->mSamples.begin(); 572 if (it->mBuffer != NULL) { 573 it->mBuffer->release(); 574 } 575 info->mSamples.erase(it); 576 577 if (info->mSamples.empty()) { 578 minIndex = fetchAllTrackSamples(); 579 if (minIndex < 0) { 580 return ERROR_END_OF_STREAM; 581 } 582 info = &mSelectedTracks.editItemAt(minIndex); 583 if (info == NULL || info->mSamples.empty()) { 584 return ERROR_END_OF_STREAM; 585 } 586 } 587 return OK; 588 } 589 590 status_t NuMediaExtractor::appendVorbisNumPageSamples( 591 MediaBufferBase *mbuf, const sp<ABuffer> &buffer) { 592 int32_t numPageSamples; 593 if (!mbuf->meta_data().findInt32( 594 kKeyValidSamples, &numPageSamples)) { 595 numPageSamples = -1; 596 } 597 598 memcpy((uint8_t *)buffer->data() + mbuf->range_length(), 599 &numPageSamples, 600 sizeof(numPageSamples)); 601 602 uint32_t type; 603 const void *data; 604 size_t size, size2; 605 if (mbuf->meta_data().findData(kKeyEncryptedSizes, &type, &data, &size)) { 606 // Signal numPageSamples (a plain int32_t) is appended at the end, 607 // i.e. sizeof(numPageSamples) plain bytes + 0 encrypted bytes 608 if (SIZE_MAX - size < sizeof(int32_t)) { 609 return -ENOMEM; 610 } 611 612 size_t newSize = size + sizeof(int32_t); 613 sp<ABuffer> abuf = new ABuffer(newSize); 614 uint8_t *adata = static_cast<uint8_t *>(abuf->data()); 615 if (adata == NULL) { 616 return -ENOMEM; 617 } 618 619 // append 0 to encrypted sizes 620 int32_t zero = 0; 621 memcpy(adata, data, size); 622 memcpy(adata + size, &zero, sizeof(zero)); 623 mbuf->meta_data().setData(kKeyEncryptedSizes, type, adata, newSize); 624 625 if (mbuf->meta_data().findData(kKeyPlainSizes, &type, &data, &size2)) { 626 if (size2 != size) { 627 return ERROR_MALFORMED; 628 } 629 memcpy(adata, data, size); 630 } else { 631 // if sample meta data does not include plain size array, assume filled with zeros, 632 // i.e. entire buffer is encrypted 633 memset(adata, 0, size); 634 } 635 // append sizeof(numPageSamples) to plain sizes. 636 int32_t int32Size = sizeof(numPageSamples); 637 memcpy(adata + size, &int32Size, sizeof(int32Size)); 638 mbuf->meta_data().setData(kKeyPlainSizes, type, adata, newSize); 639 } 640 641 return OK; 642 } 643 644 status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) { 645 Mutex::Autolock autoLock(mLock); 646 647 ssize_t minIndex = fetchAllTrackSamples(); 648 649 if (minIndex < 0) { 650 return ERROR_END_OF_STREAM; 651 } 652 653 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); 654 655 auto it = info->mSamples.begin(); 656 size_t sampleSize = it->mBuffer->range_length(); 657 658 if (info->mTrackFlags & kIsVorbis) { 659 // Each sample's data is suffixed by the number of page samples 660 // or -1 if not available. 661 sampleSize += sizeof(int32_t); 662 } 663 664 if (buffer->capacity() < sampleSize) { 665 return -ENOMEM; 666 } 667 668 const uint8_t *src = 669 (const uint8_t *)it->mBuffer->data() 670 + it->mBuffer->range_offset(); 671 672 memcpy((uint8_t *)buffer->data(), src, it->mBuffer->range_length()); 673 674 status_t err = OK; 675 if (info->mTrackFlags & kIsVorbis) { 676 err = appendVorbisNumPageSamples(it->mBuffer, buffer); 677 } 678 679 if (err == OK) { 680 buffer->setRange(0, sampleSize); 681 } 682 683 return err; 684 } 685 686 status_t NuMediaExtractor::getSampleSize(size_t *sampleSize) { 687 Mutex::Autolock autoLock(mLock); 688 689 ssize_t minIndex = fetchAllTrackSamples(); 690 691 if (minIndex < 0) { 692 return ERROR_END_OF_STREAM; 693 } 694 695 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); 696 auto it = info->mSamples.begin(); 697 *sampleSize = it->mBuffer->range_length(); 698 699 if (info->mTrackFlags & kIsVorbis) { 700 // Each sample's data is suffixed by the number of page samples 701 // or -1 if not available. 702 *sampleSize += sizeof(int32_t); 703 } 704 705 return OK; 706 } 707 708 status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) { 709 Mutex::Autolock autoLock(mLock); 710 711 ssize_t minIndex = fetchAllTrackSamples(); 712 713 if (minIndex < 0) { 714 return ERROR_END_OF_STREAM; 715 } 716 717 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); 718 *trackIndex = info->mTrackIndex; 719 720 return OK; 721 } 722 723 status_t NuMediaExtractor::getSampleTime(int64_t *sampleTimeUs) { 724 Mutex::Autolock autoLock(mLock); 725 726 ssize_t minIndex = fetchAllTrackSamples(); 727 728 if (minIndex < 0) { 729 return ERROR_END_OF_STREAM; 730 } 731 732 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); 733 *sampleTimeUs = info->mSamples.begin()->mSampleTimeUs; 734 735 return OK; 736 } 737 738 status_t NuMediaExtractor::getSampleMeta(sp<MetaData> *sampleMeta) { 739 Mutex::Autolock autoLock(mLock); 740 741 *sampleMeta = NULL; 742 743 ssize_t minIndex = fetchAllTrackSamples(); 744 745 if (minIndex < 0) { 746 status_t err = minIndex; 747 return err; 748 } 749 750 TrackInfo *info = &mSelectedTracks.editItemAt(minIndex); 751 *sampleMeta = new MetaData(info->mSamples.begin()->mBuffer->meta_data()); 752 753 return OK; 754 } 755 756 status_t NuMediaExtractor::getMetrics(Parcel *reply) { 757 if (mImpl == NULL) { 758 return -EINVAL; 759 } 760 status_t status = mImpl->getMetrics(reply); 761 return status; 762 } 763 764 bool NuMediaExtractor::getTotalBitrate(int64_t *bitrate) const { 765 if (mTotalBitrate > 0) { 766 *bitrate = mTotalBitrate; 767 return true; 768 } 769 770 off64_t size; 771 if (mDurationUs > 0 && mDataSource->getSize(&size) == OK) { 772 *bitrate = size * 8000000LL / mDurationUs; // in bits/sec 773 return true; 774 } 775 776 return false; 777 } 778 779 // Returns true iff cached duration is available/applicable. 780 bool NuMediaExtractor::getCachedDuration( 781 int64_t *durationUs, bool *eos) const { 782 Mutex::Autolock autoLock(mLock); 783 784 off64_t cachedDataRemaining = -1; 785 status_t finalStatus = mDataSource->getAvailableSize(-1, &cachedDataRemaining); 786 787 int64_t bitrate; 788 if (cachedDataRemaining >= 0 789 && getTotalBitrate(&bitrate)) { 790 *durationUs = cachedDataRemaining * 8000000ll / bitrate; 791 *eos = (finalStatus != OK); 792 return true; 793 } 794 795 return false; 796 } 797 798 // Return OK if we have received an audio presentation info. 799 // Return ERROR_END_OF_STREAM if no tracks are available. 800 // Return ERROR_UNSUPPORTED if the track has no audio presentation. 801 // Return INVALID_OPERATION if audio presentation metadata version does not match. 802 status_t NuMediaExtractor::getAudioPresentations( 803 size_t trackIndex, AudioPresentationCollection *presentations) { 804 Mutex::Autolock autoLock(mLock); 805 ssize_t minIndex = fetchAllTrackSamples(); 806 if (minIndex < 0) { 807 return ERROR_END_OF_STREAM; 808 } 809 for (size_t i = 0; i < mSelectedTracks.size(); ++i) { 810 TrackInfo *info = &mSelectedTracks.editItemAt(i); 811 812 if (info->mTrackIndex == trackIndex) { 813 sp<MetaData> meta = new MetaData(info->mSamples.begin()->mBuffer->meta_data()); 814 815 uint32_t type; 816 const void *data; 817 size_t size; 818 if (meta != NULL && meta->findData(kKeyAudioPresentationInfo, &type, &data, &size)) { 819 std::istringstream inStream(std::string(static_cast<const char*>(data), size)); 820 return deserializeAudioPresentations(&inStream, presentations); 821 } 822 ALOGV("Track %zu does not contain any audio presentation", trackIndex); 823 return ERROR_UNSUPPORTED; 824 } 825 } 826 ALOGV("Source does not contain any audio presentation"); 827 return ERROR_UNSUPPORTED; 828 } 829 830 } // namespace android 831