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 35extern "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 43namespace android { 44 45struct 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 56protected: 57 virtual ~OggSource(); 58 59private: 60 sp<OggExtractor> mExtractor; 61 bool mStarted; 62 63 OggSource(const OggSource &); 64 OggSource &operator=(const OggSource &); 65}; 66 67struct 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 83private: 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 127OggSource::OggSource(const sp<OggExtractor> &extractor) 128 : mExtractor(extractor), 129 mStarted(false) { 130} 131 132OggSource::~OggSource() { 133 if (mStarted) { 134 stop(); 135 } 136} 137 138sp<MetaData> OggSource::getFormat() { 139 return mExtractor->mImpl->getFormat(); 140} 141 142status_t OggSource::start(MetaData *params) { 143 if (mStarted) { 144 return INVALID_OPERATION; 145 } 146 147 mStarted = true; 148 149 return OK; 150} 151 152status_t OggSource::stop() { 153 mStarted = false; 154 155 return OK; 156} 157 158status_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 198MyVorbisExtractor::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 213MyVorbisExtractor::~MyVorbisExtractor() { 214 vorbis_comment_clear(&mVc); 215 vorbis_info_clear(&mVi); 216} 217 218sp<MetaData> MyVorbisExtractor::getFormat() const { 219 return mMeta; 220} 221 222status_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. 253uint64_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 295status_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 327ssize_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 390status_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 523status_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 567status_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 645uint64_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 653void 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 { "ALBUMARTIST", kKeyAlbumArtist }, 664 { "ALBUM ARTIST", kKeyAlbumArtist }, 665 { "COMPILATION", kKeyCompilation }, 666 { "ALBUM", kKeyAlbum }, 667 { "COMPOSER", kKeyComposer }, 668 { "GENRE", kKeyGenre }, 669 { "AUTHOR", kKeyAuthor }, 670 { "TRACKNUMBER", kKeyCDTrackNumber }, 671 { "DISCNUMBER", kKeyDiscNumber }, 672 { "DATE", kKeyDate }, 673 { "LYRICIST", kKeyWriter }, 674 { "METADATA_BLOCK_PICTURE", kKeyAlbumArt }, 675 { "ANDROID_LOOP", kKeyAutoLoop }, 676 }; 677 678 for (int i = 0; i < mVc.comments; ++i) { 679 const char *comment = mVc.user_comments[i]; 680 681 for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) { 682 size_t tagLen = strlen(kMap[j].mTag); 683 if (!strncasecmp(kMap[j].mTag, comment, tagLen) 684 && comment[tagLen] == '=') { 685 if (kMap[j].mKey == kKeyAlbumArt) { 686 extractAlbumArt( 687 &comment[tagLen + 1], 688 mVc.comment_lengths[i] - tagLen - 1); 689 } else if (kMap[j].mKey == kKeyAutoLoop) { 690 if (!strcasecmp(&comment[tagLen + 1], "true")) { 691 mFileMeta->setInt32(kKeyAutoLoop, true); 692 } 693 } else { 694 mFileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]); 695 } 696 } 697 } 698 } 699 700#if 0 701 for (int i = 0; i < mVc.comments; ++i) { 702 LOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]); 703 } 704#endif 705} 706 707// The returned buffer should be free()d. 708static uint8_t *DecodeBase64(const char *s, size_t size, size_t *outSize) { 709 *outSize = 0; 710 711 if ((size % 4) != 0) { 712 return NULL; 713 } 714 715 size_t n = size; 716 size_t padding = 0; 717 if (n >= 1 && s[n - 1] == '=') { 718 padding = 1; 719 720 if (n >= 2 && s[n - 2] == '=') { 721 padding = 2; 722 } 723 } 724 725 size_t outLen = 3 * size / 4 - padding; 726 727 *outSize = outLen; 728 729 void *buffer = malloc(outLen); 730 731 uint8_t *out = (uint8_t *)buffer; 732 size_t j = 0; 733 uint32_t accum = 0; 734 for (size_t i = 0; i < n; ++i) { 735 char c = s[i]; 736 unsigned value; 737 if (c >= 'A' && c <= 'Z') { 738 value = c - 'A'; 739 } else if (c >= 'a' && c <= 'z') { 740 value = 26 + c - 'a'; 741 } else if (c >= '0' && c <= '9') { 742 value = 52 + c - '0'; 743 } else if (c == '+') { 744 value = 62; 745 } else if (c == '/') { 746 value = 63; 747 } else if (c != '=') { 748 return NULL; 749 } else { 750 if (i < n - padding) { 751 return NULL; 752 } 753 754 value = 0; 755 } 756 757 accum = (accum << 6) | value; 758 759 if (((i + 1) % 4) == 0) { 760 out[j++] = (accum >> 16); 761 762 if (j < outLen) { out[j++] = (accum >> 8) & 0xff; } 763 if (j < outLen) { out[j++] = accum & 0xff; } 764 765 accum = 0; 766 } 767 } 768 769 return (uint8_t *)buffer; 770} 771 772void MyVorbisExtractor::extractAlbumArt(const void *data, size_t size) { 773 LOGV("extractAlbumArt from '%s'", (const char *)data); 774 775 size_t flacSize; 776 uint8_t *flac = DecodeBase64((const char *)data, size, &flacSize); 777 778 if (flac == NULL) { 779 LOGE("malformed base64 encoded data."); 780 return; 781 } 782 783 LOGV("got flac of size %d", flacSize); 784 785 uint32_t picType; 786 uint32_t typeLen; 787 uint32_t descLen; 788 uint32_t dataLen; 789 char type[128]; 790 791 if (flacSize < 8) { 792 goto exit; 793 } 794 795 picType = U32_AT(flac); 796 797 if (picType != 3) { 798 // This is not a front cover. 799 goto exit; 800 } 801 802 typeLen = U32_AT(&flac[4]); 803 if (typeLen + 1 > sizeof(type)) { 804 goto exit; 805 } 806 807 if (flacSize < 8 + typeLen) { 808 goto exit; 809 } 810 811 memcpy(type, &flac[8], typeLen); 812 type[typeLen] = '\0'; 813 814 LOGV("picType = %d, type = '%s'", picType, type); 815 816 if (!strcmp(type, "-->")) { 817 // This is not inline cover art, but an external url instead. 818 goto exit; 819 } 820 821 descLen = U32_AT(&flac[8 + typeLen]); 822 823 if (flacSize < 32 + typeLen + descLen) { 824 goto exit; 825 } 826 827 dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]); 828 829 if (flacSize < 32 + typeLen + descLen + dataLen) { 830 goto exit; 831 } 832 833 LOGV("got image data, %d trailing bytes", 834 flacSize - 32 - typeLen - descLen - dataLen); 835 836 mFileMeta->setData( 837 kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen); 838 839 mFileMeta->setCString(kKeyAlbumArtMIME, type); 840 841exit: 842 free(flac); 843 flac = NULL; 844} 845 846//////////////////////////////////////////////////////////////////////////////// 847 848OggExtractor::OggExtractor(const sp<DataSource> &source) 849 : mDataSource(source), 850 mInitCheck(NO_INIT), 851 mImpl(NULL) { 852 mImpl = new MyVorbisExtractor(mDataSource); 853 mInitCheck = mImpl->seekToOffset(0); 854 855 if (mInitCheck == OK) { 856 mInitCheck = mImpl->init(); 857 } 858} 859 860OggExtractor::~OggExtractor() { 861 delete mImpl; 862 mImpl = NULL; 863} 864 865size_t OggExtractor::countTracks() { 866 return mInitCheck != OK ? 0 : 1; 867} 868 869sp<MediaSource> OggExtractor::getTrack(size_t index) { 870 if (index >= 1) { 871 return NULL; 872 } 873 874 return new OggSource(this); 875} 876 877sp<MetaData> OggExtractor::getTrackMetaData( 878 size_t index, uint32_t flags) { 879 if (index >= 1) { 880 return NULL; 881 } 882 883 return mImpl->getFormat(); 884} 885 886sp<MetaData> OggExtractor::getMetaData() { 887 return mImpl->getFileMetaData(); 888} 889 890bool SniffOgg( 891 const sp<DataSource> &source, String8 *mimeType, float *confidence, 892 sp<AMessage> *) { 893 char tmp[4]; 894 if (source->readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) { 895 return false; 896 } 897 898 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_OGG); 899 *confidence = 0.2f; 900 901 return true; 902} 903 904} // namespace android 905