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