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