1 /* 2 * Copyright (C) 2010 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 "OggExtractor" 19 #include <utils/Log.h> 20 21 #include "include/OggExtractor.h" 22 23 #include <cutils/properties.h> 24 #include <media/stagefright/foundation/ADebug.h> 25 #include <media/stagefright/DataSource.h> 26 #include <media/stagefright/MediaBuffer.h> 27 #include <media/stagefright/MediaBufferGroup.h> 28 #include <media/stagefright/MediaDefs.h> 29 #include <media/stagefright/MediaErrors.h> 30 #include <media/stagefright/MediaSource.h> 31 #include <media/stagefright/MetaData.h> 32 #include <media/stagefright/Utils.h> 33 #include <utils/String8.h> 34 35 extern "C" { 36 #include <Tremolo/codec_internal.h> 37 38 int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb); 39 int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb); 40 int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb); 41 long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op); 42 } 43 44 namespace android { 45 46 struct OggSource : public MediaSource { 47 OggSource(const sp<OggExtractor> &extractor); 48 49 virtual sp<MetaData> getFormat(); 50 51 virtual status_t start(MetaData *params = NULL); 52 virtual status_t stop(); 53 54 virtual status_t read( 55 MediaBuffer **buffer, const ReadOptions *options = NULL); 56 57 protected: 58 virtual ~OggSource(); 59 60 private: 61 sp<OggExtractor> mExtractor; 62 bool mStarted; 63 64 OggSource(const OggSource &); 65 OggSource &operator=(const OggSource &); 66 }; 67 68 struct MyVorbisExtractor { 69 MyVorbisExtractor(const sp<DataSource> &source); 70 virtual ~MyVorbisExtractor(); 71 72 sp<MetaData> getFormat() const; 73 74 // Returns an approximate bitrate in bits per second. 75 uint64_t approxBitrate(); 76 77 status_t seekToTime(int64_t timeUs); 78 status_t seekToOffset(off64_t offset); 79 status_t readNextPacket(MediaBuffer **buffer, bool conf); 80 81 status_t init(); 82 83 sp<MetaData> getFileMetaData() { return mFileMeta; } 84 85 private: 86 struct Page { 87 uint64_t mGranulePosition; 88 int32_t mPrevPacketSize; 89 uint64_t mPrevPacketPos; 90 uint32_t mSerialNo; 91 uint32_t mPageNo; 92 uint8_t mFlags; 93 uint8_t mNumSegments; 94 uint8_t mLace[255]; 95 }; 96 97 struct TOCEntry { 98 off64_t mPageOffset; 99 int64_t mTimeUs; 100 }; 101 102 sp<DataSource> mSource; 103 off64_t mOffset; 104 Page mCurrentPage; 105 uint64_t mPrevGranulePosition; 106 size_t mCurrentPageSize; 107 bool mFirstPacketInPage; 108 uint64_t mCurrentPageSamples; 109 size_t mNextLaceIndex; 110 111 off64_t mFirstDataOffset; 112 113 vorbis_info mVi; 114 vorbis_comment mVc; 115 116 sp<MetaData> mMeta; 117 sp<MetaData> mFileMeta; 118 119 Vector<TOCEntry> mTableOfContents; 120 121 ssize_t readPage(off64_t offset, Page *page); 122 status_t findNextPage(off64_t startOffset, off64_t *pageOffset); 123 124 status_t verifyHeader( 125 MediaBuffer *buffer, uint8_t type); 126 127 int32_t packetBlockSize(MediaBuffer *buffer); 128 129 void parseFileMetaData(); 130 131 status_t findPrevGranulePosition(off64_t pageOffset, uint64_t *granulePos); 132 133 void buildTableOfContents(); 134 135 MyVorbisExtractor(const MyVorbisExtractor &); 136 MyVorbisExtractor &operator=(const MyVorbisExtractor &); 137 }; 138 139 static void extractAlbumArt( 140 const sp<MetaData> &fileMeta, const void *data, size_t size); 141 142 //////////////////////////////////////////////////////////////////////////////// 143 144 OggSource::OggSource(const sp<OggExtractor> &extractor) 145 : mExtractor(extractor), 146 mStarted(false) { 147 } 148 149 OggSource::~OggSource() { 150 if (mStarted) { 151 stop(); 152 } 153 } 154 155 sp<MetaData> OggSource::getFormat() { 156 return mExtractor->mImpl->getFormat(); 157 } 158 159 status_t OggSource::start(MetaData * /* params */) { 160 if (mStarted) { 161 return INVALID_OPERATION; 162 } 163 164 mStarted = true; 165 166 return OK; 167 } 168 169 status_t OggSource::stop() { 170 mStarted = false; 171 172 return OK; 173 } 174 175 status_t OggSource::read( 176 MediaBuffer **out, const ReadOptions *options) { 177 *out = NULL; 178 179 int64_t seekTimeUs; 180 ReadOptions::SeekMode mode; 181 if (options && options->getSeekTo(&seekTimeUs, &mode)) { 182 if (mExtractor->mImpl->seekToTime(seekTimeUs) != OK) { 183 return ERROR_END_OF_STREAM; 184 } 185 } 186 187 MediaBuffer *packet; 188 status_t err = mExtractor->mImpl->readNextPacket(&packet, /* conf = */ false); 189 190 if (err != OK) { 191 return err; 192 } 193 194 #if 0 195 int64_t timeUs; 196 if (packet->meta_data()->findInt64(kKeyTime, &timeUs)) { 197 ALOGI("found time = %lld us", timeUs); 198 } else { 199 ALOGI("NO time"); 200 } 201 #endif 202 203 packet->meta_data()->setInt32(kKeyIsSyncFrame, 1); 204 205 *out = packet; 206 207 return OK; 208 } 209 210 //////////////////////////////////////////////////////////////////////////////// 211 212 MyVorbisExtractor::MyVorbisExtractor(const sp<DataSource> &source) 213 : mSource(source), 214 mOffset(0), 215 mPrevGranulePosition(0), 216 mCurrentPageSize(0), 217 mFirstPacketInPage(true), 218 mCurrentPageSamples(0), 219 mNextLaceIndex(0), 220 mFirstDataOffset(-1) { 221 mCurrentPage.mNumSegments = 0; 222 223 vorbis_info_init(&mVi); 224 vorbis_comment_init(&mVc); 225 } 226 227 MyVorbisExtractor::~MyVorbisExtractor() { 228 vorbis_comment_clear(&mVc); 229 vorbis_info_clear(&mVi); 230 } 231 232 sp<MetaData> MyVorbisExtractor::getFormat() const { 233 return mMeta; 234 } 235 236 status_t MyVorbisExtractor::findNextPage( 237 off64_t startOffset, off64_t *pageOffset) { 238 *pageOffset = startOffset; 239 240 for (;;) { 241 char signature[4]; 242 ssize_t n = mSource->readAt(*pageOffset, &signature, 4); 243 244 if (n < 4) { 245 *pageOffset = 0; 246 247 return (n < 0) ? n : (status_t)ERROR_END_OF_STREAM; 248 } 249 250 if (!memcmp(signature, "OggS", 4)) { 251 if (*pageOffset > startOffset) { 252 ALOGV("skipped %lld bytes of junk to reach next frame", 253 *pageOffset - startOffset); 254 } 255 256 return OK; 257 } 258 259 ++*pageOffset; 260 } 261 } 262 263 // Given the offset of the "current" page, find the page immediately preceding 264 // it (if any) and return its granule position. 265 // To do this we back up from the "current" page's offset until we find any 266 // page preceding it and then scan forward to just before the current page. 267 status_t MyVorbisExtractor::findPrevGranulePosition( 268 off64_t pageOffset, uint64_t *granulePos) { 269 *granulePos = 0; 270 271 off64_t prevPageOffset = 0; 272 off64_t prevGuess = pageOffset; 273 for (;;) { 274 if (prevGuess >= 5000) { 275 prevGuess -= 5000; 276 } else { 277 prevGuess = 0; 278 } 279 280 ALOGV("backing up %lld bytes", pageOffset - prevGuess); 281 282 status_t err = findNextPage(prevGuess, &prevPageOffset); 283 if (err != OK) { 284 return err; 285 } 286 287 if (prevPageOffset < pageOffset || prevGuess == 0) { 288 break; 289 } 290 } 291 292 if (prevPageOffset == pageOffset) { 293 // We did not find a page preceding this one. 294 return UNKNOWN_ERROR; 295 } 296 297 ALOGV("prevPageOffset at %lld, pageOffset at %lld", 298 prevPageOffset, pageOffset); 299 300 for (;;) { 301 Page prevPage; 302 ssize_t n = readPage(prevPageOffset, &prevPage); 303 304 if (n <= 0) { 305 return (status_t)n; 306 } 307 308 prevPageOffset += n; 309 310 if (prevPageOffset == pageOffset) { 311 *granulePos = prevPage.mGranulePosition; 312 return OK; 313 } 314 } 315 } 316 317 status_t MyVorbisExtractor::seekToTime(int64_t timeUs) { 318 if (mTableOfContents.isEmpty()) { 319 // Perform approximate seeking based on avg. bitrate. 320 321 off64_t pos = timeUs * approxBitrate() / 8000000ll; 322 323 ALOGV("seeking to offset %lld", pos); 324 return seekToOffset(pos); 325 } 326 327 size_t left = 0; 328 size_t right_plus_one = mTableOfContents.size(); 329 while (left < right_plus_one) { 330 size_t center = left + (right_plus_one - left) / 2; 331 332 const TOCEntry &entry = mTableOfContents.itemAt(center); 333 334 if (timeUs < entry.mTimeUs) { 335 right_plus_one = center; 336 } else if (timeUs > entry.mTimeUs) { 337 left = center + 1; 338 } else { 339 left = center; 340 break; 341 } 342 } 343 344 if (left == mTableOfContents.size()) { 345 --left; 346 } 347 348 const TOCEntry &entry = mTableOfContents.itemAt(left); 349 350 ALOGV("seeking to entry %zu / %zu at offset %lld", 351 left, mTableOfContents.size(), entry.mPageOffset); 352 353 return seekToOffset(entry.mPageOffset); 354 } 355 356 status_t MyVorbisExtractor::seekToOffset(off64_t offset) { 357 if (mFirstDataOffset >= 0 && offset < mFirstDataOffset) { 358 // Once we know where the actual audio data starts (past the headers) 359 // don't ever seek to anywhere before that. 360 offset = mFirstDataOffset; 361 } 362 363 off64_t pageOffset; 364 status_t err = findNextPage(offset, &pageOffset); 365 366 if (err != OK) { 367 return err; 368 } 369 370 // We found the page we wanted to seek to, but we'll also need 371 // the page preceding it to determine how many valid samples are on 372 // this page. 373 findPrevGranulePosition(pageOffset, &mPrevGranulePosition); 374 375 mOffset = pageOffset; 376 377 mCurrentPageSize = 0; 378 mFirstPacketInPage = true; 379 mCurrentPageSamples = 0; 380 mCurrentPage.mNumSegments = 0; 381 mCurrentPage.mPrevPacketSize = -1; 382 mNextLaceIndex = 0; 383 384 // XXX what if new page continues packet from last??? 385 386 return OK; 387 } 388 389 ssize_t MyVorbisExtractor::readPage(off64_t offset, Page *page) { 390 uint8_t header[27]; 391 ssize_t n; 392 if ((n = mSource->readAt(offset, header, sizeof(header))) 393 < (ssize_t)sizeof(header)) { 394 ALOGV("failed to read %zu bytes at offset 0x%016llx, got %zd bytes", 395 sizeof(header), offset, n); 396 397 if (n < 0) { 398 return n; 399 } else if (n == 0) { 400 return ERROR_END_OF_STREAM; 401 } else { 402 return ERROR_IO; 403 } 404 } 405 406 if (memcmp(header, "OggS", 4)) { 407 return ERROR_MALFORMED; 408 } 409 410 if (header[4] != 0) { 411 // Wrong version. 412 413 return ERROR_UNSUPPORTED; 414 } 415 416 page->mFlags = header[5]; 417 418 if (page->mFlags & ~7) { 419 // Only bits 0-2 are defined in version 0. 420 return ERROR_MALFORMED; 421 } 422 423 page->mGranulePosition = U64LE_AT(&header[6]); 424 425 #if 0 426 printf("granulePosition = %llu (0x%llx)\n", 427 page->mGranulePosition, page->mGranulePosition); 428 #endif 429 430 page->mSerialNo = U32LE_AT(&header[14]); 431 page->mPageNo = U32LE_AT(&header[18]); 432 433 page->mNumSegments = header[26]; 434 if (mSource->readAt( 435 offset + sizeof(header), page->mLace, page->mNumSegments) 436 < (ssize_t)page->mNumSegments) { 437 return ERROR_IO; 438 } 439 440 size_t totalSize = 0;; 441 for (size_t i = 0; i < page->mNumSegments; ++i) { 442 totalSize += page->mLace[i]; 443 } 444 445 #if 0 446 String8 tmp; 447 for (size_t i = 0; i < page->mNumSegments; ++i) { 448 char x[32]; 449 sprintf(x, "%s%u", i > 0 ? ", " : "", (unsigned)page->mLace[i]); 450 451 tmp.append(x); 452 } 453 454 ALOGV("%c %s", page->mFlags & 1 ? '+' : ' ', tmp.string()); 455 #endif 456 457 return sizeof(header) + page->mNumSegments + totalSize; 458 } 459 460 status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out, bool conf) { 461 *out = NULL; 462 463 MediaBuffer *buffer = NULL; 464 int64_t timeUs = -1; 465 466 for (;;) { 467 size_t i; 468 size_t packetSize = 0; 469 bool gotFullPacket = false; 470 for (i = mNextLaceIndex; i < mCurrentPage.mNumSegments; ++i) { 471 uint8_t lace = mCurrentPage.mLace[i]; 472 473 packetSize += lace; 474 475 if (lace < 255) { 476 gotFullPacket = true; 477 ++i; 478 break; 479 } 480 } 481 482 if (mNextLaceIndex < mCurrentPage.mNumSegments) { 483 off64_t dataOffset = mOffset + 27 + mCurrentPage.mNumSegments; 484 for (size_t j = 0; j < mNextLaceIndex; ++j) { 485 dataOffset += mCurrentPage.mLace[j]; 486 } 487 488 size_t fullSize = packetSize; 489 if (buffer != NULL) { 490 fullSize += buffer->range_length(); 491 } 492 MediaBuffer *tmp = new MediaBuffer(fullSize); 493 if (buffer != NULL) { 494 memcpy(tmp->data(), buffer->data(), buffer->range_length()); 495 tmp->set_range(0, buffer->range_length()); 496 buffer->release(); 497 } else { 498 tmp->set_range(0, 0); 499 } 500 buffer = tmp; 501 502 ssize_t n = mSource->readAt( 503 dataOffset, 504 (uint8_t *)buffer->data() + buffer->range_length(), 505 packetSize); 506 507 if (n < (ssize_t)packetSize) { 508 ALOGV("failed to read %zu bytes at 0x%016llx, got %zd bytes", 509 packetSize, dataOffset, n); 510 return ERROR_IO; 511 } 512 513 buffer->set_range(0, fullSize); 514 515 mNextLaceIndex = i; 516 517 if (gotFullPacket) { 518 // We've just read the entire packet. 519 520 if (mFirstPacketInPage) { 521 buffer->meta_data()->setInt32( 522 kKeyValidSamples, mCurrentPageSamples); 523 mFirstPacketInPage = false; 524 } 525 526 // ignore timestamp for configuration packets 527 if (!conf) { 528 int32_t curBlockSize = packetBlockSize(buffer); 529 if (mCurrentPage.mPrevPacketSize < 0) { 530 mCurrentPage.mPrevPacketSize = curBlockSize; 531 mCurrentPage.mPrevPacketPos = 532 mCurrentPage.mGranulePosition - mCurrentPageSamples; 533 timeUs = mCurrentPage.mPrevPacketPos * 1000000ll / mVi.rate; 534 } else { 535 // The effective block size is the average of the two overlapped blocks 536 int32_t actualBlockSize = 537 (curBlockSize + mCurrentPage.mPrevPacketSize) / 2; 538 timeUs = mCurrentPage.mPrevPacketPos * 1000000ll / mVi.rate; 539 // The actual size output by the decoder will be half the effective 540 // size, due to the overlap 541 mCurrentPage.mPrevPacketPos += actualBlockSize / 2; 542 mCurrentPage.mPrevPacketSize = curBlockSize; 543 } 544 buffer->meta_data()->setInt64(kKeyTime, timeUs); 545 } 546 *out = buffer; 547 548 return OK; 549 } 550 551 // fall through, the buffer now contains the start of the packet. 552 } 553 554 CHECK_EQ(mNextLaceIndex, mCurrentPage.mNumSegments); 555 556 mOffset += mCurrentPageSize; 557 ssize_t n = readPage(mOffset, &mCurrentPage); 558 559 if (n <= 0) { 560 if (buffer) { 561 buffer->release(); 562 buffer = NULL; 563 } 564 565 ALOGV("readPage returned %zd", n); 566 567 return n < 0 ? n : (status_t)ERROR_END_OF_STREAM; 568 } 569 570 mCurrentPageSamples = 571 mCurrentPage.mGranulePosition - mPrevGranulePosition; 572 mFirstPacketInPage = true; 573 574 mPrevGranulePosition = mCurrentPage.mGranulePosition; 575 576 mCurrentPageSize = n; 577 mNextLaceIndex = 0; 578 579 if (buffer != NULL) { 580 if ((mCurrentPage.mFlags & 1) == 0) { 581 // This page does not continue the packet, i.e. the packet 582 // is already complete. 583 584 if (timeUs >= 0) { 585 buffer->meta_data()->setInt64(kKeyTime, timeUs); 586 } 587 588 buffer->meta_data()->setInt32( 589 kKeyValidSamples, mCurrentPageSamples); 590 mFirstPacketInPage = false; 591 592 *out = buffer; 593 594 return OK; 595 } 596 } 597 } 598 } 599 600 status_t MyVorbisExtractor::init() { 601 mMeta = new MetaData; 602 mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS); 603 604 MediaBuffer *packet; 605 status_t err; 606 if ((err = readNextPacket(&packet, /* conf = */ true)) != OK) { 607 return err; 608 } 609 ALOGV("read packet of size %zu\n", packet->range_length()); 610 err = verifyHeader(packet, 1); 611 packet->release(); 612 packet = NULL; 613 if (err != OK) { 614 return err; 615 } 616 617 if ((err = readNextPacket(&packet, /* conf = */ true)) != OK) { 618 return err; 619 } 620 ALOGV("read packet of size %zu\n", packet->range_length()); 621 err = verifyHeader(packet, 3); 622 packet->release(); 623 packet = NULL; 624 if (err != OK) { 625 return err; 626 } 627 628 if ((err = readNextPacket(&packet, /* conf = */ true)) != OK) { 629 return err; 630 } 631 ALOGV("read packet of size %zu\n", packet->range_length()); 632 err = verifyHeader(packet, 5); 633 packet->release(); 634 packet = NULL; 635 if (err != OK) { 636 return err; 637 } 638 639 mFirstDataOffset = mOffset + mCurrentPageSize; 640 641 off64_t size; 642 uint64_t lastGranulePosition; 643 if (!(mSource->flags() & DataSource::kIsCachingDataSource) 644 && mSource->getSize(&size) == OK 645 && findPrevGranulePosition(size, &lastGranulePosition) == OK) { 646 // Let's assume it's cheap to seek to the end. 647 // The granule position of the final page in the stream will 648 // give us the exact duration of the content, something that 649 // we can only approximate using avg. bitrate if seeking to 650 // the end is too expensive or impossible (live streaming). 651 652 int64_t durationUs = lastGranulePosition * 1000000ll / mVi.rate; 653 654 mMeta->setInt64(kKeyDuration, durationUs); 655 656 buildTableOfContents(); 657 } 658 659 return OK; 660 } 661 662 void MyVorbisExtractor::buildTableOfContents() { 663 off64_t offset = mFirstDataOffset; 664 Page page; 665 ssize_t pageSize; 666 while ((pageSize = readPage(offset, &page)) > 0) { 667 mTableOfContents.push(); 668 669 TOCEntry &entry = 670 mTableOfContents.editItemAt(mTableOfContents.size() - 1); 671 672 entry.mPageOffset = offset; 673 entry.mTimeUs = page.mGranulePosition * 1000000ll / mVi.rate; 674 675 offset += (size_t)pageSize; 676 } 677 678 // Limit the maximum amount of RAM we spend on the table of contents, 679 // if necessary thin out the table evenly to trim it down to maximum 680 // size. 681 682 static const size_t kMaxTOCSize = 8192; 683 static const size_t kMaxNumTOCEntries = kMaxTOCSize / sizeof(TOCEntry); 684 685 size_t numerator = mTableOfContents.size(); 686 687 if (numerator > kMaxNumTOCEntries) { 688 size_t denom = numerator - kMaxNumTOCEntries; 689 690 size_t accum = 0; 691 for (ssize_t i = mTableOfContents.size() - 1; i >= 0; --i) { 692 accum += denom; 693 if (accum >= numerator) { 694 mTableOfContents.removeAt(i); 695 accum -= numerator; 696 } 697 } 698 } 699 } 700 701 int32_t MyVorbisExtractor::packetBlockSize(MediaBuffer *buffer) { 702 const uint8_t *data = 703 (const uint8_t *)buffer->data() + buffer->range_offset(); 704 705 size_t size = buffer->range_length(); 706 707 ogg_buffer buf; 708 buf.data = (uint8_t *)data; 709 buf.size = size; 710 buf.refcount = 1; 711 buf.ptr.owner = NULL; 712 713 ogg_reference ref; 714 ref.buffer = &buf; 715 ref.begin = 0; 716 ref.length = size; 717 ref.next = NULL; 718 719 ogg_packet pack; 720 pack.packet = &ref; 721 pack.bytes = ref.length; 722 pack.b_o_s = 0; 723 pack.e_o_s = 0; 724 pack.granulepos = 0; 725 pack.packetno = 0; 726 727 return vorbis_packet_blocksize(&mVi, &pack); 728 } 729 730 status_t MyVorbisExtractor::verifyHeader( 731 MediaBuffer *buffer, uint8_t type) { 732 const uint8_t *data = 733 (const uint8_t *)buffer->data() + buffer->range_offset(); 734 735 size_t size = buffer->range_length(); 736 737 if (size < 7 || data[0] != type || memcmp(&data[1], "vorbis", 6)) { 738 return ERROR_MALFORMED; 739 } 740 741 ogg_buffer buf; 742 buf.data = (uint8_t *)data; 743 buf.size = size; 744 buf.refcount = 1; 745 buf.ptr.owner = NULL; 746 747 ogg_reference ref; 748 ref.buffer = &buf; 749 ref.begin = 0; 750 ref.length = size; 751 ref.next = NULL; 752 753 oggpack_buffer bits; 754 oggpack_readinit(&bits, &ref); 755 756 CHECK_EQ(oggpack_read(&bits, 8), type); 757 for (size_t i = 0; i < 6; ++i) { 758 oggpack_read(&bits, 8); // skip 'vorbis' 759 } 760 761 switch (type) { 762 case 1: 763 { 764 CHECK_EQ(0, _vorbis_unpack_info(&mVi, &bits)); 765 766 mMeta->setData(kKeyVorbisInfo, 0, data, size); 767 mMeta->setInt32(kKeySampleRate, mVi.rate); 768 mMeta->setInt32(kKeyChannelCount, mVi.channels); 769 770 ALOGV("lower-bitrate = %ld", mVi.bitrate_lower); 771 ALOGV("upper-bitrate = %ld", mVi.bitrate_upper); 772 ALOGV("nominal-bitrate = %ld", mVi.bitrate_nominal); 773 ALOGV("window-bitrate = %ld", mVi.bitrate_window); 774 ALOGV("blocksizes: %d/%d", 775 vorbis_info_blocksize(&mVi, 0), 776 vorbis_info_blocksize(&mVi, 1) 777 ); 778 779 off64_t size; 780 if (mSource->getSize(&size) == OK) { 781 uint64_t bps = approxBitrate(); 782 if (bps != 0) { 783 mMeta->setInt64(kKeyDuration, size * 8000000ll / bps); 784 } 785 } 786 break; 787 } 788 789 case 3: 790 { 791 if (0 != _vorbis_unpack_comment(&mVc, &bits)) { 792 return ERROR_MALFORMED; 793 } 794 795 parseFileMetaData(); 796 break; 797 } 798 799 case 5: 800 { 801 if (0 != _vorbis_unpack_books(&mVi, &bits)) { 802 return ERROR_MALFORMED; 803 } 804 805 mMeta->setData(kKeyVorbisBooks, 0, data, size); 806 break; 807 } 808 } 809 810 return OK; 811 } 812 813 uint64_t MyVorbisExtractor::approxBitrate() { 814 if (mVi.bitrate_nominal != 0) { 815 return mVi.bitrate_nominal; 816 } 817 818 return (mVi.bitrate_lower + mVi.bitrate_upper) / 2; 819 } 820 821 void MyVorbisExtractor::parseFileMetaData() { 822 mFileMeta = new MetaData; 823 mFileMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG); 824 825 for (int i = 0; i < mVc.comments; ++i) { 826 const char *comment = mVc.user_comments[i]; 827 size_t commentLength = mVc.comment_lengths[i]; 828 parseVorbisComment(mFileMeta, comment, commentLength); 829 //ALOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]); 830 } 831 } 832 833 void parseVorbisComment( 834 const sp<MetaData> &fileMeta, const char *comment, size_t commentLength) 835 { 836 struct { 837 const char *const mTag; 838 uint32_t mKey; 839 } kMap[] = { 840 { "TITLE", kKeyTitle }, 841 { "ARTIST", kKeyArtist }, 842 { "ALBUMARTIST", kKeyAlbumArtist }, 843 { "ALBUM ARTIST", kKeyAlbumArtist }, 844 { "COMPILATION", kKeyCompilation }, 845 { "ALBUM", kKeyAlbum }, 846 { "COMPOSER", kKeyComposer }, 847 { "GENRE", kKeyGenre }, 848 { "AUTHOR", kKeyAuthor }, 849 { "TRACKNUMBER", kKeyCDTrackNumber }, 850 { "DISCNUMBER", kKeyDiscNumber }, 851 { "DATE", kKeyDate }, 852 { "LYRICIST", kKeyWriter }, 853 { "METADATA_BLOCK_PICTURE", kKeyAlbumArt }, 854 { "ANDROID_LOOP", kKeyAutoLoop }, 855 }; 856 857 for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) { 858 size_t tagLen = strlen(kMap[j].mTag); 859 if (!strncasecmp(kMap[j].mTag, comment, tagLen) 860 && comment[tagLen] == '=') { 861 if (kMap[j].mKey == kKeyAlbumArt) { 862 extractAlbumArt( 863 fileMeta, 864 &comment[tagLen + 1], 865 commentLength - tagLen - 1); 866 } else if (kMap[j].mKey == kKeyAutoLoop) { 867 if (!strcasecmp(&comment[tagLen + 1], "true")) { 868 fileMeta->setInt32(kKeyAutoLoop, true); 869 } 870 } else { 871 fileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]); 872 } 873 } 874 } 875 876 } 877 878 // The returned buffer should be free()d. 879 static uint8_t *DecodeBase64(const char *s, size_t size, size_t *outSize) { 880 *outSize = 0; 881 882 if ((size % 4) != 0) { 883 return NULL; 884 } 885 886 size_t n = size; 887 size_t padding = 0; 888 if (n >= 1 && s[n - 1] == '=') { 889 padding = 1; 890 891 if (n >= 2 && s[n - 2] == '=') { 892 padding = 2; 893 } 894 } 895 896 size_t outLen = 3 * size / 4 - padding; 897 898 *outSize = outLen; 899 900 void *buffer = malloc(outLen); 901 902 uint8_t *out = (uint8_t *)buffer; 903 size_t j = 0; 904 uint32_t accum = 0; 905 for (size_t i = 0; i < n; ++i) { 906 char c = s[i]; 907 unsigned value; 908 if (c >= 'A' && c <= 'Z') { 909 value = c - 'A'; 910 } else if (c >= 'a' && c <= 'z') { 911 value = 26 + c - 'a'; 912 } else if (c >= '0' && c <= '9') { 913 value = 52 + c - '0'; 914 } else if (c == '+') { 915 value = 62; 916 } else if (c == '/') { 917 value = 63; 918 } else if (c != '=') { 919 return NULL; 920 } else { 921 if (i < n - padding) { 922 return NULL; 923 } 924 925 value = 0; 926 } 927 928 accum = (accum << 6) | value; 929 930 if (((i + 1) % 4) == 0) { 931 out[j++] = (accum >> 16); 932 933 if (j < outLen) { out[j++] = (accum >> 8) & 0xff; } 934 if (j < outLen) { out[j++] = accum & 0xff; } 935 936 accum = 0; 937 } 938 } 939 940 return (uint8_t *)buffer; 941 } 942 943 static void extractAlbumArt( 944 const sp<MetaData> &fileMeta, const void *data, size_t size) { 945 ALOGV("extractAlbumArt from '%s'", (const char *)data); 946 947 size_t flacSize; 948 uint8_t *flac = DecodeBase64((const char *)data, size, &flacSize); 949 950 if (flac == NULL) { 951 ALOGE("malformed base64 encoded data."); 952 return; 953 } 954 955 ALOGV("got flac of size %zu", flacSize); 956 957 uint32_t picType; 958 uint32_t typeLen; 959 uint32_t descLen; 960 uint32_t dataLen; 961 char type[128]; 962 963 if (flacSize < 8) { 964 goto exit; 965 } 966 967 picType = U32_AT(flac); 968 969 if (picType != 3) { 970 // This is not a front cover. 971 goto exit; 972 } 973 974 typeLen = U32_AT(&flac[4]); 975 if (typeLen + 1 > sizeof(type)) { 976 goto exit; 977 } 978 979 if (flacSize < 8 + typeLen) { 980 goto exit; 981 } 982 983 memcpy(type, &flac[8], typeLen); 984 type[typeLen] = '\0'; 985 986 ALOGV("picType = %d, type = '%s'", picType, type); 987 988 if (!strcmp(type, "-->")) { 989 // This is not inline cover art, but an external url instead. 990 goto exit; 991 } 992 993 descLen = U32_AT(&flac[8 + typeLen]); 994 995 if (flacSize < 32 + typeLen + descLen) { 996 goto exit; 997 } 998 999 dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]); 1000 1001 if (flacSize < 32 + typeLen + descLen + dataLen) { 1002 goto exit; 1003 } 1004 1005 ALOGV("got image data, %zu trailing bytes", 1006 flacSize - 32 - typeLen - descLen - dataLen); 1007 1008 fileMeta->setData( 1009 kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen); 1010 1011 fileMeta->setCString(kKeyAlbumArtMIME, type); 1012 1013 exit: 1014 free(flac); 1015 flac = NULL; 1016 } 1017 1018 //////////////////////////////////////////////////////////////////////////////// 1019 1020 OggExtractor::OggExtractor(const sp<DataSource> &source) 1021 : mDataSource(source), 1022 mInitCheck(NO_INIT), 1023 mImpl(NULL) { 1024 mImpl = new MyVorbisExtractor(mDataSource); 1025 mInitCheck = mImpl->seekToOffset(0); 1026 1027 if (mInitCheck == OK) { 1028 mInitCheck = mImpl->init(); 1029 } 1030 } 1031 1032 OggExtractor::~OggExtractor() { 1033 delete mImpl; 1034 mImpl = NULL; 1035 } 1036 1037 size_t OggExtractor::countTracks() { 1038 return mInitCheck != OK ? 0 : 1; 1039 } 1040 1041 sp<MediaSource> OggExtractor::getTrack(size_t index) { 1042 if (index >= 1) { 1043 return NULL; 1044 } 1045 1046 return new OggSource(this); 1047 } 1048 1049 sp<MetaData> OggExtractor::getTrackMetaData( 1050 size_t index, uint32_t /* flags */) { 1051 if (index >= 1) { 1052 return NULL; 1053 } 1054 1055 return mImpl->getFormat(); 1056 } 1057 1058 sp<MetaData> OggExtractor::getMetaData() { 1059 return mImpl->getFileMetaData(); 1060 } 1061 1062 bool SniffOgg( 1063 const sp<DataSource> &source, String8 *mimeType, float *confidence, 1064 sp<AMessage> *) { 1065 char tmp[4]; 1066 if (source->readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) { 1067 return false; 1068 } 1069 1070 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_OGG); 1071 *confidence = 0.2f; 1072 1073 return true; 1074 } 1075 1076 } // namespace android 1077