status_t MyVorbisExtractor::init() { mMeta = new MetaData; mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS); MediaBuffer *packet; status_t err; if ((err = readNextPacket(&packet)) != OK) { return err; } ALOGV("read packet of size %d\n", packet->range_length()); err = verifyHeader(packet, 1); packet->release(); packet = NULL; if (err != OK) { return err; } if ((err = readNextPacket(&packet)) != OK) { return err; } ALOGV("read packet of size %d\n", packet->range_length()); err = verifyHeader(packet, 3); packet->release(); packet = NULL; if (err != OK) { return err; } if ((err = readNextPacket(&packet)) != OK) { return err; } ALOGV("read packet of size %d\n", packet->range_length()); err = verifyHeader(packet, 5); packet->release(); packet = NULL; if (err != OK) { return err; } mFirstDataOffset = mOffset + mCurrentPageSize; off64_t size; uint64_t lastGranulePosition; if (mSource->getSize(&size) == OK && findPrevGranulePosition(size, &lastGranulePosition) == OK) { // Let's assume it's cheap to seek to the end. // The granule position of the final page in the stream will // give us the exact duration of the content, something that // we can only approximate using avg. bitrate if seeking to // the end is too expensive or impossible (live streaming). int64_t durationUs = lastGranulePosition * 1000000ll / mVi.rate; mMeta->setInt64(kKeyDuration, durationUs); buildTableOfContents(); } return OK; }
status_t MyVorbisExtractor::seekToOffset(off64_t offset) { if (mFirstDataOffset >= 0 && offset < mFirstDataOffset) { // Once we know where the actual audio data starts (past the headers) // don't ever seek to anywhere before that. offset = mFirstDataOffset; } off64_t pageOffset; status_t err = findNextPage(offset, &pageOffset); if (err != OK) { return err; } // We found the page we wanted to seek to, but we'll also need // the page preceding it to determine how many valid samples are on // this page. findPrevGranulePosition(pageOffset, &mPrevGranulePosition); mOffset = pageOffset; mCurrentPageSize = 0; mFirstPacketInPage = true; mCurrentPageSamples = 0; mCurrentPage.mNumSegments = 0; mNextLaceIndex = 0; // XXX what if new page continues packet from last??? return OK; }
status_t MyVorbisExtractor::findGranulePositionofPage(off64_t offset,uint64_t *granulePositionofPage) { if (mFirstDataOffset >= 0 && offset < mFirstDataOffset) { // Once we know where the actual audio data starts (past the headers) // don't ever seek to anywhere before that. offset = mFirstDataOffset; } if(((uint64_t)offset) == mFileSize) { findPrevGranulePosition(mFileSize, granulePositionofPage); if((*granulePositionofPage) < 0xFFFFFFFFFFFF) return OK; else return UNKNOWN_ERROR; } off64_t pageOffset; status_t err = findNextPage_l(offset, &pageOffset); if (err != OK) { err = findNextPage(offset, &pageOffset); if((err == OK) && (offset == pageOffset)) { Page page; readPage(offset, &page); *granulePositionofPage = page.mGranulePosition; } else findPrevGranulePosition(mFileSize, granulePositionofPage); if((*granulePositionofPage) < 0xFFFFFFFFFFFF) return OK; else return UNKNOWN_ERROR; } // We found the page we wanted to seek to, but we'll also need // the page preceding it to determine how many valid samples are on // this page. findPrevGranulePosition(pageOffset, granulePositionofPage); if((*granulePositionofPage) < 0xFFFFFFFFFFFF) return OK; else return UNKNOWN_ERROR; }