OggExtractor.cpp revision 5a4001ddb2536d65d966970fc0579bf6bd11b5a0
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    if (options && options->getSeekTo(&seekTimeUs)) {
159        off_t pos = seekTimeUs * mExtractor->mImpl->approxBitrate() / 8000000ll;
160        LOGI("seeking to offset %ld", pos);
161
162        if (mExtractor->mImpl->seekToOffset(pos) != OK) {
163            return ERROR_END_OF_STREAM;
164        }
165    }
166
167    MediaBuffer *packet;
168    status_t err = mExtractor->mImpl->readNextPacket(&packet);
169
170    if (err != OK) {
171        return err;
172    }
173
174#if 0
175    int64_t timeUs;
176    if (packet->meta_data()->findInt64(kKeyTime, &timeUs)) {
177        LOGI("found time = %lld us", timeUs);
178    } else {
179        LOGI("NO time");
180    }
181#endif
182
183    *out = packet;
184
185    return OK;
186}
187
188////////////////////////////////////////////////////////////////////////////////
189
190MyVorbisExtractor::MyVorbisExtractor(const sp<DataSource> &source)
191    : mSource(source),
192      mOffset(0),
193      mCurrentPageSize(0),
194      mNextLaceIndex(0),
195      mFirstDataOffset(-1) {
196    mCurrentPage.mNumSegments = 0;
197
198    vorbis_info_init(&mVi);
199    vorbis_comment_init(&mVc);
200}
201
202MyVorbisExtractor::~MyVorbisExtractor() {
203    vorbis_comment_clear(&mVc);
204    vorbis_info_clear(&mVi);
205}
206
207sp<MetaData> MyVorbisExtractor::getFormat() const {
208    return mMeta;
209}
210
211status_t MyVorbisExtractor::findNextPage(
212        off_t startOffset, off_t *pageOffset) {
213    *pageOffset = startOffset;
214
215    for (;;) {
216        char signature[4];
217        ssize_t n = mSource->readAt(*pageOffset, &signature, 4);
218
219        if (n < 4) {
220            *pageOffset = 0;
221
222            return (n < 0) ? n : (status_t)ERROR_END_OF_STREAM;
223        }
224
225        if (!memcmp(signature, "OggS", 4)) {
226            if (*pageOffset > startOffset) {
227                LOGV("skipped %ld bytes of junk to reach next frame",
228                     *pageOffset - startOffset);
229            }
230
231            return OK;
232        }
233
234        ++*pageOffset;
235    }
236}
237
238status_t MyVorbisExtractor::seekToOffset(off_t offset) {
239    if (mFirstDataOffset >= 0 && offset < mFirstDataOffset) {
240        // Once we know where the actual audio data starts (past the headers)
241        // don't ever seek to anywhere before that.
242        offset = mFirstDataOffset;
243    }
244
245    off_t pageOffset;
246    status_t err = findNextPage(offset, &pageOffset);
247
248    if (err != OK) {
249        return err;
250    }
251
252    mOffset = pageOffset;
253
254    mCurrentPageSize = 0;
255    mCurrentPage.mNumSegments = 0;
256    mNextLaceIndex = 0;
257
258    // XXX what if new page continues packet from last???
259
260    return OK;
261}
262
263ssize_t MyVorbisExtractor::readPage(off_t offset, Page *page) {
264    uint8_t header[27];
265    if (mSource->readAt(offset, header, sizeof(header))
266            < (ssize_t)sizeof(header)) {
267        LOGE("failed to read %d bytes at offset 0x%08lx", sizeof(header), offset);
268
269        return ERROR_IO;
270    }
271
272    if (memcmp(header, "OggS", 4)) {
273        return ERROR_MALFORMED;
274    }
275
276    if (header[4] != 0) {
277        // Wrong version.
278
279        return ERROR_UNSUPPORTED;
280    }
281
282    page->mFlags = header[5];
283
284    if (page->mFlags & ~7) {
285        // Only bits 0-2 are defined in version 0.
286        return ERROR_MALFORMED;
287    }
288
289    page->mGranulePosition = U64LE_AT(&header[6]);
290
291#if 0
292    printf("granulePosition = %llu (0x%llx)\n",
293           page->mGranulePosition, page->mGranulePosition);
294#endif
295
296    page->mSerialNo = U32LE_AT(&header[14]);
297    page->mPageNo = U32LE_AT(&header[18]);
298
299    page->mNumSegments = header[26];
300    if (mSource->readAt(
301                offset + sizeof(header), page->mLace, page->mNumSegments)
302            < (ssize_t)page->mNumSegments) {
303        return ERROR_IO;
304    }
305
306    size_t totalSize = 0;;
307    for (size_t i = 0; i < page->mNumSegments; ++i) {
308        totalSize += page->mLace[i];
309    }
310
311#if 0
312    String8 tmp;
313    for (size_t i = 0; i < page->mNumSegments; ++i) {
314        char x[32];
315        sprintf(x, "%s%u", i > 0 ? ", " : "", (unsigned)page->mLace[i]);
316
317        tmp.append(x);
318    }
319
320    LOGV("%c %s", page->mFlags & 1 ? '+' : ' ', tmp.string());
321#endif
322
323    return sizeof(header) + page->mNumSegments + totalSize;
324}
325
326status_t MyVorbisExtractor::readNextPacket(MediaBuffer **out) {
327    *out = NULL;
328
329    MediaBuffer *buffer = NULL;
330    int64_t timeUs = -1;
331
332    for (;;) {
333        size_t i;
334        size_t packetSize = 0;
335        bool gotFullPacket = false;
336        for (i = mNextLaceIndex; i < mCurrentPage.mNumSegments; ++i) {
337            uint8_t lace = mCurrentPage.mLace[i];
338
339            packetSize += lace;
340
341            if (lace < 255) {
342                gotFullPacket = true;
343                ++i;
344                break;
345            }
346        }
347
348        if (mNextLaceIndex < mCurrentPage.mNumSegments) {
349            off_t dataOffset = mOffset + 27 + mCurrentPage.mNumSegments;
350            for (size_t j = 0; j < mNextLaceIndex; ++j) {
351                dataOffset += mCurrentPage.mLace[j];
352            }
353
354            size_t fullSize = packetSize;
355            if (buffer != NULL) {
356                fullSize += buffer->range_length();
357            }
358            MediaBuffer *tmp = new MediaBuffer(fullSize);
359            if (buffer != NULL) {
360                memcpy(tmp->data(), buffer->data(), buffer->range_length());
361                tmp->set_range(0, buffer->range_length());
362                buffer->release();
363            } else {
364                // XXX Not only is this not technically the correct time for
365                // this packet, we also stamp every packet in this page
366                // with the same time. This needs fixing later.
367                timeUs = mCurrentPage.mGranulePosition * 1000000ll / mVi.rate;
368                tmp->set_range(0, 0);
369            }
370            buffer = tmp;
371
372            ssize_t n = mSource->readAt(
373                    dataOffset,
374                    (uint8_t *)buffer->data() + buffer->range_length(),
375                    packetSize);
376
377            if (n < (ssize_t)packetSize) {
378                LOGE("failed to read %d bytes at 0x%08lx", packetSize, dataOffset);
379                return ERROR_IO;
380            }
381
382            buffer->set_range(0, fullSize);
383
384            mNextLaceIndex = i;
385
386            if (gotFullPacket) {
387                // We've just read the entire packet.
388
389                if (timeUs >= 0) {
390                    buffer->meta_data()->setInt64(kKeyTime, timeUs);
391                }
392
393                *out = buffer;
394
395                return OK;
396            }
397
398            // fall through, the buffer now contains the start of the packet.
399        }
400
401        CHECK_EQ(mNextLaceIndex, mCurrentPage.mNumSegments);
402
403        mOffset += mCurrentPageSize;
404        ssize_t n = readPage(mOffset, &mCurrentPage);
405
406        if (n <= 0) {
407            if (buffer) {
408                buffer->release();
409                buffer = NULL;
410            }
411
412            LOGE("readPage returned %ld", n);
413
414            return n < 0 ? n : (status_t)ERROR_END_OF_STREAM;
415        }
416
417        mCurrentPageSize = n;
418        mNextLaceIndex = 0;
419
420        if (buffer != NULL) {
421            if ((mCurrentPage.mFlags & 1) == 0) {
422                // This page does not continue the packet, i.e. the packet
423                // is already complete.
424
425                if (timeUs >= 0) {
426                    buffer->meta_data()->setInt64(kKeyTime, timeUs);
427                }
428
429                *out = buffer;
430
431                return OK;
432            }
433        }
434    }
435}
436
437status_t MyVorbisExtractor::init() {
438    mMeta = new MetaData;
439    mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_VORBIS);
440
441    MediaBuffer *packet;
442    status_t err;
443    if ((err = readNextPacket(&packet)) != OK) {
444        return err;
445    }
446    LOGV("read packet of size %d\n", packet->range_length());
447    err = verifyHeader(packet, 1);
448    packet->release();
449    packet = NULL;
450    if (err != OK) {
451        return err;
452    }
453
454    if ((err = readNextPacket(&packet)) != OK) {
455        return err;
456    }
457    LOGV("read packet of size %d\n", packet->range_length());
458    err = verifyHeader(packet, 3);
459    packet->release();
460    packet = NULL;
461    if (err != OK) {
462        return err;
463    }
464
465    if ((err = readNextPacket(&packet)) != OK) {
466        return err;
467    }
468    LOGV("read packet of size %d\n", packet->range_length());
469    err = verifyHeader(packet, 5);
470    packet->release();
471    packet = NULL;
472    if (err != OK) {
473        return err;
474    }
475
476    mFirstDataOffset = mOffset + mCurrentPageSize;
477
478    return OK;
479}
480
481status_t MyVorbisExtractor::verifyHeader(
482        MediaBuffer *buffer, uint8_t type) {
483    const uint8_t *data =
484        (const uint8_t *)buffer->data() + buffer->range_offset();
485
486    size_t size = buffer->range_length();
487
488    if (size < 7 || data[0] != type || memcmp(&data[1], "vorbis", 6)) {
489        return ERROR_MALFORMED;
490    }
491
492    ogg_buffer buf;
493    buf.data = (uint8_t *)data;
494    buf.size = size;
495    buf.refcount = 1;
496    buf.ptr.owner = NULL;
497
498    ogg_reference ref;
499    ref.buffer = &buf;
500    ref.begin = 0;
501    ref.length = size;
502    ref.next = NULL;
503
504    oggpack_buffer bits;
505    oggpack_readinit(&bits, &ref);
506
507    CHECK_EQ(oggpack_read(&bits, 8), type);
508    for (size_t i = 0; i < 6; ++i) {
509        oggpack_read(&bits, 8);  // skip 'vorbis'
510    }
511
512    switch (type) {
513        case 1:
514        {
515            CHECK_EQ(0, _vorbis_unpack_info(&mVi, &bits));
516
517            mMeta->setData(kKeyVorbisInfo, 0, data, size);
518            mMeta->setInt32(kKeySampleRate, mVi.rate);
519            mMeta->setInt32(kKeyChannelCount, mVi.channels);
520
521            LOGV("lower-bitrate = %ld", mVi.bitrate_lower);
522            LOGV("upper-bitrate = %ld", mVi.bitrate_upper);
523            LOGV("nominal-bitrate = %ld", mVi.bitrate_nominal);
524            LOGV("window-bitrate = %ld", mVi.bitrate_window);
525
526            off_t size;
527            if (mSource->getSize(&size) == OK) {
528                uint64_t bps = approxBitrate();
529
530                mMeta->setInt64(kKeyDuration, size * 8000000ll / bps);
531            }
532            break;
533        }
534
535        case 3:
536        {
537            if (0 != _vorbis_unpack_comment(&mVc, &bits)) {
538                return ERROR_MALFORMED;
539            }
540
541            parseFileMetaData();
542            break;
543        }
544
545        case 5:
546        {
547            if (0 != _vorbis_unpack_books(&mVi, &bits)) {
548                return ERROR_MALFORMED;
549            }
550
551            mMeta->setData(kKeyVorbisBooks, 0, data, size);
552            break;
553        }
554    }
555
556    return OK;
557}
558
559uint64_t MyVorbisExtractor::approxBitrate() {
560    if (mVi.bitrate_nominal != 0) {
561        return mVi.bitrate_nominal;
562    }
563
564    return (mVi.bitrate_lower + mVi.bitrate_upper) / 2;
565}
566
567void MyVorbisExtractor::parseFileMetaData() {
568    mFileMeta = new MetaData;
569    mFileMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_OGG);
570
571    struct {
572        const char *const mTag;
573        uint32_t mKey;
574    } kMap[] = {
575        { "TITLE", kKeyTitle },
576        { "ARTIST", kKeyArtist },
577        { "ALBUM", kKeyAlbum },
578        { "COMPOSER", kKeyComposer },
579        { "GENRE", kKeyGenre },
580        { "AUTHOR", kKeyAuthor },
581        { "TRACKNUMBER", kKeyCDTrackNumber },
582        { "DISCNUMBER", kKeyDiscNumber },
583        { "DATE", kKeyDate },
584        { "LYRICIST", kKeyWriter },
585        { "METADATA_BLOCK_PICTURE", kKeyAlbumArt },
586    };
587
588    for (int i = 0; i < mVc.comments; ++i) {
589        const char *comment = mVc.user_comments[i];
590
591        for (size_t j = 0; j < sizeof(kMap) / sizeof(kMap[0]); ++j) {
592            size_t tagLen = strlen(kMap[j].mTag);
593            if (!strncasecmp(kMap[j].mTag, comment, tagLen)
594                    && comment[tagLen] == '=') {
595                if (kMap[j].mKey == kKeyAlbumArt) {
596                    extractAlbumArt(
597                            &comment[tagLen + 1],
598                            mVc.comment_lengths[i] - tagLen - 1);
599                } else {
600                    mFileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
601                }
602            }
603        }
604
605    }
606
607#if 0
608    for (int i = 0; i < mVc.comments; ++i) {
609        LOGI("comment #%d: '%s'", i + 1, mVc.user_comments[i]);
610    }
611#endif
612}
613
614// The returned buffer should be free()d.
615static uint8_t *DecodeBase64(const char *s, size_t size, size_t *outSize) {
616    *outSize = 0;
617
618    if ((size % 4) != 0) {
619        return NULL;
620    }
621
622    size_t n = size;
623    size_t padding = 0;
624    if (n >= 1 && s[n - 1] == '=') {
625        padding = 1;
626
627        if (n >= 2 && s[n - 2] == '=') {
628            padding = 2;
629        }
630    }
631
632    size_t outLen = 3 * size / 4 - padding;
633
634    *outSize = outLen;
635
636    void *buffer = malloc(outLen);
637
638    uint8_t *out = (uint8_t *)buffer;
639    size_t j = 0;
640    uint32_t accum = 0;
641    for (size_t i = 0; i < n; ++i) {
642        char c = s[i];
643        unsigned value;
644        if (c >= 'A' && c <= 'Z') {
645            value = c - 'A';
646        } else if (c >= 'a' && c <= 'z') {
647            value = 26 + c - 'a';
648        } else if (c >= '0' && c <= '9') {
649            value = 52 + c - '0';
650        } else if (c == '+') {
651            value = 62;
652        } else if (c == '/') {
653            value = 63;
654        } else if (c != '=') {
655            return NULL;
656        } else {
657            if (i < n - padding) {
658                return NULL;
659            }
660
661            value = 0;
662        }
663
664        accum = (accum << 6) | value;
665
666        if (((i + 1) % 4) == 0) {
667            out[j++] = (accum >> 16);
668
669            if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
670            if (j < outLen) { out[j++] = accum & 0xff; }
671
672            accum = 0;
673        }
674    }
675
676    return (uint8_t *)buffer;
677}
678
679void MyVorbisExtractor::extractAlbumArt(const void *data, size_t size) {
680    LOGV("extractAlbumArt from '%s'", (const char *)data);
681
682    size_t flacSize;
683    uint8_t *flac = DecodeBase64((const char *)data, size, &flacSize);
684
685    if (flac == NULL) {
686        LOGE("malformed base64 encoded data.");
687        return;
688    }
689
690    LOGV("got flac of size %d", flacSize);
691
692    uint32_t picType;
693    uint32_t typeLen;
694    uint32_t descLen;
695    uint32_t dataLen;
696    char type[128];
697
698    if (flacSize < 8) {
699        goto exit;
700    }
701
702    picType = U32_AT(flac);
703
704    if (picType != 3) {
705        // This is not a front cover.
706        goto exit;
707    }
708
709    typeLen = U32_AT(&flac[4]);
710    if (typeLen + 1 > sizeof(type)) {
711        goto exit;
712    }
713
714    if (flacSize < 8 + typeLen) {
715        goto exit;
716    }
717
718    memcpy(type, &flac[8], typeLen);
719    type[typeLen] = '\0';
720
721    LOGV("picType = %d, type = '%s'", picType, type);
722
723    if (!strcmp(type, "-->")) {
724        // This is not inline cover art, but an external url instead.
725        goto exit;
726    }
727
728    descLen = U32_AT(&flac[8 + typeLen]);
729
730    if (flacSize < 32 + typeLen + descLen) {
731        goto exit;
732    }
733
734    dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
735
736    if (flacSize < 32 + typeLen + descLen + dataLen) {
737        goto exit;
738    }
739
740    LOGV("got image data, %d trailing bytes",
741         flacSize - 32 - typeLen - descLen - dataLen);
742
743    mFileMeta->setData(
744            kKeyAlbumArt, 0, &flac[8 + typeLen + 4 + descLen + 20], dataLen);
745
746    mFileMeta->setCString(kKeyAlbumArtMIME, type);
747
748exit:
749    free(flac);
750    flac = NULL;
751}
752
753////////////////////////////////////////////////////////////////////////////////
754
755OggExtractor::OggExtractor(const sp<DataSource> &source)
756    : mDataSource(source),
757      mInitCheck(NO_INIT),
758      mImpl(NULL) {
759    mImpl = new MyVorbisExtractor(mDataSource);
760    mInitCheck = mImpl->seekToOffset(0);
761
762    if (mInitCheck == OK) {
763        mInitCheck = mImpl->init();
764    }
765}
766
767OggExtractor::~OggExtractor() {
768    delete mImpl;
769    mImpl = NULL;
770}
771
772size_t OggExtractor::countTracks() {
773    return mInitCheck != OK ? 0 : 1;
774}
775
776sp<MediaSource> OggExtractor::getTrack(size_t index) {
777    if (index >= 1) {
778        return NULL;
779    }
780
781    return new OggSource(this);
782}
783
784sp<MetaData> OggExtractor::getTrackMetaData(
785        size_t index, uint32_t flags) {
786    if (index >= 1) {
787        return NULL;
788    }
789
790    return mImpl->getFormat();
791}
792
793sp<MetaData> OggExtractor::getMetaData() {
794    return mImpl->getFileMetaData();
795}
796
797bool SniffOgg(
798        const sp<DataSource> &source, String8 *mimeType, float *confidence) {
799    char tmp[4];
800    if (source->readAt(0, tmp, 4) < 4 || memcmp(tmp, "OggS", 4)) {
801        return false;
802    }
803
804    mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_OGG);
805    *confidence = 0.2f;
806
807    return true;
808}
809
810}  // namespace android
811