diff options
| -rw-r--r-- | include/media/stagefright/MediaDefs.h | 3 | ||||
| -rw-r--r-- | include/media/stagefright/MetaData.h | 2 | ||||
| -rw-r--r-- | include/media/stagefright/Utils.h | 4 | ||||
| -rw-r--r-- | media/libstagefright/Android.mk | 7 | ||||
| -rw-r--r-- | media/libstagefright/DataSource.cpp | 4 | ||||
| -rw-r--r-- | media/libstagefright/MediaDefs.cpp | 3 | ||||
| -rw-r--r-- | media/libstagefright/MediaExtractor.cpp | 6 | ||||
| -rw-r--r-- | media/libstagefright/OMXCodec.cpp | 4 | ||||
| -rw-r--r-- | media/libstagefright/OggExtractor.cpp | 586 | ||||
| -rw-r--r-- | media/libstagefright/StagefrightMediaScanner.cpp | 4 | ||||
| -rw-r--r-- | media/libstagefright/Utils.cpp | 12 | ||||
| -rw-r--r-- | media/libstagefright/VorbisExtractor.cpp | 343 | ||||
| -rw-r--r-- | media/libstagefright/codecs/vorbis/Android.mk | 4 | ||||
| -rw-r--r-- | media/libstagefright/codecs/vorbis/dec/Android.mk | 13 | ||||
| -rw-r--r-- | media/libstagefright/codecs/vorbis/dec/VorbisDecoder.cpp | 246 | ||||
| -rw-r--r-- | media/libstagefright/include/OggExtractor.h (renamed from media/libstagefright/include/VorbisExtractor.h) | 32 | ||||
| -rw-r--r-- | media/libstagefright/include/VorbisDecoder.h | 71 | 
17 files changed, 972 insertions, 372 deletions
| diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h index 4edfb88d6a6c..207195a4d688 100644 --- a/include/media/stagefright/MediaDefs.h +++ b/include/media/stagefright/MediaDefs.h @@ -32,11 +32,12 @@ extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB;  extern const char *MEDIA_MIMETYPE_AUDIO_MPEG;  extern const char *MEDIA_MIMETYPE_AUDIO_AAC;  extern const char *MEDIA_MIMETYPE_AUDIO_QCELP; +extern const char *MEDIA_MIMETYPE_AUDIO_VORBIS;  extern const char *MEDIA_MIMETYPE_AUDIO_RAW;  extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;  extern const char *MEDIA_MIMETYPE_CONTAINER_WAV; -extern const char *MEDIA_MIMETYPE_CONTAINER_VORBIS; +extern const char *MEDIA_MIMETYPE_CONTAINER_OGG;  }  // namespace android diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h index 45cc4f63b1d3..dc2bd50204ad 100644 --- a/include/media/stagefright/MetaData.h +++ b/include/media/stagefright/MetaData.h @@ -37,6 +37,8 @@ enum {      kKeyBitRate           = 'brte',  // int32_t (bps)      kKeyESDS              = 'esds',  // raw data      kKeyAVCC              = 'avcc',  // raw data +    kKeyVorbisInfo        = 'vinf',  // raw data +    kKeyVorbisBooks       = 'vboo',  // raw data      kKeyWantsNALFragments = 'NALf',      kKeyIsSyncFrame       = 'sync',  // int32_t (bool)      kKeyIsCodecConfig     = 'conf',  // int32_t (bool) diff --git a/include/media/stagefright/Utils.h b/include/media/stagefright/Utils.h index 30c7f1158138..498b525c7bd9 100644 --- a/include/media/stagefright/Utils.h +++ b/include/media/stagefright/Utils.h @@ -29,6 +29,10 @@ uint16_t U16_AT(const uint8_t *ptr);  uint32_t U32_AT(const uint8_t *ptr);  uint64_t U64_AT(const uint8_t *ptr); +uint16_t U16LE_AT(const uint8_t *ptr); +uint32_t U32LE_AT(const uint8_t *ptr); +uint64_t U64LE_AT(const uint8_t *ptr); +  uint64_t ntoh64(uint64_t x);  uint64_t hton64(uint64_t x); diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 0420a601ed6a..81f995b13758 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -31,6 +31,7 @@ LOCAL_SRC_FILES +=                \          MPEG4Extractor.cpp        \          MPEG4Writer.cpp           \          MediaExtractor.cpp        \ +        OggExtractor.cpp          \          Prefetcher.cpp            \          SampleIterator.cpp        \          SampleTable.cpp           \ @@ -39,7 +40,6 @@ LOCAL_SRC_FILES +=                \          StagefrightMetadataRetriever.cpp \          TimeSource.cpp            \          TimedEventQueue.cpp       \ -        VorbisExtractor.cpp       \          WAVExtractor.cpp          \          string.cpp @@ -50,7 +50,7 @@ LOCAL_C_INCLUDES:= \  	$(JNI_H_INCLUDE) \          $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \          $(TOP)/external/opencore/android \ -        $(TOP)/external/tremolo/Tremolo +        $(TOP)/external/tremolo  LOCAL_SHARED_LIBRARIES := \          libbinder         \ @@ -70,7 +70,8 @@ LOCAL_STATIC_LIBRARIES := \          libstagefright_amrwbdec \          libstagefright_avcdec \          libstagefright_m4vh263dec \ -        libstagefright_mp3dec +        libstagefright_mp3dec \ +        libstagefright_vorbisdec  LOCAL_SHARED_LIBRARIES += \          libstagefright_amrnb_common \ diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 5db3201e998b..a66f86b885fb 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -18,7 +18,7 @@  #include "include/MP3Extractor.h"  #include "include/MPEG4Extractor.h"  #include "include/WAVExtractor.h" -#include "include/VorbisExtractor.h" +#include "include/OggExtractor.h"  #include <media/stagefright/CachingDataSource.h>  #include <media/stagefright/DataSource.h> @@ -93,7 +93,7 @@ void DataSource::RegisterDefaultSniffers() {      RegisterSniffer(SniffMPEG4);      RegisterSniffer(SniffAMR);      RegisterSniffer(SniffWAV); -    RegisterSniffer(SniffVorbis); +    RegisterSniffer(SniffOgg);  }  // static diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp index db18ab6777c5..4b3813b69cd9 100644 --- a/media/libstagefright/MediaDefs.cpp +++ b/media/libstagefright/MediaDefs.cpp @@ -30,10 +30,11 @@ const char *MEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";  const char *MEDIA_MIMETYPE_AUDIO_MPEG = "audio/mpeg";  const char *MEDIA_MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";  const char *MEDIA_MIMETYPE_AUDIO_QCELP = "audio/qcelp"; +const char *MEDIA_MIMETYPE_AUDIO_VORBIS = "audio/vorbis";  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"; +const char *MEDIA_MIMETYPE_CONTAINER_OGG = "application/ogg";  }  // namespace android diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp index dfddbe0b132e..513f49c88b46 100644 --- a/media/libstagefright/MediaExtractor.cpp +++ b/media/libstagefright/MediaExtractor.cpp @@ -22,7 +22,7 @@  #include "include/MP3Extractor.h"  #include "include/MPEG4Extractor.h"  #include "include/WAVExtractor.h" -#include "include/VorbisExtractor.h" +#include "include/OggExtractor.h"  #include <media/stagefright/DataSource.h>  #include <media/stagefright/MediaDefs.h> @@ -67,8 +67,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); +    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) { +        return new OggExtractor(source);      }      return NULL; diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 6ed384cb75c0..69da7efe6915 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -25,6 +25,7 @@  #include "include/AVCDecoder.h"  #include "include/M4vH263Decoder.h"  #include "include/MP3Decoder.h" +#include "include/VorbisDecoder.h"  #include "include/ESDS.h" @@ -67,6 +68,7 @@ FACTORY_CREATE(AMRWBDecoder)  FACTORY_CREATE(AACDecoder)  FACTORY_CREATE(AVCDecoder)  FACTORY_CREATE(M4vH263Decoder) +FACTORY_CREATE(VorbisDecoder)  FACTORY_CREATE(AMRNBEncoder)  static sp<MediaSource> InstantiateSoftwareCodec( @@ -83,6 +85,7 @@ static sp<MediaSource> InstantiateSoftwareCodec(          FACTORY_REF(AACDecoder)          FACTORY_REF(AVCDecoder)          FACTORY_REF(M4vH263Decoder) +        FACTORY_REF(VorbisDecoder)          FACTORY_REF(AMRNBEncoder)      };      for (size_t i = 0; @@ -123,6 +126,7 @@ static const CodecInfo kDecoderInfo[] = {      { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.Decoder" },      { MEDIA_MIMETYPE_VIDEO_AVC, "AVCDecoder" },  //    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcdec" }, +    { MEDIA_MIMETYPE_AUDIO_VORBIS, "VorbisDecoder" },  };  static const CodecInfo kEncoderInfo[] = { diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp new file mode 100644 index 000000000000..699b9551b34f --- /dev/null +++ b/media/libstagefright/OggExtractor.cpp @@ -0,0 +1,586 @@ +/* + * 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 "OggExtractor" +#include <utils/Log.h> + +#include "include/OggExtractor.h" + +#include <cutils/properties.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 <media/stagefright/Utils.h> +#include <utils/String8.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 { + +struct OggSource : public MediaSource { +    OggSource(const sp<OggExtractor> &extractor); + +    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 ~OggSource(); + +private: +    sp<OggExtractor> mExtractor; +    bool mStarted; + +    OggSource(const OggSource &); +    OggSource &operator=(const OggSource &); +}; + +struct MyVorbisExtractor { +    MyVorbisExtractor(const sp<DataSource> &source); +    virtual ~MyVorbisExtractor(); + +    sp<MetaData> getFormat() const; + +    // Returns an approximate bitrate in bits per second. +    uint64_t approxBitrate(); + +    status_t seekToOffset(off_t offset); +    status_t readNextPacket(MediaBuffer **buffer); + +    void init(); + +private: +    struct Page { +        uint64_t mGranulePosition; +        uint32_t mSerialNo; +        uint32_t mPageNo; +        uint8_t mFlags; +        uint8_t mNumSegments; +        uint8_t mLace[255]; +    }; + +    sp<DataSource> mSource; +    off_t mOffset; +    Page mCurrentPage; +    size_t mCurrentPageSize; +    size_t mNextLaceIndex; + +    vorbis_info mVi; +    vorbis_comment mVc; + +    sp<MetaData> mMeta; + +    ssize_t readPage(off_t offset, Page *page); +    status_t findNextPage(off_t startOffset, off_t *pageOffset); + +    void verifyHeader( +            MediaBuffer *buffer, uint8_t type); + +    MyVorbisExtractor(const MyVorbisExtractor &); +    MyVorbisExtractor &operator=(const MyVorbisExtractor &); +}; + +//////////////////////////////////////////////////////////////////////////////// + +OggSource::OggSource(const sp<OggExtractor> &extractor) +    : mExtractor(extractor), +      mStarted(false) { +} + +OggSource::~OggSource() { +    if (mStarted) { +        stop(); +    } +} + +sp<MetaData> OggSource::getFormat() { +    return mExtractor->mImpl->getFormat(); +} + +status_t OggSource::start(MetaData *params) { +    if (mStarted) { +        return INVALID_OPERATION; +    } + +    mStarted = true; + +    return OK; +} + +status_t OggSource::stop() { +    mStarted = false; + +    return OK; +} + +status_t OggSource::read( +        MediaBuffer **out, const ReadOptions *options) { +    *out = NULL; + +    int64_t seekTimeUs; +    if (options && options->getSeekTo(&seekTimeUs)) { +        off_t pos = seekTimeUs * mExtractor->mImpl->approxBitrate() / 8000000ll; +        LOGI("seeking to offset %ld", pos); + +        if (mExtractor->mImpl->seekToOffset(pos) != OK) { +            return ERROR_END_OF_STREAM; +        } +    } + +    MediaBuffer *packet; +    status_t err = mExtractor->mImpl->readNextPacket(&packet); + +    if (err != OK) { +        return err; +    } + +#if 0 +    int64_t timeUs; +    if (packet->meta_data()->findInt64(kKeyTime, &timeUs)) { +        LOGI("found time = %lld us", timeUs); +    } else { +        LOGI("NO time"); +    } +#endif + +    *out = packet; + +    return OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +MyVorbisExtractor::MyVorbisExtractor(const sp<DataSource> &source) +    : mSource(source), +      mOffset(0), +      mCurrentPageSize(0), +      mNextLaceIndex(0) { +    mCurrentPage.mNumSegments = 0; +} + +MyVorbisExtractor::~MyVorbisExtractor() { +} + +sp<MetaData> MyVorbisExtractor::getFormat() const { +    return mMeta; +} + +status_t MyVorbisExtractor::findNextPage( +        off_t startOffset, off_t *pageOffset) { +    *pageOffset = startOffset; + +    for (;;) { +        char signature[4]; +        ssize_t n = mSource->readAt(*pageOffset, &signature, 4); + +        if (n < 4) { +            *pageOffset = 0; + +            return (n < 0) ? n : (status_t)ERROR_END_OF_STREAM; +        } + +        if (!memcmp(signature, "OggS", 4)) { +            if (*pageOffset > startOffset) { +                LOGV("skipped %ld bytes of junk to reach next frame", +                     *pageOffset - startOffset); +            } + +            return OK; +        } + +        ++*pageOffset; +    } +} + +status_t MyVorbisExtractor::seekToOffset(off_t offset) { +    off_t pageOffset; +    status_t err = findNextPage(offset, &pageOffset); + +    if (err != OK) { +        return err; +    } + +    mOffset = pageOffset; + +    mCurrentPageSize = 0; +    mCurrentPage.mNumSegments = 0; +    mNextLaceIndex = 0; + +    // XXX what if new page continues packet from last??? + +    return OK; +} + +ssize_t MyVorbisExtractor::readPage(off_t offset, Page *page) { +    uint8_t header[27]; +    if (mSource->readAt(offset, header, sizeof(header)) +            < (ssize_t)sizeof(header)) { +        LOGE("failed to read %d bytes at offset 0x%08lx", sizeof(header), offset); + +        return ERROR_IO; +    } + +    if (memcmp(header, "OggS", 4)) { +        return ERROR_MALFORMED; +    } + +    if (header[4] != 0) { +        // Wrong version. + +        return ERROR_UNSUPPORTED; +    } + +    page->mFlags = header[5]; + +    if (page->mFlags & ~7) { +        // Only bits 0-2 are defined in version 0. +        return ERROR_MALFORMED; +    } + +    page->mGranulePosition = U64LE_AT(&header[6]); + +#if 0 +    printf("granulePosition = %llu (0x%llx)\n", +           page->mGranulePosition, page->mGranulePosition); +#endif + +    page->mSerialNo = U32LE_AT(&header[14]); +    page->mPageNo = U32LE_AT(&header[18]); + +    page->mNumSegments = header[26]; +    if (mSource->readAt( +                offset + sizeof(header), page->mLace, page->mNumSegments) +            < (ssize_t)page->mNumSegments) { +        return ERROR_IO; +    } + +    size_t totalSize = 0;; +    for (size_t i = 0; i < page->mNumSegments; ++i) { +        totalSize += page->mLace[i]; +    } + +    String8 tmp; +    for (size_t i = 0; i < page->mNumSegments; ++i) { +        char x[32]; +        sprintf(x, "%s%u", i > 0 ? ", " : "", (unsigned)page->mLace[i]); + +        tmp.append(x); +    } + +    LOGV("%c %s", page->mFlags & 1 ? '+' : ' ', tmp.string()); + +    return sizeof(header) + page->mNumSegments + totalSize; +} + +status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) { +    *out = NULL; + +    MediaBuffer *buffer = NULL; +    int64_t timeUs = -1; + +    for (;;) { +        size_t i; +        size_t packetSize = 0; +        bool gotFullPacket = false; +        for (i = mNextLaceIndex; i < mCurrentPage.mNumSegments; ++i) { +            uint8_t lace = mCurrentPage.mLace[i]; + +            packetSize += lace; + +            if (lace < 255) { +                gotFullPacket = true; +                ++i; +                break; +            } +        } + +        if (mNextLaceIndex < mCurrentPage.mNumSegments) { +            off_t dataOffset = mOffset + 27 + mCurrentPage.mNumSegments; +            for (size_t j = 0; j < mNextLaceIndex; ++j) { +                dataOffset += mCurrentPage.mLace[j]; +            } + +            size_t fullSize = packetSize; +            if (buffer != NULL) { +                fullSize += buffer->range_length(); +            } +            MediaBuffer *tmp = new MediaBuffer(fullSize); +            if (buffer != NULL) { +                memcpy(tmp->data(), buffer->data(), buffer->range_length()); +                tmp->set_range(0, buffer->range_length()); +                buffer->release(); +            } else { +                // XXX Not only is this not technically the correct time for +                // this packet, we also stamp every packet in this page +                // with the same time. This needs fixing later. +                timeUs = mCurrentPage.mGranulePosition * 1000000ll / mVi.rate; +                tmp->set_range(0, 0); +            } +            buffer = tmp; + +            ssize_t n = mSource->readAt( +                    dataOffset, +                    (uint8_t *)buffer->data() + buffer->range_length(), +                    packetSize); + +            if (n < (ssize_t)packetSize) { +                LOGE("failed to read %d bytes at 0x%08lx", packetSize, dataOffset); +                return ERROR_IO; +            } + +            buffer->set_range(0, fullSize); + +            mNextLaceIndex = i; + +            if (gotFullPacket) { +                // We've just read the entire packet. + +                if (timeUs >= 0) { +                    buffer->meta_data()->setInt64(kKeyTime, timeUs); +                } + +                *out = buffer; + +                return OK; +            } + +            // fall through, the buffer now contains the start of the packet. +        } + +        CHECK_EQ(mNextLaceIndex, mCurrentPage.mNumSegments); + +        mOffset += mCurrentPageSize; +        ssize_t n = readPage(mOffset, &mCurrentPage); + +        if (n <= 0) { +            if (buffer) { +                buffer->release(); +                buffer = NULL; +            } + +            LOGE("readPage returned %ld", n); + +            return n < 0 ? n : (status_t)ERROR_END_OF_STREAM; +        } + +        mCurrentPageSize = n; +        mNextLaceIndex = 0; + +        if (buffer != NULL) { +            if ((mCurrentPage.mFlags & 1) == 0) { +                // This page does not continue the packet, i.e. the packet +                // is already complete. + +                if (timeUs >= 0) { +                    buffer->meta_data()->setInt64(kKeyTime, timeUs); +                } + +                *out = buffer; + +                return OK; +            } +        } +    } +} + +void MyVorbisExtractor::init() { +    vorbis_info_init(&mVi); + +    vorbis_comment mVc; + +    mMeta = new MetaData; +    mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS); + +    MediaBuffer *packet; +    CHECK_EQ(readNextPacket(&packet), OK); +    LOGV("read packet of size %d\n", packet->range_length()); +    verifyHeader(packet, 1); +    packet->release(); +    packet = NULL; + +    CHECK_EQ(readNextPacket(&packet), OK); +    LOGV("read packet of size %d\n", packet->range_length()); +    verifyHeader(packet, 3); +    packet->release(); +    packet = NULL; + +    CHECK_EQ(readNextPacket(&packet), OK); +    LOGV("read packet of size %d\n", packet->range_length()); +    verifyHeader(packet, 5); +    packet->release(); +    packet = NULL; +} + +void MyVorbisExtractor::verifyHeader( +        MediaBuffer *buffer, uint8_t type) { +    const uint8_t *data = +        (const uint8_t *)buffer->data() + buffer->range_offset(); + +    size_t size = buffer->range_length(); + +    CHECK(size >= 7); + +    CHECK_EQ(data[0], type); +    CHECK(!memcmp(&data[1], "vorbis", 6)); + +    ogg_buffer buf; +    buf.data = (uint8_t *)data; +    buf.size = size; +    buf.refcount = 1; +    buf.ptr.owner = NULL; + +    ogg_reference ref; +    ref.buffer = &buf; +    ref.begin = 0; +    ref.length = size; +    ref.next = NULL; + +    oggpack_buffer bits; +    oggpack_readinit(&bits, &ref); + +    CHECK_EQ(oggpack_read(&bits, 8), type); +    for (size_t i = 0; i < 6; ++i) { +        oggpack_read(&bits, 8);  // skip 'vorbis' +    } + +    switch (type) { +        case 1: +        { +            CHECK_EQ(0, _vorbis_unpack_info(&mVi, &bits)); + +            mMeta->setData(kKeyVorbisInfo, 0, data, size); +            mMeta->setInt32(kKeySampleRate, mVi.rate); +            mMeta->setInt32(kKeyChannelCount, mVi.channels); + +            LOGV("lower-bitrate = %ld", mVi.bitrate_lower); +            LOGV("upper-bitrate = %ld", mVi.bitrate_upper); +            LOGV("nominal-bitrate = %ld", mVi.bitrate_nominal); +            LOGV("window-bitrate = %ld", mVi.bitrate_window); + +            off_t size; +            if (mSource->getSize(&size) == OK) { +                uint64_t bps = approxBitrate(); + +                mMeta->setInt64(kKeyDuration, size * 8000000ll / bps); +            } +            break; +        } + +        case 3: +        { +            CHECK_EQ(0, _vorbis_unpack_comment(&mVc, &bits)); +            break; +        } + +        case 5: +        { +            CHECK_EQ(0, _vorbis_unpack_books(&mVi, &bits)); + +            mMeta->setData(kKeyVorbisBooks, 0, data, size); +            break; +        } +    } +} + +uint64_t MyVorbisExtractor::approxBitrate() { +    if (mVi.bitrate_nominal != 0) { +        return mVi.bitrate_nominal; +    } + +    return (mVi.bitrate_lower + mVi.bitrate_upper) / 2; +} + +//////////////////////////////////////////////////////////////////////////////// + +OggExtractor::OggExtractor(const sp<DataSource> &source) +    : mDataSource(source), +      mInitCheck(NO_INIT), +      mImpl(NULL) { +    mImpl = new MyVorbisExtractor(mDataSource); +    CHECK_EQ(mImpl->seekToOffset(0), OK); +    mImpl->init(); + +    mInitCheck = OK; +} + +OggExtractor::~OggExtractor() { +    delete mImpl; +    mImpl = NULL; +} + +size_t OggExtractor::countTracks() { +    return mInitCheck != OK ? 0 : 1; +} + +sp<MediaSource> OggExtractor::getTrack(size_t index) { +    if (index >= 1) { +        return NULL; +    } + +    return new OggSource(this); +} + +sp<MetaData> OggExtractor::getTrackMetaData( +        size_t index, uint32_t flags) { +    if (index >= 1) { +        return NULL; +    } + +    return mImpl->getFormat(); +} + +sp<MetaData> OggExtractor::getMetaData() { +    sp<MetaData> meta = new MetaData; + +    if (mInitCheck != OK) { +        return meta; +    } + +    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG); + +    return meta; +} + +bool SniffOgg( +        const sp<DataSource> &source, String8 *mimeType, float *confidence) { +    char tmp[4]; +    if (source->readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) { +        return false; +    } + +    mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_OGG); +    *confidence = 0.2f; + +    return true; +} + +}  // namespace android diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp index 34fb2bc68a43..03287dd1fe4c 100644 --- a/media/libstagefright/StagefrightMediaScanner.cpp +++ b/media/libstagefright/StagefrightMediaScanner.cpp @@ -27,8 +27,8 @@  #include <libsonivox/eas.h>  // Ogg Vorbis includes -#include "ivorbiscodec.h" -#include "ivorbisfile.h" +#include <Tremolo/ivorbiscodec.h> +#include <Tremolo/ivorbisfile.h>  namespace android { diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index 2720f93e14e0..c563ce64b0a1 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -32,6 +32,18 @@ uint64_t U64_AT(const uint8_t *ptr) {      return ((uint64_t)U32_AT(ptr)) << 32 | U32_AT(ptr + 4);  } +uint16_t U16LE_AT(const uint8_t *ptr) { +    return ptr[0] | (ptr[1] << 8); +} + +uint32_t U32LE_AT(const uint8_t *ptr) { +    return ptr[3] << 24 | ptr[2] << 16 | ptr[1] << 8 | ptr[0]; +} + +uint64_t U64LE_AT(const uint8_t *ptr) { +    return ((uint64_t)U32LE_AT(ptr + 4)) << 32 | U32LE_AT(ptr); +} +  // XXX warning: these won't work on big-endian host.  uint64_t ntoh64(uint64_t x) {      return ((uint64_t)ntohl(x & 0xffffffff) << 32) | ntohl(x >> 32); diff --git a/media/libstagefright/VorbisExtractor.cpp b/media/libstagefright/VorbisExtractor.cpp deleted file mode 100644 index e7b62d6502e1..000000000000 --- a/media/libstagefright/VorbisExtractor.cpp +++ /dev/null @@ -1,343 +0,0 @@ -/* - * 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 <cutils/properties.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; -    bool mSeekDisabled; -}; - -static bool ShouldDisableSeek(const sp<DataSource> &source) { -    char value[PROPERTY_VALUE_MAX]; -    if (property_get("media.vorbis.always-allow-seek", value, NULL) -            && (!strcmp(value, "1") || !strcasecmp(value, "true"))) { -        return false; -    } - -    // This is a workaround for an application streaming data through -    // a local HTTP proxy that doesn't really conform to the HTTP/1.1 -    // specs. We have to disable seek functionality in this case. - -    return source->flags() & DataSource::kStreamedFromLocalHost; -} - -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; - -    if (vds->mSeekDisabled) { -        errno = ESPIPE; -        return -1; -    } - -    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; -    mVorbisDataSource->mSeekDisabled = ShouldDisableSeek(mDataSource); - -    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; -    vds.mSeekDisabled = ShouldDisableSeek(source); - -    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; -} - -uint32_t VorbisExtractor::flags() const { -    if (ShouldDisableSeek(mDataSource)) { -        LOGI("This is streamed from local host, seek disabled"); -        return CAN_PAUSE; -    } else { -        return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE; -    } -} - -}  // namespace android diff --git a/media/libstagefright/codecs/vorbis/Android.mk b/media/libstagefright/codecs/vorbis/Android.mk new file mode 100644 index 000000000000..2e431205aa6d --- /dev/null +++ b/media/libstagefright/codecs/vorbis/Android.mk @@ -0,0 +1,4 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/media/libstagefright/codecs/vorbis/dec/Android.mk b/media/libstagefright/codecs/vorbis/dec/Android.mk new file mode 100644 index 000000000000..5c768c8aa0c5 --- /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 000000000000..5485f253d554 --- /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 diff --git a/media/libstagefright/include/VorbisExtractor.h b/media/libstagefright/include/OggExtractor.h index 2bb7deb9c783..7066669d01c7 100644 --- a/media/libstagefright/include/VorbisExtractor.h +++ b/media/libstagefright/include/OggExtractor.h @@ -14,23 +14,22 @@   * limitations under the License.   */ -#ifndef VORBIS_EXTRACTOR_H_ +#ifndef OGG_EXTRACTOR_H_ -#define VORBIS_EXTRACTOR_H_ +#define OGG_EXTRACTOR_H_  #include <media/stagefright/MediaExtractor.h> -struct OggVorbis_File; -  namespace android {  class DataSource;  class String8; -struct VorbisDataSource; +struct MyVorbisExtractor; +struct OggSource; -struct VorbisExtractor : public MediaExtractor { -    VorbisExtractor(const sp<DataSource> &source); +struct OggExtractor : public MediaExtractor { +    OggExtractor(const sp<DataSource> &source);      virtual size_t countTracks();      virtual sp<MediaSource> getTrack(size_t index); @@ -38,25 +37,24 @@ struct VorbisExtractor : public MediaExtractor {      virtual sp<MetaData> getMetaData(); -    uint32_t flags() const; -  protected: -    virtual ~VorbisExtractor(); +    virtual ~OggExtractor();  private: +    friend struct OggSource; +      sp<DataSource> mDataSource; -    struct OggVorbis_File *mFile; -    struct VorbisDataSource *mVorbisDataSource;      status_t mInitCheck; -    sp<MetaData> mMeta; -    VorbisExtractor(const VorbisExtractor &); -    VorbisExtractor &operator=(const VorbisExtractor &); +    MyVorbisExtractor *mImpl; + +    OggExtractor(const OggExtractor &); +    OggExtractor &operator=(const OggExtractor &);  }; -bool SniffVorbis( +bool SniffOgg(          const sp<DataSource> &source, String8 *mimeType, float *confidence);  }  // namespace android -#endif  // VORBIS_EXTRACTOR_H_ +#endif  // OGG_EXTRACTOR_H_ diff --git a/media/libstagefright/include/VorbisDecoder.h b/media/libstagefright/include/VorbisDecoder.h new file mode 100644 index 000000000000..e9a488a42a91 --- /dev/null +++ b/media/libstagefright/include/VorbisDecoder.h @@ -0,0 +1,71 @@ +/* + * 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_DECODER_H_ + +#define VORBIS_DECODER_H_ + +#include <media/stagefright/MediaSource.h> + +struct vorbis_dsp_state; +struct vorbis_info; + +namespace android { + +struct MediaBufferGroup; + +struct VorbisDecoder : public MediaSource { +    VorbisDecoder(const sp<MediaSource> &source); + +    virtual status_t start(MetaData *params); +    virtual status_t stop(); + +    virtual sp<MetaData> getFormat(); + +    virtual status_t read( +            MediaBuffer **buffer, const ReadOptions *options); + +protected: +    virtual ~VorbisDecoder(); + +private: +    enum { +        kMaxNumSamplesPerBuffer = 8192 * 2 +    }; + +    sp<MediaSource> mSource; +    bool mStarted; + +    MediaBufferGroup *mBufferGroup; + +    int32_t mNumChannels; +    int32_t mSampleRate; +    int64_t mAnchorTimeUs; +    int64_t mNumFramesOutput; + +    vorbis_dsp_state *mState; +    vorbis_info *mVi; + +    int decodePacket(MediaBuffer *packet, MediaBuffer *out); + +    VorbisDecoder(const VorbisDecoder &); +    VorbisDecoder &operator=(const VorbisDecoder &); +}; + +}  // namespace android + +#endif  // VORBIS_DECODER_H_ + |