OggExtractor.cpp revision efdd088a71ddd0a96cf9ca2f58e8703fe8c5c494
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "OggExtractor"
19#include <utils/Log.h>
20
21#include "include/OggExtractor.h"
22
23#include <cutils/properties.h>
24#include <media/stagefright/DataSource.h>
25#include <media/stagefright/MediaBuffer.h>
26#include <media/stagefright/MediaBufferGroup.h>
27#include <media/stagefright/MediaDebug.h>
28#include <media/stagefright/MediaDefs.h>
29#include <media/stagefright/MediaErrors.h>
30#include <media/stagefright/MediaSource.h>
31#include <media/stagefright/MetaData.h>
32#include <media/stagefright/Utils.h>
33#include <utils/String8.h>
34
35extern "C" {
36    #include <Tremolo/codec_internal.h>
37
38    int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb);
39    int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb);
40    int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb);
41}
42
43namespace android {
44
45struct OggSource : public MediaSource {
46    OggSource(const sp<OggExtractor> &extractor);
47
48    virtual sp<MetaData> getFormat();
49
50    virtual status_t start(MetaData *params = NULL);
51    virtual status_t stop();
52
53    virtual status_t read(
54            MediaBuffer **buffer, const ReadOptions *options = NULL);
55
56protected:
57    virtual ~OggSource();
58
59private:
60    sp<OggExtractor> mExtractor;
61    bool mStarted;
62
63    OggSource(const OggSource &);
64    OggSource &operator=(const OggSource &);
65};
66
67struct MyVorbisExtractor {
68    MyVorbisExtractor(const sp<DataSource> &source);
69    virtual ~MyVorbisExtractor();
70
71    sp<MetaData> getFormat() const;
72
73    // Returns an approximate bitrate in bits per second.
74    uint64_t approxBitrate();
75
76    status_t seekToOffset(off_t offset);
77    status_t readNextPacket(MediaBuffer **buffer);
78
79    status_t init();
80
81    sp<MetaData> getFileMetaData() { return mFileMeta; }
82
83private:
84    struct Page {
85        uint64_t mGranulePosition;
86        uint32_t mSerialNo;
87        uint32_t mPageNo;
88        uint8_t mFlags;
89        uint8_t mNumSegments;
90        uint8_t mLace[255];
91    };
92
93    sp<DataSource> mSource;
94    off_t mOffset;
95    Page mCurrentPage;
96    size_t mCurrentPageSize;
97    size_t mNextLaceIndex;
98
99    off_t mFirstDataOffset;
100
101    vorbis_info mVi;
102    vorbis_comment mVc;
103
104    sp<MetaData> mMeta;
105    sp<MetaData> mFileMeta;
106
107    ssize_t readPage(off_t offset, Page *page);
108    status_t findNextPage(off_t startOffset, off_t *pageOffset);
109
110    status_t verifyHeader(
111            MediaBuffer *buffer, uint8_t type);
112
113    void parseFileMetaData();
114    void extractAlbumArt(const void *data, size_t size);
115
116    MyVorbisExtractor(const MyVorbisExtractor &);
117    MyVorbisExtractor &operator=(const MyVorbisExtractor &);
118};
119
120////////////////////////////////////////////////////////////////////////////////
121
122OggSource::OggSource(const sp<OggExtractor> &extractor)
123    : mExtractor(extractor),
124      mStarted(false) {
125}
126
127OggSource::~OggSource() {
128    if (mStarted) {
129        stop();
130    }
131}
132
133sp<MetaData> OggSource::getFormat() {
134    return mExtractor->mImpl->getFormat();
135}
136
137status_t OggSource::start(MetaData *params) {
138    if (mStarted) {
139        return INVALID_OPERATION;
140    }
141
142    mStarted = true;
143
144    return OK;
145}
146
147status_t OggSource::stop() {
148    mStarted = false;
149
150    return OK;
151}
152
153status_t OggSource::read(
154        MediaBuffer **out, const ReadOptions *options) {
155    *out = NULL;
156
157    int64_t seekTimeUs;
158    ReadOptions::SeekMode mode;
159    if (options && options->getSeekTo(&seekTimeUs, &mode)) {
160        off_t pos = seekTimeUs * mExtractor->mImpl->approxBitrate() / 8000000ll;
161        LOGV("seeking to offset %ld", pos);
162
163        if (mExtractor->mImpl->seekToOffset(pos) != OK) {
164            return ERROR_END_OF_STREAM;
165        }
166    }
167
168    MediaBuffer *packet;
169    status_t err = mExtractor->mImpl->readNextPacket(&packet);
170
171    if (err != OK) {
172        return err;
173    }
174
175#if 0
176    int64_t timeUs;
177    if (packet->meta_data()->findInt64(kKeyTime, &timeUs)) {
178        LOGI("found time = %lld us", timeUs);
179    } else {
180        LOGI("NO time");
181    }
182#endif
183
184    packet->meta_data()->setInt32(kKeyIsSyncFrame, 1);
185
186    *out = packet;
187
188    return OK;
189}
190
191////////////////////////////////////////////////////////////////////////////////
192
193MyVorbisExtractor::MyVorbisExtractor(const sp<DataSource> &source)
194    : mSource(source),
195      mOffset(0),
196      mCurrentPageSize(0),
197      mNextLaceIndex(0),
198      mFirstDataOffset(-1) {
199    mCurrentPage.mNumSegments = 0;
200
201    vorbis_info_init(&mVi);
202    vorbis_comment_init(&mVc);
203}
204
205MyVorbisExtractor::~MyVorbisExtractor() {
206    vorbis_comment_clear(&mVc);
207    vorbis_info_clear(&mVi);
208}
209
210sp<MetaData> MyVorbisExtractor::getFormat() const {
211    return mMeta;
212}
213
214status_t MyVorbisExtractor::findNextPage(
215        off_t startOffset, off_t *pageOffset) {
216    *pageOffset = startOffset;
217
218    for (;;) {
219        char signature[4];
220        ssize_t n = mSource->readAt(*pageOffset, &signature, 4);
221
222        if (n < 4) {
223            *pageOffset = 0;
224
225            return (n < 0) ? n : (status_t)ERROR_END_OF_STREAM;
226        }
227
228        if (!memcmp(signature, "OggS", 4)) {
229            if (*pageOffset > startOffset) {
230                LOGV("skipped %ld bytes of junk to reach next frame",
231                     *pageOffset - startOffset);
232            }
233
234            return OK;
235        }
236
237        ++*pageOffset;
238    }
239}
240
241status_t MyVorbisExtractor::seekToOffset(off_t offset) {
242    if (mFirstDataOffset >= 0 && offset < mFirstDataOffset) {
243        // Once we know where the actual audio data starts (past the headers)
244        // don't ever seek to anywhere before that.
245        offset = mFirstDataOffset;
246    }
247
248    off_t pageOffset;
249    status_t err = findNextPage(offset, &pageOffset);
250
251    if (err != OK) {
252        return err;
253    }
254
255    mOffset = pageOffset;
256
257    mCurrentPageSize = 0;
258    mCurrentPage.mNumSegments = 0;
259    mNextLaceIndex = 0;
260
261    // XXX what if new page continues packet from last???
262
263    return OK;
264}
265
266ssize_t MyVorbisExtractor::readPage(off_t offset, Page *page) {
267    uint8_t header[27];
268    if (mSource->readAt(offset, header, sizeof(header))
269            < (ssize_t)sizeof(header)) {
270        LOGV("failed to read %d bytes at offset 0x%08lx", sizeof(header), offset);
271
272        return ERROR_IO;
273    }
274
275    if (memcmp(header, "OggS", 4)) {
276        return ERROR_MALFORMED;
277    }
278
279    if (header[4] != 0) {
280        // Wrong version.
281
282        return ERROR_UNSUPPORTED;
283    }
284
285    page->mFlags = header[5];
286
287    if (page->mFlags & ~7) {
288        // Only bits 0-2 are defined in version 0.
289        return ERROR_MALFORMED;
290    }
291
292    page->mGranulePosition = U64LE_AT(&header[6]);
293
294#if 0
295    printf("granulePosition = %llu (0x%llx)\n",
296           page->mGranulePosition, page->mGranulePosition);
297#endif
298
299    page->mSerialNo = U32LE_AT(&header[14]);
300    page->mPageNo = U32LE_AT(&header[18]);
301
302    page->mNumSegments = header[26];
303    if (mSource->readAt(
304                offset + sizeof(header), page->mLace, page->mNumSegments)
305            < (ssize_t)page->mNumSegments) {
306        return ERROR_IO;
307    }
308
309    size_t totalSize = 0;;
310    for (size_t i = 0; i < page->mNumSegments; ++i) {
311        totalSize += page->mLace[i];
312    }
313
314#if 0
315    String8 tmp;
316    for (size_t i = 0; i < page->mNumSegments; ++i) {
317        char x[32];
318        sprintf(x, "%s%u", i > 0 ? ", " : "", (unsigned)page->mLace[i]);
319
320        tmp.append(x);
321    }
322
323    LOGV("%c %s", page->mFlags & 1 ? '+' : ' ', tmp.string());
324#endif
325
326    return sizeof(header) + page->mNumSegments + totalSize;
327}
328
329status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) {
330    *out = NULL;
331
332    MediaBuffer *buffer = NULL;
333    int64_t timeUs = -1;
334
335    for (;;) {
336        size_t i;
337        size_t packetSize = 0;
338        bool gotFullPacket = false;
339        for (i = mNextLaceIndex; i < mCurrentPage.mNumSegments; ++i) {
340            uint8_t lace = mCurrentPage.mLace[i];
341
342            packetSize += lace;
343
344            if (lace < 255) {
345                gotFullPacket = true;
346                ++i;
347                break;
348            }
349        }
350
351        if (mNextLaceIndex < mCurrentPage.mNumSegments) {
352            off_t dataOffset = mOffset + 27 + mCurrentPage.mNumSegments;
353            for (size_t j = 0; j < mNextLaceIndex; ++j) {
354                dataOffset += mCurrentPage.mLace[j];
355            }
356
357            size_t fullSize = packetSize;
358            if (buffer != NULL) {
359                fullSize += buffer->range_length();
360            }
361            MediaBuffer *tmp = new MediaBuffer(fullSize);
362            if (buffer != NULL) {
363                memcpy(tmp->data(), buffer->data(), buffer->range_length());
364                tmp->set_range(0, buffer->range_length());
365                buffer->release();
366            } else {
367                // XXX Not only is this not technically the correct time for
368                // this packet, we also stamp every packet in this page
369                // with the same time. This needs fixing later.
370
371                if (mVi.rate) {
372                    // Rate may not have been initialized yet if we're currently
373                    // reading the configuration packets...
374                    // Fortunately, the timestamp doesn't matter for those.
375                    timeUs = mCurrentPage.mGranulePosition * 1000000ll / mVi.rate;
376                }
377                tmp->set_range(0, 0);
378            }
379            buffer = tmp;
380
381            ssize_t n = mSource->readAt(
382                    dataOffset,
383                    (uint8_t *)buffer->data() + buffer->range_length(),
384                    packetSize);
385
386            if (n < (ssize_t)packetSize) {
387                LOGV("failed to read %d bytes at 0x%08lx", packetSize, dataOffset);
388                return ERROR_IO;
389            }
390
391            buffer->set_range(0, fullSize);
392
393            mNextLaceIndex = i;
394
395            if (gotFullPacket) {
396                // We've just read the entire packet.
397
398                if (timeUs >= 0) {
399                    buffer->meta_data()->setInt64(kKeyTime, timeUs);
400                }
401
402                *out = buffer;
403
404                return OK;
405            }
406
407            // fall through, the buffer now contains the start of the packet.
408        }
409
410        CHECK_EQ(mNextLaceIndex, mCurrentPage.mNumSegments);
411
412        mOffset += mCurrentPageSize;
413        ssize_t n = readPage(mOffset, &mCurrentPage);
414
415        if (n <= 0) {
416            if (buffer) {
417                buffer->release();
418                buffer = NULL;
419            }
420
421            LOGV("readPage returned %ld", n);
422
423            return n < 0 ? n : (status_t)ERROR_END_OF_STREAM;
424        }
425
426        mCurrentPageSize = n;
427        mNextLaceIndex = 0;
428
429        if (buffer != NULL) {
430            if ((mCurrentPage.mFlags & 1) == 0) {
431                // This page does not continue the packet, i.e. the packet
432                // is already complete.
433
434                if (timeUs >= 0) {
435                    buffer->meta_data()->setInt64(kKeyTime, timeUs);
436                }
437
438                *out = buffer;
439
440                return OK;
441            }
442        }
443    }
444}
445
446status_t MyVorbisExtractor::init() {
447    mMeta = new MetaData;
448    mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
449
450    MediaBuffer *packet;
451    status_t err;
452    if ((err = readNextPacket(&packet)) != OK) {
453        return err;
454    }
455    LOGV("read packet of size %d\n", packet->range_length());
456    err = verifyHeader(packet, 1);
457    packet->release();
458    packet = NULL;
459    if (err != OK) {
460        return err;
461    }
462
463    if ((err = readNextPacket(&packet)) != OK) {
464        return err;
465    }
466    LOGV("read packet of size %d\n", packet->range_length());
467    err = verifyHeader(packet, 3);
468    packet->release();
469    packet = NULL;
470    if (err != OK) {
471        return err;
472    }
473
474    if ((err = readNextPacket(&packet)) != OK) {
475        return err;
476    }
477    LOGV("read packet of size %d\n", packet->range_length());
478    err = verifyHeader(packet, 5);
479    packet->release();
480    packet = NULL;
481    if (err != OK) {
482        return err;
483    }
484
485    mFirstDataOffset = mOffset + mCurrentPageSize;
486
487    return OK;
488}
489
490status_t MyVorbisExtractor::verifyHeader(
491        MediaBuffer *buffer, uint8_t type) {
492    const uint8_t *data =
493        (const uint8_t *)buffer->data() + buffer->range_offset();
494
495    size_t size = buffer->range_length();
496
497    if (size < 7 || data[0] != type || memcmp(&data[1], "vorbis", 6)) {
498        return ERROR_MALFORMED;
499    }
500
501    ogg_buffer buf;
502    buf.data = (uint8_t *)data;
503    buf.size = size;
504    buf.refcount = 1;
505    buf.ptr.owner = NULL;
506
507    ogg_reference ref;
508    ref.buffer = &buf;
509    ref.begin = 0;
510    ref.length = size;
511    ref.next = NULL;
512
513    oggpack_buffer bits;
514    oggpack_readinit(&bits, &ref);
515
516    CHECK_EQ(oggpack_read(&bits, 8), type);
517    for (size_t i = 0; i < 6; ++i) {
518        oggpack_read(&bits, 8);  // skip 'vorbis'
519    }
520
521    switch (type) {
522        case 1:
523        {
524            CHECK_EQ(0, _vorbis_unpack_info(&mVi, &bits));
525
526            mMeta->setData(kKeyVorbisInfo, 0, data, size);
527            mMeta->setInt32(kKeySampleRate, mVi.rate);
528            mMeta->setInt32(kKeyChannelCount, mVi.channels);
529
530            LOGV("lower-bitrate = %ld", mVi.bitrate_lower);
531            LOGV("upper-bitrate = %ld", mVi.bitrate_upper);
532            LOGV("nominal-bitrate = %ld", mVi.bitrate_nominal);
533            LOGV("window-bitrate = %ld", mVi.bitrate_window);
534
535            off_t size;
536            if (mSource->getSize(&size) == OK) {
537                uint64_t bps = approxBitrate();
538
539                mMeta->setInt64(kKeyDuration, size * 8000000ll / bps);
540            }
541            break;
542        }
543
544        case 3:
545        {
546            if (0 != _vorbis_unpack_comment(&mVc, &bits)) {
547                return ERROR_MALFORMED;
548            }
549
550            parseFileMetaData();
551            break;
552        }
553
554        case 5:
555        {
556            if (0 != _vorbis_unpack_books(&mVi, &bits)) {
557                return ERROR_MALFORMED;
558            }
559
560            mMeta->setData(kKeyVorbisBooks, 0, data, size);
561            break;
562        }
563    }
564
565    return OK;
566}
567
568uint64_t MyVorbisExtractor::approxBitrate() {
569    if (mVi.bitrate_nominal != 0) {
570        return mVi.bitrate_nominal;
571    }
572
573    return (mVi.bitrate_lower + mVi.bitrate_upper) / 2;
574}
575
576void MyVorbisExtractor::parseFileMetaData() {
577    mFileMeta = new MetaData;
578    mFileMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
579
580    struct {
581        const char *const mTag;
582        uint32_t mKey;
583    } kMap[] = {
584        { "TITLE", kKeyTitle },
585        { "ARTIST", kKeyArtist },
586        { "ALBUM", kKeyAlbum },
587        { "COMPOSER", kKeyComposer },
588        { "GENRE", kKeyGenre },
589        { "AUTHOR", kKeyAuthor },
590        { "TRACKNUMBER", kKeyCDTrackNumber },
591        { "DISCNUMBER", kKeyDiscNumber },
592        { "DATE", kKeyDate },
593        { "LYRICIST", kKeyWriter },
594        { "METADATA_BLOCK_PICTURE", kKeyAlbumArt },
595    };
596
597    for (int i = 0; i < mVc.comments; ++i) {
598        const char *comment = mVc.user_comments[i];
599
600        for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
601            size_t tagLen = strlen(kMap[j].mTag);
602            if (!strncasecmp(kMap[j].mTag, comment, tagLen)
603                    && comment[tagLen] == '=') {
604                if (kMap[j].mKey == kKeyAlbumArt) {
605                    extractAlbumArt(
606                            &comment[tagLen + 1],
607                            mVc.comment_lengths[i] - tagLen - 1);
608                } else {
609                    mFileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
610                }
611            }
612        }
613
614    }
615
616#if 0
617    for (int i = 0; i < mVc.comments; ++i) {
618        LOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
619    }
620#endif
621}
622
623// The returned buffer should be free()d.
624static uint8_t *DecodeBase64(const char *s, size_t size, size_t *outSize) {
625    *outSize = 0;
626
627    if ((size % 4) != 0) {
628        return NULL;
629    }
630
631    size_t n = size;
632    size_t padding = 0;
633    if (n >= 1 && s[n - 1] == '=') {
634        padding = 1;
635
636        if (n >= 2 && s[n - 2] == '=') {
637            padding = 2;
638        }
639    }
640
641    size_t outLen = 3 * size / 4 - padding;
642
643    *outSize = outLen;
644
645    void *buffer = malloc(outLen);
646
647    uint8_t *out = (uint8_t *)buffer;
648    size_t j = 0;
649    uint32_t accum = 0;
650    for (size_t i = 0; i < n; ++i) {
651        char c = s[i];
652        unsigned value;
653        if (c >= 'A' && c <= 'Z') {
654            value = c - 'A';
655        } else if (c >= 'a' && c <= 'z') {
656            value = 26 + c - 'a';
657        } else if (c >= '0' && c <= '9') {
658            value = 52 + c - '0';
659        } else if (c == '+') {
660            value = 62;
661        } else if (c == '/') {
662            value = 63;
663        } else if (c != '=') {
664            return NULL;
665        } else {
666            if (i < n - padding) {
667                return NULL;
668            }
669
670            value = 0;
671        }
672
673        accum = (accum << 6) | value;
674
675        if (((i + 1) % 4) == 0) {
676            out[j++] = (accum >> 16);
677
678            if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
679            if (j < outLen) { out[j++] = accum & 0xff; }
680
681            accum = 0;
682        }
683    }
684
685    return (uint8_t *)buffer;
686}
687
688void MyVorbisExtractor::extractAlbumArt(const void *data, size_t size) {
689    LOGV("extractAlbumArt from '%s'", (const char *)data);
690
691    size_t flacSize;
692    uint8_t *flac = DecodeBase64((const char *)data, size, &flacSize);
693
694    if (flac == NULL) {
695        LOGE("malformed base64 encoded data.");
696        return;
697    }
698
699    LOGV("got flac of size %d", flacSize);
700
701    uint32_t picType;
702    uint32_t typeLen;
703    uint32_t descLen;
704    uint32_t dataLen;
705    char type[128];
706
707    if (flacSize < 8) {
708        goto exit;
709    }
710
711    picType = U32_AT(flac);
712
713    if (picType != 3) {
714        // This is not a front cover.
715        goto exit;
716    }
717
718    typeLen = U32_AT(&flac[4]);
719    if (typeLen + 1 > sizeof(type)) {
720        goto exit;
721    }
722
723    if (flacSize < 8 + typeLen) {
724        goto exit;
725    }
726
727    memcpy(type, &flac[8], typeLen);
728    type[typeLen] = '\0';
729
730    LOGV("picType = %d, type = '%s'", picType, type);
731
732    if (!strcmp(type, "-->")) {
733        // This is not inline cover art, but an external url instead.
734        goto exit;
735    }
736
737    descLen = U32_AT(&flac[8 + typeLen]);
738
739    if (flacSize < 32 + typeLen + descLen) {
740        goto exit;
741    }
742
743    dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
744
745    if (flacSize < 32 + typeLen + descLen + dataLen) {
746        goto exit;
747    }
748
749    LOGV("got image data, %d trailing bytes",
750         flacSize - 32 - typeLen - descLen - dataLen);
751
752    mFileMeta->setData(
753            kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen);
754
755    mFileMeta->setCString(kKeyAlbumArtMIME, type);
756
757exit:
758    free(flac);
759    flac = NULL;
760}
761
762////////////////////////////////////////////////////////////////////////////////
763
764OggExtractor::OggExtractor(const sp<DataSource> &source)
765    : mDataSource(source),
766      mInitCheck(NO_INIT),
767      mImpl(NULL) {
768    mImpl = new MyVorbisExtractor(mDataSource);
769    mInitCheck = mImpl->seekToOffset(0);
770
771    if (mInitCheck == OK) {
772        mInitCheck = mImpl->init();
773    }
774}
775
776OggExtractor::~OggExtractor() {
777    delete mImpl;
778    mImpl = NULL;
779}
780
781size_t OggExtractor::countTracks() {
782    return mInitCheck != OK ? 0 : 1;
783}
784
785sp<MediaSource> OggExtractor::getTrack(size_t index) {
786    if (index >= 1) {
787        return NULL;
788    }
789
790    return new OggSource(this);
791}
792
793sp<MetaData> OggExtractor::getTrackMetaData(
794        size_t index, uint32_t flags) {
795    if (index >= 1) {
796        return NULL;
797    }
798
799    return mImpl->getFormat();
800}
801
802sp<MetaData> OggExtractor::getMetaData() {
803    return mImpl->getFileMetaData();
804}
805
806bool SniffOgg(
807        const sp<DataSource> &source, String8 *mimeType, float *confidence,
808        sp<AMessage> *) {
809    char tmp[4];
810    if (source->readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) {
811        return false;
812    }
813
814    mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_OGG);
815    *confidence = 0.2f;
816
817    return true;
818}
819
820}  // namespace android
821