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