/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "VorbisDecoder.h" #include #include #include #include #include extern "C" { #include int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb); int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb); int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb); } namespace android { VorbisDecoder::VorbisDecoder(const sp &source) : mSource(source), mStarted(false), mBufferGroup(NULL), mAnchorTimeUs(0), mNumFramesOutput(0), mState(NULL), mVi(NULL) { sp srcFormat = mSource->getFormat(); CHECK(srcFormat->findInt32(kKeyChannelCount, &mNumChannels)); CHECK(srcFormat->findInt32(kKeySampleRate, &mSampleRate)); } VorbisDecoder::~VorbisDecoder() { if (mStarted) { stop(); } } static void makeBitReader( const void *data, size_t size, ogg_buffer *buf, ogg_reference *ref, oggpack_buffer *bits) { buf->data = (uint8_t *)data; buf->size = size; buf->refcount = 1; buf->ptr.owner = NULL; ref->buffer = buf; ref->begin = 0; ref->length = size; ref->next = NULL; oggpack_readinit(bits, ref); } status_t VorbisDecoder::start(MetaData *params) { CHECK(!mStarted); mBufferGroup = new MediaBufferGroup; mBufferGroup->add_buffer( new MediaBuffer(kMaxNumSamplesPerBuffer * sizeof(int16_t))); mSource->start(); sp meta = mSource->getFormat(); mVi = new vorbis_info; vorbis_info_init(mVi); /////////////////////////////////////////////////////////////////////////// uint32_t type; const void *data; size_t size; CHECK(meta->findData(kKeyVorbisInfo, &type, &data, &size)); ogg_buffer buf; ogg_reference ref; oggpack_buffer bits; makeBitReader((const uint8_t *)data + 7, size - 7, &buf, &ref, &bits); CHECK_EQ(0, _vorbis_unpack_info(mVi, &bits)); /////////////////////////////////////////////////////////////////////////// CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size)); makeBitReader((const uint8_t *)data + 7, size - 7, &buf, &ref, &bits); CHECK_EQ(0, _vorbis_unpack_books(mVi, &bits)); /////////////////////////////////////////////////////////////////////////// mState = new vorbis_dsp_state; CHECK_EQ(0, vorbis_dsp_init(mState, mVi)); mAnchorTimeUs = 0; mNumFramesOutput = 0; mStarted = true; return OK; } status_t VorbisDecoder::stop() { CHECK(mStarted); vorbis_dsp_clear(mState); delete mState; mState = NULL; vorbis_info_clear(mVi); delete mVi; mVi = NULL; delete mBufferGroup; mBufferGroup = NULL; mSource->stop(); mStarted = false; return OK; } sp VorbisDecoder::getFormat() { sp srcFormat = mSource->getFormat(); sp meta = new MetaData; meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); meta->setInt32(kKeyChannelCount, mNumChannels); meta->setInt32(kKeySampleRate, mSampleRate); int64_t durationUs; if (srcFormat->findInt64(kKeyDuration, &durationUs)) { meta->setInt64(kKeyDuration, durationUs); } meta->setCString(kKeyDecoderComponent, "VorbisDecoder"); return meta; } int VorbisDecoder::decodePacket(MediaBuffer *packet, MediaBuffer *out) { ogg_buffer buf; buf.data = (uint8_t *)packet->data() + packet->range_offset(); buf.size = packet->range_length(); buf.refcount = 1; buf.ptr.owner = NULL; ogg_reference ref; ref.buffer = &buf; ref.begin = 0; ref.length = packet->range_length(); ref.next = NULL; ogg_packet pack; pack.packet = &ref; pack.bytes = packet->range_length(); pack.b_o_s = 0; pack.e_o_s = 0; pack.granulepos = 0; pack.packetno = 0; int numFrames = 0; int err = vorbis_dsp_synthesis(mState, &pack, 1); if (err != 0) { LOGW("vorbis_dsp_synthesis returned %d", err); } else { numFrames = vorbis_dsp_pcmout( mState, (int16_t *)out->data(), kMaxNumSamplesPerBuffer); if (numFrames < 0) { LOGE("vorbis_dsp_pcmout returned %d", numFrames); numFrames = 0; } } out->set_range(0, numFrames * sizeof(int16_t) * mNumChannels); return numFrames; } status_t VorbisDecoder::read( MediaBuffer **out, const ReadOptions *options) { status_t err; *out = NULL; int64_t seekTimeUs; ReadOptions::SeekMode mode; if (options && options->getSeekTo(&seekTimeUs, &mode)) { CHECK(seekTimeUs >= 0); mNumFramesOutput = 0; vorbis_dsp_restart(mState); } else { seekTimeUs = -1; } MediaBuffer *inputBuffer; err = mSource->read(&inputBuffer, options); if (err != OK) { return ERROR_END_OF_STREAM; } int64_t timeUs; if (inputBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) { mAnchorTimeUs = timeUs; mNumFramesOutput = 0; } else { // We must have a new timestamp after seeking. CHECK(seekTimeUs < 0); } MediaBuffer *outputBuffer; CHECK_EQ(mBufferGroup->acquire_buffer(&outputBuffer), OK); int numFrames = decodePacket(inputBuffer, outputBuffer); inputBuffer->release(); inputBuffer = NULL; outputBuffer->meta_data()->setInt64( kKeyTime, mAnchorTimeUs + (mNumFramesOutput * 1000000ll) / mSampleRate); mNumFramesOutput += numFrames; *out = outputBuffer; return OK; } } // namespace android