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