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