MPEG4Writer.cpp revision a472613aec322e25891abf5c77bf3f7e3c244920
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    if (mIsRealTimeRecording && mOwner->numTracks() > 1) {
1285        /*
1286         * This extra delay of accepting incoming audio/video signals
1287         * helps to align a/v start time at the beginning of a recording
1288         * session, and it also helps eliminate the "recording" sound for
1289         * camcorder applications.
1290         *
1291         * Ideally, this platform-specific value should be defined
1292         * in media_profiles.xml file
1293         */
1294        startTimeUs += 700000;
1295    }
1296
1297    meta->setInt64(kKeyTime, startTimeUs);
1298
1299    status_t err = mSource->start(meta.get());
1300    if (err != OK) {
1301        mDone = mReachedEOS = true;
1302        return err;
1303    }
1304
1305    pthread_attr_t attr;
1306    pthread_attr_init(&attr);
1307    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1308
1309    mDone = false;
1310    mStarted = true;
1311    mTrackDurationUs = 0;
1312    mReachedEOS = false;
1313    mEstimatedTrackSizeBytes = 0;
1314    mNumStcoTableEntries = 0;
1315    mNumStssTableEntries = 0;
1316    mNumStscTableEntries = 0;
1317    mNumSttsTableEntries = 0;
1318    mMdatSizeBytes = 0;
1319    mIsMediaTimeAdjustmentOn = false;
1320    mPrevMediaTimeAdjustTimestampUs = 0;
1321    mMediaTimeAdjustNumFrames = 0;
1322    mPrevMediaTimeAdjustSample = 0;
1323    mTotalDriftTimeToAdjustUs = 0;
1324    mPrevTotalAccumDriftTimeUs = 0;
1325
1326    pthread_create(&mThread, &attr, ThreadWrapper, this);
1327    pthread_attr_destroy(&attr);
1328
1329    return OK;
1330}
1331
1332status_t MPEG4Writer::Track::pause() {
1333    mPaused = true;
1334    return OK;
1335}
1336
1337status_t MPEG4Writer::Track::stop() {
1338    LOGD("Stopping %s track", mIsAudio? "Audio": "Video");
1339    if (!mStarted) {
1340        LOGE("Stop() called but track is not started");
1341        return ERROR_END_OF_STREAM;
1342    }
1343
1344    if (mDone) {
1345        return OK;
1346    }
1347    mDone = true;
1348
1349    void *dummy;
1350    pthread_join(mThread, &dummy);
1351
1352    status_t err = (status_t) dummy;
1353
1354    LOGD("Stopping %s track source", mIsAudio? "Audio": "Video");
1355    {
1356        status_t status = mSource->stop();
1357        if (err == OK && status != OK && status != ERROR_END_OF_STREAM) {
1358            err = status;
1359        }
1360    }
1361
1362    LOGD("%s track stopped", mIsAudio? "Audio": "Video");
1363    return err;
1364}
1365
1366bool MPEG4Writer::Track::reachedEOS() {
1367    return mReachedEOS;
1368}
1369
1370// static
1371void *MPEG4Writer::Track::ThreadWrapper(void *me) {
1372    Track *track = static_cast<Track *>(me);
1373
1374    status_t err = track->threadEntry();
1375    return (void *) err;
1376}
1377
1378static void getNalUnitType(uint8_t byte, uint8_t* type) {
1379    LOGV("getNalUnitType: %d", byte);
1380
1381    // nal_unit_type: 5-bit unsigned integer
1382    *type = (byte & 0x1F);
1383}
1384
1385static const uint8_t *findNextStartCode(
1386        const uint8_t *data, size_t length) {
1387
1388    LOGV("findNextStartCode: %p %d", data, length);
1389
1390    size_t bytesLeft = length;
1391    while (bytesLeft > 4  &&
1392            memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) {
1393        --bytesLeft;
1394    }
1395    if (bytesLeft <= 4) {
1396        bytesLeft = 0; // Last parameter set
1397    }
1398    return &data[length - bytesLeft];
1399}
1400
1401const uint8_t *MPEG4Writer::Track::parseParamSet(
1402        const uint8_t *data, size_t length, int type, size_t *paramSetLen) {
1403
1404    LOGV("parseParamSet");
1405    CHECK(type == kNalUnitTypeSeqParamSet ||
1406          type == kNalUnitTypePicParamSet);
1407
1408    const uint8_t *nextStartCode = findNextStartCode(data, length);
1409    *paramSetLen = nextStartCode - data;
1410    if (*paramSetLen == 0) {
1411        LOGE("Param set is malformed, since its length is 0");
1412        return NULL;
1413    }
1414
1415    AVCParamSet paramSet(*paramSetLen, data);
1416    if (type == kNalUnitTypeSeqParamSet) {
1417        if (*paramSetLen < 4) {
1418            LOGE("Seq parameter set malformed");
1419            return NULL;
1420        }
1421        if (mSeqParamSets.empty()) {
1422            mProfileIdc = data[1];
1423            mProfileCompatible = data[2];
1424            mLevelIdc = data[3];
1425        } else {
1426            if (mProfileIdc != data[1] ||
1427                mProfileCompatible != data[2] ||
1428                mLevelIdc != data[3]) {
1429                LOGE("Inconsistent profile/level found in seq parameter sets");
1430                return NULL;
1431            }
1432        }
1433        mSeqParamSets.push_back(paramSet);
1434    } else {
1435        mPicParamSets.push_back(paramSet);
1436    }
1437    return nextStartCode;
1438}
1439
1440status_t MPEG4Writer::Track::copyAVCCodecSpecificData(
1441        const uint8_t *data, size_t size) {
1442    LOGV("copyAVCCodecSpecificData");
1443
1444    // 2 bytes for each of the parameter set length field
1445    // plus the 7 bytes for the header
1446    if (size < 4 + 7) {
1447        LOGE("Codec specific data length too short: %d", size);
1448        return ERROR_MALFORMED;
1449    }
1450
1451    mCodecSpecificDataSize = size;
1452    mCodecSpecificData = malloc(size);
1453    memcpy(mCodecSpecificData, data, size);
1454    return OK;
1455}
1456
1457status_t MPEG4Writer::Track::parseAVCCodecSpecificData(
1458        const uint8_t *data, size_t size) {
1459
1460    LOGV("parseAVCCodecSpecificData");
1461    // Data starts with a start code.
1462    // SPS and PPS are separated with start codes.
1463    // Also, SPS must come before PPS
1464    uint8_t type = kNalUnitTypeSeqParamSet;
1465    bool gotSps = false;
1466    bool gotPps = false;
1467    const uint8_t *tmp = data;
1468    const uint8_t *nextStartCode = data;
1469    size_t bytesLeft = size;
1470    size_t paramSetLen = 0;
1471    mCodecSpecificDataSize = 0;
1472    while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) {
1473        getNalUnitType(*(tmp + 4), &type);
1474        if (type == kNalUnitTypeSeqParamSet) {
1475            if (gotPps) {
1476                LOGE("SPS must come before PPS");
1477                return ERROR_MALFORMED;
1478            }
1479            if (!gotSps) {
1480                gotSps = true;
1481            }
1482            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
1483        } else if (type == kNalUnitTypePicParamSet) {
1484            if (!gotSps) {
1485                LOGE("SPS must come before PPS");
1486                return ERROR_MALFORMED;
1487            }
1488            if (!gotPps) {
1489                gotPps = true;
1490            }
1491            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
1492        } else {
1493            LOGE("Only SPS and PPS Nal units are expected");
1494            return ERROR_MALFORMED;
1495        }
1496
1497        if (nextStartCode == NULL) {
1498            return ERROR_MALFORMED;
1499        }
1500
1501        // Move on to find the next parameter set
1502        bytesLeft -= nextStartCode - tmp;
1503        tmp = nextStartCode;
1504        mCodecSpecificDataSize += (2 + paramSetLen);
1505    }
1506
1507    {
1508        // Check on the number of seq parameter sets
1509        size_t nSeqParamSets = mSeqParamSets.size();
1510        if (nSeqParamSets == 0) {
1511            LOGE("Cound not find sequence parameter set");
1512            return ERROR_MALFORMED;
1513        }
1514
1515        if (nSeqParamSets > 0x1F) {
1516            LOGE("Too many seq parameter sets (%d) found", nSeqParamSets);
1517            return ERROR_MALFORMED;
1518        }
1519    }
1520
1521    {
1522        // Check on the number of pic parameter sets
1523        size_t nPicParamSets = mPicParamSets.size();
1524        if (nPicParamSets == 0) {
1525            LOGE("Cound not find picture parameter set");
1526            return ERROR_MALFORMED;
1527        }
1528        if (nPicParamSets > 0xFF) {
1529            LOGE("Too many pic parameter sets (%d) found", nPicParamSets);
1530            return ERROR_MALFORMED;
1531        }
1532    }
1533
1534    {
1535        // Check on the profiles
1536        // These profiles requires additional parameter set extensions
1537        if (mProfileIdc == 100 || mProfileIdc == 110 ||
1538            mProfileIdc == 122 || mProfileIdc == 144) {
1539            LOGE("Sorry, no support for profile_idc: %d!", mProfileIdc);
1540            return BAD_VALUE;
1541        }
1542    }
1543
1544    return OK;
1545}
1546
1547status_t MPEG4Writer::Track::makeAVCCodecSpecificData(
1548        const uint8_t *data, size_t size) {
1549
1550    if (mCodecSpecificData != NULL) {
1551        LOGE("Already have codec specific data");
1552        return ERROR_MALFORMED;
1553    }
1554
1555    if (size < 4) {
1556        LOGE("Codec specific data length too short: %d", size);
1557        return ERROR_MALFORMED;
1558    }
1559
1560    // Data is in the form of AVCCodecSpecificData
1561    if (memcmp("\x00\x00\x00\x01", data, 4)) {
1562        return copyAVCCodecSpecificData(data, size);
1563    }
1564
1565    if (parseAVCCodecSpecificData(data, size) != OK) {
1566        return ERROR_MALFORMED;
1567    }
1568
1569    // ISO 14496-15: AVC file format
1570    mCodecSpecificDataSize += 7;  // 7 more bytes in the header
1571    mCodecSpecificData = malloc(mCodecSpecificDataSize);
1572    uint8_t *header = (uint8_t *)mCodecSpecificData;
1573    header[0] = 1;                     // version
1574    header[1] = mProfileIdc;           // profile indication
1575    header[2] = mProfileCompatible;    // profile compatibility
1576    header[3] = mLevelIdc;
1577
1578    // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne
1579    if (mOwner->useNalLengthFour()) {
1580        header[4] = 0xfc | 3;  // length size == 4 bytes
1581    } else {
1582        header[4] = 0xfc | 1;  // length size == 2 bytes
1583    }
1584
1585    // 3-bit '111' followed by 5-bit numSequenceParameterSets
1586    int nSequenceParamSets = mSeqParamSets.size();
1587    header[5] = 0xe0 | nSequenceParamSets;
1588    header += 6;
1589    for (List<AVCParamSet>::iterator it = mSeqParamSets.begin();
1590         it != mSeqParamSets.end(); ++it) {
1591        // 16-bit sequence parameter set length
1592        uint16_t seqParamSetLength = it->mLength;
1593        header[0] = seqParamSetLength >> 8;
1594        header[1] = seqParamSetLength & 0xff;
1595
1596        // SPS NAL unit (sequence parameter length bytes)
1597        memcpy(&header[2], it->mData, seqParamSetLength);
1598        header += (2 + seqParamSetLength);
1599    }
1600
1601    // 8-bit nPictureParameterSets
1602    int nPictureParamSets = mPicParamSets.size();
1603    header[0] = nPictureParamSets;
1604    header += 1;
1605    for (List<AVCParamSet>::iterator it = mPicParamSets.begin();
1606         it != mPicParamSets.end(); ++it) {
1607        // 16-bit picture parameter set length
1608        uint16_t picParamSetLength = it->mLength;
1609        header[0] = picParamSetLength >> 8;
1610        header[1] = picParamSetLength & 0xff;
1611
1612        // PPS Nal unit (picture parameter set length bytes)
1613        memcpy(&header[2], it->mData, picParamSetLength);
1614        header += (2 + picParamSetLength);
1615    }
1616
1617    return OK;
1618}
1619
1620/*
1621* The video track's media time adjustment for real-time applications
1622* is described as follows:
1623*
1624* First, the media time adjustment is done for every period of
1625* kVideoMediaTimeAdjustPeriodTimeUs. kVideoMediaTimeAdjustPeriodTimeUs
1626* is currently a fixed value chosen heuristically. The value of
1627* kVideoMediaTimeAdjustPeriodTimeUs should not be very large or very small
1628* for two considerations: on one hand, a relatively large value
1629* helps reduce large fluctuation of drift time in the audio encoding
1630* path; while on the other hand, a relatively small value helps keep
1631* restoring synchronization in audio/video more frequently. Note for the
1632* very first period of kVideoMediaTimeAdjustPeriodTimeUs, there is
1633* no media time adjustment for the video track.
1634*
1635* Second, the total accumulated audio track time drift found
1636* in a period of kVideoMediaTimeAdjustPeriodTimeUs is distributed
1637* over a stream of incoming video frames. The number of video frames
1638* affected is determined based on the number of recorded video frames
1639* within the past kVideoMediaTimeAdjustPeriodTimeUs period.
1640* We choose to distribute the drift time over only a portion
1641* (rather than all) of the total number of recorded video frames
1642* in order to make sure that the video track media time adjustment is
1643* completed for the current period before the next video track media
1644* time adjustment period starts. Currently, the portion chosen is a
1645* half (0.5).
1646*
1647* Last, various additional checks are performed to ensure that
1648* the actual audio encoding path does not have too much drift.
1649* In particular, 1) we want to limit the average incremental time
1650* adjustment for each video frame to be less than a threshold
1651* for a single period of kVideoMediaTimeAdjustPeriodTimeUs.
1652* Currently, the threshold is set to 5 ms. If the average incremental
1653* media time adjustment for a video frame is larger than the
1654* threshold, the audio encoding path has too much time drift.
1655* 2) We also want to limit the total time drift in the audio
1656* encoding path to be less than a threshold for a period of
1657* kVideoMediaTimeAdjustPeriodTimeUs. Currently, the threshold
1658* is 0.5% of kVideoMediaTimeAdjustPeriodTimeUs. If the time drift of
1659* the audio encoding path is larger than the threshold, the audio
1660* encoding path has too much time drift. We treat the large time
1661* drift of the audio encoding path as errors, since there is no
1662* way to keep audio/video in synchronization for real-time
1663* applications if the time drift is too large unless we drop some
1664* video frames, which has its own problems that we don't want
1665* to get into for the time being.
1666*/
1667void MPEG4Writer::Track::adjustMediaTime(int64_t *timestampUs) {
1668    if (*timestampUs - mPrevMediaTimeAdjustTimestampUs >=
1669        kVideoMediaTimeAdjustPeriodTimeUs) {
1670
1671        LOGV("New media time adjustment period at %lld us", *timestampUs);
1672        mIsMediaTimeAdjustmentOn = true;
1673        mMediaTimeAdjustNumFrames =
1674                (mNumSamples - mPrevMediaTimeAdjustSample) >> 1;
1675
1676        mPrevMediaTimeAdjustTimestampUs = *timestampUs;
1677        mPrevMediaTimeAdjustSample = mNumSamples;
1678        int64_t totalAccumDriftTimeUs = mOwner->getDriftTimeUs();
1679        mTotalDriftTimeToAdjustUs =
1680                totalAccumDriftTimeUs - mPrevTotalAccumDriftTimeUs;
1681
1682        mPrevTotalAccumDriftTimeUs = totalAccumDriftTimeUs;
1683
1684        // Check on incremental adjusted time per frame
1685        int64_t adjustTimePerFrameUs =
1686                mTotalDriftTimeToAdjustUs / mMediaTimeAdjustNumFrames;
1687
1688        if (adjustTimePerFrameUs < 0) {
1689            adjustTimePerFrameUs = -adjustTimePerFrameUs;
1690        }
1691        if (adjustTimePerFrameUs >= 5000) {
1692            LOGE("Adjusted time per video frame is %lld us",
1693                adjustTimePerFrameUs);
1694            CHECK(!"Video frame time adjustment is too large!");
1695        }
1696
1697        // Check on total accumulated time drift within a period of
1698        // kVideoMediaTimeAdjustPeriodTimeUs.
1699        int64_t driftPercentage = (mTotalDriftTimeToAdjustUs * 1000)
1700                / kVideoMediaTimeAdjustPeriodTimeUs;
1701
1702        if (driftPercentage < 0) {
1703            driftPercentage = -driftPercentage;
1704        }
1705        if (driftPercentage > 5) {
1706            LOGE("Audio track has time drift %lld us over %lld us",
1707                mTotalDriftTimeToAdjustUs,
1708                kVideoMediaTimeAdjustPeriodTimeUs);
1709
1710            CHECK(!"The audio track media time drifts too much!");
1711        }
1712
1713    }
1714
1715    if (mIsMediaTimeAdjustmentOn) {
1716        if (mNumSamples - mPrevMediaTimeAdjustSample <=
1717            mMediaTimeAdjustNumFrames) {
1718
1719            // Do media time incremental adjustment
1720            int64_t incrementalAdjustTimeUs =
1721                        (mTotalDriftTimeToAdjustUs *
1722                            (mNumSamples - mPrevMediaTimeAdjustSample))
1723                                / mMediaTimeAdjustNumFrames;
1724
1725            *timestampUs +=
1726                (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs);
1727
1728            LOGV("Incremental video frame media time adjustment: %lld us",
1729                (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs));
1730        } else {
1731            // Within the remaining adjustment period,
1732            // no incremental adjustment is needed.
1733            *timestampUs +=
1734                (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs);
1735
1736            LOGV("Fixed video frame media time adjustment: %lld us",
1737                (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs));
1738        }
1739    }
1740}
1741
1742/*
1743 * Updates the drift time from the audio track so that
1744 * the video track can get the updated drift time information
1745 * from the file writer. The fluctuation of the drift time of the audio
1746 * encoding path is smoothed out with a simple filter by giving a larger
1747 * weight to more recently drift time. The filter coefficients, 0.5 and 0.5,
1748 * are heuristically determined.
1749 */
1750void MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) {
1751    int64_t driftTimeUs = 0;
1752    if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) {
1753        int64_t prevDriftTimeUs = mOwner->getDriftTimeUs();
1754        int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1;
1755        mOwner->setDriftTimeUs(timeUs);
1756    }
1757}
1758
1759status_t MPEG4Writer::Track::threadEntry() {
1760    int32_t count = 0;
1761    const int64_t interleaveDurationUs = mOwner->interleaveDuration();
1762    int64_t chunkTimestampUs = 0;
1763    int32_t nChunks = 0;
1764    int32_t nZeroLengthFrames = 0;
1765    int64_t lastTimestampUs = 0;  // Previous sample time stamp in ms
1766    int64_t lastDurationUs = 0;   // Between the previous two samples in ms
1767    int64_t currDurationTicks = 0;  // Timescale based ticks
1768    int64_t lastDurationTicks = 0;  // Timescale based ticks
1769    int32_t sampleCount = 1;      // Sample count in the current stts table entry
1770    uint32_t previousSampleSize = 0;  // Size of the previous sample
1771    int64_t previousPausedDurationUs = 0;
1772    int64_t timestampUs;
1773
1774    if (mIsAudio) {
1775        prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
1776    } else {
1777        prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0);
1778    }
1779    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
1780
1781    sp<MetaData> meta_data;
1782
1783    mNumSamples = 0;
1784    status_t err = OK;
1785    MediaBuffer *buffer;
1786    while (!mDone && (err = mSource->read(&buffer)) == OK) {
1787        if (buffer->range_length() == 0) {
1788            buffer->release();
1789            buffer = NULL;
1790            ++nZeroLengthFrames;
1791            continue;
1792        }
1793
1794        // If the codec specific data has not been received yet, delay pause.
1795        // After the codec specific data is received, discard what we received
1796        // when the track is to be paused.
1797        if (mPaused && !mResumed) {
1798            buffer->release();
1799            buffer = NULL;
1800            continue;
1801        }
1802
1803        ++count;
1804
1805        int32_t isCodecConfig;
1806        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
1807                && isCodecConfig) {
1808            CHECK(!mGotAllCodecSpecificData);
1809
1810            if (mIsAvc) {
1811                status_t err = makeAVCCodecSpecificData(
1812                        (const uint8_t *)buffer->data()
1813                            + buffer->range_offset(),
1814                        buffer->range_length());
1815                CHECK_EQ(OK, err);
1816            } else if (mIsMPEG4) {
1817                mCodecSpecificDataSize = buffer->range_length();
1818                mCodecSpecificData = malloc(mCodecSpecificDataSize);
1819                memcpy(mCodecSpecificData,
1820                        (const uint8_t *)buffer->data()
1821                            + buffer->range_offset(),
1822                       buffer->range_length());
1823            }
1824
1825            buffer->release();
1826            buffer = NULL;
1827
1828            mGotAllCodecSpecificData = true;
1829            continue;
1830        }
1831
1832        // Make a deep copy of the MediaBuffer and Metadata and release
1833        // the original as soon as we can
1834        MediaBuffer *copy = new MediaBuffer(buffer->range_length());
1835        memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(),
1836                buffer->range_length());
1837        copy->set_range(0, buffer->range_length());
1838        meta_data = new MetaData(*buffer->meta_data().get());
1839        buffer->release();
1840        buffer = NULL;
1841
1842        if (mIsAvc) StripStartcode(copy);
1843
1844        size_t sampleSize = copy->range_length();
1845        if (mIsAvc) {
1846            if (mOwner->useNalLengthFour()) {
1847                sampleSize += 4;
1848            } else {
1849                sampleSize += 2;
1850            }
1851        }
1852
1853        // Max file size or duration handling
1854        mMdatSizeBytes += sampleSize;
1855        updateTrackSizeEstimate();
1856
1857        if (mOwner->exceedsFileSizeLimit()) {
1858            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
1859            break;
1860        }
1861        if (mOwner->exceedsFileDurationLimit()) {
1862            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
1863            break;
1864        }
1865
1866
1867        int32_t isSync = false;
1868        meta_data->findInt32(kKeyIsSyncFrame, &isSync);
1869
1870        /*
1871         * The original timestamp found in the data buffer will be modified as below:
1872         *
1873         * There is a playback offset into this track if the track's start time
1874         * is not the same as the movie start time, which will be recorded in edst
1875         * box of the output file. The playback offset is to make sure that the
1876         * starting time of the audio/video tracks are synchronized. Although the
1877         * track's media timestamp may be subject to various modifications
1878         * as outlined below, the track's playback offset time remains unchanged
1879         * once the first data buffer of the track is received.
1880         *
1881         * The media time stamp will be calculated by subtracting the playback offset
1882         * (and potential pause durations) from the original timestamp in the buffer.
1883         *
1884         * If this track is a video track for a real-time recording application with
1885         * both audio and video tracks, its media timestamp will subject to further
1886         * modification based on the media clock of the audio track. This modification
1887         * is needed for the purpose of maintaining good audio/video synchronization.
1888         *
1889         * If the recording session is paused and resumed multiple times, the track
1890         * media timestamp will be modified as if the  recording session had never been
1891         * paused at all during playback of the recorded output file. In other words,
1892         * the output file will have no memory of pause/resume durations.
1893         *
1894         */
1895        CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
1896        LOGV("%s timestampUs: %lld", mIsAudio? "Audio": "Video", timestampUs);
1897
1898////////////////////////////////////////////////////////////////////////////////
1899        if (mSampleSizes.empty()) {
1900            mStartTimestampUs = timestampUs;
1901            mOwner->setStartTimestampUs(mStartTimestampUs);
1902            previousPausedDurationUs = mStartTimestampUs;
1903        }
1904
1905        if (mResumed) {
1906            int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
1907            CHECK(durExcludingEarlierPausesUs >= 0);
1908            int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
1909            CHECK(pausedDurationUs >= lastDurationUs);
1910            previousPausedDurationUs += pausedDurationUs - lastDurationUs;
1911            mResumed = false;
1912        }
1913
1914        timestampUs -= previousPausedDurationUs;
1915        CHECK(timestampUs >= 0);
1916
1917        // Media time adjustment for real-time applications
1918        if (mIsRealTimeRecording) {
1919            if (mIsAudio) {
1920                updateDriftTime(meta_data);
1921            } else {
1922                adjustMediaTime(&timestampUs);
1923            }
1924        }
1925
1926        CHECK(timestampUs >= 0);
1927        if (mNumSamples > 1) {
1928            if (timestampUs <= lastTimestampUs) {
1929                LOGW("Frame arrives too late!");
1930                // Don't drop the late frame, since dropping a frame may cause
1931                // problems later during playback
1932
1933                // The idea here is to avoid having two or more samples with the
1934                // same timestamp in the output file.
1935                if (mTimeScale >= 1000000LL) {
1936                    timestampUs = lastTimestampUs + 1;
1937                } else {
1938                    timestampUs = lastTimestampUs + (1000000LL + (mTimeScale >> 1)) / mTimeScale;
1939                }
1940            }
1941        }
1942
1943        LOGV("%s media time stamp: %lld and previous paused duration %lld",
1944                mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs);
1945        if (timestampUs > mTrackDurationUs) {
1946            mTrackDurationUs = timestampUs;
1947        }
1948
1949        mSampleSizes.push_back(sampleSize);
1950        ++mNumSamples;
1951        if (mNumSamples > 2) {
1952            // We need to use the time scale based ticks, rather than the
1953            // timestamp itself to determine whether we have to use a new
1954            // stts entry, since we may have rounding errors.
1955            // The calculation is intended to reduce the accumulated
1956            // rounding errors.
1957            currDurationTicks =
1958                     ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
1959                     (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
1960
1961            // Force the first sample to have its own stts entry so that
1962            // we can adjust its value later to maintain the A/V sync.
1963            if (mNumSamples == 3 || currDurationTicks != lastDurationTicks) {
1964                LOGV("%s lastDurationUs: %lld us, currDurationTicks: %lld us",
1965                        mIsAudio? "Audio": "Video", lastDurationUs, currDurationTicks);
1966                addOneSttsTableEntry(sampleCount, lastDurationUs);
1967                sampleCount = 1;
1968            } else {
1969                ++sampleCount;
1970            }
1971        }
1972        if (mSamplesHaveSameSize) {
1973            if (mNumSamples >= 2 && previousSampleSize != sampleSize) {
1974                mSamplesHaveSameSize = false;
1975            }
1976            previousSampleSize = sampleSize;
1977        }
1978        LOGV("%s timestampUs/lastTimestampUs: %lld/%lld",
1979                mIsAudio? "Audio": "Video", timestampUs, lastTimestampUs);
1980        lastDurationUs = timestampUs - lastTimestampUs;
1981        lastDurationTicks = currDurationTicks;
1982        lastTimestampUs = timestampUs;
1983
1984        if (isSync != 0) {
1985            addOneStssTableEntry(mNumSamples);
1986        }
1987
1988        if (mTrackingProgressStatus) {
1989            if (mPreviousTrackTimeUs <= 0) {
1990                mPreviousTrackTimeUs = mStartTimestampUs;
1991            }
1992            trackProgressStatus(timestampUs);
1993        }
1994        if (mOwner->numTracks() == 1) {
1995            off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy)
1996                                 : mOwner->addSample_l(copy);
1997            if (mChunkOffsets.empty()) {
1998                addChunkOffset(offset);
1999            }
2000            copy->release();
2001            copy = NULL;
2002            continue;
2003        }
2004
2005        mChunkSamples.push_back(copy);
2006        if (interleaveDurationUs == 0) {
2007            addOneStscTableEntry(++nChunks, 1);
2008            bufferChunk(timestampUs);
2009        } else {
2010            if (chunkTimestampUs == 0) {
2011                chunkTimestampUs = timestampUs;
2012            } else {
2013                if (timestampUs - chunkTimestampUs > interleaveDurationUs) {
2014                    ++nChunks;
2015                    if (nChunks == 1 ||  // First chunk
2016                        (--(mStscTableEntries.end()))->samplesPerChunk !=
2017                         mChunkSamples.size()) {
2018                        addOneStscTableEntry(nChunks, mChunkSamples.size());
2019                    }
2020                    bufferChunk(timestampUs);
2021                    chunkTimestampUs = timestampUs;
2022                }
2023            }
2024        }
2025
2026    }
2027
2028    if (mSampleSizes.empty() ||                      // no samples written
2029        (!mIsAudio && mNumStssTableEntries == 0) ||  // no sync frames for video
2030        (OK != checkCodecSpecificData())) {          // no codec specific data
2031        err = ERROR_MALFORMED;
2032    }
2033    mOwner->trackProgressStatus(this, -1, err);
2034
2035    // Last chunk
2036    if (mOwner->numTracks() == 1) {
2037        addOneStscTableEntry(1, mNumSamples);
2038    } else if (!mChunkSamples.empty()) {
2039        addOneStscTableEntry(++nChunks, mChunkSamples.size());
2040        bufferChunk(timestampUs);
2041    }
2042
2043    // We don't really know how long the last frame lasts, since
2044    // there is no frame time after it, just repeat the previous
2045    // frame's duration.
2046    if (mNumSamples == 1) {
2047        lastDurationUs = 0;  // A single sample's duration
2048    } else {
2049        ++sampleCount;  // Count for the last sample
2050    }
2051
2052    if (mNumSamples <= 2) {
2053        addOneSttsTableEntry(1, lastDurationUs);
2054        if (sampleCount - 1 > 0) {
2055            addOneSttsTableEntry(sampleCount - 1, lastDurationUs);
2056        }
2057    } else {
2058        addOneSttsTableEntry(sampleCount, lastDurationUs);
2059    }
2060
2061    mTrackDurationUs += lastDurationUs;
2062    mReachedEOS = true;
2063    LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s",
2064            count, nZeroLengthFrames, mNumSamples, mIsAudio? "audio": "video");
2065    if (mIsAudio) {
2066        LOGI("Audio track drift time: %lld us", mOwner->getDriftTimeUs());
2067    }
2068
2069    if (err == ERROR_END_OF_STREAM) {
2070        return OK;
2071    }
2072    return err;
2073}
2074
2075void MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) {
2076    LOGV("trackProgressStatus: %lld us", timeUs);
2077    if (mTrackEveryTimeDurationUs > 0 &&
2078        timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) {
2079        LOGV("Fire time tracking progress status at %lld us", timeUs);
2080        mOwner->trackProgressStatus(this, timeUs - mPreviousTrackTimeUs, err);
2081        mPreviousTrackTimeUs = timeUs;
2082    }
2083}
2084
2085void MPEG4Writer::trackProgressStatus(
2086        const MPEG4Writer::Track* track, int64_t timeUs, status_t err) {
2087    Mutex::Autolock lock(mLock);
2088    int32_t nTracks = mTracks.size();
2089    CHECK(nTracks >= 1);
2090    CHECK(nTracks < 64);  // Arbitrary number
2091
2092    int32_t trackNum = 0;
2093    CHECK(trackNum < nTracks);
2094    trackNum <<= 16;
2095
2096    // Error notification
2097    // Do not consider ERROR_END_OF_STREAM an error
2098    if (err != OK && err != ERROR_END_OF_STREAM) {
2099        notify(MEDIA_RECORDER_EVENT_ERROR,
2100               trackNum | MEDIA_RECORDER_ERROR_UNKNOWN,
2101               err);
2102        return;
2103    }
2104
2105    if (timeUs == -1) {
2106        // Send completion notification
2107        notify(MEDIA_RECORDER_EVENT_INFO,
2108               trackNum | MEDIA_RECORDER_INFO_COMPLETION_STATUS,
2109               err);
2110        return;
2111    } else {
2112        // Send progress status
2113        notify(MEDIA_RECORDER_EVENT_INFO,
2114               trackNum | MEDIA_RECORDER_INFO_PROGRESS_TIME_STATUS,
2115               timeUs / 1000);
2116    }
2117}
2118
2119void MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) {
2120    LOGV("setDriftTimeUs: %lld us", driftTimeUs);
2121    Mutex::Autolock autolock(mLock);
2122    mDriftTimeUs = driftTimeUs;
2123}
2124
2125int64_t MPEG4Writer::getDriftTimeUs() {
2126    LOGV("getDriftTimeUs: %lld us", mDriftTimeUs);
2127    Mutex::Autolock autolock(mLock);
2128    return mDriftTimeUs;
2129}
2130
2131bool MPEG4Writer::useNalLengthFour() {
2132    return mUse4ByteNalLength;
2133}
2134
2135void MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
2136    LOGV("bufferChunk");
2137
2138    Chunk chunk(this, timestampUs, mChunkSamples);
2139    mOwner->bufferChunk(chunk);
2140    mChunkSamples.clear();
2141}
2142
2143int64_t MPEG4Writer::Track::getDurationUs() const {
2144    return mTrackDurationUs;
2145}
2146
2147int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
2148    return mEstimatedTrackSizeBytes;
2149}
2150
2151status_t MPEG4Writer::Track::checkCodecSpecificData() const {
2152    const char *mime;
2153    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
2154    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) ||
2155        !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
2156        !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2157        if (!mCodecSpecificData ||
2158            mCodecSpecificDataSize <= 0) {
2159            LOGE("Missing codec specific data");
2160            return ERROR_MALFORMED;
2161        }
2162    } else {
2163        if (mCodecSpecificData ||
2164            mCodecSpecificDataSize > 0) {
2165            LOGE("Unexepected codec specific data found");
2166            return ERROR_MALFORMED;
2167        }
2168    }
2169    return OK;
2170}
2171
2172void MPEG4Writer::Track::writeTrackHeader(
2173        int32_t trackID, bool use32BitOffset) {
2174    const char *mime;
2175    bool success = mMeta->findCString(kKeyMIMEType, &mime);
2176    CHECK(success);
2177
2178    LOGV("%s track time scale: %d",
2179        mIsAudio? "Audio": "Video", mTimeScale);
2180
2181    time_t now = time(NULL);
2182    int32_t mvhdTimeScale = mOwner->getTimeScale();
2183    int64_t trakDurationUs = getDurationUs();
2184
2185    // Compensate for small start time difference from different media tracks
2186    int64_t trackStartTimeOffsetUs = 0;
2187
2188    mOwner->beginBox("trak");
2189
2190      mOwner->beginBox("tkhd");
2191        // Flags = 7 to indicate that the track is enabled, and
2192        // part of the presentation
2193        mOwner->writeInt32(0x07);          // version=0, flags=7
2194        mOwner->writeInt32(now);           // creation time
2195        mOwner->writeInt32(now);           // modification time
2196        mOwner->writeInt32(trackID);
2197        mOwner->writeInt32(0);             // reserved
2198        int32_t tkhdDuration =
2199            (trakDurationUs * mvhdTimeScale + 5E5) / 1E6;
2200        mOwner->writeInt32(tkhdDuration);  // in mvhd timescale
2201        mOwner->writeInt32(0);             // reserved
2202        mOwner->writeInt32(0);             // reserved
2203        mOwner->writeInt16(0);             // layer
2204        mOwner->writeInt16(0);             // alternate group
2205        mOwner->writeInt16(mIsAudio ? 0x100 : 0);  // volume
2206        mOwner->writeInt16(0);             // reserved
2207
2208        mOwner->writeCompositionMatrix(mRotation);       // matrix
2209
2210        if (mIsAudio) {
2211            mOwner->writeInt32(0);
2212            mOwner->writeInt32(0);
2213        } else {
2214            int32_t width, height;
2215            bool success = mMeta->findInt32(kKeyWidth, &width);
2216            success = success && mMeta->findInt32(kKeyHeight, &height);
2217            CHECK(success);
2218
2219            mOwner->writeInt32(width << 16);   // 32-bit fixed-point value
2220            mOwner->writeInt32(height << 16);  // 32-bit fixed-point value
2221        }
2222      mOwner->endBox();  // tkhd
2223
2224      int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
2225      if (mStartTimestampUs != moovStartTimeUs) {
2226          CHECK(mStartTimestampUs > moovStartTimeUs);
2227          trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
2228      }
2229
2230      mOwner->beginBox("mdia");
2231
2232        mOwner->beginBox("mdhd");
2233          mOwner->writeInt32(0);             // version=0, flags=0
2234          mOwner->writeInt32(now);           // creation time
2235          mOwner->writeInt32(now);           // modification time
2236          mOwner->writeInt32(mTimeScale);    // media timescale
2237          int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6;
2238          mOwner->writeInt32(mdhdDuration);  // use media timescale
2239          // Language follows the three letter standard ISO-639-2/T
2240          // 'e', 'n', 'g' for "English", for instance.
2241          // Each character is packed as the difference between its ASCII value and 0x60.
2242          // For "English", these are 00101, 01110, 00111.
2243          // XXX: Where is the padding bit located: 0x15C7?
2244          mOwner->writeInt16(0);             // language code
2245          mOwner->writeInt16(0);             // predefined
2246        mOwner->endBox();
2247
2248        mOwner->beginBox("hdlr");
2249          mOwner->writeInt32(0);             // version=0, flags=0
2250          mOwner->writeInt32(0);             // component type: should be mhlr
2251          mOwner->writeFourcc(mIsAudio ? "soun" : "vide");  // component subtype
2252          mOwner->writeInt32(0);             // reserved
2253          mOwner->writeInt32(0);             // reserved
2254          mOwner->writeInt32(0);             // reserved
2255          // Removing "r" for the name string just makes the string 4 byte aligned
2256          mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle");  // name
2257        mOwner->endBox();
2258
2259        mOwner->beginBox("minf");
2260          if (mIsAudio) {
2261              mOwner->beginBox("smhd");
2262              mOwner->writeInt32(0);           // version=0, flags=0
2263              mOwner->writeInt16(0);           // balance
2264              mOwner->writeInt16(0);           // reserved
2265              mOwner->endBox();
2266          } else {
2267              mOwner->beginBox("vmhd");
2268              mOwner->writeInt32(0x01);        // version=0, flags=1
2269              mOwner->writeInt16(0);           // graphics mode
2270              mOwner->writeInt16(0);           // opcolor
2271              mOwner->writeInt16(0);
2272              mOwner->writeInt16(0);
2273              mOwner->endBox();
2274          }
2275
2276          mOwner->beginBox("dinf");
2277            mOwner->beginBox("dref");
2278              mOwner->writeInt32(0);  // version=0, flags=0
2279              mOwner->writeInt32(1);  // entry count (either url or urn)
2280              // The table index here refers to the sample description index
2281              // in the sample table entries.
2282              mOwner->beginBox("url ");
2283                mOwner->writeInt32(1);  // version=0, flags=1 (self-contained)
2284              mOwner->endBox();  // url
2285            mOwner->endBox();  // dref
2286          mOwner->endBox();  // dinf
2287
2288        mOwner->beginBox("stbl");
2289
2290          mOwner->beginBox("stsd");
2291            mOwner->writeInt32(0);               // version=0, flags=0
2292            mOwner->writeInt32(1);               // entry count
2293            if (mIsAudio) {
2294                const char *fourcc = NULL;
2295                if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
2296                    fourcc = "samr";
2297                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2298                    fourcc = "sawb";
2299                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2300                    fourcc = "mp4a";
2301                } else {
2302                    LOGE("Unknown mime type '%s'.", mime);
2303                    CHECK(!"should not be here, unknown mime type.");
2304                }
2305
2306                mOwner->beginBox(fourcc);          // audio format
2307                  mOwner->writeInt32(0);           // reserved
2308                  mOwner->writeInt16(0);           // reserved
2309                  mOwner->writeInt16(0x1);         // data ref index
2310                  mOwner->writeInt32(0);           // reserved
2311                  mOwner->writeInt32(0);           // reserved
2312                  int32_t nChannels;
2313                  CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels));
2314                  mOwner->writeInt16(nChannels);   // channel count
2315                  mOwner->writeInt16(16);          // sample size
2316                  mOwner->writeInt16(0);           // predefined
2317                  mOwner->writeInt16(0);           // reserved
2318
2319                  int32_t samplerate;
2320                  bool success = mMeta->findInt32(kKeySampleRate, &samplerate);
2321                  CHECK(success);
2322                  mOwner->writeInt32(samplerate << 16);
2323                  if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2324                    mOwner->beginBox("esds");
2325                        CHECK(mCodecSpecificData);
2326                        CHECK(mCodecSpecificDataSize > 0);
2327
2328                        // Make sure all sizes encode to a single byte.
2329                        CHECK(mCodecSpecificDataSize + 23 < 128);
2330
2331                        mOwner->writeInt32(0);     // version=0, flags=0
2332                        mOwner->writeInt8(0x03);   // ES_DescrTag
2333                        mOwner->writeInt8(23 + mCodecSpecificDataSize);
2334                        mOwner->writeInt16(0x0000);// ES_ID
2335                        mOwner->writeInt8(0x00);
2336
2337                        mOwner->writeInt8(0x04);   // DecoderConfigDescrTag
2338                        mOwner->writeInt8(15 + mCodecSpecificDataSize);
2339                        mOwner->writeInt8(0x40);   // objectTypeIndication ISO/IEC 14492-2
2340                        mOwner->writeInt8(0x15);   // streamType AudioStream
2341
2342                        mOwner->writeInt16(0x03);  // XXX
2343                        mOwner->writeInt8(0x00);   // buffer size 24-bit
2344                        mOwner->writeInt32(96000); // max bit rate
2345                        mOwner->writeInt32(96000); // avg bit rate
2346
2347                        mOwner->writeInt8(0x05);   // DecoderSpecificInfoTag
2348                        mOwner->writeInt8(mCodecSpecificDataSize);
2349                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2350
2351                        static const uint8_t kData2[] = {
2352                            0x06,  // SLConfigDescriptorTag
2353                            0x01,
2354                            0x02
2355                        };
2356                        mOwner->write(kData2, sizeof(kData2));
2357
2358                    mOwner->endBox();  // esds
2359                  } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) ||
2360                             !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2361                    // 3gpp2 Spec AMRSampleEntry fields
2362                    mOwner->beginBox("damr");
2363                      mOwner->writeCString("   ");  // vendor: 4 bytes
2364                      mOwner->writeInt8(0);         // decoder version
2365                      mOwner->writeInt16(0x83FF);   // mode set: all enabled
2366                      mOwner->writeInt8(0);         // mode change period
2367                      mOwner->writeInt8(1);         // frames per sample
2368                    mOwner->endBox();
2369                  }
2370                mOwner->endBox();
2371            } else {
2372                if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2373                    mOwner->beginBox("mp4v");
2374                } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2375                    mOwner->beginBox("s263");
2376                } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2377                    mOwner->beginBox("avc1");
2378                } else {
2379                    LOGE("Unknown mime type '%s'.", mime);
2380                    CHECK(!"should not be here, unknown mime type.");
2381                }
2382
2383                  mOwner->writeInt32(0);           // reserved
2384                  mOwner->writeInt16(0);           // reserved
2385                  mOwner->writeInt16(1);           // data ref index
2386                  mOwner->writeInt16(0);           // predefined
2387                  mOwner->writeInt16(0);           // reserved
2388                  mOwner->writeInt32(0);           // predefined
2389                  mOwner->writeInt32(0);           // predefined
2390                  mOwner->writeInt32(0);           // predefined
2391
2392                  int32_t width, height;
2393                  bool success = mMeta->findInt32(kKeyWidth, &width);
2394                  success = success && mMeta->findInt32(kKeyHeight, &height);
2395                  CHECK(success);
2396
2397                  mOwner->writeInt16(width);
2398                  mOwner->writeInt16(height);
2399                  mOwner->writeInt32(0x480000);    // horiz resolution
2400                  mOwner->writeInt32(0x480000);    // vert resolution
2401                  mOwner->writeInt32(0);           // reserved
2402                  mOwner->writeInt16(1);           // frame count
2403                  mOwner->write("                                ", 32);
2404                  mOwner->writeInt16(0x18);        // depth
2405                  mOwner->writeInt16(-1);          // predefined
2406
2407                  CHECK(23 + mCodecSpecificDataSize < 128);
2408
2409                  if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2410                      CHECK(mCodecSpecificData);
2411                      CHECK(mCodecSpecificDataSize > 0);
2412                      mOwner->beginBox("esds");
2413
2414                        mOwner->writeInt32(0);           // version=0, flags=0
2415
2416                        mOwner->writeInt8(0x03);  // ES_DescrTag
2417                        mOwner->writeInt8(23 + mCodecSpecificDataSize);
2418                        mOwner->writeInt16(0x0000);  // ES_ID
2419                        mOwner->writeInt8(0x1f);
2420
2421                        mOwner->writeInt8(0x04);  // DecoderConfigDescrTag
2422                        mOwner->writeInt8(15 + mCodecSpecificDataSize);
2423                        mOwner->writeInt8(0x20);  // objectTypeIndication ISO/IEC 14492-2
2424                        mOwner->writeInt8(0x11);  // streamType VisualStream
2425
2426                        static const uint8_t kData[] = {
2427                            0x01, 0x77, 0x00,
2428                            0x00, 0x03, 0xe8, 0x00,
2429                            0x00, 0x03, 0xe8, 0x00
2430                        };
2431                        mOwner->write(kData, sizeof(kData));
2432
2433                        mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
2434
2435                        mOwner->writeInt8(mCodecSpecificDataSize);
2436                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2437
2438                        static const uint8_t kData2[] = {
2439                            0x06,  // SLConfigDescriptorTag
2440                            0x01,
2441                            0x02
2442                        };
2443                        mOwner->write(kData2, sizeof(kData2));
2444
2445                      mOwner->endBox();  // esds
2446                  } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2447                      mOwner->beginBox("d263");
2448
2449                          mOwner->writeInt32(0);  // vendor
2450                          mOwner->writeInt8(0);   // decoder version
2451                          mOwner->writeInt8(10);  // level: 10
2452                          mOwner->writeInt8(0);   // profile: 0
2453
2454                      mOwner->endBox();  // d263
2455                  } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2456                      CHECK(mCodecSpecificData);
2457                      CHECK(mCodecSpecificDataSize >= 5);
2458
2459                      // Patch avcc's lengthSize field to match the number
2460                      // of bytes we use to indicate the size of a nal unit.
2461                      uint8_t *ptr = (uint8_t *)mCodecSpecificData;
2462                      ptr[4] =
2463                          (ptr[4] & 0xfc)
2464                            | (mOwner->useNalLengthFour() ? 3 : 1);
2465
2466                      mOwner->beginBox("avcC");
2467                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2468                      mOwner->endBox();  // avcC
2469                  }
2470
2471                  mOwner->beginBox("pasp");
2472                    // This is useful if the pixel is not square
2473                    mOwner->writeInt32(1 << 16);  // hspacing
2474                    mOwner->writeInt32(1 << 16);  // vspacing
2475                  mOwner->endBox();  // pasp
2476                mOwner->endBox();  // mp4v, s263 or avc1
2477            }
2478          mOwner->endBox();  // stsd
2479
2480          mOwner->beginBox("stts");
2481            mOwner->writeInt32(0);  // version=0, flags=0
2482            mOwner->writeInt32(mNumSttsTableEntries);
2483            int64_t prevTimestampUs = trackStartTimeOffsetUs;
2484            for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
2485                 it != mSttsTableEntries.end(); ++it) {
2486                mOwner->writeInt32(it->sampleCount);
2487
2488                // Make sure that we are calculating the sample duration the exactly
2489                // same way as we made decision on how to create stts entries.
2490                int64_t currTimestampUs = prevTimestampUs + it->sampleDurationUs;
2491                int32_t dur = ((currTimestampUs * mTimeScale + 500000LL) / 1000000LL -
2492                               (prevTimestampUs * mTimeScale + 500000LL) / 1000000LL);
2493                prevTimestampUs += (it->sampleCount * it->sampleDurationUs);
2494
2495                mOwner->writeInt32(dur);
2496            }
2497          mOwner->endBox();  // stts
2498
2499          if (!mIsAudio) {
2500            mOwner->beginBox("stss");
2501              mOwner->writeInt32(0);  // version=0, flags=0
2502              mOwner->writeInt32(mNumStssTableEntries);  // number of sync frames
2503              for (List<int32_t>::iterator it = mStssTableEntries.begin();
2504                   it != mStssTableEntries.end(); ++it) {
2505                  mOwner->writeInt32(*it);
2506              }
2507            mOwner->endBox();  // stss
2508          }
2509
2510          mOwner->beginBox("stsz");
2511            mOwner->writeInt32(0);  // version=0, flags=0
2512            if (mSamplesHaveSameSize) {
2513                List<size_t>::iterator it = mSampleSizes.begin();
2514                mOwner->writeInt32(*it);  // default sample size
2515            } else {
2516                mOwner->writeInt32(0);
2517            }
2518            mOwner->writeInt32(mNumSamples);
2519            if (!mSamplesHaveSameSize) {
2520                for (List<size_t>::iterator it = mSampleSizes.begin();
2521                     it != mSampleSizes.end(); ++it) {
2522                    mOwner->writeInt32(*it);
2523                }
2524            }
2525          mOwner->endBox();  // stsz
2526
2527          mOwner->beginBox("stsc");
2528            mOwner->writeInt32(0);  // version=0, flags=0
2529            mOwner->writeInt32(mNumStscTableEntries);
2530            for (List<StscTableEntry>::iterator it = mStscTableEntries.begin();
2531                 it != mStscTableEntries.end(); ++it) {
2532                mOwner->writeInt32(it->firstChunk);
2533                mOwner->writeInt32(it->samplesPerChunk);
2534                mOwner->writeInt32(it->sampleDescriptionId);
2535            }
2536          mOwner->endBox();  // stsc
2537          mOwner->beginBox(use32BitOffset? "stco": "co64");
2538            mOwner->writeInt32(0);  // version=0, flags=0
2539            mOwner->writeInt32(mNumStcoTableEntries);
2540            for (List<off64_t>::iterator it = mChunkOffsets.begin();
2541                 it != mChunkOffsets.end(); ++it) {
2542                if (use32BitOffset) {
2543                    mOwner->writeInt32(static_cast<int32_t>(*it));
2544                } else {
2545                    mOwner->writeInt64((*it));
2546                }
2547            }
2548          mOwner->endBox();  // stco or co64
2549
2550        mOwner->endBox();  // stbl
2551       mOwner->endBox();  // minf
2552      mOwner->endBox();  // mdia
2553    mOwner->endBox();  // trak
2554}
2555
2556}  // namespace android
2557