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