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