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