MPEG4Writer.cpp revision fcac8fa9421f442f024018628a6042d7a14fbfb0
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 <pthread.h>
24#include <sys/prctl.h>
25#include <sys/resource.h>
26
27#include <media/stagefright/MPEG4Writer.h>
28#include <media/stagefright/MediaBuffer.h>
29#include <media/stagefright/MetaData.h>
30#include <media/stagefright/MediaDebug.h>
31#include <media/stagefright/MediaDefs.h>
32#include <media/stagefright/MediaErrors.h>
33#include <media/stagefright/MediaSource.h>
34#include <media/stagefright/Utils.h>
35#include <media/mediarecorder.h>
36#include <sys/types.h>
37#include <sys/stat.h>
38#include <fcntl.h>
39#include <unistd.h>
40
41#include "include/ESDS.h"
42
43namespace android {
44
45static const int64_t kMax32BitFileSize = 0x007fffffffLL;
46static const uint8_t kNalUnitTypeSeqParamSet = 0x07;
47static const uint8_t kNalUnitTypePicParamSet = 0x08;
48
49// Using longer adjustment period to suppress fluctuations in
50// the audio encoding paths
51static const int64_t kVideoMediaTimeAdjustPeriodTimeUs = 600000000LL;  // 10 minutes
52
53class MPEG4Writer::Track {
54public:
55    Track(MPEG4Writer *owner, const sp<MediaSource> &source);
56
57    ~Track();
58
59    status_t start(MetaData *params);
60    status_t stop();
61    status_t pause();
62    bool reachedEOS();
63
64    int64_t getDurationUs() const;
65    int64_t getEstimatedTrackSizeBytes() const;
66    void writeTrackHeader(int32_t trackID, bool use32BitOffset = true);
67    void bufferChunk(int64_t timestampUs);
68    bool isAvc() const { return mIsAvc; }
69    bool isAudio() const { return mIsAudio; }
70    bool isMPEG4() const { return mIsMPEG4; }
71    void addChunkOffset(off64_t offset);
72    status_t dump(int fd, const Vector<String16>& args) const;
73
74private:
75    MPEG4Writer *mOwner;
76    sp<MetaData> mMeta;
77    sp<MediaSource> mSource;
78    volatile bool mDone;
79    volatile bool mPaused;
80    volatile bool mResumed;
81    volatile bool mStarted;
82    bool mIsAvc;
83    bool mIsAudio;
84    bool mIsMPEG4;
85    int64_t mTrackDurationUs;
86
87    // For realtime applications, we need to adjust the media clock
88    // for video track based on the audio media clock
89    bool mIsRealTimeRecording;
90    int64_t mMaxTimeStampUs;
91    int64_t mEstimatedTrackSizeBytes;
92    int64_t mMdatSizeBytes;
93    int32_t mTimeScale;
94
95    pthread_t mThread;
96
97    // mNumSamples is used to track how many samples in mSampleSizes List.
98    // This is to reduce the cost associated with mSampleSizes.size() call,
99    // since it is O(n). Ideally, the fix should be in List class.
100    size_t              mNumSamples;
101    List<size_t>        mSampleSizes;
102    bool                mSamplesHaveSameSize;
103
104    List<MediaBuffer *> mChunkSamples;
105
106    size_t              mNumStcoTableEntries;
107    List<off64_t>         mChunkOffsets;
108
109    size_t              mNumStscTableEntries;
110    struct StscTableEntry {
111
112        StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id)
113            : firstChunk(chunk),
114              samplesPerChunk(samples),
115              sampleDescriptionId(id) {}
116
117        uint32_t firstChunk;
118        uint32_t samplesPerChunk;
119        uint32_t sampleDescriptionId;
120    };
121    List<StscTableEntry> mStscTableEntries;
122
123    size_t        mNumStssTableEntries;
124    List<int32_t> mStssTableEntries;
125
126    size_t        mNumSttsTableEntries;
127    struct SttsTableEntry {
128
129        SttsTableEntry(uint32_t count, uint32_t durationUs)
130            : sampleCount(count), sampleDurationUs(durationUs) {}
131
132        uint32_t sampleCount;
133        uint32_t sampleDurationUs;
134    };
135    List<SttsTableEntry> mSttsTableEntries;
136
137    // Sequence parameter set or picture parameter set
138    struct AVCParamSet {
139        AVCParamSet(uint16_t length, const uint8_t *data)
140            : mLength(length), mData(data) {}
141
142        uint16_t mLength;
143        const uint8_t *mData;
144    };
145    List<AVCParamSet> mSeqParamSets;
146    List<AVCParamSet> mPicParamSets;
147    uint8_t mProfileIdc;
148    uint8_t mProfileCompatible;
149    uint8_t mLevelIdc;
150
151    void *mCodecSpecificData;
152    size_t mCodecSpecificDataSize;
153    bool mGotAllCodecSpecificData;
154    bool mTrackingProgressStatus;
155
156    bool mReachedEOS;
157    int64_t mStartTimestampUs;
158    int64_t mPreviousTrackTimeUs;
159    int64_t mTrackEveryTimeDurationUs;
160
161    // Has the media time adjustment for video started?
162    bool    mIsMediaTimeAdjustmentOn;
163    // The time stamp when previous media time adjustment period starts
164    int64_t mPrevMediaTimeAdjustTimestampUs;
165    // Number of vidoe frames whose time stamp may be adjusted
166    int64_t mMediaTimeAdjustNumFrames;
167    // The sample number when previous meida time adjustmnet period starts
168    int64_t mPrevMediaTimeAdjustSample;
169    // The total accumulated drift time within a period of
170    // kVideoMediaTimeAdjustPeriodTimeUs.
171    int64_t mTotalDriftTimeToAdjustUs;
172    // The total accumalated drift time since the start of the recording
173    // excluding the current time adjustment period
174    int64_t mPrevTotalAccumDriftTimeUs;
175
176    // Update the audio track's drift information.
177    void updateDriftTime(const sp<MetaData>& meta);
178
179    // Adjust the time stamp of the video track according to
180    // the drift time information from the audio track.
181    void adjustMediaTime(int64_t *timestampUs);
182
183    static void *ThreadWrapper(void *me);
184    status_t threadEntry();
185
186    const uint8_t *parseParamSet(
187        const uint8_t *data, size_t length, int type, size_t *paramSetLen);
188
189    status_t makeAVCCodecSpecificData(
190            const uint8_t *data, size_t size);
191    status_t copyAVCCodecSpecificData(
192            const uint8_t *data, size_t size);
193    status_t parseAVCCodecSpecificData(
194            const uint8_t *data, size_t size);
195
196    // Track authoring progress status
197    void trackProgressStatus(int64_t timeUs, status_t err = OK);
198    void initTrackingProgressStatus(MetaData *params);
199
200    void getCodecSpecificDataFromInputFormatIfPossible();
201
202    // Determine the track time scale
203    // If it is an audio track, try to use the sampling rate as
204    // the time scale; however, if user chooses the overwrite
205    // value, the user-supplied time scale will be used.
206    void setTimeScale();
207
208    // Simple validation on the codec specific data
209    status_t checkCodecSpecificData() const;
210    int32_t mRotation;
211
212    void updateTrackSizeEstimate();
213    void addOneStscTableEntry(size_t chunkId, size_t sampleId);
214    void addOneStssTableEntry(size_t sampleId);
215    void addOneSttsTableEntry(size_t sampleCount, int64_t durationUs);
216
217    Track(const Track &);
218    Track &operator=(const Track &);
219};
220
221MPEG4Writer::MPEG4Writer(const char *filename)
222    : mFd(-1),
223      mInitCheck(NO_INIT),
224      mUse4ByteNalLength(true),
225      mUse32BitOffset(true),
226      mIsFileSizeLimitExplicitlyRequested(false),
227      mPaused(false),
228      mStarted(false),
229      mOffset(0),
230      mMdatOffset(0),
231      mEstimatedMoovBoxSize(0),
232      mInterleaveDurationUs(1000000) {
233
234    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC);
235    if (mFd >= 0) {
236        mInitCheck = OK;
237    }
238}
239
240MPEG4Writer::MPEG4Writer(int fd)
241    : mFd(dup(fd)),
242      mInitCheck(mFd < 0? NO_INIT: OK),
243      mUse4ByteNalLength(true),
244      mUse32BitOffset(true),
245      mIsFileSizeLimitExplicitlyRequested(false),
246      mPaused(false),
247      mStarted(false),
248      mOffset(0),
249      mMdatOffset(0),
250      mEstimatedMoovBoxSize(0),
251      mInterleaveDurationUs(1000000) {
252}
253
254MPEG4Writer::~MPEG4Writer() {
255    stop();
256
257    while (!mTracks.empty()) {
258        List<Track *>::iterator it = mTracks.begin();
259        delete *it;
260        (*it) = NULL;
261        mTracks.erase(it);
262    }
263    mTracks.clear();
264}
265
266status_t MPEG4Writer::dump(
267        int fd, const Vector<String16>& args) {
268    const size_t SIZE = 256;
269    char buffer[SIZE];
270    String8 result;
271    snprintf(buffer, SIZE, "   MPEG4Writer %p\n", this);
272    result.append(buffer);
273    snprintf(buffer, SIZE, "     mStarted: %s\n", mStarted? "true": "false");
274    result.append(buffer);
275    ::write(fd, result.string(), result.size());
276    for (List<Track *>::iterator it = mTracks.begin();
277         it != mTracks.end(); ++it) {
278        (*it)->dump(fd, args);
279    }
280    return OK;
281}
282
283status_t MPEG4Writer::Track::dump(
284        int fd, const Vector<String16>& args) const {
285    const size_t SIZE = 256;
286    char buffer[SIZE];
287    String8 result;
288    snprintf(buffer, SIZE, "     %s track\n", mIsAudio? "Audio": "Video");
289    result.append(buffer);
290    snprintf(buffer, SIZE, "       reached EOS: %s\n",
291            mReachedEOS? "true": "false");
292    result.append(buffer);
293    ::write(fd, result.string(), result.size());
294    return OK;
295}
296
297status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
298    Track *track = new Track(this, source);
299    mTracks.push_back(track);
300
301    return OK;
302}
303
304status_t MPEG4Writer::startTracks(MetaData *params) {
305    for (List<Track *>::iterator it = mTracks.begin();
306         it != mTracks.end(); ++it) {
307        status_t err = (*it)->start(params);
308
309        if (err != OK) {
310            for (List<Track *>::iterator it2 = mTracks.begin();
311                 it2 != it; ++it2) {
312                (*it2)->stop();
313            }
314
315            return err;
316        }
317    }
318    return OK;
319}
320
321int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) {
322    // This implementation is highly experimental/heurisitic.
323    //
324    // Statistical analysis shows that metadata usually accounts
325    // for a small portion of the total file size, usually < 0.6%.
326
327    // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2,
328    // where 1MB is the common file size limit for MMS application.
329    // The default MAX _MOOV_BOX_SIZE value is based on about 3
330    // minute video recording with a bit rate about 3 Mbps, because
331    // statistics also show that most of the video captured are going
332    // to be less than 3 minutes.
333
334    // If the estimation is wrong, we will pay the price of wasting
335    // some reserved space. This should not happen so often statistically.
336    static const int32_t factor = mUse32BitOffset? 1: 2;
337    static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024;  // 3 KB
338    static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000);
339    int64_t size = MIN_MOOV_BOX_SIZE;
340
341    // Max file size limit is set
342    if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
343        size = mMaxFileSizeLimitBytes * 6 / 1000;
344    }
345
346    // Max file duration limit is set
347    if (mMaxFileDurationLimitUs != 0) {
348        if (bitRate > 0) {
349            int64_t size2 =
350                ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000);
351            if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
352                // When both file size and duration limits are set,
353                // we use the smaller limit of the two.
354                if (size > size2) {
355                    size = size2;
356                }
357            } else {
358                // Only max file duration limit is set
359                size = size2;
360            }
361        }
362    }
363
364    if (size < MIN_MOOV_BOX_SIZE) {
365        size = MIN_MOOV_BOX_SIZE;
366    }
367
368    // Any long duration recording will be probably end up with
369    // non-streamable mp4 file.
370    if (size > MAX_MOOV_BOX_SIZE) {
371        size = MAX_MOOV_BOX_SIZE;
372    }
373
374    LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated"
375         " moov size %lld bytes",
376         mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size);
377    return factor * size;
378}
379
380status_t MPEG4Writer::start(MetaData *param) {
381    if (mInitCheck != OK) {
382        return UNKNOWN_ERROR;
383    }
384
385    /*
386     * Check mMaxFileSizeLimitBytes at the beginning
387     * since mMaxFileSizeLimitBytes may be implicitly
388     * changed later for 32-bit file offset even if
389     * user does not ask to set it explicitly.
390     */
391    if (mMaxFileSizeLimitBytes != 0) {
392        mIsFileSizeLimitExplicitlyRequested = true;
393    }
394
395    int32_t use64BitOffset;
396    if (param &&
397        param->findInt32(kKey64BitFileOffset, &use64BitOffset) &&
398        use64BitOffset) {
399        mUse32BitOffset = false;
400    }
401
402    if (mUse32BitOffset) {
403        // Implicit 32 bit file size limit
404        if (mMaxFileSizeLimitBytes == 0) {
405            mMaxFileSizeLimitBytes = kMax32BitFileSize;
406        }
407
408        // If file size is set to be larger than the 32 bit file
409        // size limit, treat it as an error.
410        if (mMaxFileSizeLimitBytes > kMax32BitFileSize) {
411            LOGW("32-bit file size limit (%lld bytes) too big. "
412                 "It is changed to %lld bytes",
413                mMaxFileSizeLimitBytes, kMax32BitFileSize);
414            mMaxFileSizeLimitBytes = kMax32BitFileSize;
415        }
416    }
417
418    int32_t use2ByteNalLength;
419    if (param &&
420        param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) &&
421        use2ByteNalLength) {
422        mUse4ByteNalLength = false;
423    }
424
425    mStartTimestampUs = -1;
426
427    if (mStarted) {
428        if (mPaused) {
429            mPaused = false;
430            return startTracks(param);
431        }
432        return OK;
433    }
434
435    if (!param ||
436        !param->findInt32(kKeyTimeScale, &mTimeScale)) {
437        mTimeScale = 1000;
438    }
439    CHECK(mTimeScale > 0);
440    LOGV("movie time scale: %d", mTimeScale);
441
442    mStreamableFile = true;
443    mWriteMoovBoxToMemory = false;
444    mMoovBoxBuffer = NULL;
445    mMoovBoxBufferOffset = 0;
446
447    beginBox("ftyp");
448      {
449        int32_t fileType;
450        if (param && param->findInt32(kKeyFileType, &fileType) &&
451            fileType != OUTPUT_FORMAT_MPEG_4) {
452            writeFourcc("3gp4");
453        } else {
454            writeFourcc("isom");
455        }
456      }
457      writeInt32(0);
458      writeFourcc("isom");
459      writeFourcc("3gp4");
460    endBox();
461
462    mFreeBoxOffset = mOffset;
463
464    if (mEstimatedMoovBoxSize == 0) {
465        int32_t bitRate = -1;
466        if (param) {
467            param->findInt32(kKeyBitRate, &bitRate);
468        }
469        mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate);
470    }
471    CHECK(mEstimatedMoovBoxSize >= 8);
472    lseek64(mFd, mFreeBoxOffset, SEEK_SET);
473    writeInt32(mEstimatedMoovBoxSize);
474    write("free", 4);
475
476    mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize;
477    mOffset = mMdatOffset;
478    lseek64(mFd, mMdatOffset, SEEK_SET);
479    if (mUse32BitOffset) {
480        write("????mdat", 8);
481    } else {
482        write("\x00\x00\x00\x01mdat????????", 16);
483    }
484
485    status_t err = startWriterThread();
486    if (err != OK) {
487        return err;
488    }
489
490    err = startTracks(param);
491    if (err != OK) {
492        return err;
493    }
494
495    mStarted = true;
496    return OK;
497}
498
499bool MPEG4Writer::use32BitFileOffset() const {
500    return mUse32BitOffset;
501}
502
503status_t MPEG4Writer::pause() {
504    if (mInitCheck != OK) {
505        return OK;
506    }
507    mPaused = true;
508    status_t err = OK;
509    for (List<Track *>::iterator it = mTracks.begin();
510         it != mTracks.end(); ++it) {
511        status_t status = (*it)->pause();
512        if (status != OK) {
513            err = status;
514        }
515    }
516    return err;
517}
518
519void MPEG4Writer::stopWriterThread() {
520    LOGD("Stopping writer thread");
521
522    {
523        Mutex::Autolock autolock(mLock);
524
525        mDone = true;
526        mChunkReadyCondition.signal();
527    }
528
529    void *dummy;
530    pthread_join(mThread, &dummy);
531    LOGD("Writer thread stopped");
532}
533
534/*
535 * MP4 file standard defines a composition matrix:
536 * | a  b  u |
537 * | c  d  v |
538 * | x  y  w |
539 *
540 * the element in the matrix is stored in the following
541 * order: {a, b, u, c, d, v, x, y, w},
542 * where a, b, c, d, x, and y is in 16.16 format, while
543 * u, v and w is in 2.30 format.
544 */
545void MPEG4Writer::writeCompositionMatrix(int degrees) {
546    LOGV("writeCompositionMatrix");
547    uint32_t a = 0x00010000;
548    uint32_t b = 0;
549    uint32_t c = 0;
550    uint32_t d = 0x00010000;
551    switch (degrees) {
552        case 0:
553            break;
554        case 90:
555            a = 0;
556            b = 0x00010000;
557            c = 0xFFFF0000;
558            d = 0;
559            break;
560        case 180:
561            a = 0xFFFF0000;
562            d = 0xFFFF0000;
563            break;
564        case 270:
565            a = 0;
566            b = 0xFFFF0000;
567            c = 0x00010000;
568            d = 0;
569            break;
570        default:
571            CHECK(!"Should never reach this unknown rotation");
572            break;
573    }
574
575    writeInt32(a);           // a
576    writeInt32(b);           // b
577    writeInt32(0);           // u
578    writeInt32(c);           // c
579    writeInt32(d);           // d
580    writeInt32(0);           // v
581    writeInt32(0);           // x
582    writeInt32(0);           // y
583    writeInt32(0x40000000);  // w
584}
585
586
587status_t MPEG4Writer::stop() {
588    if (mInitCheck != OK) {
589        return OK;
590    }
591
592    status_t err = OK;
593    int64_t maxDurationUs = 0;
594    int64_t minDurationUs = 0x7fffffffffffffffLL;
595    for (List<Track *>::iterator it = mTracks.begin();
596         it != mTracks.end(); ++it) {
597        status_t status = (*it)->stop();
598        if (err == OK && status != OK) {
599            err = status;
600        }
601
602        int64_t durationUs = (*it)->getDurationUs();
603        if (durationUs > maxDurationUs) {
604            maxDurationUs = durationUs;
605        }
606        if (durationUs < minDurationUs) {
607            minDurationUs = durationUs;
608        }
609    }
610
611    if (mTracks.size() > 1) {
612        LOGD("Duration from tracks range is [%lld, %lld] us",
613            minDurationUs, maxDurationUs);
614    }
615
616    stopWriterThread();
617
618    // Do not write out movie header on error.
619    if (err != OK) {
620        close(mFd);
621        mFd = -1;
622        mInitCheck = NO_INIT;
623        mStarted = false;
624        return err;
625    }
626
627    // Fix up the size of the 'mdat' chunk.
628    if (mUse32BitOffset) {
629        lseek64(mFd, mMdatOffset, SEEK_SET);
630        int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset));
631        ::write(mFd, &size, 4);
632    } else {
633        lseek64(mFd, mMdatOffset + 8, SEEK_SET);
634        int64_t size = mOffset - mMdatOffset;
635        size = hton64(size);
636        ::write(mFd, &size, 8);
637    }
638    lseek64(mFd, mOffset, SEEK_SET);
639
640    time_t now = time(NULL);
641    const off64_t moovOffset = mOffset;
642    mWriteMoovBoxToMemory = true;
643    mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
644    mMoovBoxBufferOffset = 0;
645    CHECK(mMoovBoxBuffer != NULL);
646    int32_t duration = (maxDurationUs * mTimeScale + 5E5) / 1E6;
647
648    beginBox("moov");
649
650      beginBox("mvhd");
651        writeInt32(0);             // version=0, flags=0
652        writeInt32(now);           // creation time
653        writeInt32(now);           // modification time
654        writeInt32(mTimeScale);    // mvhd timescale
655        writeInt32(duration);
656        writeInt32(0x10000);       // rate: 1.0
657        writeInt16(0x100);         // volume
658        writeInt16(0);             // reserved
659        writeInt32(0);             // reserved
660        writeInt32(0);             // reserved
661        writeCompositionMatrix(0); // matrix
662        writeInt32(0);             // predefined
663        writeInt32(0);             // predefined
664        writeInt32(0);             // predefined
665        writeInt32(0);             // predefined
666        writeInt32(0);             // predefined
667        writeInt32(0);             // predefined
668        writeInt32(mTracks.size() + 1);  // nextTrackID
669      endBox();  // mvhd
670
671      int32_t id = 1;
672      for (List<Track *>::iterator it = mTracks.begin();
673           it != mTracks.end(); ++it, ++id) {
674          (*it)->writeTrackHeader(id, mUse32BitOffset);
675      }
676    endBox();  // moov
677
678    mWriteMoovBoxToMemory = false;
679    if (mStreamableFile) {
680        CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize);
681
682        // Moov box
683        lseek64(mFd, mFreeBoxOffset, SEEK_SET);
684        mOffset = mFreeBoxOffset;
685        write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset);
686
687        // Free box
688        lseek64(mFd, mOffset, SEEK_SET);
689        writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset);
690        write("free", 4);
691
692        // Free temp memory
693        free(mMoovBoxBuffer);
694        mMoovBoxBuffer = NULL;
695        mMoovBoxBufferOffset = 0;
696    } else {
697        LOGI("The mp4 file will not be streamable.");
698    }
699
700    CHECK(mBoxes.empty());
701
702    close(mFd);
703    mFd = -1;
704    mInitCheck = NO_INIT;
705    mStarted = false;
706    return err;
707}
708
709status_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) {
710    mInterleaveDurationUs = durationUs;
711    return OK;
712}
713
714void MPEG4Writer::lock() {
715    mLock.lock();
716}
717
718void MPEG4Writer::unlock() {
719    mLock.unlock();
720}
721
722off64_t MPEG4Writer::addSample_l(MediaBuffer *buffer) {
723    off64_t old_offset = mOffset;
724
725    ::write(mFd,
726          (const uint8_t *)buffer->data() + buffer->range_offset(),
727          buffer->range_length());
728
729    mOffset += buffer->range_length();
730
731    return old_offset;
732}
733
734static void StripStartcode(MediaBuffer *buffer) {
735    if (buffer->range_length() < 4) {
736        return;
737    }
738
739    const uint8_t *ptr =
740        (const uint8_t *)buffer->data() + buffer->range_offset();
741
742    if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
743        buffer->set_range(
744                buffer->range_offset() + 4, buffer->range_length() - 4);
745    }
746}
747
748off64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
749    off64_t old_offset = mOffset;
750
751    size_t length = buffer->range_length();
752
753    if (mUse4ByteNalLength) {
754        uint8_t x = length >> 24;
755        ::write(mFd, &x, 1);
756        x = (length >> 16) & 0xff;
757        ::write(mFd, &x, 1);
758        x = (length >> 8) & 0xff;
759        ::write(mFd, &x, 1);
760        x = length & 0xff;
761        ::write(mFd, &x, 1);
762
763        ::write(mFd,
764              (const uint8_t *)buffer->data() + buffer->range_offset(),
765              length);
766
767        mOffset += length + 4;
768    } else {
769        CHECK(length < 65536);
770
771        uint8_t x = length >> 8;
772        ::write(mFd, &x, 1);
773        x = length & 0xff;
774        ::write(mFd, &x, 1);
775        ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length);
776        mOffset += length + 2;
777    }
778
779    return old_offset;
780}
781
782size_t MPEG4Writer::write(
783        const void *ptr, size_t size, size_t nmemb) {
784
785    const size_t bytes = size * nmemb;
786    if (mWriteMoovBoxToMemory) {
787        // This happens only when we write the moov box at the end of
788        // recording, not for each output video/audio frame we receive.
789        off64_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes;
790        if (moovBoxSize > mEstimatedMoovBoxSize) {
791            for (List<off64_t>::iterator it = mBoxes.begin();
792                 it != mBoxes.end(); ++it) {
793                (*it) += mOffset;
794            }
795            lseek64(mFd, mOffset, SEEK_SET);
796            ::write(mFd, mMoovBoxBuffer, mMoovBoxBufferOffset);
797            ::write(mFd, ptr, size * nmemb);
798            mOffset += (bytes + mMoovBoxBufferOffset);
799            free(mMoovBoxBuffer);
800            mMoovBoxBuffer = NULL;
801            mMoovBoxBufferOffset = 0;
802            mWriteMoovBoxToMemory = false;
803            mStreamableFile = false;
804        } else {
805            memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes);
806            mMoovBoxBufferOffset += bytes;
807        }
808    } else {
809        ::write(mFd, ptr, size * nmemb);
810        mOffset += bytes;
811    }
812    return bytes;
813}
814
815void MPEG4Writer::beginBox(const char *fourcc) {
816    CHECK_EQ(strlen(fourcc), 4);
817
818    mBoxes.push_back(mWriteMoovBoxToMemory?
819            mMoovBoxBufferOffset: mOffset);
820
821    writeInt32(0);
822    writeFourcc(fourcc);
823}
824
825void MPEG4Writer::endBox() {
826    CHECK(!mBoxes.empty());
827
828    off64_t offset = *--mBoxes.end();
829    mBoxes.erase(--mBoxes.end());
830
831    if (mWriteMoovBoxToMemory) {
832       int32_t x = htonl(mMoovBoxBufferOffset - offset);
833       memcpy(mMoovBoxBuffer + offset, &x, 4);
834    } else {
835        lseek64(mFd, offset, SEEK_SET);
836        writeInt32(mOffset - offset);
837        mOffset -= 4;
838        lseek64(mFd, mOffset, SEEK_SET);
839    }
840}
841
842void MPEG4Writer::writeInt8(int8_t x) {
843    write(&x, 1, 1);
844}
845
846void MPEG4Writer::writeInt16(int16_t x) {
847    x = htons(x);
848    write(&x, 1, 2);
849}
850
851void MPEG4Writer::writeInt32(int32_t x) {
852    x = htonl(x);
853    write(&x, 1, 4);
854}
855
856void MPEG4Writer::writeInt64(int64_t x) {
857    x = hton64(x);
858    write(&x, 1, 8);
859}
860
861void MPEG4Writer::writeCString(const char *s) {
862    size_t n = strlen(s);
863    write(s, 1, n + 1);
864}
865
866void MPEG4Writer::writeFourcc(const char *s) {
867    CHECK_EQ(strlen(s), 4);
868    write(s, 1, 4);
869}
870
871void MPEG4Writer::write(const void *data, size_t size) {
872    write(data, 1, size);
873}
874
875bool MPEG4Writer::isFileStreamable() const {
876    return mStreamableFile;
877}
878
879bool MPEG4Writer::exceedsFileSizeLimit() {
880    // No limit
881    if (mMaxFileSizeLimitBytes == 0) {
882        return false;
883    }
884
885    int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize);
886    for (List<Track *>::iterator it = mTracks.begin();
887         it != mTracks.end(); ++it) {
888        nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
889    }
890
891    // Be conservative in the estimate: do not exceed 95% of
892    // the target file limit. For small target file size limit, though,
893    // this will not help.
894    return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100);
895}
896
897bool MPEG4Writer::exceedsFileDurationLimit() {
898    // No limit
899    if (mMaxFileDurationLimitUs == 0) {
900        return false;
901    }
902
903    for (List<Track *>::iterator it = mTracks.begin();
904         it != mTracks.end(); ++it) {
905        if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) {
906            return true;
907        }
908    }
909    return false;
910}
911
912bool MPEG4Writer::reachedEOS() {
913    bool allDone = true;
914    for (List<Track *>::iterator it = mTracks.begin();
915         it != mTracks.end(); ++it) {
916        if (!(*it)->reachedEOS()) {
917            allDone = false;
918            break;
919        }
920    }
921
922    return allDone;
923}
924
925void MPEG4Writer::setStartTimestampUs(int64_t timeUs) {
926    LOGI("setStartTimestampUs: %lld", timeUs);
927    CHECK(timeUs >= 0);
928    Mutex::Autolock autoLock(mLock);
929    if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) {
930        mStartTimestampUs = timeUs;
931        LOGI("Earliest track starting time: %lld", mStartTimestampUs);
932    }
933}
934
935int64_t MPEG4Writer::getStartTimestampUs() {
936    Mutex::Autolock autoLock(mLock);
937    return mStartTimestampUs;
938}
939
940size_t MPEG4Writer::numTracks() {
941    Mutex::Autolock autolock(mLock);
942    return mTracks.size();
943}
944
945////////////////////////////////////////////////////////////////////////////////
946
947MPEG4Writer::Track::Track(
948        MPEG4Writer *owner, const sp<MediaSource> &source)
949    : mOwner(owner),
950      mMeta(source->getFormat()),
951      mSource(source),
952      mDone(false),
953      mPaused(false),
954      mResumed(false),
955      mStarted(false),
956      mTrackDurationUs(0),
957      mEstimatedTrackSizeBytes(0),
958      mSamplesHaveSameSize(true),
959      mCodecSpecificData(NULL),
960      mCodecSpecificDataSize(0),
961      mGotAllCodecSpecificData(false),
962      mReachedEOS(false),
963      mRotation(0) {
964    getCodecSpecificDataFromInputFormatIfPossible();
965
966    const char *mime;
967    mMeta->findCString(kKeyMIMEType, &mime);
968    mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
969    mIsAudio = !strncasecmp(mime, "audio/", 6);
970    mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
971               !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
972
973    setTimeScale();
974}
975
976void MPEG4Writer::Track::updateTrackSizeEstimate() {
977
978    int64_t stcoBoxSizeBytes = mOwner->use32BitFileOffset()
979                                ? mNumStcoTableEntries * 4
980                                : mNumStcoTableEntries * 8;
981
982    int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mNumSamples * 4);
983
984    mEstimatedTrackSizeBytes = mMdatSizeBytes;  // media data size
985    if (!mOwner->isFileStreamable()) {
986        // Reserved free space is not large enough to hold
987        // all meta data and thus wasted.
988        mEstimatedTrackSizeBytes += mNumStscTableEntries * 12 +  // stsc box size
989                                    mNumStssTableEntries * 4 +   // stss box size
990                                    mNumSttsTableEntries * 8 +   // stts box size
991                                    stcoBoxSizeBytes +           // stco box size
992                                    stszBoxSizeBytes;            // stsz box size
993    }
994}
995
996void MPEG4Writer::Track::addOneStscTableEntry(
997        size_t chunkId, size_t sampleId) {
998
999        StscTableEntry stscEntry(chunkId, sampleId, 1);
1000        mStscTableEntries.push_back(stscEntry);
1001        ++mNumStscTableEntries;
1002}
1003
1004void MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) {
1005    mStssTableEntries.push_back(sampleId);
1006    ++mNumStssTableEntries;
1007}
1008
1009void MPEG4Writer::Track::addOneSttsTableEntry(
1010        size_t sampleCount, int64_t durationUs) {
1011
1012    SttsTableEntry sttsEntry(sampleCount, durationUs);
1013    mSttsTableEntries.push_back(sttsEntry);
1014    ++mNumSttsTableEntries;
1015}
1016
1017void MPEG4Writer::Track::addChunkOffset(off64_t offset) {
1018    ++mNumStcoTableEntries;
1019    mChunkOffsets.push_back(offset);
1020}
1021
1022void MPEG4Writer::Track::setTimeScale() {
1023    LOGV("setTimeScale");
1024    // Default time scale
1025    mTimeScale = 90000;
1026
1027    if (mIsAudio) {
1028        // Use the sampling rate as the default time scale for audio track.
1029        int32_t sampleRate;
1030        bool success = mMeta->findInt32(kKeySampleRate, &sampleRate);
1031        CHECK(success);
1032        mTimeScale = sampleRate;
1033    }
1034
1035    // If someone would like to overwrite the timescale, use user-supplied value.
1036    int32_t timeScale;
1037    if (mMeta->findInt32(kKeyTimeScale, &timeScale)) {
1038        mTimeScale = timeScale;
1039    }
1040
1041    CHECK(mTimeScale > 0);
1042}
1043
1044void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
1045    const char *mime;
1046    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
1047
1048    if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
1049        uint32_t type;
1050        const void *data;
1051        size_t size;
1052        if (mMeta->findData(kKeyAVCC, &type, &data, &size)) {
1053            mCodecSpecificData = malloc(size);
1054            mCodecSpecificDataSize = size;
1055            memcpy(mCodecSpecificData, data, size);
1056            mGotAllCodecSpecificData = true;
1057        }
1058    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
1059            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
1060        uint32_t type;
1061        const void *data;
1062        size_t size;
1063        if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
1064            ESDS esds(data, size);
1065            if (esds.getCodecSpecificInfo(&data, &size) == OK) {
1066                mCodecSpecificData = malloc(size);
1067                mCodecSpecificDataSize = size;
1068                memcpy(mCodecSpecificData, data, size);
1069                mGotAllCodecSpecificData = true;
1070            }
1071        }
1072    }
1073}
1074
1075MPEG4Writer::Track::~Track() {
1076    stop();
1077
1078    if (mCodecSpecificData != NULL) {
1079        free(mCodecSpecificData);
1080        mCodecSpecificData = NULL;
1081    }
1082}
1083
1084void MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) {
1085    LOGV("initTrackingProgressStatus");
1086    mPreviousTrackTimeUs = -1;
1087    mTrackingProgressStatus = false;
1088    mTrackEveryTimeDurationUs = 0;
1089    {
1090        int64_t timeUs;
1091        if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) {
1092            LOGV("Receive request to track progress status for every %lld us", timeUs);
1093            mTrackEveryTimeDurationUs = timeUs;
1094            mTrackingProgressStatus = true;
1095        }
1096    }
1097}
1098
1099// static
1100void *MPEG4Writer::ThreadWrapper(void *me) {
1101    LOGV("ThreadWrapper: %p", me);
1102    MPEG4Writer *writer = static_cast<MPEG4Writer *>(me);
1103    writer->threadFunc();
1104    return NULL;
1105}
1106
1107void MPEG4Writer::bufferChunk(const Chunk& chunk) {
1108    LOGV("bufferChunk: %p", chunk.mTrack);
1109    Mutex::Autolock autolock(mLock);
1110    CHECK_EQ(mDone, false);
1111
1112    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
1113         it != mChunkInfos.end(); ++it) {
1114
1115        if (chunk.mTrack == it->mTrack) {  // Found owner
1116            it->mChunks.push_back(chunk);
1117            mChunkReadyCondition.signal();
1118            return;
1119        }
1120    }
1121
1122    CHECK("Received a chunk for a unknown track" == 0);
1123}
1124
1125void MPEG4Writer::writeChunkToFile(Chunk* chunk) {
1126    LOGV("writeChunkToFile: %lld from %s track",
1127        chunk.mTimestampUs, chunk.mTrack->isAudio()? "audio": "video");
1128
1129    int32_t isFirstSample = true;
1130    while (!chunk->mSamples.empty()) {
1131        List<MediaBuffer *>::iterator it = chunk->mSamples.begin();
1132
1133        off64_t offset = chunk->mTrack->isAvc()
1134                                ? addLengthPrefixedSample_l(*it)
1135                                : addSample_l(*it);
1136
1137        if (isFirstSample) {
1138            chunk->mTrack->addChunkOffset(offset);
1139            isFirstSample = false;
1140        }
1141
1142        (*it)->release();
1143        (*it) = NULL;
1144        chunk->mSamples.erase(it);
1145    }
1146    chunk->mSamples.clear();
1147}
1148
1149void MPEG4Writer::writeAllChunks() {
1150    LOGV("writeAllChunks");
1151    size_t outstandingChunks = 0;
1152    while (!mChunkInfos.empty()) {
1153        List<ChunkInfo>::iterator it = mChunkInfos.begin();
1154        while (!it->mChunks.empty()) {
1155            Chunk chunk;
1156            if (findChunkToWrite(&chunk)) {
1157                writeChunkToFile(&chunk);
1158                ++outstandingChunks;
1159            }
1160        }
1161        it->mTrack = NULL;
1162        mChunkInfos.erase(it);
1163    }
1164    mChunkInfos.clear();
1165    LOGD("%d chunks are written in the last batch", outstandingChunks);
1166}
1167
1168bool MPEG4Writer::findChunkToWrite(Chunk *chunk) {
1169    LOGV("findChunkToWrite");
1170
1171    // Find the smallest timestamp, and write that chunk out
1172    // XXX: What if some track is just too slow?
1173    int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL;
1174    Track *track = NULL;
1175    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
1176         it != mChunkInfos.end(); ++it) {
1177        if (!it->mChunks.empty()) {
1178            List<Chunk>::iterator chunkIt = it->mChunks.begin();
1179            if (chunkIt->mTimeStampUs < minTimestampUs) {
1180                minTimestampUs = chunkIt->mTimeStampUs;
1181                track = it->mTrack;
1182            }
1183        }
1184    }
1185
1186    if (track == NULL) {
1187        LOGV("Nothing to be written after all");
1188        return false;
1189    }
1190
1191    if (mIsFirstChunk) {
1192        mIsFirstChunk = false;
1193    }
1194
1195    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
1196         it != mChunkInfos.end(); ++it) {
1197        if (it->mTrack == track) {
1198            *chunk = *(it->mChunks.begin());
1199            it->mChunks.erase(it->mChunks.begin());
1200            CHECK_EQ(chunk->mTrack, track);
1201            return true;
1202        }
1203    }
1204
1205    return false;
1206}
1207
1208void MPEG4Writer::threadFunc() {
1209    LOGV("threadFunc");
1210
1211    prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0);
1212
1213    Mutex::Autolock autoLock(mLock);
1214    while (!mDone) {
1215        Chunk chunk;
1216        bool chunkFound = false;
1217
1218        while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) {
1219            mChunkReadyCondition.wait(mLock);
1220        }
1221
1222        // Actual write without holding the lock in order to
1223        // reduce the blocking time for media track threads.
1224        if (chunkFound) {
1225            mLock.unlock();
1226            writeChunkToFile(&chunk);
1227            mLock.lock();
1228        }
1229    }
1230
1231    writeAllChunks();
1232}
1233
1234status_t MPEG4Writer::startWriterThread() {
1235    LOGV("startWriterThread");
1236
1237    mDone = false;
1238    mIsFirstChunk = true;
1239    mDriftTimeUs = 0;
1240    for (List<Track *>::iterator it = mTracks.begin();
1241         it != mTracks.end(); ++it) {
1242        ChunkInfo info;
1243        info.mTrack = *it;
1244        mChunkInfos.push_back(info);
1245    }
1246
1247    pthread_attr_t attr;
1248    pthread_attr_init(&attr);
1249    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1250    pthread_create(&mThread, &attr, ThreadWrapper, this);
1251    pthread_attr_destroy(&attr);
1252    return OK;
1253}
1254
1255
1256status_t MPEG4Writer::Track::start(MetaData *params) {
1257    if (!mDone && mPaused) {
1258        mPaused = false;
1259        mResumed = true;
1260        return OK;
1261    }
1262
1263    int64_t startTimeUs;
1264    if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) {
1265        startTimeUs = 0;
1266    }
1267
1268    int32_t rotationDegrees;
1269    if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) {
1270        mRotation = rotationDegrees;
1271    }
1272
1273    mIsRealTimeRecording = true;
1274    {
1275        int32_t isNotRealTime;
1276        if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) {
1277            mIsRealTimeRecording = (isNotRealTime == 0);
1278        }
1279    }
1280
1281    initTrackingProgressStatus(params);
1282
1283    sp<MetaData> meta = new MetaData;
1284    meta->setInt64(kKeyTime, startTimeUs);
1285    status_t err = mSource->start(meta.get());
1286    if (err != OK) {
1287        mDone = mReachedEOS = true;
1288        return err;
1289    }
1290
1291    pthread_attr_t attr;
1292    pthread_attr_init(&attr);
1293    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1294
1295    mDone = false;
1296    mStarted = true;
1297    mTrackDurationUs = 0;
1298    mReachedEOS = false;
1299    mEstimatedTrackSizeBytes = 0;
1300    mNumStcoTableEntries = 0;
1301    mNumStssTableEntries = 0;
1302    mNumStscTableEntries = 0;
1303    mNumSttsTableEntries = 0;
1304    mMdatSizeBytes = 0;
1305    mIsMediaTimeAdjustmentOn = false;
1306    mPrevMediaTimeAdjustTimestampUs = 0;
1307    mMediaTimeAdjustNumFrames = 0;
1308    mPrevMediaTimeAdjustSample = 0;
1309    mTotalDriftTimeToAdjustUs = 0;
1310    mPrevTotalAccumDriftTimeUs = 0;
1311
1312    pthread_create(&mThread, &attr, ThreadWrapper, this);
1313    pthread_attr_destroy(&attr);
1314
1315    return OK;
1316}
1317
1318status_t MPEG4Writer::Track::pause() {
1319    mPaused = true;
1320    return OK;
1321}
1322
1323status_t MPEG4Writer::Track::stop() {
1324    LOGD("Stopping %s track", mIsAudio? "Audio": "Video");
1325    if (!mStarted) {
1326        LOGE("Stop() called but track is not started");
1327        return ERROR_END_OF_STREAM;
1328    }
1329
1330    if (mDone) {
1331        return OK;
1332    }
1333    mDone = true;
1334
1335    void *dummy;
1336    pthread_join(mThread, &dummy);
1337
1338    status_t err = (status_t) dummy;
1339
1340    LOGD("Stopping %s track source", mIsAudio? "Audio": "Video");
1341    {
1342        status_t status = mSource->stop();
1343        if (err == OK && status != OK && status != ERROR_END_OF_STREAM) {
1344            err = status;
1345        }
1346    }
1347
1348    LOGD("%s track stopped", mIsAudio? "Audio": "Video");
1349    return err;
1350}
1351
1352bool MPEG4Writer::Track::reachedEOS() {
1353    return mReachedEOS;
1354}
1355
1356// static
1357void *MPEG4Writer::Track::ThreadWrapper(void *me) {
1358    Track *track = static_cast<Track *>(me);
1359
1360    status_t err = track->threadEntry();
1361    return (void *) err;
1362}
1363
1364static void getNalUnitType(uint8_t byte, uint8_t* type) {
1365    LOGV("getNalUnitType: %d", byte);
1366
1367    // nal_unit_type: 5-bit unsigned integer
1368    *type = (byte & 0x1F);
1369}
1370
1371static const uint8_t *findNextStartCode(
1372        const uint8_t *data, size_t length) {
1373
1374    LOGV("findNextStartCode: %p %d", data, length);
1375
1376    size_t bytesLeft = length;
1377    while (bytesLeft > 4  &&
1378            memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) {
1379        --bytesLeft;
1380    }
1381    if (bytesLeft <= 4) {
1382        bytesLeft = 0; // Last parameter set
1383    }
1384    return &data[length - bytesLeft];
1385}
1386
1387const uint8_t *MPEG4Writer::Track::parseParamSet(
1388        const uint8_t *data, size_t length, int type, size_t *paramSetLen) {
1389
1390    LOGV("parseParamSet");
1391    CHECK(type == kNalUnitTypeSeqParamSet ||
1392          type == kNalUnitTypePicParamSet);
1393
1394    const uint8_t *nextStartCode = findNextStartCode(data, length);
1395    *paramSetLen = nextStartCode - data;
1396    if (*paramSetLen == 0) {
1397        LOGE("Param set is malformed, since its length is 0");
1398        return NULL;
1399    }
1400
1401    AVCParamSet paramSet(*paramSetLen, data);
1402    if (type == kNalUnitTypeSeqParamSet) {
1403        if (*paramSetLen < 4) {
1404            LOGE("Seq parameter set malformed");
1405            return NULL;
1406        }
1407        if (mSeqParamSets.empty()) {
1408            mProfileIdc = data[1];
1409            mProfileCompatible = data[2];
1410            mLevelIdc = data[3];
1411        } else {
1412            if (mProfileIdc != data[1] ||
1413                mProfileCompatible != data[2] ||
1414                mLevelIdc != data[3]) {
1415                LOGE("Inconsistent profile/level found in seq parameter sets");
1416                return NULL;
1417            }
1418        }
1419        mSeqParamSets.push_back(paramSet);
1420    } else {
1421        mPicParamSets.push_back(paramSet);
1422    }
1423    return nextStartCode;
1424}
1425
1426status_t MPEG4Writer::Track::copyAVCCodecSpecificData(
1427        const uint8_t *data, size_t size) {
1428    LOGV("copyAVCCodecSpecificData");
1429
1430    // 2 bytes for each of the parameter set length field
1431    // plus the 7 bytes for the header
1432    if (size < 4 + 7) {
1433        LOGE("Codec specific data length too short: %d", size);
1434        return ERROR_MALFORMED;
1435    }
1436
1437    mCodecSpecificDataSize = size;
1438    mCodecSpecificData = malloc(size);
1439    memcpy(mCodecSpecificData, data, size);
1440    return OK;
1441}
1442
1443status_t MPEG4Writer::Track::parseAVCCodecSpecificData(
1444        const uint8_t *data, size_t size) {
1445
1446    LOGV("parseAVCCodecSpecificData");
1447    // Data starts with a start code.
1448    // SPS and PPS are separated with start codes.
1449    // Also, SPS must come before PPS
1450    uint8_t type = kNalUnitTypeSeqParamSet;
1451    bool gotSps = false;
1452    bool gotPps = false;
1453    const uint8_t *tmp = data;
1454    const uint8_t *nextStartCode = data;
1455    size_t bytesLeft = size;
1456    size_t paramSetLen = 0;
1457    mCodecSpecificDataSize = 0;
1458    while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) {
1459        getNalUnitType(*(tmp + 4), &type);
1460        if (type == kNalUnitTypeSeqParamSet) {
1461            if (gotPps) {
1462                LOGE("SPS must come before PPS");
1463                return ERROR_MALFORMED;
1464            }
1465            if (!gotSps) {
1466                gotSps = true;
1467            }
1468            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
1469        } else if (type == kNalUnitTypePicParamSet) {
1470            if (!gotSps) {
1471                LOGE("SPS must come before PPS");
1472                return ERROR_MALFORMED;
1473            }
1474            if (!gotPps) {
1475                gotPps = true;
1476            }
1477            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
1478        } else {
1479            LOGE("Only SPS and PPS Nal units are expected");
1480            return ERROR_MALFORMED;
1481        }
1482
1483        if (nextStartCode == NULL) {
1484            return ERROR_MALFORMED;
1485        }
1486
1487        // Move on to find the next parameter set
1488        bytesLeft -= nextStartCode - tmp;
1489        tmp = nextStartCode;
1490        mCodecSpecificDataSize += (2 + paramSetLen);
1491    }
1492
1493    {
1494        // Check on the number of seq parameter sets
1495        size_t nSeqParamSets = mSeqParamSets.size();
1496        if (nSeqParamSets == 0) {
1497            LOGE("Cound not find sequence parameter set");
1498            return ERROR_MALFORMED;
1499        }
1500
1501        if (nSeqParamSets > 0x1F) {
1502            LOGE("Too many seq parameter sets (%d) found", nSeqParamSets);
1503            return ERROR_MALFORMED;
1504        }
1505    }
1506
1507    {
1508        // Check on the number of pic parameter sets
1509        size_t nPicParamSets = mPicParamSets.size();
1510        if (nPicParamSets == 0) {
1511            LOGE("Cound not find picture parameter set");
1512            return ERROR_MALFORMED;
1513        }
1514        if (nPicParamSets > 0xFF) {
1515            LOGE("Too many pic parameter sets (%d) found", nPicParamSets);
1516            return ERROR_MALFORMED;
1517        }
1518    }
1519
1520    {
1521        // Check on the profiles
1522        // These profiles requires additional parameter set extensions
1523        if (mProfileIdc == 100 || mProfileIdc == 110 ||
1524            mProfileIdc == 122 || mProfileIdc == 144) {
1525            LOGE("Sorry, no support for profile_idc: %d!", mProfileIdc);
1526            return BAD_VALUE;
1527        }
1528    }
1529
1530    return OK;
1531}
1532
1533status_t MPEG4Writer::Track::makeAVCCodecSpecificData(
1534        const uint8_t *data, size_t size) {
1535
1536    if (mCodecSpecificData != NULL) {
1537        LOGE("Already have codec specific data");
1538        return ERROR_MALFORMED;
1539    }
1540
1541    if (size < 4) {
1542        LOGE("Codec specific data length too short: %d", size);
1543        return ERROR_MALFORMED;
1544    }
1545
1546    // Data is in the form of AVCCodecSpecificData
1547    if (memcmp("\x00\x00\x00\x01", data, 4)) {
1548        return copyAVCCodecSpecificData(data, size);
1549    }
1550
1551    if (parseAVCCodecSpecificData(data, size) != OK) {
1552        return ERROR_MALFORMED;
1553    }
1554
1555    // ISO 14496-15: AVC file format
1556    mCodecSpecificDataSize += 7;  // 7 more bytes in the header
1557    mCodecSpecificData = malloc(mCodecSpecificDataSize);
1558    uint8_t *header = (uint8_t *)mCodecSpecificData;
1559    header[0] = 1;                     // version
1560    header[1] = mProfileIdc;           // profile indication
1561    header[2] = mProfileCompatible;    // profile compatibility
1562    header[3] = mLevelIdc;
1563
1564    // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne
1565    if (mOwner->useNalLengthFour()) {
1566        header[4] = 0xfc | 3;  // length size == 4 bytes
1567    } else {
1568        header[4] = 0xfc | 1;  // length size == 2 bytes
1569    }
1570
1571    // 3-bit '111' followed by 5-bit numSequenceParameterSets
1572    int nSequenceParamSets = mSeqParamSets.size();
1573    header[5] = 0xe0 | nSequenceParamSets;
1574    header += 6;
1575    for (List<AVCParamSet>::iterator it = mSeqParamSets.begin();
1576         it != mSeqParamSets.end(); ++it) {
1577        // 16-bit sequence parameter set length
1578        uint16_t seqParamSetLength = it->mLength;
1579        header[0] = seqParamSetLength >> 8;
1580        header[1] = seqParamSetLength & 0xff;
1581
1582        // SPS NAL unit (sequence parameter length bytes)
1583        memcpy(&header[2], it->mData, seqParamSetLength);
1584        header += (2 + seqParamSetLength);
1585    }
1586
1587    // 8-bit nPictureParameterSets
1588    int nPictureParamSets = mPicParamSets.size();
1589    header[0] = nPictureParamSets;
1590    header += 1;
1591    for (List<AVCParamSet>::iterator it = mPicParamSets.begin();
1592         it != mPicParamSets.end(); ++it) {
1593        // 16-bit picture parameter set length
1594        uint16_t picParamSetLength = it->mLength;
1595        header[0] = picParamSetLength >> 8;
1596        header[1] = picParamSetLength & 0xff;
1597
1598        // PPS Nal unit (picture parameter set length bytes)
1599        memcpy(&header[2], it->mData, picParamSetLength);
1600        header += (2 + picParamSetLength);
1601    }
1602
1603    return OK;
1604}
1605
1606/*
1607* The video track's media time adjustment for real-time applications
1608* is described as follows:
1609*
1610* First, the media time adjustment is done for every period of
1611* kVideoMediaTimeAdjustPeriodTimeUs. kVideoMediaTimeAdjustPeriodTimeUs
1612* is currently a fixed value chosen heuristically. The value of
1613* kVideoMediaTimeAdjustPeriodTimeUs should not be very large or very small
1614* for two considerations: on one hand, a relatively large value
1615* helps reduce large fluctuation of drift time in the audio encoding
1616* path; while on the other hand, a relatively small value helps keep
1617* restoring synchronization in audio/video more frequently. Note for the
1618* very first period of kVideoMediaTimeAdjustPeriodTimeUs, there is
1619* no media time adjustment for the video track.
1620*
1621* Second, the total accumulated audio track time drift found
1622* in a period of kVideoMediaTimeAdjustPeriodTimeUs is distributed
1623* over a stream of incoming video frames. The number of video frames
1624* affected is determined based on the number of recorded video frames
1625* within the past kVideoMediaTimeAdjustPeriodTimeUs period.
1626* We choose to distribute the drift time over only a portion
1627* (rather than all) of the total number of recorded video frames
1628* in order to make sure that the video track media time adjustment is
1629* completed for the current period before the next video track media
1630* time adjustment period starts. Currently, the portion chosen is a
1631* half (0.5).
1632*
1633* Last, various additional checks are performed to ensure that
1634* the actual audio encoding path does not have too much drift.
1635* In particular, 1) we want to limit the average incremental time
1636* adjustment for each video frame to be less than a threshold
1637* for a single period of kVideoMediaTimeAdjustPeriodTimeUs.
1638* Currently, the threshold is set to 5 ms. If the average incremental
1639* media time adjustment for a video frame is larger than the
1640* threshold, the audio encoding path has too much time drift.
1641* 2) We also want to limit the total time drift in the audio
1642* encoding path to be less than a threshold for a period of
1643* kVideoMediaTimeAdjustPeriodTimeUs. Currently, the threshold
1644* is 0.5% of kVideoMediaTimeAdjustPeriodTimeUs. If the time drift of
1645* the audio encoding path is larger than the threshold, the audio
1646* encoding path has too much time drift. We treat the large time
1647* drift of the audio encoding path as errors, since there is no
1648* way to keep audio/video in synchronization for real-time
1649* applications if the time drift is too large unless we drop some
1650* video frames, which has its own problems that we don't want
1651* to get into for the time being.
1652*/
1653void MPEG4Writer::Track::adjustMediaTime(int64_t *timestampUs) {
1654    if (*timestampUs - mPrevMediaTimeAdjustTimestampUs >=
1655        kVideoMediaTimeAdjustPeriodTimeUs) {
1656
1657        LOGV("New media time adjustment period at %lld us", *timestampUs);
1658        mIsMediaTimeAdjustmentOn = true;
1659        mMediaTimeAdjustNumFrames =
1660                (mNumSamples - mPrevMediaTimeAdjustSample) >> 1;
1661
1662        mPrevMediaTimeAdjustTimestampUs = *timestampUs;
1663        mPrevMediaTimeAdjustSample = mNumSamples;
1664        int64_t totalAccumDriftTimeUs = mOwner->getDriftTimeUs();
1665        mTotalDriftTimeToAdjustUs =
1666                totalAccumDriftTimeUs - mPrevTotalAccumDriftTimeUs;
1667
1668        mPrevTotalAccumDriftTimeUs = totalAccumDriftTimeUs;
1669
1670        // Check on incremental adjusted time per frame
1671        int64_t adjustTimePerFrameUs =
1672                mTotalDriftTimeToAdjustUs / mMediaTimeAdjustNumFrames;
1673
1674        if (adjustTimePerFrameUs < 0) {
1675            adjustTimePerFrameUs = -adjustTimePerFrameUs;
1676        }
1677        if (adjustTimePerFrameUs >= 5000) {
1678            LOGE("Adjusted time per video frame is %lld us",
1679                adjustTimePerFrameUs);
1680            CHECK(!"Video frame time adjustment is too large!");
1681        }
1682
1683        // Check on total accumulated time drift within a period of
1684        // kVideoMediaTimeAdjustPeriodTimeUs.
1685        int64_t driftPercentage = (mTotalDriftTimeToAdjustUs * 1000)
1686                / kVideoMediaTimeAdjustPeriodTimeUs;
1687
1688        if (driftPercentage < 0) {
1689            driftPercentage = -driftPercentage;
1690        }
1691        if (driftPercentage > 5) {
1692            LOGE("Audio track has time drift %lld us over %lld us",
1693                mTotalDriftTimeToAdjustUs,
1694                kVideoMediaTimeAdjustPeriodTimeUs);
1695
1696            CHECK(!"The audio track media time drifts too much!");
1697        }
1698
1699    }
1700
1701    if (mIsMediaTimeAdjustmentOn) {
1702        if (mNumSamples - mPrevMediaTimeAdjustSample <=
1703            mMediaTimeAdjustNumFrames) {
1704
1705            // Do media time incremental adjustment
1706            int64_t incrementalAdjustTimeUs =
1707                        (mTotalDriftTimeToAdjustUs *
1708                            (mNumSamples - mPrevMediaTimeAdjustSample))
1709                                / mMediaTimeAdjustNumFrames;
1710
1711            *timestampUs +=
1712                (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs);
1713
1714            LOGV("Incremental video frame media time adjustment: %lld us",
1715                (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs));
1716        } else {
1717            // Within the remaining adjustment period,
1718            // no incremental adjustment is needed.
1719            *timestampUs +=
1720                (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs);
1721
1722            LOGV("Fixed video frame media time adjustment: %lld us",
1723                (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs));
1724        }
1725    }
1726}
1727
1728/*
1729 * Updates the drift time from the audio track so that
1730 * the video track can get the updated drift time information
1731 * from the file writer. The fluctuation of the drift time of the audio
1732 * encoding path is smoothed out with a simple filter by giving a larger
1733 * weight to more recently drift time. The filter coefficients, 0.5 and 0.5,
1734 * are heuristically determined.
1735 */
1736void MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) {
1737    int64_t driftTimeUs = 0;
1738    if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) {
1739        int64_t prevDriftTimeUs = mOwner->getDriftTimeUs();
1740        int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1;
1741        mOwner->setDriftTimeUs(timeUs);
1742    }
1743}
1744
1745status_t MPEG4Writer::Track::threadEntry() {
1746    int32_t count = 0;
1747    const int64_t interleaveDurationUs = mOwner->interleaveDuration();
1748    int64_t chunkTimestampUs = 0;
1749    int32_t nChunks = 0;
1750    int32_t nZeroLengthFrames = 0;
1751    int64_t lastTimestampUs = 0;  // Previous sample time stamp in ms
1752    int64_t lastDurationUs = 0;   // Between the previous two samples in ms
1753    int64_t currDurationTicks = 0;  // Timescale based ticks
1754    int64_t lastDurationTicks = 0;  // Timescale based ticks
1755    int32_t sampleCount = 1;      // Sample count in the current stts table entry
1756    uint32_t previousSampleSize = 0;  // Size of the previous sample
1757    int64_t previousPausedDurationUs = 0;
1758    int64_t timestampUs;
1759
1760    if (mIsAudio) {
1761        prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
1762    } else {
1763        prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0);
1764    }
1765    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
1766
1767    sp<MetaData> meta_data;
1768
1769    mNumSamples = 0;
1770    status_t err = OK;
1771    MediaBuffer *buffer;
1772    while (!mDone && (err = mSource->read(&buffer)) == OK) {
1773        if (buffer->range_length() == 0) {
1774            buffer->release();
1775            buffer = NULL;
1776            ++nZeroLengthFrames;
1777            continue;
1778        }
1779
1780        // If the codec specific data has not been received yet, delay pause.
1781        // After the codec specific data is received, discard what we received
1782        // when the track is to be paused.
1783        if (mPaused && !mResumed) {
1784            buffer->release();
1785            buffer = NULL;
1786            continue;
1787        }
1788
1789        ++count;
1790
1791        int32_t isCodecConfig;
1792        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
1793                && isCodecConfig) {
1794            CHECK(!mGotAllCodecSpecificData);
1795
1796            if (mIsAvc) {
1797                status_t err = makeAVCCodecSpecificData(
1798                        (const uint8_t *)buffer->data()
1799                            + buffer->range_offset(),
1800                        buffer->range_length());
1801                CHECK_EQ(OK, err);
1802            } else if (mIsMPEG4) {
1803                mCodecSpecificDataSize = buffer->range_length();
1804                mCodecSpecificData = malloc(mCodecSpecificDataSize);
1805                memcpy(mCodecSpecificData,
1806                        (const uint8_t *)buffer->data()
1807                            + buffer->range_offset(),
1808                       buffer->range_length());
1809            }
1810
1811            buffer->release();
1812            buffer = NULL;
1813
1814            mGotAllCodecSpecificData = true;
1815            continue;
1816        }
1817
1818        // Make a deep copy of the MediaBuffer and Metadata and release
1819        // the original as soon as we can
1820        MediaBuffer *copy = new MediaBuffer(buffer->range_length());
1821        memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(),
1822                buffer->range_length());
1823        copy->set_range(0, buffer->range_length());
1824        meta_data = new MetaData(*buffer->meta_data().get());
1825        buffer->release();
1826        buffer = NULL;
1827
1828        if (mIsAvc) StripStartcode(copy);
1829
1830        size_t sampleSize = copy->range_length();
1831        if (mIsAvc) {
1832            if (mOwner->useNalLengthFour()) {
1833                sampleSize += 4;
1834            } else {
1835                sampleSize += 2;
1836            }
1837        }
1838
1839        // Max file size or duration handling
1840        mMdatSizeBytes += sampleSize;
1841        updateTrackSizeEstimate();
1842
1843        if (mOwner->exceedsFileSizeLimit()) {
1844            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
1845            break;
1846        }
1847        if (mOwner->exceedsFileDurationLimit()) {
1848            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
1849            break;
1850        }
1851
1852
1853        int32_t isSync = false;
1854        meta_data->findInt32(kKeyIsSyncFrame, &isSync);
1855
1856        /*
1857         * The original timestamp found in the data buffer will be modified as below:
1858         *
1859         * There is a playback offset into this track if the track's start time
1860         * is not the same as the movie start time, which will be recorded in edst
1861         * box of the output file. The playback offset is to make sure that the
1862         * starting time of the audio/video tracks are synchronized. Although the
1863         * track's media timestamp may be subject to various modifications
1864         * as outlined below, the track's playback offset time remains unchanged
1865         * once the first data buffer of the track is received.
1866         *
1867         * The media time stamp will be calculated by subtracting the playback offset
1868         * (and potential pause durations) from the original timestamp in the buffer.
1869         *
1870         * If this track is a video track for a real-time recording application with
1871         * both audio and video tracks, its media timestamp will subject to further
1872         * modification based on the media clock of the audio track. This modification
1873         * is needed for the purpose of maintaining good audio/video synchronization.
1874         *
1875         * If the recording session is paused and resumed multiple times, the track
1876         * media timestamp will be modified as if the  recording session had never been
1877         * paused at all during playback of the recorded output file. In other words,
1878         * the output file will have no memory of pause/resume durations.
1879         *
1880         */
1881        CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
1882        LOGV("%s timestampUs: %lld", mIsAudio? "Audio": "Video", timestampUs);
1883
1884////////////////////////////////////////////////////////////////////////////////
1885        if (mSampleSizes.empty()) {
1886            mStartTimestampUs = timestampUs;
1887            mOwner->setStartTimestampUs(mStartTimestampUs);
1888            previousPausedDurationUs = mStartTimestampUs;
1889        }
1890
1891        if (mResumed) {
1892            int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
1893            CHECK(durExcludingEarlierPausesUs >= 0);
1894            int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
1895            CHECK(pausedDurationUs >= lastDurationUs);
1896            previousPausedDurationUs += pausedDurationUs - lastDurationUs;
1897            mResumed = false;
1898        }
1899
1900        timestampUs -= previousPausedDurationUs;
1901        CHECK(timestampUs >= 0);
1902
1903        // Media time adjustment for real-time applications
1904        if (mIsRealTimeRecording) {
1905            if (mIsAudio) {
1906                updateDriftTime(meta_data);
1907            } else {
1908                adjustMediaTime(&timestampUs);
1909            }
1910        }
1911
1912        CHECK(timestampUs >= 0);
1913        if (mNumSamples > 1) {
1914            if (timestampUs <= lastTimestampUs) {
1915                LOGW("Frame arrives too late!");
1916                // Don't drop the late frame, since dropping a frame may cause
1917                // problems later during playback
1918
1919                // The idea here is to avoid having two or more samples with the
1920                // same timestamp in the output file.
1921                if (mTimeScale >= 1000000LL) {
1922                    timestampUs = lastTimestampUs + 1;
1923                } else {
1924                    timestampUs = lastTimestampUs + (1000000LL + (mTimeScale >> 1)) / mTimeScale;
1925                }
1926            }
1927        }
1928
1929        LOGV("%s media time stamp: %lld and previous paused duration %lld",
1930                mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs);
1931        if (timestampUs > mTrackDurationUs) {
1932            mTrackDurationUs = timestampUs;
1933        }
1934
1935        mSampleSizes.push_back(sampleSize);
1936        ++mNumSamples;
1937        if (mNumSamples > 2) {
1938            // We need to use the time scale based ticks, rather than the
1939            // timestamp itself to determine whether we have to use a new
1940            // stts entry, since we may have rounding errors.
1941            // The calculation is intended to reduce the accumulated
1942            // rounding errors.
1943            currDurationTicks =
1944                     ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
1945                     (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
1946
1947            if (currDurationTicks != lastDurationTicks) {
1948                addOneSttsTableEntry(sampleCount, lastDurationUs);
1949                sampleCount = 1;
1950            } else {
1951                ++sampleCount;
1952            }
1953        }
1954        if (mSamplesHaveSameSize) {
1955            if (mNumSamples >= 2 && previousSampleSize != sampleSize) {
1956                mSamplesHaveSameSize = false;
1957            }
1958            previousSampleSize = sampleSize;
1959        }
1960        lastDurationUs = timestampUs - lastTimestampUs;
1961        lastDurationTicks = currDurationTicks;
1962        lastTimestampUs = timestampUs;
1963
1964        if (isSync != 0) {
1965            addOneStssTableEntry(mNumSamples);
1966        }
1967
1968        if (mTrackingProgressStatus) {
1969            if (mPreviousTrackTimeUs <= 0) {
1970                mPreviousTrackTimeUs = mStartTimestampUs;
1971            }
1972            trackProgressStatus(timestampUs);
1973        }
1974        if (mOwner->numTracks() == 1) {
1975            off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy)
1976                                 : mOwner->addSample_l(copy);
1977            if (mChunkOffsets.empty()) {
1978                addChunkOffset(offset);
1979            }
1980            copy->release();
1981            copy = NULL;
1982            continue;
1983        }
1984
1985        mChunkSamples.push_back(copy);
1986        if (interleaveDurationUs == 0) {
1987            addOneStscTableEntry(++nChunks, 1);
1988            bufferChunk(timestampUs);
1989        } else {
1990            if (chunkTimestampUs == 0) {
1991                chunkTimestampUs = timestampUs;
1992            } else {
1993                if (timestampUs - chunkTimestampUs > interleaveDurationUs) {
1994                    ++nChunks;
1995                    if (nChunks == 1 ||  // First chunk
1996                        (--(mStscTableEntries.end()))->samplesPerChunk !=
1997                         mChunkSamples.size()) {
1998                        addOneStscTableEntry(nChunks, mChunkSamples.size());
1999                    }
2000                    bufferChunk(timestampUs);
2001                    chunkTimestampUs = timestampUs;
2002                }
2003            }
2004        }
2005
2006    }
2007
2008    if (mSampleSizes.empty() ||                      // no samples written
2009        (!mIsAudio && mNumStssTableEntries == 0) ||  // no sync frames for video
2010        (OK != checkCodecSpecificData())) {          // no codec specific data
2011        err = ERROR_MALFORMED;
2012    }
2013    mOwner->trackProgressStatus(this, -1, err);
2014
2015    // Last chunk
2016    if (mOwner->numTracks() == 1) {
2017        addOneStscTableEntry(1, mNumSamples);
2018    } else if (!mChunkSamples.empty()) {
2019        addOneStscTableEntry(++nChunks, mChunkSamples.size());
2020        bufferChunk(timestampUs);
2021    }
2022
2023    // We don't really know how long the last frame lasts, since
2024    // there is no frame time after it, just repeat the previous
2025    // frame's duration.
2026    if (mNumSamples == 1) {
2027        lastDurationUs = 0;  // A single sample's duration
2028    } else {
2029        ++sampleCount;  // Count for the last sample
2030    }
2031    addOneSttsTableEntry(sampleCount, lastDurationUs);
2032    mTrackDurationUs += lastDurationUs;
2033    mReachedEOS = true;
2034    LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s",
2035            count, nZeroLengthFrames, mNumSamples, mIsAudio? "audio": "video");
2036    if (mIsAudio) {
2037        LOGI("Audio track drift time: %lld us", mOwner->getDriftTimeUs());
2038    }
2039
2040    if (err == ERROR_END_OF_STREAM) {
2041        return OK;
2042    }
2043    return err;
2044}
2045
2046void MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) {
2047    LOGV("trackProgressStatus: %lld us", timeUs);
2048    if (mTrackEveryTimeDurationUs > 0 &&
2049        timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) {
2050        LOGV("Fire time tracking progress status at %lld us", timeUs);
2051        mOwner->trackProgressStatus(this, timeUs - mPreviousTrackTimeUs, err);
2052        mPreviousTrackTimeUs = timeUs;
2053    }
2054}
2055
2056void MPEG4Writer::trackProgressStatus(
2057        const MPEG4Writer::Track* track, int64_t timeUs, status_t err) {
2058    Mutex::Autolock lock(mLock);
2059    int32_t nTracks = mTracks.size();
2060    CHECK(nTracks >= 1);
2061    CHECK(nTracks < 64);  // Arbitrary number
2062
2063    int32_t trackNum = 0;
2064    CHECK(trackNum < nTracks);
2065    trackNum <<= 16;
2066
2067    // Error notification
2068    // Do not consider ERROR_END_OF_STREAM an error
2069    if (err != OK && err != ERROR_END_OF_STREAM) {
2070        notify(MEDIA_RECORDER_EVENT_ERROR,
2071               trackNum | MEDIA_RECORDER_ERROR_UNKNOWN,
2072               err);
2073        return;
2074    }
2075
2076    if (timeUs == -1) {
2077        // Send completion notification
2078        notify(MEDIA_RECORDER_EVENT_INFO,
2079               trackNum | MEDIA_RECORDER_INFO_COMPLETION_STATUS,
2080               err);
2081        return;
2082    } else {
2083        // Send progress status
2084        notify(MEDIA_RECORDER_EVENT_INFO,
2085               trackNum | MEDIA_RECORDER_INFO_PROGRESS_TIME_STATUS,
2086               timeUs / 1000);
2087    }
2088}
2089
2090void MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) {
2091    LOGV("setDriftTimeUs: %lld us", driftTimeUs);
2092    Mutex::Autolock autolock(mLock);
2093    mDriftTimeUs = driftTimeUs;
2094}
2095
2096int64_t MPEG4Writer::getDriftTimeUs() {
2097    LOGV("getDriftTimeUs: %lld us", mDriftTimeUs);
2098    Mutex::Autolock autolock(mLock);
2099    return mDriftTimeUs;
2100}
2101
2102bool MPEG4Writer::useNalLengthFour() {
2103    return mUse4ByteNalLength;
2104}
2105
2106void MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
2107    LOGV("bufferChunk");
2108
2109    Chunk chunk(this, timestampUs, mChunkSamples);
2110    mOwner->bufferChunk(chunk);
2111    mChunkSamples.clear();
2112}
2113
2114int64_t MPEG4Writer::Track::getDurationUs() const {
2115    return mTrackDurationUs;
2116}
2117
2118int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
2119    return mEstimatedTrackSizeBytes;
2120}
2121
2122status_t MPEG4Writer::Track::checkCodecSpecificData() const {
2123    const char *mime;
2124    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
2125    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) ||
2126        !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
2127        !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2128        if (!mCodecSpecificData ||
2129            mCodecSpecificDataSize <= 0) {
2130            LOGE("Missing codec specific data");
2131            return ERROR_MALFORMED;
2132        }
2133    } else {
2134        if (mCodecSpecificData ||
2135            mCodecSpecificDataSize > 0) {
2136            LOGE("Unexepected codec specific data found");
2137            return ERROR_MALFORMED;
2138        }
2139    }
2140    return OK;
2141}
2142
2143void MPEG4Writer::Track::writeTrackHeader(
2144        int32_t trackID, bool use32BitOffset) {
2145    const char *mime;
2146    bool success = mMeta->findCString(kKeyMIMEType, &mime);
2147    CHECK(success);
2148
2149    LOGV("%s track time scale: %d",
2150        mIsAudio? "Audio": "Video", mTimeScale);
2151
2152    time_t now = time(NULL);
2153    int32_t mvhdTimeScale = mOwner->getTimeScale();
2154    int64_t trakDurationUs = getDurationUs();
2155
2156    mOwner->beginBox("trak");
2157
2158      mOwner->beginBox("tkhd");
2159        // Flags = 7 to indicate that the track is enabled, and
2160        // part of the presentation
2161        mOwner->writeInt32(0x07);          // version=0, flags=7
2162        mOwner->writeInt32(now);           // creation time
2163        mOwner->writeInt32(now);           // modification time
2164        mOwner->writeInt32(trackID);
2165        mOwner->writeInt32(0);             // reserved
2166        int32_t tkhdDuration =
2167            (trakDurationUs * mvhdTimeScale + 5E5) / 1E6;
2168        mOwner->writeInt32(tkhdDuration);  // in mvhd timescale
2169        mOwner->writeInt32(0);             // reserved
2170        mOwner->writeInt32(0);             // reserved
2171        mOwner->writeInt16(0);             // layer
2172        mOwner->writeInt16(0);             // alternate group
2173        mOwner->writeInt16(mIsAudio ? 0x100 : 0);  // volume
2174        mOwner->writeInt16(0);             // reserved
2175
2176        mOwner->writeCompositionMatrix(mRotation);       // matrix
2177
2178        if (mIsAudio) {
2179            mOwner->writeInt32(0);
2180            mOwner->writeInt32(0);
2181        } else {
2182            int32_t width, height;
2183            bool success = mMeta->findInt32(kKeyWidth, &width);
2184            success = success && mMeta->findInt32(kKeyHeight, &height);
2185            CHECK(success);
2186
2187            mOwner->writeInt32(width << 16);   // 32-bit fixed-point value
2188            mOwner->writeInt32(height << 16);  // 32-bit fixed-point value
2189        }
2190      mOwner->endBox();  // tkhd
2191
2192      int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
2193      if (mStartTimestampUs != moovStartTimeUs) {
2194        mOwner->beginBox("edts");
2195          mOwner->beginBox("elst");
2196            mOwner->writeInt32(0);           // version=0, flags=0: 32-bit time
2197            mOwner->writeInt32(2);           // never ends with an empty list
2198
2199            // First elst entry: specify the starting time offset
2200            int64_t offsetUs = mStartTimestampUs - moovStartTimeUs;
2201            LOGV("OffsetUs: %lld", offsetUs);
2202            int32_t seg = (offsetUs * mvhdTimeScale + 5E5) / 1E6;
2203            mOwner->writeInt32(seg);         // in mvhd timecale
2204            mOwner->writeInt32(-1);          // starting time offset
2205            mOwner->writeInt32(1 << 16);     // rate = 1.0
2206
2207            // Second elst entry: specify the track duration
2208            seg = (trakDurationUs * mvhdTimeScale + 5E5) / 1E6;
2209            mOwner->writeInt32(seg);         // in mvhd timescale
2210            mOwner->writeInt32(0);
2211            mOwner->writeInt32(1 << 16);
2212          mOwner->endBox();
2213        mOwner->endBox();
2214      }
2215
2216      mOwner->beginBox("mdia");
2217
2218        mOwner->beginBox("mdhd");
2219          mOwner->writeInt32(0);             // version=0, flags=0
2220          mOwner->writeInt32(now);           // creation time
2221          mOwner->writeInt32(now);           // modification time
2222          mOwner->writeInt32(mTimeScale);    // media timescale
2223          int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6;
2224          mOwner->writeInt32(mdhdDuration);  // use media timescale
2225          // Language follows the three letter standard ISO-639-2/T
2226          // 'e', 'n', 'g' for "English", for instance.
2227          // Each character is packed as the difference between its ASCII value and 0x60.
2228          // For "English", these are 00101, 01110, 00111.
2229          // XXX: Where is the padding bit located: 0x15C7?
2230          mOwner->writeInt16(0);             // language code
2231          mOwner->writeInt16(0);             // predefined
2232        mOwner->endBox();
2233
2234        mOwner->beginBox("hdlr");
2235          mOwner->writeInt32(0);             // version=0, flags=0
2236          mOwner->writeInt32(0);             // component type: should be mhlr
2237          mOwner->writeFourcc(mIsAudio ? "soun" : "vide");  // component subtype
2238          mOwner->writeInt32(0);             // reserved
2239          mOwner->writeInt32(0);             // reserved
2240          mOwner->writeInt32(0);             // reserved
2241          // Removing "r" for the name string just makes the string 4 byte aligned
2242          mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle");  // name
2243        mOwner->endBox();
2244
2245        mOwner->beginBox("minf");
2246          if (mIsAudio) {
2247              mOwner->beginBox("smhd");
2248              mOwner->writeInt32(0);           // version=0, flags=0
2249              mOwner->writeInt16(0);           // balance
2250              mOwner->writeInt16(0);           // reserved
2251              mOwner->endBox();
2252          } else {
2253              mOwner->beginBox("vmhd");
2254              mOwner->writeInt32(0x01);        // version=0, flags=1
2255              mOwner->writeInt16(0);           // graphics mode
2256              mOwner->writeInt16(0);           // opcolor
2257              mOwner->writeInt16(0);
2258              mOwner->writeInt16(0);
2259              mOwner->endBox();
2260          }
2261
2262          mOwner->beginBox("dinf");
2263            mOwner->beginBox("dref");
2264              mOwner->writeInt32(0);  // version=0, flags=0
2265              mOwner->writeInt32(1);  // entry count (either url or urn)
2266              // The table index here refers to the sample description index
2267              // in the sample table entries.
2268              mOwner->beginBox("url ");
2269                mOwner->writeInt32(1);  // version=0, flags=1 (self-contained)
2270              mOwner->endBox();  // url
2271            mOwner->endBox();  // dref
2272          mOwner->endBox();  // dinf
2273
2274        mOwner->beginBox("stbl");
2275
2276          mOwner->beginBox("stsd");
2277            mOwner->writeInt32(0);               // version=0, flags=0
2278            mOwner->writeInt32(1);               // entry count
2279            if (mIsAudio) {
2280                const char *fourcc = NULL;
2281                if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
2282                    fourcc = "samr";
2283                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2284                    fourcc = "sawb";
2285                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2286                    fourcc = "mp4a";
2287                } else {
2288                    LOGE("Unknown mime type '%s'.", mime);
2289                    CHECK(!"should not be here, unknown mime type.");
2290                }
2291
2292                mOwner->beginBox(fourcc);          // audio format
2293                  mOwner->writeInt32(0);           // reserved
2294                  mOwner->writeInt16(0);           // reserved
2295                  mOwner->writeInt16(0x1);         // data ref index
2296                  mOwner->writeInt32(0);           // reserved
2297                  mOwner->writeInt32(0);           // reserved
2298                  int32_t nChannels;
2299                  CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels));
2300                  mOwner->writeInt16(nChannels);   // channel count
2301                  mOwner->writeInt16(16);          // sample size
2302                  mOwner->writeInt16(0);           // predefined
2303                  mOwner->writeInt16(0);           // reserved
2304
2305                  int32_t samplerate;
2306                  bool success = mMeta->findInt32(kKeySampleRate, &samplerate);
2307                  CHECK(success);
2308                  mOwner->writeInt32(samplerate << 16);
2309                  if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2310                    mOwner->beginBox("esds");
2311                        CHECK(mCodecSpecificData);
2312                        CHECK(mCodecSpecificDataSize > 0);
2313
2314                        // Make sure all sizes encode to a single byte.
2315                        CHECK(mCodecSpecificDataSize + 23 < 128);
2316
2317                        mOwner->writeInt32(0);     // version=0, flags=0
2318                        mOwner->writeInt8(0x03);   // ES_DescrTag
2319                        mOwner->writeInt8(23 + mCodecSpecificDataSize);
2320                        mOwner->writeInt16(0x0000);// ES_ID
2321                        mOwner->writeInt8(0x00);
2322
2323                        mOwner->writeInt8(0x04);   // DecoderConfigDescrTag
2324                        mOwner->writeInt8(15 + mCodecSpecificDataSize);
2325                        mOwner->writeInt8(0x40);   // objectTypeIndication ISO/IEC 14492-2
2326                        mOwner->writeInt8(0x15);   // streamType AudioStream
2327
2328                        mOwner->writeInt16(0x03);  // XXX
2329                        mOwner->writeInt8(0x00);   // buffer size 24-bit
2330                        mOwner->writeInt32(96000); // max bit rate
2331                        mOwner->writeInt32(96000); // avg bit rate
2332
2333                        mOwner->writeInt8(0x05);   // DecoderSpecificInfoTag
2334                        mOwner->writeInt8(mCodecSpecificDataSize);
2335                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2336
2337                        static const uint8_t kData2[] = {
2338                            0x06,  // SLConfigDescriptorTag
2339                            0x01,
2340                            0x02
2341                        };
2342                        mOwner->write(kData2, sizeof(kData2));
2343
2344                    mOwner->endBox();  // esds
2345                  } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) ||
2346                             !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2347                    // 3gpp2 Spec AMRSampleEntry fields
2348                    mOwner->beginBox("damr");
2349                      mOwner->writeCString("   ");  // vendor: 4 bytes
2350                      mOwner->writeInt8(0);         // decoder version
2351                      mOwner->writeInt16(0x83FF);   // mode set: all enabled
2352                      mOwner->writeInt8(0);         // mode change period
2353                      mOwner->writeInt8(1);         // frames per sample
2354                    mOwner->endBox();
2355                  }
2356                mOwner->endBox();
2357            } else {
2358                if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2359                    mOwner->beginBox("mp4v");
2360                } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2361                    mOwner->beginBox("s263");
2362                } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2363                    mOwner->beginBox("avc1");
2364                } else {
2365                    LOGE("Unknown mime type '%s'.", mime);
2366                    CHECK(!"should not be here, unknown mime type.");
2367                }
2368
2369                  mOwner->writeInt32(0);           // reserved
2370                  mOwner->writeInt16(0);           // reserved
2371                  mOwner->writeInt16(1);           // data ref index
2372                  mOwner->writeInt16(0);           // predefined
2373                  mOwner->writeInt16(0);           // reserved
2374                  mOwner->writeInt32(0);           // predefined
2375                  mOwner->writeInt32(0);           // predefined
2376                  mOwner->writeInt32(0);           // predefined
2377
2378                  int32_t width, height;
2379                  bool success = mMeta->findInt32(kKeyWidth, &width);
2380                  success = success && mMeta->findInt32(kKeyHeight, &height);
2381                  CHECK(success);
2382
2383                  mOwner->writeInt16(width);
2384                  mOwner->writeInt16(height);
2385                  mOwner->writeInt32(0x480000);    // horiz resolution
2386                  mOwner->writeInt32(0x480000);    // vert resolution
2387                  mOwner->writeInt32(0);           // reserved
2388                  mOwner->writeInt16(1);           // frame count
2389                  mOwner->write("                                ", 32);
2390                  mOwner->writeInt16(0x18);        // depth
2391                  mOwner->writeInt16(-1);          // predefined
2392
2393                  CHECK(23 + mCodecSpecificDataSize < 128);
2394
2395                  if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2396                      CHECK(mCodecSpecificData);
2397                      CHECK(mCodecSpecificDataSize > 0);
2398                      mOwner->beginBox("esds");
2399
2400                        mOwner->writeInt32(0);           // version=0, flags=0
2401
2402                        mOwner->writeInt8(0x03);  // ES_DescrTag
2403                        mOwner->writeInt8(23 + mCodecSpecificDataSize);
2404                        mOwner->writeInt16(0x0000);  // ES_ID
2405                        mOwner->writeInt8(0x1f);
2406
2407                        mOwner->writeInt8(0x04);  // DecoderConfigDescrTag
2408                        mOwner->writeInt8(15 + mCodecSpecificDataSize);
2409                        mOwner->writeInt8(0x20);  // objectTypeIndication ISO/IEC 14492-2
2410                        mOwner->writeInt8(0x11);  // streamType VisualStream
2411
2412                        static const uint8_t kData[] = {
2413                            0x01, 0x77, 0x00,
2414                            0x00, 0x03, 0xe8, 0x00,
2415                            0x00, 0x03, 0xe8, 0x00
2416                        };
2417                        mOwner->write(kData, sizeof(kData));
2418
2419                        mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
2420
2421                        mOwner->writeInt8(mCodecSpecificDataSize);
2422                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2423
2424                        static const uint8_t kData2[] = {
2425                            0x06,  // SLConfigDescriptorTag
2426                            0x01,
2427                            0x02
2428                        };
2429                        mOwner->write(kData2, sizeof(kData2));
2430
2431                      mOwner->endBox();  // esds
2432                  } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2433                      mOwner->beginBox("d263");
2434
2435                          mOwner->writeInt32(0);  // vendor
2436                          mOwner->writeInt8(0);   // decoder version
2437                          mOwner->writeInt8(10);  // level: 10
2438                          mOwner->writeInt8(0);   // profile: 0
2439
2440                      mOwner->endBox();  // d263
2441                  } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2442                      CHECK(mCodecSpecificData);
2443                      CHECK(mCodecSpecificDataSize >= 5);
2444
2445                      // Patch avcc's lengthSize field to match the number
2446                      // of bytes we use to indicate the size of a nal unit.
2447                      uint8_t *ptr = (uint8_t *)mCodecSpecificData;
2448                      ptr[4] =
2449                          (ptr[4] & 0xfc)
2450                            | (mOwner->useNalLengthFour() ? 3 : 1);
2451
2452                      mOwner->beginBox("avcC");
2453                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2454                      mOwner->endBox();  // avcC
2455                  }
2456
2457                  mOwner->beginBox("pasp");
2458                    // This is useful if the pixel is not square
2459                    mOwner->writeInt32(1 << 16);  // hspacing
2460                    mOwner->writeInt32(1 << 16);  // vspacing
2461                  mOwner->endBox();  // pasp
2462                mOwner->endBox();  // mp4v, s263 or avc1
2463            }
2464          mOwner->endBox();  // stsd
2465
2466          mOwner->beginBox("stts");
2467            mOwner->writeInt32(0);  // version=0, flags=0
2468            mOwner->writeInt32(mNumSttsTableEntries);
2469            int64_t prevTimestampUs = 0;
2470            for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
2471                 it != mSttsTableEntries.end(); ++it) {
2472                mOwner->writeInt32(it->sampleCount);
2473
2474                // Make sure that we are calculating the sample duration the exactly
2475                // same way as we made decision on how to create stts entries.
2476                int64_t currTimestampUs = prevTimestampUs + it->sampleDurationUs;
2477                int32_t dur = ((currTimestampUs * mTimeScale + 500000LL) / 1000000LL -
2478                               (prevTimestampUs * mTimeScale + 500000LL) / 1000000LL);
2479                prevTimestampUs += (it->sampleCount * it->sampleDurationUs);
2480
2481                mOwner->writeInt32(dur);
2482            }
2483          mOwner->endBox();  // stts
2484
2485          if (!mIsAudio) {
2486            mOwner->beginBox("stss");
2487              mOwner->writeInt32(0);  // version=0, flags=0
2488              mOwner->writeInt32(mNumStssTableEntries);  // number of sync frames
2489              for (List<int32_t>::iterator it = mStssTableEntries.begin();
2490                   it != mStssTableEntries.end(); ++it) {
2491                  mOwner->writeInt32(*it);
2492              }
2493            mOwner->endBox();  // stss
2494          }
2495
2496          mOwner->beginBox("stsz");
2497            mOwner->writeInt32(0);  // version=0, flags=0
2498            if (mSamplesHaveSameSize) {
2499                List<size_t>::iterator it = mSampleSizes.begin();
2500                mOwner->writeInt32(*it);  // default sample size
2501            } else {
2502                mOwner->writeInt32(0);
2503            }
2504            mOwner->writeInt32(mNumSamples);
2505            if (!mSamplesHaveSameSize) {
2506                for (List<size_t>::iterator it = mSampleSizes.begin();
2507                     it != mSampleSizes.end(); ++it) {
2508                    mOwner->writeInt32(*it);
2509                }
2510            }
2511          mOwner->endBox();  // stsz
2512
2513          mOwner->beginBox("stsc");
2514            mOwner->writeInt32(0);  // version=0, flags=0
2515            mOwner->writeInt32(mNumStscTableEntries);
2516            for (List<StscTableEntry>::iterator it = mStscTableEntries.begin();
2517                 it != mStscTableEntries.end(); ++it) {
2518                mOwner->writeInt32(it->firstChunk);
2519                mOwner->writeInt32(it->samplesPerChunk);
2520                mOwner->writeInt32(it->sampleDescriptionId);
2521            }
2522          mOwner->endBox();  // stsc
2523          mOwner->beginBox(use32BitOffset? "stco": "co64");
2524            mOwner->writeInt32(0);  // version=0, flags=0
2525            mOwner->writeInt32(mNumStcoTableEntries);
2526            for (List<off64_t>::iterator it = mChunkOffsets.begin();
2527                 it != mChunkOffsets.end(); ++it) {
2528                if (use32BitOffset) {
2529                    mOwner->writeInt32(static_cast<int32_t>(*it));
2530                } else {
2531                    mOwner->writeInt64((*it));
2532                }
2533            }
2534          mOwner->endBox();  // stco or co64
2535
2536        mOwner->endBox();  // stbl
2537       mOwner->endBox();  // minf
2538      mOwner->endBox();  // mdia
2539    mOwner->endBox();  // trak
2540}
2541
2542}  // namespace android
2543