MPEG4Writer.cpp revision 2dec2b5be2056c6d9428897dc672185872d30d17
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#include <media/mediarecorder.h>
35#include <cutils/properties.h>
36
37namespace android {
38
39class MPEG4Writer::Track {
40public:
41    Track(MPEG4Writer *owner, const sp<MediaSource> &source);
42    ~Track();
43
44    status_t start(int64_t startTimeUs);
45    void stop();
46    void pause();
47    bool reachedEOS();
48
49    int64_t getDurationUs() const;
50    int64_t getEstimatedTrackSizeBytes() const;
51    void writeTrackHeader(int32_t trackID, bool use32BitOffset = true);
52
53private:
54    MPEG4Writer *mOwner;
55    sp<MetaData> mMeta;
56    sp<MediaSource> mSource;
57    volatile bool mDone;
58    volatile bool mPaused;
59    volatile bool mResumed;
60    int64_t mMaxTimeStampUs;
61    int64_t mEstimatedTrackSizeBytes;
62
63    pthread_t mThread;
64
65    struct SampleInfo {
66        size_t size;
67        int64_t timestamp;
68    };
69    List<SampleInfo>    mSampleInfos;
70    bool                mSamplesHaveSameSize;
71
72    List<MediaBuffer *> mChunkSamples;
73    List<off_t>         mChunkOffsets;
74
75    struct StscTableEntry {
76
77        StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id)
78            : firstChunk(chunk),
79              samplesPerChunk(samples),
80              sampleDescriptionId(id) {}
81
82        uint32_t firstChunk;
83        uint32_t samplesPerChunk;
84        uint32_t sampleDescriptionId;
85    };
86    List<StscTableEntry> mStscTableEntries;
87
88    List<int32_t> mStssTableEntries;
89    List<int64_t> mChunkDurations;
90
91    struct SttsTableEntry {
92
93        SttsTableEntry(uint32_t count, uint32_t duration)
94            : sampleCount(count), sampleDuration(duration) {}
95
96        uint32_t sampleCount;
97        uint32_t sampleDuration;
98    };
99    List<SttsTableEntry> mSttsTableEntries;
100
101    void *mCodecSpecificData;
102    size_t mCodecSpecificDataSize;
103    bool mGotAllCodecSpecificData;
104
105    bool mReachedEOS;
106    int64_t mStartTimestampUs;
107
108    static void *ThreadWrapper(void *me);
109    void threadEntry();
110
111    status_t makeAVCCodecSpecificData(
112            const uint8_t *data, size_t size);
113    void writeOneChunk(bool isAvc);
114    void logStatisticalData(bool isAudio);
115    void findMinMaxFrameRates(float *minFps, float *maxFps);
116    void findMinMaxChunkDurations(int64_t *min, int64_t *max);
117
118    Track(const Track &);
119    Track &operator=(const Track &);
120};
121
122#define USE_NALLEN_FOUR         1
123
124MPEG4Writer::MPEG4Writer(const char *filename)
125    : mFile(fopen(filename, "wb")),
126      mUse32BitOffset(true),
127      mPaused(false),
128      mStarted(false),
129      mOffset(0),
130      mMdatOffset(0),
131      mEstimatedMoovBoxSize(0),
132      mInterleaveDurationUs(500000) {
133    CHECK(mFile != NULL);
134}
135
136MPEG4Writer::MPEG4Writer(int fd)
137    : mFile(fdopen(fd, "wb")),
138      mUse32BitOffset(true),
139      mPaused(false),
140      mStarted(false),
141      mOffset(0),
142      mMdatOffset(0),
143      mEstimatedMoovBoxSize(0),
144      mInterleaveDurationUs(500000) {
145    CHECK(mFile != NULL);
146}
147
148MPEG4Writer::~MPEG4Writer() {
149    stop();
150
151    for (List<Track *>::iterator it = mTracks.begin();
152         it != mTracks.end(); ++it) {
153        delete *it;
154    }
155    mTracks.clear();
156}
157
158status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
159    Track *track = new Track(this, source);
160    mTracks.push_back(track);
161
162    return OK;
163}
164
165status_t MPEG4Writer::startTracks() {
166    int64_t startTimeUs = systemTime() / 1000;
167    for (List<Track *>::iterator it = mTracks.begin();
168         it != mTracks.end(); ++it) {
169        status_t err = (*it)->start(startTimeUs);
170
171        if (err != OK) {
172            for (List<Track *>::iterator it2 = mTracks.begin();
173                 it2 != it; ++it2) {
174                (*it2)->stop();
175            }
176
177            return err;
178        }
179    }
180    return OK;
181}
182
183int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) {
184    // This implementation is highly experimental/heurisitic.
185    //
186    // Statistical analysis shows that metadata usually accounts
187    // for a small portion of the total file size, usually < 0.6%.
188    // Currently, lets set to 0.4% for now.
189
190    // The default MIN_MOOV_BOX_SIZE is set to 0.4% x 1MB,
191    // where 1MB is the common file size limit for MMS application.
192    // The default MAX _MOOV_BOX_SIZE value is based on about 4
193    // minute video recording with a bit rate about 3 Mbps, because
194    // statistics also show that most of the video captured are going
195    // to be less than 3 minutes.
196
197    // If the estimation is wrong, we will pay the price of wasting
198    // some reserved space. This should not happen so often statistically.
199    static const int32_t factor = mUse32BitOffset? 1: 2;
200    static const int64_t MIN_MOOV_BOX_SIZE = 4 * 1024;  // 4 KB
201    static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000);
202    int64_t size = MIN_MOOV_BOX_SIZE;
203
204    if (mMaxFileSizeLimitBytes != 0) {
205        size = mMaxFileSizeLimitBytes * 4 / 1000;
206    } else if (mMaxFileDurationLimitUs != 0) {
207        if (bitRate <= 0) {
208            // We could not estimate the file size since bitRate is not set.
209            size = MIN_MOOV_BOX_SIZE;
210        } else {
211            size = ((mMaxFileDurationLimitUs * bitRate * 4) / 1000 / 8000000);
212        }
213    }
214    if (size < MIN_MOOV_BOX_SIZE) {
215        size = MIN_MOOV_BOX_SIZE;
216    }
217
218    // Any long duration recording will be probably end up with
219    // non-streamable mp4 file.
220    if (size > MAX_MOOV_BOX_SIZE) {
221        size = MAX_MOOV_BOX_SIZE;
222    }
223
224    LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated"
225         " moov size %lld bytes",
226         mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size);
227    return factor * size;
228}
229
230status_t MPEG4Writer::start(MetaData *param) {
231    if (mFile == NULL) {
232        return UNKNOWN_ERROR;
233    }
234
235    int32_t use64BitOffset;
236    if (param &&
237        param->findInt32(kKey64BitFileOffset, &use64BitOffset) &&
238        use64BitOffset) {
239        mUse32BitOffset = false;
240    }
241
242    // System property can overwrite the file offset bits parameter
243    char value[PROPERTY_VALUE_MAX];
244    if (property_get("media.stagefright.record-64bits", value, NULL)
245        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
246        mUse32BitOffset = false;
247    }
248
249    mStartTimestampUs = -1;
250    if (mStarted) {
251        if (mPaused) {
252            mPaused = false;
253            return startTracks();
254        }
255        return OK;
256    }
257
258    mStreamableFile = true;
259    mWriteMoovBoxToMemory = false;
260    mMoovBoxBuffer = NULL;
261    mMoovBoxBufferOffset = 0;
262
263    beginBox("ftyp");
264      writeFourcc("isom");
265      writeInt32(0);
266      writeFourcc("isom");
267    endBox();
268
269    mFreeBoxOffset = mOffset;
270
271    if (mEstimatedMoovBoxSize == 0) {
272        int32_t bitRate = -1;
273        if (param) {
274            param->findInt32(kKeyBitRate, &bitRate);
275        }
276        mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate);
277    }
278    CHECK(mEstimatedMoovBoxSize >= 8);
279    fseeko(mFile, mFreeBoxOffset, SEEK_SET);
280    writeInt32(mEstimatedMoovBoxSize);
281    write("free", 4);
282
283    mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize;
284    mOffset = mMdatOffset;
285    fseeko(mFile, mMdatOffset, SEEK_SET);
286    if (mUse32BitOffset) {
287        write("????mdat", 8);
288    } else {
289        write("\x00\x00\x00\x01mdat????????", 16);
290    }
291
292    status_t err = startTracks();
293    if (err != OK) {
294        return err;
295    }
296    mStarted = true;
297    return OK;
298}
299
300void MPEG4Writer::pause() {
301    if (mFile == NULL) {
302        return;
303    }
304    mPaused = true;
305    for (List<Track *>::iterator it = mTracks.begin();
306         it != mTracks.end(); ++it) {
307        (*it)->pause();
308    }
309}
310
311void MPEG4Writer::stop() {
312    if (mFile == NULL) {
313        return;
314    }
315
316    int64_t max_duration = 0;
317    for (List<Track *>::iterator it = mTracks.begin();
318         it != mTracks.end(); ++it) {
319        (*it)->stop();
320
321        int64_t duration = (*it)->getDurationUs();
322        if (duration > max_duration) {
323            max_duration = duration;
324        }
325    }
326
327
328    // Fix up the size of the 'mdat' chunk.
329    if (mUse32BitOffset) {
330        fseeko(mFile, mMdatOffset, SEEK_SET);
331        int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset));
332        fwrite(&size, 1, 4, mFile);
333    } else {
334        fseeko(mFile, mMdatOffset + 8, SEEK_SET);
335        int64_t size = mOffset - mMdatOffset;
336        size = hton64(size);
337        fwrite(&size, 1, 8, mFile);
338    }
339    fseeko(mFile, mOffset, SEEK_SET);
340
341    time_t now = time(NULL);
342    const off_t moovOffset = mOffset;
343    mWriteMoovBoxToMemory = true;
344    mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
345    mMoovBoxBufferOffset = 0;
346    CHECK(mMoovBoxBuffer != NULL);
347    int32_t timeScale = 1000;
348    int32_t duration = max_duration / timeScale;
349
350    beginBox("moov");
351
352      beginBox("mvhd");
353        writeInt32(0);             // version=0, flags=0
354        writeInt32(now);           // creation time
355        writeInt32(now);           // modification time
356        writeInt32(timeScale);          // timescale
357        writeInt32(duration);
358        writeInt32(0x10000);       // rate: 1.0
359        writeInt16(0x100);         // volume
360        writeInt16(0);             // reserved
361        writeInt32(0);             // reserved
362        writeInt32(0);             // reserved
363        writeInt32(0x10000);       // matrix
364        writeInt32(0);
365        writeInt32(0);
366        writeInt32(0);
367        writeInt32(0x10000);
368        writeInt32(0);
369        writeInt32(0);
370        writeInt32(0);
371        writeInt32(0x40000000);
372        writeInt32(0);             // predefined
373        writeInt32(0);             // predefined
374        writeInt32(0);             // predefined
375        writeInt32(0);             // predefined
376        writeInt32(0);             // predefined
377        writeInt32(0);             // predefined
378        writeInt32(mTracks.size() + 1);  // nextTrackID
379      endBox();  // mvhd
380
381      int32_t id = 1;
382      for (List<Track *>::iterator it = mTracks.begin();
383           it != mTracks.end(); ++it, ++id) {
384          (*it)->writeTrackHeader(id, mUse32BitOffset);
385      }
386    endBox();  // moov
387
388    mWriteMoovBoxToMemory = false;
389    if (mStreamableFile) {
390        CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize);
391
392        // Moov box
393        fseeko(mFile, mFreeBoxOffset, SEEK_SET);
394        mOffset = mFreeBoxOffset;
395        write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, mFile);
396
397        // Free box
398        fseeko(mFile, mOffset, SEEK_SET);
399        writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset);
400        write("free", 4);
401
402        // Free temp memory
403        free(mMoovBoxBuffer);
404        mMoovBoxBuffer = NULL;
405        mMoovBoxBufferOffset = 0;
406    } else {
407        LOGI("The mp4 file will not be streamable.");
408    }
409
410    CHECK(mBoxes.empty());
411
412    fflush(mFile);
413    fclose(mFile);
414    mFile = NULL;
415    mStarted = false;
416}
417
418status_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) {
419    mInterleaveDurationUs = durationUs;
420    return OK;
421}
422
423void MPEG4Writer::lock() {
424    mLock.lock();
425}
426
427void MPEG4Writer::unlock() {
428    mLock.unlock();
429}
430
431off_t MPEG4Writer::addSample_l(MediaBuffer *buffer) {
432    off_t old_offset = mOffset;
433
434    fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
435           1, buffer->range_length(), mFile);
436
437    mOffset += buffer->range_length();
438
439    return old_offset;
440}
441
442static void StripStartcode(MediaBuffer *buffer) {
443    if (buffer->range_length() < 4) {
444        return;
445    }
446
447    const uint8_t *ptr =
448        (const uint8_t *)buffer->data() + buffer->range_offset();
449
450    if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
451        buffer->set_range(
452                buffer->range_offset() + 4, buffer->range_length() - 4);
453    }
454}
455
456off_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
457    off_t old_offset = mOffset;
458
459    size_t length = buffer->range_length();
460
461#if USE_NALLEN_FOUR
462    uint8_t x = length >> 24;
463    fwrite(&x, 1, 1, mFile);
464    x = (length >> 16) & 0xff;
465    fwrite(&x, 1, 1, mFile);
466    x = (length >> 8) & 0xff;
467    fwrite(&x, 1, 1, mFile);
468    x = length & 0xff;
469    fwrite(&x, 1, 1, mFile);
470#else
471    CHECK(length < 65536);
472
473    uint8_t x = length >> 8;
474    fwrite(&x, 1, 1, mFile);
475    x = length & 0xff;
476    fwrite(&x, 1, 1, mFile);
477#endif
478
479    fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
480           1, length, mFile);
481
482#if USE_NALLEN_FOUR
483    mOffset += length + 4;
484#else
485    mOffset += length + 2;
486#endif
487
488    return old_offset;
489}
490
491size_t MPEG4Writer::write(
492        const void *ptr, size_t size, size_t nmemb, FILE *stream) {
493
494    const size_t bytes = size * nmemb;
495    if (mWriteMoovBoxToMemory) {
496        off_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes;
497        if (moovBoxSize > mEstimatedMoovBoxSize) {
498            for (List<off_t>::iterator it = mBoxes.begin();
499                 it != mBoxes.end(); ++it) {
500                (*it) += mOffset;
501            }
502            fseeko(mFile, mOffset, SEEK_SET);
503            fwrite(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, stream);
504            fwrite(ptr, size, nmemb, stream);
505            mOffset += (bytes + mMoovBoxBufferOffset);
506            free(mMoovBoxBuffer);
507            mMoovBoxBuffer = NULL;
508            mMoovBoxBufferOffset = 0;
509            mWriteMoovBoxToMemory = false;
510            mStreamableFile = false;
511        } else {
512            memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes);
513            mMoovBoxBufferOffset += bytes;
514        }
515    } else {
516        fwrite(ptr, size, nmemb, stream);
517        mOffset += bytes;
518    }
519    return bytes;
520}
521
522void MPEG4Writer::beginBox(const char *fourcc) {
523    CHECK_EQ(strlen(fourcc), 4);
524
525    mBoxes.push_back(mWriteMoovBoxToMemory?
526            mMoovBoxBufferOffset: mOffset);
527
528    writeInt32(0);
529    writeFourcc(fourcc);
530}
531
532void MPEG4Writer::endBox() {
533    CHECK(!mBoxes.empty());
534
535    off_t offset = *--mBoxes.end();
536    mBoxes.erase(--mBoxes.end());
537
538    if (mWriteMoovBoxToMemory) {
539       int32_t x = htonl(mMoovBoxBufferOffset - offset);
540       memcpy(mMoovBoxBuffer + offset, &x, 4);
541    } else {
542        fseeko(mFile, offset, SEEK_SET);
543        writeInt32(mOffset - offset);
544        mOffset -= 4;
545        fseeko(mFile, mOffset, SEEK_SET);
546    }
547}
548
549void MPEG4Writer::writeInt8(int8_t x) {
550    write(&x, 1, 1, mFile);
551}
552
553void MPEG4Writer::writeInt16(int16_t x) {
554    x = htons(x);
555    write(&x, 1, 2, mFile);
556}
557
558void MPEG4Writer::writeInt32(int32_t x) {
559    x = htonl(x);
560    write(&x, 1, 4, mFile);
561}
562
563void MPEG4Writer::writeInt64(int64_t x) {
564    x = hton64(x);
565    write(&x, 1, 8, mFile);
566}
567
568void MPEG4Writer::writeCString(const char *s) {
569    size_t n = strlen(s);
570    write(s, 1, n + 1, mFile);
571}
572
573void MPEG4Writer::writeFourcc(const char *s) {
574    CHECK_EQ(strlen(s), 4);
575    write(s, 1, 4, mFile);
576}
577
578void MPEG4Writer::write(const void *data, size_t size) {
579    write(data, 1, size, mFile);
580}
581
582bool MPEG4Writer::exceedsFileSizeLimit() {
583    // No limit
584    if (mMaxFileSizeLimitBytes == 0) {
585        return false;
586    }
587
588    int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize);
589    for (List<Track *>::iterator it = mTracks.begin();
590         it != mTracks.end(); ++it) {
591        nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
592    }
593    return (nTotalBytesEstimate >= mMaxFileSizeLimitBytes);
594}
595
596bool MPEG4Writer::exceedsFileDurationLimit() {
597    // No limit
598    if (mMaxFileDurationLimitUs == 0) {
599        return false;
600    }
601
602    for (List<Track *>::iterator it = mTracks.begin();
603         it != mTracks.end(); ++it) {
604        if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) {
605            return true;
606        }
607    }
608    return false;
609}
610
611bool MPEG4Writer::reachedEOS() {
612    bool allDone = true;
613    for (List<Track *>::iterator it = mTracks.begin();
614         it != mTracks.end(); ++it) {
615        if (!(*it)->reachedEOS()) {
616            allDone = false;
617            break;
618        }
619    }
620
621    return allDone;
622}
623
624void MPEG4Writer::setStartTimestampUs(int64_t timeUs) {
625    LOGI("setStartTimestampUs: %lld", timeUs);
626    CHECK(timeUs >= 0);
627    Mutex::Autolock autoLock(mLock);
628    if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) {
629        mStartTimestampUs = timeUs;
630        LOGI("Earliest track starting time: %lld", mStartTimestampUs);
631    }
632}
633
634int64_t MPEG4Writer::getStartTimestampUs() {
635    LOGI("getStartTimestampUs: %lld", mStartTimestampUs);
636    Mutex::Autolock autoLock(mLock);
637    return mStartTimestampUs;
638}
639
640size_t MPEG4Writer::numTracks() {
641    Mutex::Autolock autolock(mLock);
642    return mTracks.size();
643}
644
645////////////////////////////////////////////////////////////////////////////////
646
647MPEG4Writer::Track::Track(
648        MPEG4Writer *owner, const sp<MediaSource> &source)
649    : mOwner(owner),
650      mMeta(source->getFormat()),
651      mSource(source),
652      mDone(false),
653      mPaused(false),
654      mResumed(false),
655      mMaxTimeStampUs(0),
656      mEstimatedTrackSizeBytes(0),
657      mSamplesHaveSameSize(true),
658      mCodecSpecificData(NULL),
659      mCodecSpecificDataSize(0),
660      mGotAllCodecSpecificData(false),
661      mReachedEOS(false) {
662}
663
664MPEG4Writer::Track::~Track() {
665    stop();
666
667    if (mCodecSpecificData != NULL) {
668        free(mCodecSpecificData);
669        mCodecSpecificData = NULL;
670    }
671}
672
673status_t MPEG4Writer::Track::start(int64_t startTimeUs) {
674    if (!mDone && mPaused) {
675        mPaused = false;
676        mResumed = true;
677        return OK;
678    }
679
680    sp<MetaData> meta = new MetaData;
681    meta->setInt64(kKeyTime, startTimeUs);
682    status_t err = mSource->start(meta.get());
683    if (err != OK) {
684        mDone = mReachedEOS = true;
685        return err;
686    }
687
688    pthread_attr_t attr;
689    pthread_attr_init(&attr);
690    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
691
692    mDone = false;
693    mMaxTimeStampUs = 0;
694    mReachedEOS = false;
695    mEstimatedTrackSizeBytes = 0;
696
697    pthread_create(&mThread, &attr, ThreadWrapper, this);
698    pthread_attr_destroy(&attr);
699
700    return OK;
701}
702
703void MPEG4Writer::Track::pause() {
704    mPaused = true;
705}
706
707void MPEG4Writer::Track::stop() {
708    if (mDone) {
709        return;
710    }
711
712    mDone = true;
713
714    void *dummy;
715    pthread_join(mThread, &dummy);
716
717    mSource->stop();
718}
719
720bool MPEG4Writer::Track::reachedEOS() {
721    return mReachedEOS;
722}
723
724// static
725void *MPEG4Writer::Track::ThreadWrapper(void *me) {
726    Track *track = static_cast<Track *>(me);
727
728    track->threadEntry();
729
730    return NULL;
731}
732
733#include <ctype.h>
734static void hexdump(const void *_data, size_t size) {
735    const uint8_t *data = (const uint8_t *)_data;
736    size_t offset = 0;
737    while (offset < size) {
738        printf("0x%04x  ", offset);
739
740        size_t n = size - offset;
741        if (n > 16) {
742            n = 16;
743        }
744
745        for (size_t i = 0; i < 16; ++i) {
746            if (i == 8) {
747                printf(" ");
748            }
749
750            if (offset + i < size) {
751                printf("%02x ", data[offset + i]);
752            } else {
753                printf("   ");
754            }
755        }
756
757        printf(" ");
758
759        for (size_t i = 0; i < n; ++i) {
760            if (isprint(data[offset + i])) {
761                printf("%c", data[offset + i]);
762            } else {
763                printf(".");
764            }
765        }
766
767        printf("\n");
768
769        offset += 16;
770    }
771}
772
773
774status_t MPEG4Writer::Track::makeAVCCodecSpecificData(
775        const uint8_t *data, size_t size) {
776    // hexdump(data, size);
777
778    if (mCodecSpecificData != NULL) {
779        LOGE("Already have codec specific data");
780        return ERROR_MALFORMED;
781    }
782
783    if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) {
784        LOGE("Must start with a start code");
785        return ERROR_MALFORMED;
786    }
787
788    size_t picParamOffset = 4;
789    while (picParamOffset + 3 < size
790            && memcmp("\x00\x00\x00\x01", &data[picParamOffset], 4)) {
791        ++picParamOffset;
792    }
793
794    if (picParamOffset + 3 >= size) {
795        LOGE("Could not find start-code for pictureParameterSet");
796        return ERROR_MALFORMED;
797    }
798
799    size_t seqParamSetLength = picParamOffset - 4;
800    size_t picParamSetLength = size - picParamOffset - 4;
801
802    mCodecSpecificDataSize =
803        6 + 1 + seqParamSetLength + 2 + picParamSetLength + 2;
804
805    mCodecSpecificData = malloc(mCodecSpecificDataSize);
806    uint8_t *header = (uint8_t *)mCodecSpecificData;
807    header[0] = 1;
808    header[1] = 0x42;  // profile
809    header[2] = 0x80;
810    header[3] = 0x1e;  // level
811
812#if USE_NALLEN_FOUR
813    header[4] = 0xfc | 3;  // length size == 4 bytes
814#else
815    header[4] = 0xfc | 1;  // length size == 2 bytes
816#endif
817
818    header[5] = 0xe0 | 1;
819    header[6] = seqParamSetLength >> 8;
820    header[7] = seqParamSetLength & 0xff;
821    memcpy(&header[8], &data[4], seqParamSetLength);
822    header += 8 + seqParamSetLength;
823    header[0] = 1;
824    header[1] = picParamSetLength >> 8;
825    header[2] = picParamSetLength & 0xff;
826    memcpy(&header[3], &data[picParamOffset + 4], picParamSetLength);
827
828    return OK;
829}
830
831void MPEG4Writer::Track::threadEntry() {
832    sp<MetaData> meta = mSource->getFormat();
833    const char *mime;
834    meta->findCString(kKeyMIMEType, &mime);
835    bool is_mpeg4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
836                    !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
837    bool is_avc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
838    bool is_audio = !strncasecmp(mime, "audio/", 6);
839    int32_t count = 0;
840    const int64_t interleaveDurationUs = mOwner->interleaveDuration();
841    int64_t chunkTimestampUs = 0;
842    int32_t nChunks = 0;
843    int32_t nZeroLengthFrames = 0;
844    int64_t lastTimestamp = 0;  // Timestamp of the previous sample
845    int64_t lastDuration = 0;   // Time spacing between the previous two samples
846    int32_t sampleCount = 1;    // Sample count in the current stts table entry
847    uint32_t previousSampleSize = 0;  // Size of the previous sample
848    int64_t previousPausedDurationUs = 0;
849    sp<MetaData> meta_data;
850
851    MediaBuffer *buffer;
852    while (!mDone && mSource->read(&buffer) == OK) {
853        if (buffer->range_length() == 0) {
854            buffer->release();
855            buffer = NULL;
856            ++nZeroLengthFrames;
857            continue;
858        }
859
860        // If the codec specific data has not been received yet, delay pause.
861        // After the codec specific data is received, discard what we received
862        // when the track is to be paused.
863        if (mPaused && !mResumed) {
864            buffer->release();
865            buffer = NULL;
866            continue;
867        }
868
869        ++count;
870
871        int32_t isCodecConfig;
872        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
873                && isCodecConfig) {
874            CHECK(!mGotAllCodecSpecificData);
875
876            if (is_avc) {
877                status_t err = makeAVCCodecSpecificData(
878                        (const uint8_t *)buffer->data()
879                            + buffer->range_offset(),
880                        buffer->range_length());
881                CHECK_EQ(OK, err);
882            } else if (is_mpeg4) {
883                mCodecSpecificDataSize = buffer->range_length();
884                mCodecSpecificData = malloc(mCodecSpecificDataSize);
885                memcpy(mCodecSpecificData,
886                        (const uint8_t *)buffer->data()
887                            + buffer->range_offset(),
888                       buffer->range_length());
889            }
890
891            buffer->release();
892            buffer = NULL;
893
894            mGotAllCodecSpecificData = true;
895            continue;
896        } else if (!mGotAllCodecSpecificData &&
897                count == 1 && is_mpeg4 && mCodecSpecificData == NULL) {
898            // The TI mpeg4 encoder does not properly set the
899            // codec-specific-data flag.
900
901            const uint8_t *data =
902                (const uint8_t *)buffer->data() + buffer->range_offset();
903
904            const size_t size = buffer->range_length();
905
906            size_t offset = 0;
907            while (offset + 3 < size) {
908                if (data[offset] == 0x00 && data[offset + 1] == 0x00
909                    && data[offset + 2] == 0x01 && data[offset + 3] == 0xb6) {
910                    break;
911                }
912
913                ++offset;
914            }
915
916            // CHECK(offset + 3 < size);
917            if (offset + 3 >= size) {
918                // XXX assume the entire first chunk of data is the codec specific
919                // data.
920                offset = size;
921            }
922
923            mCodecSpecificDataSize = offset;
924            mCodecSpecificData = malloc(offset);
925            memcpy(mCodecSpecificData, data, offset);
926
927            buffer->set_range(buffer->range_offset() + offset, size - offset);
928
929            if (size == offset) {
930                buffer->release();
931                buffer = NULL;
932
933                continue;
934            }
935
936            mGotAllCodecSpecificData = true;
937        } else if (!mGotAllCodecSpecificData && is_avc && count < 3) {
938            // The TI video encoder does not flag codec specific data
939            // as such and also splits up SPS and PPS across two buffers.
940
941            const uint8_t *data =
942                (const uint8_t *)buffer->data() + buffer->range_offset();
943
944            size_t size = buffer->range_length();
945
946            CHECK(count == 2 || mCodecSpecificData == NULL);
947
948            size_t offset = mCodecSpecificDataSize;
949            mCodecSpecificDataSize += size + 4;
950            mCodecSpecificData =
951                realloc(mCodecSpecificData, mCodecSpecificDataSize);
952
953            memcpy((uint8_t *)mCodecSpecificData + offset,
954                   "\x00\x00\x00\x01", 4);
955
956            memcpy((uint8_t *)mCodecSpecificData + offset + 4, data, size);
957
958            buffer->release();
959            buffer = NULL;
960
961            if (count == 2) {
962                void *tmp = mCodecSpecificData;
963                size = mCodecSpecificDataSize;
964                mCodecSpecificData = NULL;
965                mCodecSpecificDataSize = 0;
966
967                status_t err = makeAVCCodecSpecificData(
968                        (const uint8_t *)tmp, size);
969                free(tmp);
970                tmp = NULL;
971                CHECK_EQ(OK, err);
972
973                mGotAllCodecSpecificData = true;
974            }
975
976            continue;
977        }
978
979        if (!mGotAllCodecSpecificData) {
980            mGotAllCodecSpecificData = true;
981        }
982
983        // Make a deep copy of the MediaBuffer and Metadata and release
984        // the original as soon as we can
985        MediaBuffer *copy = new MediaBuffer(buffer->range_length());
986        memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(),
987                buffer->range_length());
988        copy->set_range(0, buffer->range_length());
989        meta_data = new MetaData(*buffer->meta_data().get());
990        buffer->release();
991        buffer = NULL;
992
993        if (is_avc) StripStartcode(copy);
994
995        SampleInfo info;
996        info.size = is_avc
997#if USE_NALLEN_FOUR
998                ? copy->range_length() + 4
999#else
1000                ? copy->range_length() + 2
1001#endif
1002                : copy->range_length();
1003
1004        // Max file size or duration handling
1005        mEstimatedTrackSizeBytes += info.size;
1006        if (mOwner->exceedsFileSizeLimit()) {
1007            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
1008            break;
1009        }
1010        if (mOwner->exceedsFileDurationLimit()) {
1011            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
1012            break;
1013        }
1014
1015
1016        int32_t isSync = false;
1017        meta_data->findInt32(kKeyIsSyncFrame, &isSync);
1018
1019        int64_t timestampUs;
1020        CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
1021
1022////////////////////////////////////////////////////////////////////////////////
1023        if (mSampleInfos.empty()) {
1024            mStartTimestampUs = timestampUs;
1025            mOwner->setStartTimestampUs(mStartTimestampUs);
1026        }
1027
1028        if (mResumed) {
1029            previousPausedDurationUs += (timestampUs - mMaxTimeStampUs - 1000 * lastDuration);
1030            mResumed = false;
1031        }
1032
1033        timestampUs -= previousPausedDurationUs;
1034        LOGV("time stamp: %lld and previous paused duration %lld",
1035                timestampUs, previousPausedDurationUs);
1036        if (timestampUs > mMaxTimeStampUs) {
1037            mMaxTimeStampUs = timestampUs;
1038        }
1039
1040        // Our timestamp is in ms.
1041        info.timestamp = (timestampUs + 500) / 1000;
1042        mSampleInfos.push_back(info);
1043        if (mSampleInfos.size() > 2) {
1044            if (lastDuration != info.timestamp - lastTimestamp) {
1045                SttsTableEntry sttsEntry(sampleCount, lastDuration);
1046                mSttsTableEntries.push_back(sttsEntry);
1047                sampleCount = 1;
1048            } else {
1049                ++sampleCount;
1050            }
1051        }
1052        if (mSamplesHaveSameSize) {
1053            if (mSampleInfos.size() >= 2 && previousSampleSize != info.size) {
1054                mSamplesHaveSameSize = false;
1055            }
1056            previousSampleSize = info.size;
1057        }
1058        lastDuration = info.timestamp - lastTimestamp;
1059        lastTimestamp = info.timestamp;
1060
1061        if (isSync != 0) {
1062            mStssTableEntries.push_back(mSampleInfos.size());
1063        }
1064
1065        if (mOwner->numTracks() == 1) {
1066            off_t offset = is_avc? mOwner->addLengthPrefixedSample_l(copy)
1067                                 : mOwner->addSample_l(copy);
1068            if (mChunkOffsets.empty()) {
1069                mChunkOffsets.push_back(offset);
1070            }
1071            copy->release();
1072            copy = NULL;
1073            continue;
1074        }
1075
1076        mChunkSamples.push_back(copy);
1077        if (interleaveDurationUs == 0) {
1078            StscTableEntry stscEntry(++nChunks, 1, 1);
1079            mStscTableEntries.push_back(stscEntry);
1080            writeOneChunk(is_avc);
1081        } else {
1082            if (chunkTimestampUs == 0) {
1083                chunkTimestampUs = timestampUs;
1084            } else {
1085                if (timestampUs - chunkTimestampUs > interleaveDurationUs) {
1086                    ++nChunks;
1087                    mChunkDurations.push_back(timestampUs - chunkTimestampUs);
1088                    if (nChunks == 1 ||  // First chunk
1089                        (--(mStscTableEntries.end()))->samplesPerChunk !=
1090                         mChunkSamples.size()) {
1091                        StscTableEntry stscEntry(nChunks,
1092                                mChunkSamples.size(), 1);
1093                        mStscTableEntries.push_back(stscEntry);
1094                    }
1095                    writeOneChunk(is_avc);
1096                    chunkTimestampUs = timestampUs;
1097                }
1098            }
1099        }
1100
1101    }
1102
1103    if (mSampleInfos.empty()) {
1104        mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_STOP_PREMATURELY, 0);
1105    }
1106
1107    // Last chunk
1108    if (mOwner->numTracks() == 1) {
1109        StscTableEntry stscEntry(1, mSampleInfos.size(), 1);
1110        mStscTableEntries.push_back(stscEntry);
1111    } else if (!mChunkSamples.empty()) {
1112        ++nChunks;
1113        StscTableEntry stscEntry(nChunks, mChunkSamples.size(), 1);
1114        mStscTableEntries.push_back(stscEntry);
1115        writeOneChunk(is_avc);
1116    }
1117
1118    // We don't really know how long the last frame lasts, since
1119    // there is no frame time after it, just repeat the previous
1120    // frame's duration.
1121    if (mSampleInfos.size() == 1) {
1122        lastDuration = 0;  // A single sample's duration
1123    } else {
1124        ++sampleCount;  // Count for the last sample
1125    }
1126    SttsTableEntry sttsEntry(sampleCount, lastDuration);
1127    mSttsTableEntries.push_back(sttsEntry);
1128    mReachedEOS = true;
1129    LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames - %s",
1130            count, nZeroLengthFrames, mSampleInfos.size(), is_audio? "audio": "video");
1131
1132    logStatisticalData(is_audio);
1133}
1134
1135void MPEG4Writer::Track::findMinMaxFrameRates(float *minFps, float *maxFps) {
1136    int32_t minSampleDuration = 0x7FFFFFFF;
1137    int32_t maxSampleDuration = 0;
1138    for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
1139        it != mSttsTableEntries.end(); ++it) {
1140        int32_t sampleDuration = static_cast<int32_t>(it->sampleDuration);
1141        if (sampleDuration > maxSampleDuration) {
1142            maxSampleDuration = sampleDuration;
1143        } else if (sampleDuration < minSampleDuration) {
1144            minSampleDuration = sampleDuration;
1145        }
1146    }
1147    CHECK(minSampleDuration != 0 && maxSampleDuration != 0);
1148    *minFps = 1000.0 / maxSampleDuration;
1149    *maxFps = 1000.0 / minSampleDuration;
1150}
1151
1152// Don't count the last duration
1153void MPEG4Writer::Track::findMinMaxChunkDurations(int64_t *min, int64_t *max) {
1154    int64_t duration = mOwner->interleaveDuration();
1155    int64_t minChunkDuration = duration;
1156    int64_t maxChunkDuration = duration;
1157    if (mChunkDurations.size() > 1) {
1158        for (List<int64_t>::iterator it = mChunkDurations.begin();
1159            it != --mChunkDurations.end(); ++it) {
1160            if (minChunkDuration > (*it)) {
1161                minChunkDuration = (*it);
1162            } else if (maxChunkDuration < (*it)) {
1163                maxChunkDuration = (*it);
1164            }
1165        }
1166    }
1167    *min = minChunkDuration;
1168    *max = maxChunkDuration;
1169}
1170
1171void MPEG4Writer::Track::logStatisticalData(bool isAudio) {
1172    if (mMaxTimeStampUs <= 0 || mSampleInfos.empty()) {
1173        LOGI("nothing is recorded");
1174        return;
1175    }
1176
1177    bool collectStats = false;
1178    char value[PROPERTY_VALUE_MAX];
1179    if (property_get("media.stagefright.record-stats", value, NULL)
1180        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
1181        collectStats = true;
1182    }
1183
1184    if (collectStats) {
1185        if (isAudio) {
1186            LOGI("audio track - duration %lld us", mMaxTimeStampUs);
1187        } else {
1188            float fps = (mSampleInfos.size() * 1000000.0) / mMaxTimeStampUs;
1189            float minFps;
1190            float maxFps;
1191            findMinMaxFrameRates(&minFps, &maxFps);
1192            LOGI("video track - duration %lld us", mMaxTimeStampUs);
1193            LOGI("min/avg/max frame rate (fps): %.2f/%.2f/%.2f",
1194                minFps, fps, maxFps);
1195        }
1196
1197        int64_t totalBytes = 0;
1198        for (List<SampleInfo>::iterator it = mSampleInfos.begin();
1199            it != mSampleInfos.end(); ++it) {
1200            totalBytes += it->size;
1201        }
1202        float bitRate = (totalBytes * 8000000.0) / mMaxTimeStampUs;
1203        LOGI("avg bit rate (bps): %.2f", bitRate);
1204
1205        int64_t duration = mOwner->interleaveDuration();
1206        if (duration != 0) {  // If interleaving is enabled
1207            int64_t minChunk, maxChunk;
1208            findMinMaxChunkDurations(&minChunk, &maxChunk);
1209            LOGI("min/avg/max chunk duration (ms): %lld/%lld/%lld",
1210                minChunk, duration, maxChunk);
1211        }
1212    }
1213}
1214
1215void MPEG4Writer::Track::writeOneChunk(bool isAvc) {
1216    mOwner->lock();
1217    for (List<MediaBuffer *>::iterator it = mChunkSamples.begin();
1218         it != mChunkSamples.end(); ++it) {
1219        off_t offset = isAvc? mOwner->addLengthPrefixedSample_l(*it)
1220                            : mOwner->addSample_l(*it);
1221        if (it == mChunkSamples.begin()) {
1222            mChunkOffsets.push_back(offset);
1223        }
1224    }
1225    mOwner->unlock();
1226    while (!mChunkSamples.empty()) {
1227        List<MediaBuffer *>::iterator it = mChunkSamples.begin();
1228        (*it)->release();
1229        (*it) = NULL;
1230        mChunkSamples.erase(it);
1231    }
1232    mChunkSamples.clear();
1233}
1234
1235int64_t MPEG4Writer::Track::getDurationUs() const {
1236    return mMaxTimeStampUs;
1237}
1238
1239int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
1240    return mEstimatedTrackSizeBytes;
1241}
1242
1243void MPEG4Writer::Track::writeTrackHeader(
1244        int32_t trackID, bool use32BitOffset) {
1245    const char *mime;
1246    bool success = mMeta->findCString(kKeyMIMEType, &mime);
1247    CHECK(success);
1248
1249    bool is_audio = !strncasecmp(mime, "audio/", 6);
1250    int32_t timeScale = 1000;
1251    int32_t duration = getDurationUs() / timeScale;
1252
1253    time_t now = time(NULL);
1254
1255    mOwner->beginBox("trak");
1256
1257      mOwner->beginBox("tkhd");
1258        // Flags = 7 to indicate that the track is enabled, and
1259        // part of the presentation
1260        mOwner->writeInt32(0x07);          // version=0, flags=7
1261        mOwner->writeInt32(now);           // creation time
1262        mOwner->writeInt32(now);           // modification time
1263        mOwner->writeInt32(trackID);
1264        mOwner->writeInt32(0);             // reserved
1265        mOwner->writeInt32(duration);
1266        mOwner->writeInt32(0);             // reserved
1267        mOwner->writeInt32(0);             // reserved
1268        mOwner->writeInt16(0);             // layer
1269        mOwner->writeInt16(0);             // alternate group
1270        mOwner->writeInt16(is_audio ? 0x100 : 0);  // volume
1271        mOwner->writeInt16(0);             // reserved
1272
1273        mOwner->writeInt32(0x10000);       // matrix
1274        mOwner->writeInt32(0);
1275        mOwner->writeInt32(0);
1276        mOwner->writeInt32(0);
1277        mOwner->writeInt32(0x10000);
1278        mOwner->writeInt32(0);
1279        mOwner->writeInt32(0);
1280        mOwner->writeInt32(0);
1281        mOwner->writeInt32(0x40000000);
1282
1283        if (is_audio) {
1284            mOwner->writeInt32(0);
1285            mOwner->writeInt32(0);
1286        } else {
1287            int32_t width, height;
1288            bool success = mMeta->findInt32(kKeyWidth, &width);
1289            success = success && mMeta->findInt32(kKeyHeight, &height);
1290            CHECK(success);
1291
1292            mOwner->writeInt32(width << 16);   // 32-bit fixed-point value
1293            mOwner->writeInt32(height << 16);  // 32-bit fixed-point value
1294        }
1295      mOwner->endBox();  // tkhd
1296
1297      int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
1298      if (mStartTimestampUs != moovStartTimeUs) {
1299        mOwner->beginBox("edts");
1300          mOwner->beginBox("elst");
1301            mOwner->writeInt32(0);           // version=0, flags=0: 32-bit time
1302            mOwner->writeInt32(2);           // never ends with an empty list
1303            int64_t durationMs =
1304                (mStartTimestampUs - moovStartTimeUs) / 1000;
1305            mOwner->writeInt32(durationMs);  // edit duration
1306            mOwner->writeInt32(-1);          // empty edit box to signal starting time offset
1307            mOwner->writeInt32(1 << 16);     // x1 rate
1308            mOwner->writeInt32(duration);
1309            mOwner->writeInt32(0);
1310            mOwner->writeInt32(1 << 16);
1311          mOwner->endBox();
1312        mOwner->endBox();
1313      }
1314
1315      mOwner->beginBox("mdia");
1316
1317        mOwner->beginBox("mdhd");
1318          mOwner->writeInt32(0);             // version=0, flags=0
1319          mOwner->writeInt32(now);           // creation time
1320          mOwner->writeInt32(now);           // modification time
1321          mOwner->writeInt32(timeScale);     // timescale
1322          mOwner->writeInt32(duration);      // duration
1323          // Language follows the three letter standard ISO-639-2/T
1324          // 'e', 'n', 'g' for "English", for instance.
1325          // Each character is packed as the difference between its ASCII value and 0x60.
1326          // For "English", these are 00101, 01110, 00111.
1327          // XXX: Where is the padding bit located: 0x15C7?
1328          mOwner->writeInt16(0);             // language code
1329          mOwner->writeInt16(0);             // predefined
1330        mOwner->endBox();
1331
1332        mOwner->beginBox("hdlr");
1333          mOwner->writeInt32(0);             // version=0, flags=0
1334          mOwner->writeInt32(0);             // component type: should be mhlr
1335          mOwner->writeFourcc(is_audio ? "soun" : "vide");  // component subtype
1336          mOwner->writeInt32(0);             // reserved
1337          mOwner->writeInt32(0);             // reserved
1338          mOwner->writeInt32(0);             // reserved
1339          // Removing "r" for the name string just makes the string 4 byte aligned
1340          mOwner->writeCString(is_audio ? "SoundHandle": "VideoHandle");  // name
1341        mOwner->endBox();
1342
1343        mOwner->beginBox("minf");
1344          if (is_audio) {
1345              mOwner->beginBox("smhd");
1346              mOwner->writeInt32(0);           // version=0, flags=0
1347              mOwner->writeInt16(0);           // balance
1348              mOwner->writeInt16(0);           // reserved
1349              mOwner->endBox();
1350          } else {
1351              mOwner->beginBox("vmhd");
1352              mOwner->writeInt32(0x01);        // version=0, flags=1
1353              mOwner->writeInt16(0);           // graphics mode
1354              mOwner->writeInt16(0);           // opcolor
1355              mOwner->writeInt16(0);
1356              mOwner->writeInt16(0);
1357              mOwner->endBox();
1358          }
1359
1360          mOwner->beginBox("dinf");
1361            mOwner->beginBox("dref");
1362              mOwner->writeInt32(0);  // version=0, flags=0
1363              mOwner->writeInt32(1);  // entry count (either url or urn)
1364              // The table index here refers to the sample description index
1365              // in the sample table entries.
1366              mOwner->beginBox("url ");
1367                mOwner->writeInt32(1);  // version=0, flags=1 (self-contained)
1368              mOwner->endBox();  // url
1369            mOwner->endBox();  // dref
1370          mOwner->endBox();  // dinf
1371
1372        mOwner->beginBox("stbl");
1373
1374          mOwner->beginBox("stsd");
1375            mOwner->writeInt32(0);               // version=0, flags=0
1376            mOwner->writeInt32(1);               // entry count
1377            if (is_audio) {
1378                const char *fourcc = NULL;
1379                if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
1380                    fourcc = "samr";
1381                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
1382                    fourcc = "sawb";
1383                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
1384                    fourcc = "mp4a";
1385                } else {
1386                    LOGE("Unknown mime type '%s'.", mime);
1387                    CHECK(!"should not be here, unknown mime type.");
1388                }
1389
1390                mOwner->beginBox(fourcc);          // audio format
1391                  mOwner->writeInt32(0);           // reserved
1392                  mOwner->writeInt16(0);           // reserved
1393                  mOwner->writeInt16(0x1);         // data ref index
1394                  mOwner->writeInt32(0);           // reserved
1395                  mOwner->writeInt32(0);           // reserved
1396                  int32_t nChannels;
1397                  CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels));
1398                  mOwner->writeInt16(nChannels);   // channel count
1399                  mOwner->writeInt16(16);          // sample size
1400                  mOwner->writeInt16(0);           // predefined
1401                  mOwner->writeInt16(0);           // reserved
1402
1403                  int32_t samplerate;
1404                  bool success = mMeta->findInt32(kKeySampleRate, &samplerate);
1405                  CHECK(success);
1406
1407                  mOwner->writeInt32(samplerate << 16);
1408                  if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
1409                    mOwner->beginBox("esds");
1410
1411                        mOwner->writeInt32(0);     // version=0, flags=0
1412                        mOwner->writeInt8(0x03);   // ES_DescrTag
1413                        mOwner->writeInt8(23 + mCodecSpecificDataSize);
1414                        mOwner->writeInt16(0x0000);// ES_ID
1415                        mOwner->writeInt8(0x00);
1416
1417                        mOwner->writeInt8(0x04);   // DecoderConfigDescrTag
1418                        mOwner->writeInt8(15 + mCodecSpecificDataSize);
1419                        mOwner->writeInt8(0x40);   // objectTypeIndication ISO/IEC 14492-2
1420                        mOwner->writeInt8(0x15);   // streamType AudioStream
1421
1422                        mOwner->writeInt16(0x03);  // XXX
1423                        mOwner->writeInt8(0x00);   // buffer size 24-bit
1424                        mOwner->writeInt32(96000); // max bit rate
1425                        mOwner->writeInt32(96000); // avg bit rate
1426
1427                        mOwner->writeInt8(0x05);   // DecoderSpecificInfoTag
1428                        mOwner->writeInt8(mCodecSpecificDataSize);
1429                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
1430
1431                        static const uint8_t kData2[] = {
1432                            0x06,  // SLConfigDescriptorTag
1433                            0x01,
1434                            0x02
1435                        };
1436                        mOwner->write(kData2, sizeof(kData2));
1437
1438                    mOwner->endBox();  // esds
1439                  }
1440                mOwner->endBox();
1441            } else {
1442                if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
1443                    mOwner->beginBox("mp4v");
1444                } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
1445                    mOwner->beginBox("s263");
1446                } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
1447                    mOwner->beginBox("avc1");
1448                } else {
1449                    LOGE("Unknown mime type '%s'.", mime);
1450                    CHECK(!"should not be here, unknown mime type.");
1451                }
1452
1453                  mOwner->writeInt32(0);           // reserved
1454                  mOwner->writeInt16(0);           // reserved
1455                  mOwner->writeInt16(1);           // data ref index
1456                  mOwner->writeInt16(0);           // predefined
1457                  mOwner->writeInt16(0);           // reserved
1458                  mOwner->writeInt32(0);           // predefined
1459                  mOwner->writeInt32(0);           // predefined
1460                  mOwner->writeInt32(0);           // predefined
1461
1462                  int32_t width, height;
1463                  bool success = mMeta->findInt32(kKeyWidth, &width);
1464                  success = success && mMeta->findInt32(kKeyHeight, &height);
1465                  CHECK(success);
1466
1467                  mOwner->writeInt16(width);
1468                  mOwner->writeInt16(height);
1469                  mOwner->writeInt32(0x480000);    // horiz resolution
1470                  mOwner->writeInt32(0x480000);    // vert resolution
1471                  mOwner->writeInt32(0);           // reserved
1472                  mOwner->writeInt16(1);           // frame count
1473                  mOwner->write("                                ", 32);
1474                  mOwner->writeInt16(0x18);        // depth
1475                  mOwner->writeInt16(-1);          // predefined
1476
1477                  CHECK(23 + mCodecSpecificDataSize < 128);
1478
1479                  if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
1480                      mOwner->beginBox("esds");
1481
1482                        mOwner->writeInt32(0);           // version=0, flags=0
1483
1484                        mOwner->writeInt8(0x03);  // ES_DescrTag
1485                        mOwner->writeInt8(23 + mCodecSpecificDataSize);
1486                        mOwner->writeInt16(0x0000);  // ES_ID
1487                        mOwner->writeInt8(0x1f);
1488
1489                        mOwner->writeInt8(0x04);  // DecoderConfigDescrTag
1490                        mOwner->writeInt8(15 + mCodecSpecificDataSize);
1491                        mOwner->writeInt8(0x20);  // objectTypeIndication ISO/IEC 14492-2
1492                        mOwner->writeInt8(0x11);  // streamType VisualStream
1493
1494                        static const uint8_t kData[] = {
1495                            0x01, 0x77, 0x00,
1496                            0x00, 0x03, 0xe8, 0x00,
1497                            0x00, 0x03, 0xe8, 0x00
1498                        };
1499                        mOwner->write(kData, sizeof(kData));
1500
1501                        mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
1502
1503                        mOwner->writeInt8(mCodecSpecificDataSize);
1504                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
1505
1506                        static const uint8_t kData2[] = {
1507                            0x06,  // SLConfigDescriptorTag
1508                            0x01,
1509                            0x02
1510                        };
1511                        mOwner->write(kData2, sizeof(kData2));
1512
1513                      mOwner->endBox();  // esds
1514                  } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
1515                      mOwner->beginBox("d263");
1516
1517                          mOwner->writeInt32(0);  // vendor
1518                          mOwner->writeInt8(0);   // decoder version
1519                          mOwner->writeInt8(10);  // level: 10
1520                          mOwner->writeInt8(0);   // profile: 0
1521
1522                      mOwner->endBox();  // d263
1523                  } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
1524                      mOwner->beginBox("avcC");
1525                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
1526                      mOwner->endBox();  // avcC
1527                  }
1528
1529                  mOwner->beginBox("pasp");
1530                    // This is useful if the pixel is not square
1531                    mOwner->writeInt32(1 << 16);  // hspacing
1532                    mOwner->writeInt32(1 << 16);  // vspacing
1533                  mOwner->endBox();  // pasp
1534                mOwner->endBox();  // mp4v, s263 or avc1
1535            }
1536          mOwner->endBox();  // stsd
1537
1538          mOwner->beginBox("stts");
1539            mOwner->writeInt32(0);  // version=0, flags=0
1540            mOwner->writeInt32(mSttsTableEntries.size());
1541            for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
1542                 it != mSttsTableEntries.end(); ++it) {
1543                mOwner->writeInt32(it->sampleCount);
1544                mOwner->writeInt32(it->sampleDuration);
1545            }
1546          mOwner->endBox();  // stts
1547
1548          if (!is_audio) {
1549            mOwner->beginBox("stss");
1550              mOwner->writeInt32(0);  // version=0, flags=0
1551              mOwner->writeInt32(mStssTableEntries.size());  // number of sync frames
1552              for (List<int32_t>::iterator it = mStssTableEntries.begin();
1553                   it != mStssTableEntries.end(); ++it) {
1554                  mOwner->writeInt32(*it);
1555              }
1556            mOwner->endBox();  // stss
1557          }
1558
1559          mOwner->beginBox("stsz");
1560            mOwner->writeInt32(0);  // version=0, flags=0
1561            if (mSamplesHaveSameSize) {
1562                List<SampleInfo>::iterator it = mSampleInfos.begin();
1563                mOwner->writeInt32(it->size);  // default sample size
1564            } else {
1565                mOwner->writeInt32(0);
1566            }
1567            mOwner->writeInt32(mSampleInfos.size());
1568            if (!mSamplesHaveSameSize) {
1569                for (List<SampleInfo>::iterator it = mSampleInfos.begin();
1570                     it != mSampleInfos.end(); ++it) {
1571                    mOwner->writeInt32((*it).size);
1572                }
1573            }
1574          mOwner->endBox();  // stsz
1575
1576          mOwner->beginBox("stsc");
1577            mOwner->writeInt32(0);  // version=0, flags=0
1578            mOwner->writeInt32(mStscTableEntries.size());
1579            for (List<StscTableEntry>::iterator it = mStscTableEntries.begin();
1580                 it != mStscTableEntries.end(); ++it) {
1581                mOwner->writeInt32(it->firstChunk);
1582                mOwner->writeInt32(it->samplesPerChunk);
1583                mOwner->writeInt32(it->sampleDescriptionId);
1584            }
1585          mOwner->endBox();  // stsc
1586          mOwner->beginBox(use32BitOffset? "stco": "co64");
1587            mOwner->writeInt32(0);  // version=0, flags=0
1588            mOwner->writeInt32(mChunkOffsets.size());
1589            for (List<off_t>::iterator it = mChunkOffsets.begin();
1590                 it != mChunkOffsets.end(); ++it) {
1591                if (use32BitOffset) {
1592                    mOwner->writeInt32(static_cast<int32_t>(*it));
1593                } else {
1594                    mOwner->writeInt64((*it));
1595                }
1596            }
1597          mOwner->endBox();  // co64
1598
1599        mOwner->endBox();  // stbl
1600       mOwner->endBox();  // minf
1601      mOwner->endBox();  // mdia
1602    mOwner->endBox();  // trak
1603}
1604
1605}  // namespace android
1606