ESQueue.cpp revision f56afa4878694803a44d1b0e9a54762d1d5ab652
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 "ESQueue"
19#include <media/stagefright/foundation/ADebug.h>
20
21#include "ESQueue.h"
22
23#include <media/stagefright/foundation/hexdump.h>
24#include <media/stagefright/foundation/ABitReader.h>
25#include <media/stagefright/foundation/ABuffer.h>
26#include <media/stagefright/foundation/AMessage.h>
27#include <media/stagefright/MediaErrors.h>
28#include <media/stagefright/MediaDefs.h>
29#include <media/stagefright/MetaData.h>
30#include <media/stagefright/Utils.h>
31
32#include "include/avc_utils.h"
33
34namespace android {
35
36ElementaryStreamQueue::ElementaryStreamQueue(Mode mode, uint32_t flags)
37    : mMode(mode),
38      mFlags(flags) {
39}
40
41sp<MetaData> ElementaryStreamQueue::getFormat() {
42    return mFormat;
43}
44
45void ElementaryStreamQueue::clear(bool clearFormat) {
46    if (mBuffer != NULL) {
47        mBuffer->setRange(0, 0);
48    }
49
50    mRangeInfos.clear();
51
52    if (clearFormat) {
53        mFormat.clear();
54    }
55}
56
57static bool IsSeeminglyValidADTSHeader(const uint8_t *ptr, size_t size) {
58    if (size < 3) {
59        // Not enough data to verify header.
60        return false;
61    }
62
63    if (ptr[0] != 0xff || (ptr[1] >> 4) != 0x0f) {
64        return false;
65    }
66
67    unsigned layer = (ptr[1] >> 1) & 3;
68
69    if (layer != 0) {
70        return false;
71    }
72
73    unsigned ID = (ptr[1] >> 3) & 1;
74    unsigned profile_ObjectType = ptr[2] >> 6;
75
76    if (ID == 1 && profile_ObjectType == 3) {
77        // MPEG-2 profile 3 is reserved.
78        return false;
79    }
80
81    return true;
82}
83
84static bool IsSeeminglyValidMPEGAudioHeader(const uint8_t *ptr, size_t size) {
85    if (size < 3) {
86        // Not enough data to verify header.
87        return false;
88    }
89
90    if (ptr[0] != 0xff || (ptr[1] >> 5) != 0x07) {
91        return false;
92    }
93
94    unsigned ID = (ptr[1] >> 3) & 3;
95
96    if (ID == 1) {
97        return false;  // reserved
98    }
99
100    unsigned layer = (ptr[1] >> 1) & 3;
101
102    if (layer == 0) {
103        return false;  // reserved
104    }
105
106    unsigned bitrateIndex = (ptr[2] >> 4);
107
108    if (bitrateIndex == 0x0f) {
109        return false;  // reserved
110    }
111
112    unsigned samplingRateIndex = (ptr[2] >> 2) & 3;
113
114    if (samplingRateIndex == 3) {
115        return false;  // reserved
116    }
117
118    return true;
119}
120
121status_t ElementaryStreamQueue::appendData(
122        const void *data, size_t size, int64_t timeUs) {
123    if (mBuffer == NULL || mBuffer->size() == 0) {
124        switch (mMode) {
125            case H264:
126            case MPEG_VIDEO:
127            {
128#if 0
129                if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) {
130                    return ERROR_MALFORMED;
131                }
132#else
133                uint8_t *ptr = (uint8_t *)data;
134
135                ssize_t startOffset = -1;
136                for (size_t i = 0; i + 3 < size; ++i) {
137                    if (!memcmp("\x00\x00\x00\x01", &ptr[i], 4)) {
138                        startOffset = i;
139                        break;
140                    }
141                }
142
143                if (startOffset < 0) {
144                    return ERROR_MALFORMED;
145                }
146
147                if (startOffset > 0) {
148                    ALOGI("found something resembling an H.264/MPEG syncword at "
149                         "offset %ld",
150                         startOffset);
151                }
152
153                data = &ptr[startOffset];
154                size -= startOffset;
155#endif
156                break;
157            }
158
159            case MPEG4_VIDEO:
160            {
161#if 0
162                if (size < 3 || memcmp("\x00\x00\x01", data, 3)) {
163                    return ERROR_MALFORMED;
164                }
165#else
166                uint8_t *ptr = (uint8_t *)data;
167
168                ssize_t startOffset = -1;
169                for (size_t i = 0; i + 2 < size; ++i) {
170                    if (!memcmp("\x00\x00\x01", &ptr[i], 3)) {
171                        startOffset = i;
172                        break;
173                    }
174                }
175
176                if (startOffset < 0) {
177                    return ERROR_MALFORMED;
178                }
179
180                if (startOffset > 0) {
181                    ALOGI("found something resembling an H.264/MPEG syncword at "
182                         "offset %ld",
183                         startOffset);
184                }
185
186                data = &ptr[startOffset];
187                size -= startOffset;
188#endif
189                break;
190            }
191
192            case AAC:
193            {
194                uint8_t *ptr = (uint8_t *)data;
195
196#if 0
197                if (size < 2 || ptr[0] != 0xff || (ptr[1] >> 4) != 0x0f) {
198                    return ERROR_MALFORMED;
199                }
200#else
201                ssize_t startOffset = -1;
202                for (size_t i = 0; i < size; ++i) {
203                    if (IsSeeminglyValidADTSHeader(&ptr[i], size - i)) {
204                        startOffset = i;
205                        break;
206                    }
207                }
208
209                if (startOffset < 0) {
210                    return ERROR_MALFORMED;
211                }
212
213                if (startOffset > 0) {
214                    ALOGI("found something resembling an AAC syncword at offset %ld",
215                         startOffset);
216                }
217
218                data = &ptr[startOffset];
219                size -= startOffset;
220#endif
221                break;
222            }
223
224            case MPEG_AUDIO:
225            {
226                uint8_t *ptr = (uint8_t *)data;
227
228                ssize_t startOffset = -1;
229                for (size_t i = 0; i < size; ++i) {
230                    if (IsSeeminglyValidMPEGAudioHeader(&ptr[i], size - i)) {
231                        startOffset = i;
232                        break;
233                    }
234                }
235
236                if (startOffset < 0) {
237                    return ERROR_MALFORMED;
238                }
239
240                if (startOffset > 0) {
241                    ALOGI("found something resembling an MPEG audio "
242                         "syncword at offset %ld",
243                         startOffset);
244                }
245
246                data = &ptr[startOffset];
247                size -= startOffset;
248                break;
249            }
250
251            default:
252                TRESPASS();
253                break;
254        }
255    }
256
257    size_t neededSize = (mBuffer == NULL ? 0 : mBuffer->size()) + size;
258    if (mBuffer == NULL || neededSize > mBuffer->capacity()) {
259        neededSize = (neededSize + 65535) & ~65535;
260
261        ALOGV("resizing buffer to size %d", neededSize);
262
263        sp<ABuffer> buffer = new ABuffer(neededSize);
264        if (mBuffer != NULL) {
265            memcpy(buffer->data(), mBuffer->data(), mBuffer->size());
266            buffer->setRange(0, mBuffer->size());
267        } else {
268            buffer->setRange(0, 0);
269        }
270
271        mBuffer = buffer;
272    }
273
274    memcpy(mBuffer->data() + mBuffer->size(), data, size);
275    mBuffer->setRange(0, mBuffer->size() + size);
276
277    RangeInfo info;
278    info.mLength = size;
279    info.mTimestampUs = timeUs;
280    mRangeInfos.push_back(info);
281
282#if 0
283    if (mMode == AAC) {
284        ALOGI("size = %d, timeUs = %.2f secs", size, timeUs / 1E6);
285        hexdump(data, size);
286    }
287#endif
288
289    return OK;
290}
291
292sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
293    if ((mFlags & kFlag_AlignedData) && mMode == H264) {
294        if (mRangeInfos.empty()) {
295            return NULL;
296        }
297
298        RangeInfo info = *mRangeInfos.begin();
299        mRangeInfos.erase(mRangeInfos.begin());
300
301        sp<ABuffer> accessUnit = new ABuffer(info.mLength);
302        memcpy(accessUnit->data(), mBuffer->data(), info.mLength);
303        accessUnit->meta()->setInt64("timeUs", info.mTimestampUs);
304
305        memmove(mBuffer->data(),
306                mBuffer->data() + info.mLength,
307                mBuffer->size() - info.mLength);
308
309        mBuffer->setRange(0, mBuffer->size() - info.mLength);
310
311        if (mFormat == NULL) {
312            mFormat = MakeAVCCodecSpecificData(accessUnit);
313        }
314
315        return accessUnit;
316    }
317
318    switch (mMode) {
319        case H264:
320            return dequeueAccessUnitH264();
321        case AAC:
322            return dequeueAccessUnitAAC();
323        case MPEG_VIDEO:
324            return dequeueAccessUnitMPEGVideo();
325        case MPEG4_VIDEO:
326            return dequeueAccessUnitMPEG4Video();
327        default:
328            CHECK_EQ((unsigned)mMode, (unsigned)MPEG_AUDIO);
329            return dequeueAccessUnitMPEGAudio();
330    }
331}
332
333sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() {
334    int64_t timeUs;
335
336    size_t offset = 0;
337    while (offset + 7 <= mBuffer->size()) {
338        ABitReader bits(mBuffer->data() + offset, mBuffer->size() - offset);
339
340        // adts_fixed_header
341
342        CHECK_EQ(bits.getBits(12), 0xfffu);
343        bits.skipBits(3);  // ID, layer
344        bool protection_absent = bits.getBits(1) != 0;
345
346        if (mFormat == NULL) {
347            unsigned profile = bits.getBits(2);
348            CHECK_NE(profile, 3u);
349            unsigned sampling_freq_index = bits.getBits(4);
350            bits.getBits(1);  // private_bit
351            unsigned channel_configuration = bits.getBits(3);
352            CHECK_NE(channel_configuration, 0u);
353            bits.skipBits(2);  // original_copy, home
354
355            mFormat = MakeAACCodecSpecificData(
356                    profile, sampling_freq_index, channel_configuration);
357
358            mFormat->setInt32(kKeyIsADTS, true);
359
360            int32_t sampleRate;
361            int32_t numChannels;
362            CHECK(mFormat->findInt32(kKeySampleRate, &sampleRate));
363            CHECK(mFormat->findInt32(kKeyChannelCount, &numChannels));
364
365            ALOGI("found AAC codec config (%d Hz, %d channels)",
366                 sampleRate, numChannels);
367        } else {
368            // profile_ObjectType, sampling_frequency_index, private_bits,
369            // channel_configuration, original_copy, home
370            bits.skipBits(12);
371        }
372
373        // adts_variable_header
374
375        // copyright_identification_bit, copyright_identification_start
376        bits.skipBits(2);
377
378        unsigned aac_frame_length = bits.getBits(13);
379
380        bits.skipBits(11);  // adts_buffer_fullness
381
382        unsigned number_of_raw_data_blocks_in_frame = bits.getBits(2);
383
384        if (number_of_raw_data_blocks_in_frame != 0) {
385            // To be implemented.
386            TRESPASS();
387        }
388
389        if (offset + aac_frame_length > mBuffer->size()) {
390            break;
391        }
392
393        size_t headerSize = protection_absent ? 7 : 9;
394
395        int64_t tmpUs = fetchTimestamp(aac_frame_length);
396        CHECK_GE(tmpUs, 0ll);
397
398        if (offset == 0) {
399            timeUs = tmpUs;
400        }
401
402        offset += aac_frame_length;
403    }
404
405    if (offset == 0) {
406        return NULL;
407    }
408
409    sp<ABuffer> accessUnit = new ABuffer(offset);
410    memcpy(accessUnit->data(), mBuffer->data(), offset);
411
412    memmove(mBuffer->data(), mBuffer->data() + offset,
413            mBuffer->size() - offset);
414    mBuffer->setRange(0, mBuffer->size() - offset);
415
416    accessUnit->meta()->setInt64("timeUs", timeUs);
417
418    return accessUnit;
419}
420
421int64_t ElementaryStreamQueue::fetchTimestamp(size_t size) {
422    int64_t timeUs = -1;
423    bool first = true;
424
425    while (size > 0) {
426        CHECK(!mRangeInfos.empty());
427
428        RangeInfo *info = &*mRangeInfos.begin();
429
430        if (first) {
431            timeUs = info->mTimestampUs;
432            first = false;
433        }
434
435        if (info->mLength > size) {
436            info->mLength -= size;
437
438            if (first) {
439                info->mTimestampUs = -1;
440            }
441
442            size = 0;
443        } else {
444            size -= info->mLength;
445
446            mRangeInfos.erase(mRangeInfos.begin());
447            info = NULL;
448        }
449    }
450
451    if (timeUs == 0ll) {
452        ALOGV("Returning 0 timestamp");
453    }
454
455    return timeUs;
456}
457
458struct NALPosition {
459    size_t nalOffset;
460    size_t nalSize;
461};
462
463sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() {
464    const uint8_t *data = mBuffer->data();
465
466    size_t size = mBuffer->size();
467    Vector<NALPosition> nals;
468
469    size_t totalSize = 0;
470
471    status_t err;
472    const uint8_t *nalStart;
473    size_t nalSize;
474    bool foundSlice = false;
475    while ((err = getNextNALUnit(&data, &size, &nalStart, &nalSize)) == OK) {
476        CHECK_GT(nalSize, 0u);
477
478        unsigned nalType = nalStart[0] & 0x1f;
479        bool flush = false;
480
481        if (nalType == 1 || nalType == 5) {
482            if (foundSlice) {
483                ABitReader br(nalStart + 1, nalSize);
484                unsigned first_mb_in_slice = parseUE(&br);
485
486                if (first_mb_in_slice == 0) {
487                    // This slice starts a new frame.
488
489                    flush = true;
490                }
491            }
492
493            foundSlice = true;
494        } else if ((nalType == 9 || nalType == 7) && foundSlice) {
495            // Access unit delimiter and SPS will be associated with the
496            // next frame.
497
498            flush = true;
499        }
500
501        if (flush) {
502            // The access unit will contain all nal units up to, but excluding
503            // the current one, separated by 0x00 0x00 0x00 0x01 startcodes.
504
505            size_t auSize = 4 * nals.size() + totalSize;
506            sp<ABuffer> accessUnit = new ABuffer(auSize);
507
508#if !LOG_NDEBUG
509            AString out;
510#endif
511
512            size_t dstOffset = 0;
513            for (size_t i = 0; i < nals.size(); ++i) {
514                const NALPosition &pos = nals.itemAt(i);
515
516                unsigned nalType = mBuffer->data()[pos.nalOffset] & 0x1f;
517
518#if !LOG_NDEBUG
519                char tmp[128];
520                sprintf(tmp, "0x%02x", nalType);
521                if (i > 0) {
522                    out.append(", ");
523                }
524                out.append(tmp);
525#endif
526
527                memcpy(accessUnit->data() + dstOffset, "\x00\x00\x00\x01", 4);
528
529                memcpy(accessUnit->data() + dstOffset + 4,
530                       mBuffer->data() + pos.nalOffset,
531                       pos.nalSize);
532
533                dstOffset += pos.nalSize + 4;
534            }
535
536            ALOGV("accessUnit contains nal types %s", out.c_str());
537
538            const NALPosition &pos = nals.itemAt(nals.size() - 1);
539            size_t nextScan = pos.nalOffset + pos.nalSize;
540
541            memmove(mBuffer->data(),
542                    mBuffer->data() + nextScan,
543                    mBuffer->size() - nextScan);
544
545            mBuffer->setRange(0, mBuffer->size() - nextScan);
546
547            int64_t timeUs = fetchTimestamp(nextScan);
548            CHECK_GE(timeUs, 0ll);
549
550            accessUnit->meta()->setInt64("timeUs", timeUs);
551
552            if (mFormat == NULL) {
553                mFormat = MakeAVCCodecSpecificData(accessUnit);
554            }
555
556            return accessUnit;
557        }
558
559        NALPosition pos;
560        pos.nalOffset = nalStart - mBuffer->data();
561        pos.nalSize = nalSize;
562
563        nals.push(pos);
564
565        totalSize += nalSize;
566    }
567    CHECK_EQ(err, (status_t)-EAGAIN);
568
569    return NULL;
570}
571
572sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGAudio() {
573    const uint8_t *data = mBuffer->data();
574    size_t size = mBuffer->size();
575
576    if (size < 4) {
577        return NULL;
578    }
579
580    uint32_t header = U32_AT(data);
581
582    size_t frameSize;
583    int samplingRate, numChannels, bitrate, numSamples;
584    CHECK(GetMPEGAudioFrameSize(
585                header, &frameSize, &samplingRate, &numChannels,
586                &bitrate, &numSamples));
587
588    if (size < frameSize) {
589        return NULL;
590    }
591
592    unsigned layer = 4 - ((header >> 17) & 3);
593
594    sp<ABuffer> accessUnit = new ABuffer(frameSize);
595    memcpy(accessUnit->data(), data, frameSize);
596
597    memmove(mBuffer->data(),
598            mBuffer->data() + frameSize,
599            mBuffer->size() - frameSize);
600
601    mBuffer->setRange(0, mBuffer->size() - frameSize);
602
603    int64_t timeUs = fetchTimestamp(frameSize);
604    CHECK_GE(timeUs, 0ll);
605
606    accessUnit->meta()->setInt64("timeUs", timeUs);
607
608    if (mFormat == NULL) {
609        mFormat = new MetaData;
610
611        switch (layer) {
612            case 1:
613                mFormat->setCString(
614                        kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
615                break;
616            case 2:
617                mFormat->setCString(
618                        kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
619                break;
620            case 3:
621                mFormat->setCString(
622                        kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
623                break;
624            default:
625                TRESPASS();
626        }
627
628        mFormat->setInt32(kKeySampleRate, samplingRate);
629        mFormat->setInt32(kKeyChannelCount, numChannels);
630    }
631
632    return accessUnit;
633}
634
635static void EncodeSize14(uint8_t **_ptr, size_t size) {
636    CHECK_LE(size, 0x3fff);
637
638    uint8_t *ptr = *_ptr;
639
640    *ptr++ = 0x80 | (size >> 7);
641    *ptr++ = size & 0x7f;
642
643    *_ptr = ptr;
644}
645
646static sp<ABuffer> MakeMPEGVideoESDS(const sp<ABuffer> &csd) {
647    sp<ABuffer> esds = new ABuffer(csd->size() + 25);
648
649    uint8_t *ptr = esds->data();
650    *ptr++ = 0x03;
651    EncodeSize14(&ptr, 22 + csd->size());
652
653    *ptr++ = 0x00;  // ES_ID
654    *ptr++ = 0x00;
655
656    *ptr++ = 0x00;  // streamDependenceFlag, URL_Flag, OCRstreamFlag
657
658    *ptr++ = 0x04;
659    EncodeSize14(&ptr, 16 + csd->size());
660
661    *ptr++ = 0x40;  // Audio ISO/IEC 14496-3
662
663    for (size_t i = 0; i < 12; ++i) {
664        *ptr++ = 0x00;
665    }
666
667    *ptr++ = 0x05;
668    EncodeSize14(&ptr, csd->size());
669
670    memcpy(ptr, csd->data(), csd->size());
671
672    return esds;
673}
674
675sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGVideo() {
676    const uint8_t *data = mBuffer->data();
677    size_t size = mBuffer->size();
678
679    bool sawPictureStart = false;
680    int pprevStartCode = -1;
681    int prevStartCode = -1;
682    int currentStartCode = -1;
683
684    size_t offset = 0;
685    while (offset + 3 < size) {
686        if (memcmp(&data[offset], "\x00\x00\x01", 3)) {
687            ++offset;
688            continue;
689        }
690
691        pprevStartCode = prevStartCode;
692        prevStartCode = currentStartCode;
693        currentStartCode = data[offset + 3];
694
695        if (currentStartCode == 0xb3 && mFormat == NULL) {
696            memmove(mBuffer->data(), mBuffer->data() + offset, size - offset);
697            size -= offset;
698            (void)fetchTimestamp(offset);
699            offset = 0;
700            mBuffer->setRange(0, size);
701        }
702
703        if ((prevStartCode == 0xb3 && currentStartCode != 0xb5)
704                || (pprevStartCode == 0xb3 && prevStartCode == 0xb5)) {
705            // seqHeader without/with extension
706
707            if (mFormat == NULL) {
708                CHECK_GE(size, 7u);
709
710                unsigned width =
711                    (data[4] << 4) | data[5] >> 4;
712
713                unsigned height =
714                    ((data[5] & 0x0f) << 8) | data[6];
715
716                mFormat = new MetaData;
717                mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2);
718                mFormat->setInt32(kKeyWidth, width);
719                mFormat->setInt32(kKeyHeight, height);
720
721                ALOGI("found MPEG2 video codec config (%d x %d)", width, height);
722
723                sp<ABuffer> csd = new ABuffer(offset);
724                memcpy(csd->data(), data, offset);
725
726                memmove(mBuffer->data(),
727                        mBuffer->data() + offset,
728                        mBuffer->size() - offset);
729
730                mBuffer->setRange(0, mBuffer->size() - offset);
731                size -= offset;
732                (void)fetchTimestamp(offset);
733                offset = 0;
734
735                // hexdump(csd->data(), csd->size());
736
737                sp<ABuffer> esds = MakeMPEGVideoESDS(csd);
738                mFormat->setData(
739                        kKeyESDS, kTypeESDS, esds->data(), esds->size());
740
741                return NULL;
742            }
743        }
744
745        if (mFormat != NULL && currentStartCode == 0x00) {
746            // Picture start
747
748            if (!sawPictureStart) {
749                sawPictureStart = true;
750            } else {
751                sp<ABuffer> accessUnit = new ABuffer(offset);
752                memcpy(accessUnit->data(), data, offset);
753
754                memmove(mBuffer->data(),
755                        mBuffer->data() + offset,
756                        mBuffer->size() - offset);
757
758                mBuffer->setRange(0, mBuffer->size() - offset);
759
760                int64_t timeUs = fetchTimestamp(offset);
761                CHECK_GE(timeUs, 0ll);
762
763                offset = 0;
764
765                accessUnit->meta()->setInt64("timeUs", timeUs);
766
767                ALOGV("returning MPEG video access unit at time %lld us",
768                      timeUs);
769
770                // hexdump(accessUnit->data(), accessUnit->size());
771
772                return accessUnit;
773            }
774        }
775
776        ++offset;
777    }
778
779    return NULL;
780}
781
782static ssize_t getNextChunkSize(
783        const uint8_t *data, size_t size) {
784    static const char kStartCode[] = "\x00\x00\x01";
785
786    if (size < 3) {
787        return -EAGAIN;
788    }
789
790    if (memcmp(kStartCode, data, 3)) {
791        TRESPASS();
792    }
793
794    size_t offset = 3;
795    while (offset + 2 < size) {
796        if (!memcmp(&data[offset], kStartCode, 3)) {
797            return offset;
798        }
799
800        ++offset;
801    }
802
803    return -EAGAIN;
804}
805
806sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEG4Video() {
807    uint8_t *data = mBuffer->data();
808    size_t size = mBuffer->size();
809
810    enum {
811        SKIP_TO_VISUAL_OBJECT_SEQ_START,
812        EXPECT_VISUAL_OBJECT_START,
813        EXPECT_VO_START,
814        EXPECT_VOL_START,
815        WAIT_FOR_VOP_START,
816        SKIP_TO_VOP_START,
817
818    } state;
819
820    if (mFormat == NULL) {
821        state = SKIP_TO_VISUAL_OBJECT_SEQ_START;
822    } else {
823        state = SKIP_TO_VOP_START;
824    }
825
826    int32_t width = -1, height = -1;
827
828    size_t offset = 0;
829    ssize_t chunkSize;
830    while ((chunkSize = getNextChunkSize(
831                    &data[offset], size - offset)) > 0) {
832        bool discard = false;
833
834        unsigned chunkType = data[offset + 3];
835
836        switch (state) {
837            case SKIP_TO_VISUAL_OBJECT_SEQ_START:
838            {
839                if (chunkType == 0xb0) {
840                    // Discard anything before this marker.
841
842                    state = EXPECT_VISUAL_OBJECT_START;
843                } else {
844                    discard = true;
845                }
846                break;
847            }
848
849            case EXPECT_VISUAL_OBJECT_START:
850            {
851                CHECK_EQ(chunkType, 0xb5);
852                state = EXPECT_VO_START;
853                break;
854            }
855
856            case EXPECT_VO_START:
857            {
858                CHECK_LE(chunkType, 0x1f);
859                state = EXPECT_VOL_START;
860                break;
861            }
862
863            case EXPECT_VOL_START:
864            {
865                CHECK((chunkType & 0xf0) == 0x20);
866
867                CHECK(ExtractDimensionsFromVOLHeader(
868                            &data[offset], chunkSize,
869                            &width, &height));
870
871                state = WAIT_FOR_VOP_START;
872                break;
873            }
874
875            case WAIT_FOR_VOP_START:
876            {
877                if (chunkType == 0xb3 || chunkType == 0xb6) {
878                    // group of VOP or VOP start.
879
880                    mFormat = new MetaData;
881                    mFormat->setCString(
882                            kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
883
884                    mFormat->setInt32(kKeyWidth, width);
885                    mFormat->setInt32(kKeyHeight, height);
886
887                    ALOGI("found MPEG4 video codec config (%d x %d)",
888                         width, height);
889
890                    sp<ABuffer> csd = new ABuffer(offset);
891                    memcpy(csd->data(), data, offset);
892
893                    // hexdump(csd->data(), csd->size());
894
895                    sp<ABuffer> esds = MakeMPEGVideoESDS(csd);
896                    mFormat->setData(
897                            kKeyESDS, kTypeESDS,
898                            esds->data(), esds->size());
899
900                    discard = true;
901                    state = SKIP_TO_VOP_START;
902                }
903
904                break;
905            }
906
907            case SKIP_TO_VOP_START:
908            {
909                if (chunkType == 0xb6) {
910                    offset += chunkSize;
911
912                    sp<ABuffer> accessUnit = new ABuffer(offset);
913                    memcpy(accessUnit->data(), data, offset);
914
915                    memmove(data, &data[offset], size - offset);
916                    size -= offset;
917                    mBuffer->setRange(0, size);
918
919                    int64_t timeUs = fetchTimestamp(offset);
920                    CHECK_GE(timeUs, 0ll);
921
922                    offset = 0;
923
924                    accessUnit->meta()->setInt64("timeUs", timeUs);
925
926                    ALOGV("returning MPEG4 video access unit at time %lld us",
927                         timeUs);
928
929                    // hexdump(accessUnit->data(), accessUnit->size());
930
931                    return accessUnit;
932                } else if (chunkType != 0xb3) {
933                    offset += chunkSize;
934                    discard = true;
935                }
936
937                break;
938            }
939
940            default:
941                TRESPASS();
942        }
943
944        if (discard) {
945            (void)fetchTimestamp(offset);
946            memmove(data, &data[offset], size - offset);
947            size -= offset;
948            offset = 0;
949            mBuffer->setRange(0, size);
950        } else {
951            offset += chunkSize;
952        }
953    }
954
955    return NULL;
956}
957
958}  // namespace android
959