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