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