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