MPEG4Writer.cpp revision 548e31844937b37518fbb62ff69e9ff1f794183b
1/*
2 * Copyright (C) 2009 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#include <arpa/inet.h>
18
19#include <ctype.h>
20#include <pthread.h>
21
22#include <media/stagefright/MPEG4Writer.h>
23#include <media/stagefright/MediaBuffer.h>
24#include <media/stagefright/MetaData.h>
25#include <media/stagefright/MediaDebug.h>
26#include <media/stagefright/MediaDefs.h>
27#include <media/stagefright/MediaErrors.h>
28#include <media/stagefright/MediaSource.h>
29#include <media/stagefright/Utils.h>
30
31namespace android {
32
33class MPEG4Writer::Track {
34public:
35    Track(MPEG4Writer *owner, const sp<MediaSource> &source);
36    ~Track();
37
38    status_t start();
39    void stop();
40    bool reachedEOS();
41
42    int64_t getDurationUs() const;
43    void writeTrackHeader(int32_t trackID);
44
45private:
46    MPEG4Writer *mOwner;
47    sp<MetaData> mMeta;
48    sp<MediaSource> mSource;
49    volatile bool mDone;
50    int64_t mMaxTimeStampUs;
51
52    pthread_t mThread;
53
54    struct SampleInfo {
55        size_t size;
56        off_t offset;
57        int64_t timestamp;
58    };
59    List<SampleInfo> mSampleInfos;
60
61    void *mCodecSpecificData;
62    size_t mCodecSpecificDataSize;
63    bool mGotAllCodecSpecificData;
64
65    bool mReachedEOS;
66
67    static void *ThreadWrapper(void *me);
68    void threadEntry();
69
70    status_t makeAVCCodecSpecificData(
71            const uint8_t *data, size_t size);
72
73    Track(const Track &);
74    Track &operator=(const Track &);
75};
76
77#define USE_NALLEN_FOUR         1
78
79MPEG4Writer::MPEG4Writer(const char *filename)
80    : mFile(fopen(filename, "wb")),
81      mOffset(0),
82      mMdatOffset(0) {
83    CHECK(mFile != NULL);
84}
85
86MPEG4Writer::MPEG4Writer(int fd)
87    : mFile(fdopen(fd, "wb")),
88      mOffset(0),
89      mMdatOffset(0) {
90    CHECK(mFile != NULL);
91}
92
93MPEG4Writer::~MPEG4Writer() {
94    stop();
95
96    for (List<Track *>::iterator it = mTracks.begin();
97         it != mTracks.end(); ++it) {
98        delete *it;
99    }
100    mTracks.clear();
101}
102
103status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
104    Track *track = new Track(this, source);
105    mTracks.push_back(track);
106
107    return OK;
108}
109
110status_t MPEG4Writer::start() {
111    if (mFile == NULL) {
112        return UNKNOWN_ERROR;
113    }
114
115    beginBox("ftyp");
116      writeFourcc("isom");
117      writeInt32(0);
118      writeFourcc("isom");
119    endBox();
120
121    mMdatOffset = mOffset;
122    write("\x00\x00\x00\x01mdat????????", 16);
123
124    for (List<Track *>::iterator it = mTracks.begin();
125         it != mTracks.end(); ++it) {
126        status_t err = (*it)->start();
127
128        if (err != OK) {
129            for (List<Track *>::iterator it2 = mTracks.begin();
130                 it2 != it; ++it2) {
131                (*it2)->stop();
132            }
133
134            return err;
135        }
136    }
137
138    return OK;
139}
140
141void MPEG4Writer::stop() {
142    if (mFile == NULL) {
143        return;
144    }
145
146    int64_t max_duration = 0;
147    for (List<Track *>::iterator it = mTracks.begin();
148         it != mTracks.end(); ++it) {
149        (*it)->stop();
150
151        int64_t duration = (*it)->getDurationUs();
152        if (duration > max_duration) {
153            max_duration = duration;
154        }
155    }
156
157    // Fix up the size of the 'mdat' chunk.
158    fseek(mFile, mMdatOffset + 8, SEEK_SET);
159    int64_t size = mOffset - mMdatOffset;
160    size = hton64(size);
161    fwrite(&size, 1, 8, mFile);
162    fseek(mFile, mOffset, SEEK_SET);
163
164    time_t now = time(NULL);
165
166    beginBox("moov");
167
168      beginBox("mvhd");
169        writeInt32(0);             // version=0, flags=0
170        writeInt32(now);           // creation time
171        writeInt32(now);           // modification time
172        writeInt32(1000);          // timescale
173        writeInt32(max_duration / 1000);
174        writeInt32(0x10000);       // rate
175        writeInt16(0x100);         // volume
176        writeInt16(0);             // reserved
177        writeInt32(0);             // reserved
178        writeInt32(0);             // reserved
179        writeInt32(0x10000);       // matrix
180        writeInt32(0);
181        writeInt32(0);
182        writeInt32(0);
183        writeInt32(0x10000);
184        writeInt32(0);
185        writeInt32(0);
186        writeInt32(0);
187        writeInt32(0x40000000);
188        writeInt32(0);             // predefined
189        writeInt32(0);             // predefined
190        writeInt32(0);             // predefined
191        writeInt32(0);             // predefined
192        writeInt32(0);             // predefined
193        writeInt32(0);             // predefined
194        writeInt32(mTracks.size() + 1);  // nextTrackID
195      endBox();  // mvhd
196
197      int32_t id = 1;
198      for (List<Track *>::iterator it = mTracks.begin();
199           it != mTracks.end(); ++it, ++id) {
200          (*it)->writeTrackHeader(id);
201      }
202    endBox();  // moov
203
204    CHECK(mBoxes.empty());
205
206    fclose(mFile);
207    mFile = NULL;
208}
209
210off_t MPEG4Writer::addSample(MediaBuffer *buffer) {
211    Mutex::Autolock autoLock(mLock);
212
213    off_t old_offset = mOffset;
214
215    fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
216           1, buffer->range_length(), mFile);
217
218    mOffset += buffer->range_length();
219
220    return old_offset;
221}
222
223static void StripStartcode(MediaBuffer *buffer) {
224    if (buffer->range_length() < 4) {
225        return;
226    }
227
228    const uint8_t *ptr =
229        (const uint8_t *)buffer->data() + buffer->range_offset();
230
231    if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
232        buffer->set_range(
233                buffer->range_offset() + 4, buffer->range_length() - 4);
234    }
235}
236
237off_t MPEG4Writer::addLengthPrefixedSample(MediaBuffer *buffer) {
238    Mutex::Autolock autoLock(mLock);
239
240    StripStartcode(buffer);
241
242    off_t old_offset = mOffset;
243
244    size_t length = buffer->range_length();
245
246#if USE_NALLEN_FOUR
247    uint8_t x = length >> 24;
248    fwrite(&x, 1, 1, mFile);
249    x = (length >> 16) & 0xff;
250    fwrite(&x, 1, 1, mFile);
251    x = (length >> 8) & 0xff;
252    fwrite(&x, 1, 1, mFile);
253    x = length & 0xff;
254    fwrite(&x, 1, 1, mFile);
255#else
256    CHECK(length < 65536);
257
258    uint8_t x = length >> 8;
259    fwrite(&x, 1, 1, mFile);
260    x = length & 0xff;
261    fwrite(&x, 1, 1, mFile);
262#endif
263
264    fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
265           1, length, mFile);
266
267#if USE_NALLEN_FOUR
268    mOffset += length + 4;
269#else
270    mOffset += length + 2;
271#endif
272
273    return old_offset;
274}
275
276void MPEG4Writer::beginBox(const char *fourcc) {
277    CHECK_EQ(strlen(fourcc), 4);
278
279    mBoxes.push_back(mOffset);
280
281    writeInt32(0);
282    writeFourcc(fourcc);
283}
284
285void MPEG4Writer::endBox() {
286    CHECK(!mBoxes.empty());
287
288    off_t offset = *--mBoxes.end();
289    mBoxes.erase(--mBoxes.end());
290
291    fseek(mFile, offset, SEEK_SET);
292    writeInt32(mOffset - offset);
293    mOffset -= 4;
294    fseek(mFile, mOffset, SEEK_SET);
295}
296
297void MPEG4Writer::writeInt8(int8_t x) {
298    fwrite(&x, 1, 1, mFile);
299    ++mOffset;
300}
301
302void MPEG4Writer::writeInt16(int16_t x) {
303    x = htons(x);
304    fwrite(&x, 1, 2, mFile);
305    mOffset += 2;
306}
307
308void MPEG4Writer::writeInt32(int32_t x) {
309    x = htonl(x);
310    fwrite(&x, 1, 4, mFile);
311    mOffset += 4;
312}
313
314void MPEG4Writer::writeInt64(int64_t x) {
315    x = hton64(x);
316    fwrite(&x, 1, 8, mFile);
317    mOffset += 8;
318}
319
320void MPEG4Writer::writeCString(const char *s) {
321    size_t n = strlen(s);
322
323    fwrite(s, 1, n + 1, mFile);
324    mOffset += n + 1;
325}
326
327void MPEG4Writer::writeFourcc(const char *s) {
328    CHECK_EQ(strlen(s), 4);
329    fwrite(s, 1, 4, mFile);
330    mOffset += 4;
331}
332
333void MPEG4Writer::write(const void *data, size_t size) {
334    fwrite(data, 1, size, mFile);
335    mOffset += size;
336}
337
338bool MPEG4Writer::reachedEOS() {
339    bool allDone = true;
340    for (List<Track *>::iterator it = mTracks.begin();
341         it != mTracks.end(); ++it) {
342        if (!(*it)->reachedEOS()) {
343            allDone = false;
344            break;
345        }
346    }
347
348    return allDone;
349}
350
351////////////////////////////////////////////////////////////////////////////////
352
353MPEG4Writer::Track::Track(
354        MPEG4Writer *owner, const sp<MediaSource> &source)
355    : mOwner(owner),
356      mMeta(source->getFormat()),
357      mSource(source),
358      mDone(false),
359      mMaxTimeStampUs(0),
360      mCodecSpecificData(NULL),
361      mCodecSpecificDataSize(0),
362      mGotAllCodecSpecificData(false),
363      mReachedEOS(false) {
364}
365
366MPEG4Writer::Track::~Track() {
367    stop();
368
369    if (mCodecSpecificData != NULL) {
370        free(mCodecSpecificData);
371        mCodecSpecificData = NULL;
372    }
373}
374
375status_t MPEG4Writer::Track::start() {
376    status_t err = mSource->start();
377
378    if (err != OK) {
379        mDone = mReachedEOS = true;
380        return err;
381    }
382
383    pthread_attr_t attr;
384    pthread_attr_init(&attr);
385    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
386
387    mDone = false;
388    mMaxTimeStampUs = 0;
389    mReachedEOS = false;
390
391    pthread_create(&mThread, &attr, ThreadWrapper, this);
392    pthread_attr_destroy(&attr);
393
394    return OK;
395}
396
397void MPEG4Writer::Track::stop() {
398    if (mDone) {
399        return;
400    }
401
402    mDone = true;
403
404    void *dummy;
405    pthread_join(mThread, &dummy);
406
407    mSource->stop();
408}
409
410bool MPEG4Writer::Track::reachedEOS() {
411    return mReachedEOS;
412}
413
414// static
415void *MPEG4Writer::Track::ThreadWrapper(void *me) {
416    Track *track = static_cast<Track *>(me);
417
418    track->threadEntry();
419
420    return NULL;
421}
422
423#include <ctype.h>
424static void hexdump(const void *_data, size_t size) {
425    const uint8_t *data = (const uint8_t *)_data;
426    size_t offset = 0;
427    while (offset < size) {
428        printf("0x%04x  ", offset);
429
430        size_t n = size - offset;
431        if (n > 16) {
432            n = 16;
433        }
434
435        for (size_t i = 0; i < 16; ++i) {
436            if (i == 8) {
437                printf(" ");
438            }
439
440            if (offset + i < size) {
441                printf("%02x ", data[offset + i]);
442            } else {
443                printf("   ");
444            }
445        }
446
447        printf(" ");
448
449        for (size_t i = 0; i < n; ++i) {
450            if (isprint(data[offset + i])) {
451                printf("%c", data[offset + i]);
452            } else {
453                printf(".");
454            }
455        }
456
457        printf("\n");
458
459        offset += 16;
460    }
461}
462
463
464status_t MPEG4Writer::Track::makeAVCCodecSpecificData(
465        const uint8_t *data, size_t size) {
466    // hexdump(data, size);
467
468    if (mCodecSpecificData != NULL) {
469        LOGE("Already have codec specific data");
470        return ERROR_MALFORMED;
471    }
472
473    if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) {
474        LOGE("Must start with a start code");
475        return ERROR_MALFORMED;
476    }
477
478    size_t picParamOffset = 4;
479    while (picParamOffset + 3 < size
480            && memcmp("\x00\x00\x00\x01", &data[picParamOffset], 4)) {
481        ++picParamOffset;
482    }
483
484    if (picParamOffset + 3 >= size) {
485        LOGE("Could not find start-code for pictureParameterSet");
486        return ERROR_MALFORMED;
487    }
488
489    size_t seqParamSetLength = picParamOffset - 4;
490    size_t picParamSetLength = size - picParamOffset - 4;
491
492    mCodecSpecificDataSize =
493        6 + 1 + seqParamSetLength + 2 + picParamSetLength + 2;
494
495    mCodecSpecificData = malloc(mCodecSpecificDataSize);
496    uint8_t *header = (uint8_t *)mCodecSpecificData;
497    header[0] = 1;
498    header[1] = 0x42;  // profile
499    header[2] = 0x80;
500    header[3] = 0x1e;  // level
501
502#if USE_NALLEN_FOUR
503    header[4] = 0xfc | 3;  // length size == 4 bytes
504#else
505    header[4] = 0xfc | 1;  // length size == 2 bytes
506#endif
507
508    header[5] = 0xe0 | 1;
509    header[6] = seqParamSetLength >> 8;
510    header[7] = seqParamSetLength & 0xff;
511    memcpy(&header[8], &data[4], seqParamSetLength);
512    header += 8 + seqParamSetLength;
513    header[0] = 1;
514    header[1] = picParamSetLength >> 8;
515    header[2] = picParamSetLength & 0xff;
516    memcpy(&header[3], &data[picParamOffset + 4], picParamSetLength);
517
518    return OK;
519}
520
521void MPEG4Writer::Track::threadEntry() {
522    sp<MetaData> meta = mSource->getFormat();
523    const char *mime;
524    meta->findCString(kKeyMIMEType, &mime);
525    bool is_mpeg4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4);
526    bool is_avc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
527    int32_t count = 0;
528
529    MediaBuffer *buffer;
530    while (!mDone && mSource->read(&buffer) == OK) {
531        if (buffer->range_length() == 0) {
532            buffer->release();
533            buffer = NULL;
534
535            continue;
536        }
537
538        ++count;
539
540        int32_t isCodecConfig;
541        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
542                && isCodecConfig) {
543            CHECK(!mGotAllCodecSpecificData);
544
545            if (is_avc) {
546                status_t err = makeAVCCodecSpecificData(
547                        (const uint8_t *)buffer->data()
548                            + buffer->range_offset(),
549                        buffer->range_length());
550
551                if (err != OK) {
552                    LOGE("failed to parse avc codec specific data.");
553                    break;
554                }
555            } else if (is_mpeg4) {
556                mCodecSpecificDataSize = buffer->range_length();
557                mCodecSpecificData = malloc(mCodecSpecificDataSize);
558                memcpy(mCodecSpecificData,
559                        (const uint8_t *)buffer->data()
560                            + buffer->range_offset(),
561                       buffer->range_length());
562            }
563
564            buffer->release();
565            buffer = NULL;
566
567            mGotAllCodecSpecificData = true;
568            continue;
569        } else if (!mGotAllCodecSpecificData &&
570                count == 1 && is_mpeg4 && mCodecSpecificData == NULL) {
571            // The TI mpeg4 encoder does not properly set the
572            // codec-specific-data flag.
573
574            const uint8_t *data =
575                (const uint8_t *)buffer->data() + buffer->range_offset();
576
577            const size_t size = buffer->range_length();
578
579            size_t offset = 0;
580            while (offset + 3 < size) {
581                if (data[offset] == 0x00 && data[offset + 1] == 0x00
582                    && data[offset + 2] == 0x01 && data[offset + 3] == 0xb6) {
583                    break;
584                }
585
586                ++offset;
587            }
588
589            // CHECK(offset + 3 < size);
590            if (offset + 3 >= size) {
591                // XXX assume the entire first chunk of data is the codec specific
592                // data.
593                offset = size;
594            }
595
596            mCodecSpecificDataSize = offset;
597            mCodecSpecificData = malloc(offset);
598            memcpy(mCodecSpecificData, data, offset);
599
600            buffer->set_range(buffer->range_offset() + offset, size - offset);
601
602            if (size == offset) {
603                buffer->release();
604                buffer = NULL;
605
606                continue;
607            }
608
609            mGotAllCodecSpecificData = true;
610        } else if (!mGotAllCodecSpecificData && is_avc && count < 3) {
611            // The TI video encoder does not flag codec specific data
612            // as such and also splits up SPS and PPS across two buffers.
613
614            const uint8_t *data =
615                (const uint8_t *)buffer->data() + buffer->range_offset();
616
617            size_t size = buffer->range_length();
618
619            CHECK(count == 2 || mCodecSpecificData == NULL);
620
621            size_t offset = mCodecSpecificDataSize;
622            mCodecSpecificDataSize += size + 4;
623            mCodecSpecificData =
624                realloc(mCodecSpecificData, mCodecSpecificDataSize);
625
626            memcpy((uint8_t *)mCodecSpecificData + offset,
627                   "\x00\x00\x00\x01", 4);
628
629            memcpy((uint8_t *)mCodecSpecificData + offset + 4, data, size);
630
631            buffer->release();
632            buffer = NULL;
633
634            if (count == 2) {
635                void *tmp = mCodecSpecificData;
636                size = mCodecSpecificDataSize;
637                mCodecSpecificData = NULL;
638                mCodecSpecificDataSize = 0;
639
640                status_t err = makeAVCCodecSpecificData(
641                        (const uint8_t *)tmp, size);
642
643                free(tmp);
644                tmp = NULL;
645
646                if (err != OK) {
647                    LOGE("failed to parse avc codec specific data.");
648                    break;
649                }
650
651                mGotAllCodecSpecificData = true;
652            }
653
654            continue;
655        }
656
657        off_t offset = is_avc ? mOwner->addLengthPrefixedSample(buffer)
658                              : mOwner->addSample(buffer);
659
660        SampleInfo info;
661        info.size = is_avc
662#if USE_NALLEN_FOUR
663            ? buffer->range_length() + 4
664#else
665            ? buffer->range_length() + 2
666#endif
667            : buffer->range_length();
668
669        info.offset = offset;
670
671        int64_t timestampUs;
672        CHECK(buffer->meta_data()->findInt64(kKeyTime, &timestampUs));
673
674        if (timestampUs > mMaxTimeStampUs) {
675            mMaxTimeStampUs = timestampUs;
676        }
677
678        // Our timestamp is in ms.
679        info.timestamp = (timestampUs + 500) / 1000;
680
681        mSampleInfos.push_back(info);
682
683        buffer->release();
684        buffer = NULL;
685    }
686
687    mReachedEOS = true;
688}
689
690int64_t MPEG4Writer::Track::getDurationUs() const {
691    return mMaxTimeStampUs;
692}
693
694void MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
695    const char *mime;
696    bool success = mMeta->findCString(kKeyMIMEType, &mime);
697    CHECK(success);
698
699    bool is_audio = !strncasecmp(mime, "audio/", 6);
700
701    time_t now = time(NULL);
702
703    mOwner->beginBox("trak");
704
705      mOwner->beginBox("tkhd");
706        mOwner->writeInt32(0);             // version=0, flags=0
707        mOwner->writeInt32(now);           // creation time
708        mOwner->writeInt32(now);           // modification time
709        mOwner->writeInt32(trackID);
710        mOwner->writeInt32(0);             // reserved
711        mOwner->writeInt32(getDurationUs() / 1000);
712        mOwner->writeInt32(0);             // reserved
713        mOwner->writeInt32(0);             // reserved
714        mOwner->writeInt16(0);             // layer
715        mOwner->writeInt16(0);             // alternate group
716        mOwner->writeInt16(is_audio ? 0x100 : 0);  // volume
717        mOwner->writeInt16(0);             // reserved
718
719        mOwner->writeInt32(0x10000);       // matrix
720        mOwner->writeInt32(0);
721        mOwner->writeInt32(0);
722        mOwner->writeInt32(0);
723        mOwner->writeInt32(0x10000);
724        mOwner->writeInt32(0);
725        mOwner->writeInt32(0);
726        mOwner->writeInt32(0);
727        mOwner->writeInt32(0x40000000);
728
729        if (is_audio) {
730            mOwner->writeInt32(0);
731            mOwner->writeInt32(0);
732        } else {
733            int32_t width, height;
734            bool success = mMeta->findInt32(kKeyWidth, &width);
735            success = success && mMeta->findInt32(kKeyHeight, &height);
736            CHECK(success);
737
738            mOwner->writeInt32(width);
739            mOwner->writeInt32(height);
740        }
741      mOwner->endBox();  // tkhd
742
743      mOwner->beginBox("mdia");
744
745        mOwner->beginBox("mdhd");
746          mOwner->writeInt32(0);             // version=0, flags=0
747          mOwner->writeInt32(now);           // creation time
748          mOwner->writeInt32(now);           // modification time
749          mOwner->writeInt32(1000);          // timescale
750          mOwner->writeInt32(getDurationUs() / 1000);
751          mOwner->writeInt16(0);             // language code XXX
752          mOwner->writeInt16(0);             // predefined
753        mOwner->endBox();
754
755        mOwner->beginBox("hdlr");
756          mOwner->writeInt32(0);             // version=0, flags=0
757          mOwner->writeInt32(0);             // predefined
758          mOwner->writeFourcc(is_audio ? "soun" : "vide");
759          mOwner->writeInt32(0);             // reserved
760          mOwner->writeInt32(0);             // reserved
761          mOwner->writeInt32(0);             // reserved
762          mOwner->writeCString("");          // name
763        mOwner->endBox();
764
765        mOwner->beginBox("minf");
766
767          mOwner->beginBox("dinf");
768            mOwner->beginBox("dref");
769              mOwner->writeInt32(0);  // version=0, flags=0
770              mOwner->writeInt32(1);
771              mOwner->beginBox("url ");
772                mOwner->writeInt32(1);  // version=0, flags=1
773              mOwner->endBox();  // url
774            mOwner->endBox();  // dref
775          mOwner->endBox();  // dinf
776
777          if (is_audio) {
778              mOwner->beginBox("smhd");
779              mOwner->writeInt32(0);           // version=0, flags=0
780              mOwner->writeInt16(0);           // balance
781              mOwner->writeInt16(0);           // reserved
782              mOwner->endBox();
783          } else {
784              mOwner->beginBox("vmhd");
785              mOwner->writeInt32(0x00000001);  // version=0, flags=1
786              mOwner->writeInt16(0);           // graphics mode
787              mOwner->writeInt16(0);           // opcolor
788              mOwner->writeInt16(0);
789              mOwner->writeInt16(0);
790              mOwner->endBox();
791          }
792        mOwner->endBox();  // minf
793
794        mOwner->beginBox("stbl");
795
796          mOwner->beginBox("stsd");
797            mOwner->writeInt32(0);               // version=0, flags=0
798            mOwner->writeInt32(1);               // entry count
799            if (is_audio) {
800                const char *fourcc = NULL;
801                if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
802                    fourcc = "samr";
803                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
804                    fourcc = "sawb";
805                } else {
806                    LOGE("Unknown mime type '%s'.", mime);
807                    CHECK(!"should not be here, unknown mime type.");
808                }
809
810                mOwner->beginBox(fourcc);          // audio format
811                  mOwner->writeInt32(0);           // reserved
812                  mOwner->writeInt16(0);           // reserved
813                  mOwner->writeInt16(0);           // data ref index
814                  mOwner->writeInt32(0);           // reserved
815                  mOwner->writeInt32(0);           // reserved
816                  mOwner->writeInt16(2);           // channel count
817                  mOwner->writeInt16(16);          // sample size
818                  mOwner->writeInt16(0);           // predefined
819                  mOwner->writeInt16(0);           // reserved
820
821                  int32_t samplerate;
822                  bool success = mMeta->findInt32(kKeySampleRate, &samplerate);
823                  CHECK(success);
824
825                  mOwner->writeInt32(samplerate << 16);
826                mOwner->endBox();
827            } else {
828                if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
829                    mOwner->beginBox("mp4v");
830                } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
831                    mOwner->beginBox("s263");
832                } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
833                    mOwner->beginBox("avc1");
834                } else {
835                    LOGE("Unknown mime type '%s'.", mime);
836                    CHECK(!"should not be here, unknown mime type.");
837                }
838
839                  mOwner->writeInt32(0);           // reserved
840                  mOwner->writeInt16(0);           // reserved
841                  mOwner->writeInt16(0);           // data ref index
842                  mOwner->writeInt16(0);           // predefined
843                  mOwner->writeInt16(0);           // reserved
844                  mOwner->writeInt32(0);           // predefined
845                  mOwner->writeInt32(0);           // predefined
846                  mOwner->writeInt32(0);           // predefined
847
848                  int32_t width, height;
849                  bool success = mMeta->findInt32(kKeyWidth, &width);
850                  success = success && mMeta->findInt32(kKeyHeight, &height);
851                  CHECK(success);
852
853                  mOwner->writeInt16(width);
854                  mOwner->writeInt16(height);
855                  mOwner->writeInt32(0x480000);    // horiz resolution
856                  mOwner->writeInt32(0x480000);    // vert resolution
857                  mOwner->writeInt32(0);           // reserved
858                  mOwner->writeInt16(1);           // frame count
859                  mOwner->write("                                ", 32);
860                  mOwner->writeInt16(0x18);        // depth
861                  mOwner->writeInt16(-1);          // predefined
862
863                  CHECK(23 + mCodecSpecificDataSize < 128);
864
865                  if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
866                      mOwner->beginBox("esds");
867
868                        mOwner->writeInt32(0);           // version=0, flags=0
869
870                        mOwner->writeInt8(0x03);  // ES_DescrTag
871                        mOwner->writeInt8(23 + mCodecSpecificDataSize);
872                        mOwner->writeInt16(0x0000);  // ES_ID
873                        mOwner->writeInt8(0x1f);
874
875                        mOwner->writeInt8(0x04);  // DecoderConfigDescrTag
876                        mOwner->writeInt8(15 + mCodecSpecificDataSize);
877                        mOwner->writeInt8(0x20);  // objectTypeIndication ISO/IEC 14492-2
878                        mOwner->writeInt8(0x11);  // streamType VisualStream
879
880                        static const uint8_t kData[] = {
881                            0x01, 0x77, 0x00,
882                            0x00, 0x03, 0xe8, 0x00,
883                            0x00, 0x03, 0xe8, 0x00
884                        };
885                        mOwner->write(kData, sizeof(kData));
886
887                        mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
888
889                        mOwner->writeInt8(mCodecSpecificDataSize);
890                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
891
892                        static const uint8_t kData2[] = {
893                            0x06,  // SLConfigDescriptorTag
894                            0x01,
895                            0x02
896                        };
897                        mOwner->write(kData2, sizeof(kData2));
898
899                      mOwner->endBox();  // esds
900                  } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
901                      mOwner->beginBox("d263");
902
903                          mOwner->writeInt32(0);  // vendor
904                          mOwner->writeInt8(0);   // decoder version
905                          mOwner->writeInt8(10);  // level: 10
906                          mOwner->writeInt8(0);   // profile: 0
907
908                      mOwner->endBox();  // d263
909                  } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
910                      mOwner->beginBox("avcC");
911                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
912                      mOwner->endBox();  // avcC
913                  }
914
915                mOwner->endBox();  // mp4v, s263 or avc1
916            }
917          mOwner->endBox();  // stsd
918
919          mOwner->beginBox("stts");
920            mOwner->writeInt32(0);  // version=0, flags=0
921            mOwner->writeInt32(mSampleInfos.size());
922
923            List<SampleInfo>::iterator it = mSampleInfos.begin();
924            int64_t last = (*it).timestamp;
925            int64_t lastDuration = 1;
926
927            ++it;
928            while (it != mSampleInfos.end()) {
929                mOwner->writeInt32(1);
930                lastDuration = (*it).timestamp - last;
931                mOwner->writeInt32(lastDuration);
932
933                last = (*it).timestamp;
934
935                ++it;
936            }
937
938            // We don't really know how long the last frame lasts, since
939            // there is no frame time after it, just repeat the previous
940            // frame's duration.
941            mOwner->writeInt32(1);
942            mOwner->writeInt32(lastDuration);
943
944          mOwner->endBox();  // stts
945
946          mOwner->beginBox("stsz");
947            mOwner->writeInt32(0);  // version=0, flags=0
948            mOwner->writeInt32(0);  // default sample size
949            mOwner->writeInt32(mSampleInfos.size());
950            for (List<SampleInfo>::iterator it = mSampleInfos.begin();
951                 it != mSampleInfos.end(); ++it) {
952                mOwner->writeInt32((*it).size);
953            }
954          mOwner->endBox();  // stsz
955
956          mOwner->beginBox("stsc");
957            mOwner->writeInt32(0);  // version=0, flags=0
958            mOwner->writeInt32(mSampleInfos.size());
959            int32_t n = 1;
960            for (List<SampleInfo>::iterator it = mSampleInfos.begin();
961                 it != mSampleInfos.end(); ++it, ++n) {
962                mOwner->writeInt32(n);
963                mOwner->writeInt32(1);
964                mOwner->writeInt32(1);
965            }
966          mOwner->endBox();  // stsc
967
968          mOwner->beginBox("co64");
969            mOwner->writeInt32(0);  // version=0, flags=0
970            mOwner->writeInt32(mSampleInfos.size());
971            for (List<SampleInfo>::iterator it = mSampleInfos.begin();
972                 it != mSampleInfos.end(); ++it, ++n) {
973                mOwner->writeInt64((*it).offset);
974            }
975          mOwner->endBox();  // co64
976
977        mOwner->endBox();  // stbl
978      mOwner->endBox();  // mdia
979    mOwner->endBox();  // trak
980}
981
982}  // namespace android
983