diff options
Diffstat (limited to 'media/libstagefright')
-rw-r--r-- | media/libstagefright/Android.mk | 1 | ||||
-rw-r--r-- | media/libstagefright/DataSource.cpp | 2 | ||||
-rw-r--r-- | media/libstagefright/MediaDefs.cpp | 1 | ||||
-rw-r--r-- | media/libstagefright/MediaExtractor.cpp | 3 | ||||
-rw-r--r-- | media/libstagefright/VorbisExtractor.cpp | 311 | ||||
-rw-r--r-- | media/libstagefright/include/VorbisExtractor.h | 60 |
6 files changed, 378 insertions, 0 deletions
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 2a65766..8191cc7 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -39,6 +39,7 @@ LOCAL_SRC_FILES += \ StagefrightMetadataRetriever.cpp \ TimeSource.cpp \ TimedEventQueue.cpp \ + VorbisExtractor.cpp \ WAVExtractor.cpp \ string.cpp diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 86e4bfe..5db3201 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -18,6 +18,7 @@ #include "include/MP3Extractor.h" #include "include/MPEG4Extractor.h" #include "include/WAVExtractor.h" +#include "include/VorbisExtractor.h" #include <media/stagefright/CachingDataSource.h> #include <media/stagefright/DataSource.h> @@ -92,6 +93,7 @@ void DataSource::RegisterDefaultSniffers() { RegisterSniffer(SniffMPEG4); RegisterSniffer(SniffAMR); RegisterSniffer(SniffWAV); + RegisterSniffer(SniffVorbis); } // static diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp index 3a89170..db18ab6 100644 --- a/media/libstagefright/MediaDefs.cpp +++ b/media/libstagefright/MediaDefs.cpp @@ -34,5 +34,6 @@ const char *MEDIA_MIMETYPE_AUDIO_RAW = "audio/raw"; const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mpeg4"; const char *MEDIA_MIMETYPE_CONTAINER_WAV = "audio/wav"; +const char *MEDIA_MIMETYPE_CONTAINER_VORBIS = "application/ogg"; } // namespace android diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp index 738e18a..832db04 100644 --- a/media/libstagefright/MediaExtractor.cpp +++ b/media/libstagefright/MediaExtractor.cpp @@ -22,6 +22,7 @@ #include "include/MP3Extractor.h" #include "include/MPEG4Extractor.h" #include "include/WAVExtractor.h" +#include "include/VorbisExtractor.h" #include <media/stagefright/DataSource.h> #include <media/stagefright/MediaDefs.h> @@ -62,6 +63,8 @@ sp<MediaExtractor> MediaExtractor::Create( return new AMRExtractor(source); } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) { return new WAVExtractor(source); + } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_VORBIS)) { + return new VorbisExtractor(source); } return NULL; diff --git a/media/libstagefright/VorbisExtractor.cpp b/media/libstagefright/VorbisExtractor.cpp new file mode 100644 index 0000000..96b05c0 --- /dev/null +++ b/media/libstagefright/VorbisExtractor.cpp @@ -0,0 +1,311 @@ +/* + * 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. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "VorbisExtractor" +#include <utils/Log.h> + +#include "include/VorbisExtractor.h" + +#include <media/stagefright/DataSource.h> +#include <media/stagefright/MediaBuffer.h> +#include <media/stagefright/MediaBufferGroup.h> +#include <media/stagefright/MediaDebug.h> +#include <media/stagefright/MediaDefs.h> +#include <media/stagefright/MediaErrors.h> +#include <media/stagefright/MediaSource.h> +#include <media/stagefright/MetaData.h> +#include <utils/String8.h> + +#include <ivorbisfile.h> + +namespace android { + +struct VorbisDataSource { + sp<DataSource> mDataSource; + off_t mOffset; +}; + +static size_t VorbisRead( + void *ptr, size_t size, size_t nmemb, void *datasource) { + VorbisDataSource *vds = (VorbisDataSource *)datasource; + + ssize_t n = vds->mDataSource->readAt(vds->mOffset, ptr, size * nmemb); + + if (n < 0) { + return n; + } + + vds->mOffset += n; + + return n / size; +} + +static int VorbisSeek( + void *datasource, ogg_int64_t offset, int whence) { + VorbisDataSource *vds = (VorbisDataSource *)datasource; + + switch (whence) { + case SEEK_SET: + vds->mOffset = offset; + break; + case SEEK_END: + { + off_t size; + if (vds->mDataSource->getSize(&size) != OK) { + errno = ESPIPE; + return -1; + } + + vds->mOffset = offset + size; + break; + } + + case SEEK_CUR: + { + vds->mOffset += offset; + break; + } + + default: + { + errno = EINVAL; + return -1; + } + } + + return 0; +} + +static int VorbisClose(void *datasource) { + return 0; +} + +static long VorbisTell(void *datasource) { + VorbisDataSource *vds = (VorbisDataSource *)datasource; + + return vds->mOffset; +} + +static const ov_callbacks gVorbisCallbacks = { + &VorbisRead, + &VorbisSeek, + &VorbisClose, + &VorbisTell +}; + +//////////////////////////////////////////////////////////////////////////////// + +struct VorbisSource : public MediaSource { + VorbisSource(const sp<VorbisExtractor> &extractor, + const sp<MetaData> &meta, OggVorbis_File *file); + + virtual sp<MetaData> getFormat(); + + virtual status_t start(MetaData *params = NULL); + virtual status_t stop(); + + virtual status_t read( + MediaBuffer **buffer, const ReadOptions *options = NULL); + +protected: + virtual ~VorbisSource(); + +private: + enum { + kMaxBufferSize = 8192 + }; + + sp<VorbisExtractor> mExtractor; + sp<MetaData> mMeta; + OggVorbis_File *mFile; + MediaBufferGroup *mGroup; + + VorbisSource(const VorbisSource &); + VorbisSource &operator=(const VorbisSource &); +}; + +VorbisSource::VorbisSource( + const sp<VorbisExtractor> &extractor, + const sp<MetaData> &meta, OggVorbis_File *file) + : mExtractor(extractor), + mMeta(meta), + mFile(file), + mGroup(NULL) { +} + +VorbisSource::~VorbisSource() { + if (mGroup) { + stop(); + } +} + +sp<MetaData> VorbisSource::getFormat() { + return mMeta; +} + +status_t VorbisSource::start(MetaData *params) { + if (mGroup != NULL) { + return INVALID_OPERATION; + } + + mGroup = new MediaBufferGroup; + mGroup->add_buffer(new MediaBuffer(kMaxBufferSize)); + + return OK; +} + +status_t VorbisSource::stop() { + delete mGroup; + mGroup = NULL; + + return OK; +} + +status_t VorbisSource::read( + MediaBuffer **out, const ReadOptions *options) { + *out = NULL; + + int64_t seekTimeUs; + if (options && options->getSeekTo(&seekTimeUs)) { + ov_time_seek(mFile, seekTimeUs / 1000ll); + } + + MediaBuffer *buffer; + CHECK_EQ(OK, mGroup->acquire_buffer(&buffer)); + + ogg_int64_t positionMs = ov_time_tell(mFile); + + int bitstream; + long n = ov_read(mFile, buffer->data(), buffer->size(), &bitstream); + + if (n <= 0) { + LOGE("ov_read returned %ld", n); + + buffer->release(); + buffer = NULL; + + return n < 0 ? ERROR_MALFORMED : ERROR_END_OF_STREAM; + } + + buffer->set_range(0, n); + buffer->meta_data()->setInt64(kKeyTime, positionMs * 1000ll); + + *out = buffer; + + return OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +VorbisExtractor::VorbisExtractor(const sp<DataSource> &source) + : mDataSource(source), + mFile(new OggVorbis_File), + mVorbisDataSource(new VorbisDataSource), + mInitCheck(NO_INIT) { + mVorbisDataSource->mDataSource = mDataSource; + mVorbisDataSource->mOffset = 0; + + int res = ov_open_callbacks( + mVorbisDataSource, mFile, NULL, 0, gVorbisCallbacks); + + if (res != 0) { + return; + } + + mMeta = new MetaData; + mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); + + vorbis_info *vi = ov_info(mFile, -1); + mMeta->setInt32(kKeySampleRate, vi->rate); + mMeta->setInt32(kKeyChannelCount, vi->channels); + + ogg_int64_t durationMs = ov_time_total(mFile, -1); + mMeta->setInt64(kKeyDuration, durationMs * 1000ll); + + LOGI("Successfully initialized."); + + mInitCheck = OK; +} + +VorbisExtractor::~VorbisExtractor() { + CHECK_EQ(0, ov_clear(mFile)); + + delete mVorbisDataSource; + mVorbisDataSource = NULL; + + delete mFile; + mFile = NULL; +} + +size_t VorbisExtractor::countTracks() { + return mInitCheck != OK ? 0 : 1; +} + +sp<MediaSource> VorbisExtractor::getTrack(size_t index) { + if (index >= 1) { + return NULL; + } + + return new VorbisSource(this, mMeta, mFile); +} + +sp<MetaData> VorbisExtractor::getTrackMetaData( + size_t index, uint32_t flags) { + if (index >= 1) { + return NULL; + } + + return mMeta; +} + +sp<MetaData> VorbisExtractor::getMetaData() { + sp<MetaData> meta = new MetaData; + + if (mInitCheck != OK) { + return meta; + } + + meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_VORBIS); + + return meta; +} + +bool SniffVorbis( + const sp<DataSource> &source, String8 *mimeType, float *confidence) { + OggVorbis_File file; + + VorbisDataSource vds; + vds.mDataSource = source; + vds.mOffset = 0; + + int res = ov_test_callbacks(&vds, &file, NULL, 0, gVorbisCallbacks); + + CHECK_EQ(0, ov_clear(&file)); + + if (res != 0) { + return false; + } + + *mimeType = MEDIA_MIMETYPE_CONTAINER_VORBIS; + *confidence = 0.4f; + + LOGV("This looks like an Ogg file."); + + return true; +} + +} // namespace android diff --git a/media/libstagefright/include/VorbisExtractor.h b/media/libstagefright/include/VorbisExtractor.h new file mode 100644 index 0000000..8e38a93 --- /dev/null +++ b/media/libstagefright/include/VorbisExtractor.h @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#ifndef VORBIS_EXTRACTOR_H_ + +#define VORBIS_EXTRACTOR_H_ + +#include <media/stagefright/MediaExtractor.h> + +struct OggVorbis_File; + +namespace android { + +class DataSource; +class String8; + +struct VorbisDataSource; + +struct VorbisExtractor : public MediaExtractor { + VorbisExtractor(const sp<DataSource> &source); + + virtual size_t countTracks(); + virtual sp<MediaSource> getTrack(size_t index); + virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags); + + virtual sp<MetaData> getMetaData(); + +protected: + virtual ~VorbisExtractor(); + +private: + sp<DataSource> mDataSource; + struct OggVorbis_File *mFile; + struct VorbisDataSource *mVorbisDataSource; + status_t mInitCheck; + sp<MetaData> mMeta; + + VorbisExtractor(const VorbisExtractor &); + VorbisExtractor &operator=(const VorbisExtractor &); +}; + +bool SniffVorbis( + const sp<DataSource> &source, String8 *mimeType, float *confidence); + +} // namespace android + +#endif // VORBIS_EXTRACTOR_H_ |