OggExtractor.cpp revision 7a493d8578bb00cf10190053a4caf1d07f4e24f7
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 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 long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op); 42} 43 44namespace android { 45 46struct 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 57protected: 58 virtual ~OggSource(); 59 60private: 61 sp<OggExtractor> mExtractor; 62 bool mStarted; 63 64 OggSource(const OggSource &); 65 OggSource &operator=(const OggSource &); 66}; 67 68struct 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); 80 81 status_t init(); 82 83 sp<MetaData> getFileMetaData() { return mFileMeta; } 84 85private: 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 139static void extractAlbumArt( 140 const sp<MetaData> &fileMeta, const void *data, size_t size); 141 142//////////////////////////////////////////////////////////////////////////////// 143 144OggSource::OggSource(const sp<OggExtractor> &extractor) 145 : mExtractor(extractor), 146 mStarted(false) { 147} 148 149OggSource::~OggSource() { 150 if (mStarted) { 151 stop(); 152 } 153} 154 155sp<MetaData> OggSource::getFormat() { 156 return mExtractor->mImpl->getFormat(); 157} 158 159status_t OggSource::start(MetaData * /* params */) { 160 if (mStarted) { 161 return INVALID_OPERATION; 162 } 163 164 mStarted = true; 165 166 return OK; 167} 168 169status_t OggSource::stop() { 170 mStarted = false; 171 172 return OK; 173} 174 175status_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); 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 212MyVorbisExtractor::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 227MyVorbisExtractor::~MyVorbisExtractor() { 228 vorbis_comment_clear(&mVc); 229 vorbis_info_clear(&mVi); 230} 231 232sp<MetaData> MyVorbisExtractor::getFormat() const { 233 return mMeta; 234} 235 236status_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. 267status_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 317status_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 356status_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 389ssize_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 460status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) { 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 if (mVi.rate) { 527 // Rate may not have been initialized yet if we're currently 528 // reading the configuration packets... 529 // Fortunately, the timestamp doesn't matter for those. 530 int32_t curBlockSize = packetBlockSize(buffer); 531 if (mCurrentPage.mPrevPacketSize < 0) { 532 mCurrentPage.mPrevPacketSize = curBlockSize; 533 mCurrentPage.mPrevPacketPos = 534 mCurrentPage.mGranulePosition - mCurrentPageSamples; 535 timeUs = mCurrentPage.mPrevPacketPos * 1000000ll / mVi.rate; 536 } else { 537 // The effective block size is the average of the two overlapped blocks 538 int32_t actualBlockSize = 539 (curBlockSize + mCurrentPage.mPrevPacketSize) / 2; 540 timeUs = mCurrentPage.mPrevPacketPos * 1000000ll / mVi.rate; 541 // The actual size output by the decoder will be half the effective 542 // size, due to the overlap 543 mCurrentPage.mPrevPacketPos += actualBlockSize / 2; 544 mCurrentPage.mPrevPacketSize = curBlockSize; 545 } 546 buffer->meta_data()->setInt64(kKeyTime, timeUs); 547 } 548 *out = buffer; 549 550 return OK; 551 } 552 553 // fall through, the buffer now contains the start of the packet. 554 } 555 556 CHECK_EQ(mNextLaceIndex, mCurrentPage.mNumSegments); 557 558 mOffset += mCurrentPageSize; 559 ssize_t n = readPage(mOffset, &mCurrentPage); 560 561 if (n <= 0) { 562 if (buffer) { 563 buffer->release(); 564 buffer = NULL; 565 } 566 567 ALOGV("readPage returned %zd", n); 568 569 return n < 0 ? n : (status_t)ERROR_END_OF_STREAM; 570 } 571 572 mCurrentPageSamples = 573 mCurrentPage.mGranulePosition - mPrevGranulePosition; 574 mFirstPacketInPage = true; 575 576 mPrevGranulePosition = mCurrentPage.mGranulePosition; 577 578 mCurrentPageSize = n; 579 mNextLaceIndex = 0; 580 581 if (buffer != NULL) { 582 if ((mCurrentPage.mFlags & 1) == 0) { 583 // This page does not continue the packet, i.e. the packet 584 // is already complete. 585 586 if (timeUs >= 0) { 587 buffer->meta_data()->setInt64(kKeyTime, timeUs); 588 } 589 590 buffer->meta_data()->setInt32( 591 kKeyValidSamples, mCurrentPageSamples); 592 mFirstPacketInPage = false; 593 594 *out = buffer; 595 596 return OK; 597 } 598 } 599 } 600} 601 602status_t MyVorbisExtractor::init() { 603 mMeta = new MetaData; 604 mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS); 605 606 MediaBuffer *packet; 607 status_t err; 608 if ((err = readNextPacket(&packet)) != OK) { 609 return err; 610 } 611 ALOGV("read packet of size %zu\n", packet->range_length()); 612 err = verifyHeader(packet, 1); 613 packet->release(); 614 packet = NULL; 615 if (err != OK) { 616 return err; 617 } 618 619 if ((err = readNextPacket(&packet)) != OK) { 620 return err; 621 } 622 ALOGV("read packet of size %zu\n", packet->range_length()); 623 err = verifyHeader(packet, 3); 624 packet->release(); 625 packet = NULL; 626 if (err != OK) { 627 return err; 628 } 629 630 if ((err = readNextPacket(&packet)) != OK) { 631 return err; 632 } 633 ALOGV("read packet of size %zu\n", packet->range_length()); 634 err = verifyHeader(packet, 5); 635 packet->release(); 636 packet = NULL; 637 if (err != OK) { 638 return err; 639 } 640 641 mFirstDataOffset = mOffset + mCurrentPageSize; 642 643 off64_t size; 644 uint64_t lastGranulePosition; 645 if (!(mSource->flags() & DataSource::kIsCachingDataSource) 646 && mSource->getSize(&size) == OK 647 && findPrevGranulePosition(size, &lastGranulePosition) == OK) { 648 // Let's assume it's cheap to seek to the end. 649 // The granule position of the final page in the stream will 650 // give us the exact duration of the content, something that 651 // we can only approximate using avg. bitrate if seeking to 652 // the end is too expensive or impossible (live streaming). 653 654 int64_t durationUs = lastGranulePosition * 1000000ll / mVi.rate; 655 656 mMeta->setInt64(kKeyDuration, durationUs); 657 658 buildTableOfContents(); 659 } 660 661 return OK; 662} 663 664void MyVorbisExtractor::buildTableOfContents() { 665 off64_t offset = mFirstDataOffset; 666 Page page; 667 ssize_t pageSize; 668 while ((pageSize = readPage(offset, &page)) > 0) { 669 mTableOfContents.push(); 670 671 TOCEntry &entry = 672 mTableOfContents.editItemAt(mTableOfContents.size() - 1); 673 674 entry.mPageOffset = offset; 675 entry.mTimeUs = page.mGranulePosition * 1000000ll / mVi.rate; 676 677 offset += (size_t)pageSize; 678 } 679 680 // Limit the maximum amount of RAM we spend on the table of contents, 681 // if necessary thin out the table evenly to trim it down to maximum 682 // size. 683 684 static const size_t kMaxTOCSize = 8192; 685 static const size_t kMaxNumTOCEntries = kMaxTOCSize / sizeof(TOCEntry); 686 687 size_t numerator = mTableOfContents.size(); 688 689 if (numerator > kMaxNumTOCEntries) { 690 size_t denom = numerator - kMaxNumTOCEntries; 691 692 size_t accum = 0; 693 for (ssize_t i = mTableOfContents.size() - 1; i >= 0; --i) { 694 accum += denom; 695 if (accum >= numerator) { 696 mTableOfContents.removeAt(i); 697 accum -= numerator; 698 } 699 } 700 } 701} 702 703int32_t MyVorbisExtractor::packetBlockSize(MediaBuffer *buffer) { 704 const uint8_t *data = 705 (const uint8_t *)buffer->data() + buffer->range_offset(); 706 707 size_t size = buffer->range_length(); 708 709 ogg_buffer buf; 710 buf.data = (uint8_t *)data; 711 buf.size = size; 712 buf.refcount = 1; 713 buf.ptr.owner = NULL; 714 715 ogg_reference ref; 716 ref.buffer = &buf; 717 ref.begin = 0; 718 ref.length = size; 719 ref.next = NULL; 720 721 ogg_packet pack; 722 pack.packet = &ref; 723 pack.bytes = ref.length; 724 pack.b_o_s = 0; 725 pack.e_o_s = 0; 726 pack.granulepos = 0; 727 pack.packetno = 0; 728 729 return vorbis_packet_blocksize(&mVi, &pack); 730} 731 732status_t MyVorbisExtractor::verifyHeader( 733 MediaBuffer *buffer, uint8_t type) { 734 const uint8_t *data = 735 (const uint8_t *)buffer->data() + buffer->range_offset(); 736 737 size_t size = buffer->range_length(); 738 739 if (size < 7 || data[0] != type || memcmp(&data[1], "vorbis", 6)) { 740 return ERROR_MALFORMED; 741 } 742 743 ogg_buffer buf; 744 buf.data = (uint8_t *)data; 745 buf.size = size; 746 buf.refcount = 1; 747 buf.ptr.owner = NULL; 748 749 ogg_reference ref; 750 ref.buffer = &buf; 751 ref.begin = 0; 752 ref.length = size; 753 ref.next = NULL; 754 755 oggpack_buffer bits; 756 oggpack_readinit(&bits, &ref); 757 758 CHECK_EQ(oggpack_read(&bits, 8), type); 759 for (size_t i = 0; i < 6; ++i) { 760 oggpack_read(&bits, 8); // skip 'vorbis' 761 } 762 763 switch (type) { 764 case 1: 765 { 766 CHECK_EQ(0, _vorbis_unpack_info(&mVi, &bits)); 767 768 mMeta->setData(kKeyVorbisInfo, 0, data, size); 769 mMeta->setInt32(kKeySampleRate, mVi.rate); 770 mMeta->setInt32(kKeyChannelCount, mVi.channels); 771 772 ALOGV("lower-bitrate = %ld", mVi.bitrate_lower); 773 ALOGV("upper-bitrate = %ld", mVi.bitrate_upper); 774 ALOGV("nominal-bitrate = %ld", mVi.bitrate_nominal); 775 ALOGV("window-bitrate = %ld", mVi.bitrate_window); 776 ALOGV("blocksizes: %d/%d", 777 vorbis_info_blocksize(&mVi, 0), 778 vorbis_info_blocksize(&mVi, 1) 779 ); 780 781 off64_t size; 782 if (mSource->getSize(&size) == OK) { 783 uint64_t bps = approxBitrate(); 784 if (bps != 0) { 785 mMeta->setInt64(kKeyDuration, size * 8000000ll / bps); 786 } 787 } 788 break; 789 } 790 791 case 3: 792 { 793 if (0 != _vorbis_unpack_comment(&mVc, &bits)) { 794 return ERROR_MALFORMED; 795 } 796 797 parseFileMetaData(); 798 break; 799 } 800 801 case 5: 802 { 803 if (0 != _vorbis_unpack_books(&mVi, &bits)) { 804 return ERROR_MALFORMED; 805 } 806 807 mMeta->setData(kKeyVorbisBooks, 0, data, size); 808 break; 809 } 810 } 811 812 return OK; 813} 814 815uint64_t MyVorbisExtractor::approxBitrate() { 816 if (mVi.bitrate_nominal != 0) { 817 return mVi.bitrate_nominal; 818 } 819 820 return (mVi.bitrate_lower + mVi.bitrate_upper) / 2; 821} 822 823void MyVorbisExtractor::parseFileMetaData() { 824 mFileMeta = new MetaData; 825 mFileMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG); 826 827 for (int i = 0; i < mVc.comments; ++i) { 828 const char *comment = mVc.user_comments[i]; 829 size_t commentLength = mVc.comment_lengths[i]; 830 parseVorbisComment(mFileMeta, comment, commentLength); 831 //ALOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]); 832 } 833} 834 835void parseVorbisComment( 836 const sp<MetaData> &fileMeta, const char *comment, size_t commentLength) 837{ 838 struct { 839 const char *const mTag; 840 uint32_t mKey; 841 } kMap[] = { 842 { "TITLE", kKeyTitle }, 843 { "ARTIST", kKeyArtist }, 844 { "ALBUMARTIST", kKeyAlbumArtist }, 845 { "ALBUM ARTIST", kKeyAlbumArtist }, 846 { "COMPILATION", kKeyCompilation }, 847 { "ALBUM", kKeyAlbum }, 848 { "COMPOSER", kKeyComposer }, 849 { "GENRE", kKeyGenre }, 850 { "AUTHOR", kKeyAuthor }, 851 { "TRACKNUMBER", kKeyCDTrackNumber }, 852 { "DISCNUMBER", kKeyDiscNumber }, 853 { "DATE", kKeyDate }, 854 { "LYRICIST", kKeyWriter }, 855 { "METADATA_BLOCK_PICTURE", kKeyAlbumArt }, 856 { "ANDROID_LOOP", kKeyAutoLoop }, 857 }; 858 859 for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) { 860 size_t tagLen = strlen(kMap[j].mTag); 861 if (!strncasecmp(kMap[j].mTag, comment, tagLen) 862 && comment[tagLen] == '=') { 863 if (kMap[j].mKey == kKeyAlbumArt) { 864 extractAlbumArt( 865 fileMeta, 866 &comment[tagLen + 1], 867 commentLength - tagLen - 1); 868 } else if (kMap[j].mKey == kKeyAutoLoop) { 869 if (!strcasecmp(&comment[tagLen + 1], "true")) { 870 fileMeta->setInt32(kKeyAutoLoop, true); 871 } 872 } else { 873 fileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]); 874 } 875 } 876 } 877 878} 879 880// The returned buffer should be free()d. 881static uint8_t *DecodeBase64(const char *s, size_t size, size_t *outSize) { 882 *outSize = 0; 883 884 if ((size % 4) != 0) { 885 return NULL; 886 } 887 888 size_t n = size; 889 size_t padding = 0; 890 if (n >= 1 && s[n - 1] == '=') { 891 padding = 1; 892 893 if (n >= 2 && s[n - 2] == '=') { 894 padding = 2; 895 } 896 } 897 898 size_t outLen = 3 * size / 4 - padding; 899 900 *outSize = outLen; 901 902 void *buffer = malloc(outLen); 903 904 uint8_t *out = (uint8_t *)buffer; 905 size_t j = 0; 906 uint32_t accum = 0; 907 for (size_t i = 0; i < n; ++i) { 908 char c = s[i]; 909 unsigned value; 910 if (c >= 'A' && c <= 'Z') { 911 value = c - 'A'; 912 } else if (c >= 'a' && c <= 'z') { 913 value = 26 + c - 'a'; 914 } else if (c >= '0' && c <= '9') { 915 value = 52 + c - '0'; 916 } else if (c == '+') { 917 value = 62; 918 } else if (c == '/') { 919 value = 63; 920 } else if (c != '=') { 921 return NULL; 922 } else { 923 if (i < n - padding) { 924 return NULL; 925 } 926 927 value = 0; 928 } 929 930 accum = (accum << 6) | value; 931 932 if (((i + 1) % 4) == 0) { 933 out[j++] = (accum >> 16); 934 935 if (j < outLen) { out[j++] = (accum >> 8) & 0xff; } 936 if (j < outLen) { out[j++] = accum & 0xff; } 937 938 accum = 0; 939 } 940 } 941 942 return (uint8_t *)buffer; 943} 944 945static void extractAlbumArt( 946 const sp<MetaData> &fileMeta, const void *data, size_t size) { 947 ALOGV("extractAlbumArt from '%s'", (const char *)data); 948 949 size_t flacSize; 950 uint8_t *flac = DecodeBase64((const char *)data, size, &flacSize); 951 952 if (flac == NULL) { 953 ALOGE("malformed base64 encoded data."); 954 return; 955 } 956 957 ALOGV("got flac of size %zu", flacSize); 958 959 uint32_t picType; 960 uint32_t typeLen; 961 uint32_t descLen; 962 uint32_t dataLen; 963 char type[128]; 964 965 if (flacSize < 8) { 966 goto exit; 967 } 968 969 picType = U32_AT(flac); 970 971 if (picType != 3) { 972 // This is not a front cover. 973 goto exit; 974 } 975 976 typeLen = U32_AT(&flac[4]); 977 if (typeLen + 1 > sizeof(type)) { 978 goto exit; 979 } 980 981 if (flacSize < 8 + typeLen) { 982 goto exit; 983 } 984 985 memcpy(type, &flac[8], typeLen); 986 type[typeLen] = '\0'; 987 988 ALOGV("picType = %d, type = '%s'", picType, type); 989 990 if (!strcmp(type, "-->")) { 991 // This is not inline cover art, but an external url instead. 992 goto exit; 993 } 994 995 descLen = U32_AT(&flac[8 + typeLen]); 996 997 if (flacSize < 32 + typeLen + descLen) { 998 goto exit; 999 } 1000 1001 dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]); 1002 1003 if (flacSize < 32 + typeLen + descLen + dataLen) { 1004 goto exit; 1005 } 1006 1007 ALOGV("got image data, %zu trailing bytes", 1008 flacSize - 32 - typeLen - descLen - dataLen); 1009 1010 fileMeta->setData( 1011 kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen); 1012 1013 fileMeta->setCString(kKeyAlbumArtMIME, type); 1014 1015exit: 1016 free(flac); 1017 flac = NULL; 1018} 1019 1020//////////////////////////////////////////////////////////////////////////////// 1021 1022OggExtractor::OggExtractor(const sp<DataSource> &source) 1023 : mDataSource(source), 1024 mInitCheck(NO_INIT), 1025 mImpl(NULL) { 1026 mImpl = new MyVorbisExtractor(mDataSource); 1027 mInitCheck = mImpl->seekToOffset(0); 1028 1029 if (mInitCheck == OK) { 1030 mInitCheck = mImpl->init(); 1031 } 1032} 1033 1034OggExtractor::~OggExtractor() { 1035 delete mImpl; 1036 mImpl = NULL; 1037} 1038 1039size_t OggExtractor::countTracks() { 1040 return mInitCheck != OK ? 0 : 1; 1041} 1042 1043sp<MediaSource> OggExtractor::getTrack(size_t index) { 1044 if (index >= 1) { 1045 return NULL; 1046 } 1047 1048 return new OggSource(this); 1049} 1050 1051sp<MetaData> OggExtractor::getTrackMetaData( 1052 size_t index, uint32_t /* flags */) { 1053 if (index >= 1) { 1054 return NULL; 1055 } 1056 1057 return mImpl->getFormat(); 1058} 1059 1060sp<MetaData> OggExtractor::getMetaData() { 1061 return mImpl->getFileMetaData(); 1062} 1063 1064bool SniffOgg( 1065 const sp<DataSource> &source, String8 *mimeType, float *confidence, 1066 sp<AMessage> *) { 1067 char tmp[4]; 1068 if (source->readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) { 1069 return false; 1070 } 1071 1072 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_OGG); 1073 *confidence = 0.2f; 1074 1075 return true; 1076} 1077 1078} // namespace android 1079