summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/codecs/vorbis/dec
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2010-05-07 10:35:13 -0700
committerAndreas Huber <andih@google.com>2010-05-07 12:01:45 -0700
commitee7ff20e69498ebd53dd9717a0f984188341a75e (patch)
tree2338621414d60b23ec50dd5f28fc413fb957a59e /media/libstagefright/codecs/vorbis/dec
parentf9325834de1ae004212aec2fd03445b4eebfa766 (diff)
downloadframeworks_av-ee7ff20e69498ebd53dd9717a0f984188341a75e.zip
frameworks_av-ee7ff20e69498ebd53dd9717a0f984188341a75e.tar.gz
frameworks_av-ee7ff20e69498ebd53dd9717a0f984188341a75e.tar.bz2
A new OggExtractor/VorbisDecoder combo to support approximate seeking.
Change-Id: Id5d0c1c8b1adc62896bb5ed951f7b5cfda811e95 related-to-bug: 2654400
Diffstat (limited to 'media/libstagefright/codecs/vorbis/dec')
-rw-r--r--media/libstagefright/codecs/vorbis/dec/Android.mk13
-rw-r--r--media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp246
2 files changed, 259 insertions, 0 deletions
diff --git a/media/libstagefright/codecs/vorbis/dec/Android.mk b/media/libstagefright/codecs/vorbis/dec/Android.mk
new file mode 100644
index 0000000..5c768c8
--- /dev/null
+++ b/media/libstagefright/codecs/vorbis/dec/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ VorbisDecoder.cpp \
+
+LOCAL_C_INCLUDES := \
+ frameworks/base/media/libstagefright/include \
+ external/tremolo
+
+LOCAL_MODULE := libstagefright_vorbisdec
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp b/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp
new file mode 100644
index 0000000..5485f25
--- /dev/null
+++ b/media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp
@@ -0,0 +1,246 @@
+/*
+ * 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 <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+
+extern "C" {
+ #include <Tremolo/codec_internal.h>
+
+ 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<MediaSource> &source)
+ : mSource(source),
+ mStarted(false),
+ mBufferGroup(NULL),
+ mAnchorTimeUs(0),
+ mNumFramesOutput(0),
+ mState(NULL),
+ mVi(NULL) {
+ sp<MetaData> 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<MetaData> 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<MetaData> VorbisDecoder::getFormat() {
+ sp<MetaData> srcFormat = mSource->getFormat();
+
+ sp<MetaData> 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 err = vorbis_dsp_synthesis(mState, &pack, 1);
+ if (err != 0) {
+ LOGW("vorbis_dsp_synthesis returned %d", err);
+ return 0;
+ }
+
+ int numFrames = vorbis_dsp_pcmout(
+ mState, (int16_t *)out->data(), kMaxNumSamplesPerBuffer);
+
+ if (numFrames < 0) {
+ LOGE("vorbis_dsp_pcmout returned %d", numFrames);
+ return 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;
+ if (options && options->getSeekTo(&seekTimeUs)) {
+ CHECK(seekTimeUs >= 0);
+
+ mNumFramesOutput = 0;
+ } 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