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