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