MPEG4Writer.cpp revision e76dba7af9589d9ed7b116eec3a74168a8352925
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
20#include <arpa/inet.h>
21#include <fcntl.h>
22#include <inttypes.h>
23#include <pthread.h>
24#include <sys/prctl.h>
25#include <sys/stat.h>
26#include <sys/types.h>
27#include <unistd.h>
28
29#include <utils/Log.h>
30
31#include <media/stagefright/foundation/ADebug.h>
32#include <media/stagefright/foundation/AMessage.h>
33#include <media/stagefright/MPEG4Writer.h>
34#include <media/stagefright/MediaBuffer.h>
35#include <media/stagefright/MetaData.h>
36#include <media/stagefright/MediaDefs.h>
37#include <media/stagefright/MediaErrors.h>
38#include <media/stagefright/MediaSource.h>
39#include <media/stagefright/Utils.h>
40#include <media/mediarecorder.h>
41#include <cutils/properties.h>
42
43#include "include/ESDS.h"
44
45
46#ifndef __predict_false
47#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
48#endif
49
50#define WARN_UNLESS(condition, message, ...) \
51( (__predict_false(condition)) ? false : ({ \
52    ALOGW("Condition %s failed "  message, #condition, ##__VA_ARGS__); \
53    true; \
54}))
55
56namespace android {
57
58static const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024;
59static const int64_t kMax32BitFileSize = 0x00ffffffffLL; // 2^32-1 : max FAT32
60                                                         // filesystem file size
61                                                         // used by most SD cards
62static const uint8_t kNalUnitTypeSeqParamSet = 0x07;
63static const uint8_t kNalUnitTypePicParamSet = 0x08;
64static const int64_t kInitialDelayTimeUs     = 700000LL;
65
66class MPEG4Writer::Track {
67public:
68    Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId);
69
70    ~Track();
71
72    status_t start(MetaData *params);
73    status_t stop();
74    status_t pause();
75    bool reachedEOS();
76
77    int64_t getDurationUs() const;
78    int64_t getEstimatedTrackSizeBytes() const;
79    void writeTrackHeader(bool use32BitOffset = true);
80    void bufferChunk(int64_t timestampUs);
81    bool isAvc() const { return mIsAvc; }
82    bool isAudio() const { return mIsAudio; }
83    bool isMPEG4() const { return mIsMPEG4; }
84    void addChunkOffset(off64_t offset);
85    int32_t getTrackId() const { return mTrackId; }
86    status_t dump(int fd, const Vector<String16>& args) const;
87
88private:
89    enum {
90        kMaxCttsOffsetTimeUs = 1000000LL,  // 1 second
91        kSampleArraySize = 1000,
92    };
93
94    // A helper class to handle faster write box with table entries
95    template<class TYPE>
96    struct ListTableEntries {
97        ListTableEntries(uint32_t elementCapacity, uint32_t entryCapacity)
98            : mElementCapacity(elementCapacity),
99            mEntryCapacity(entryCapacity),
100            mTotalNumTableEntries(0),
101            mNumValuesInCurrEntry(0),
102            mCurrTableEntriesElement(NULL) {
103            CHECK_GT(mElementCapacity, 0);
104            CHECK_GT(mEntryCapacity, 0);
105        }
106
107        // Free the allocated memory.
108        ~ListTableEntries() {
109            while (!mTableEntryList.empty()) {
110                typename List<TYPE *>::iterator it = mTableEntryList.begin();
111                delete[] (*it);
112                mTableEntryList.erase(it);
113            }
114        }
115
116        // Replace the value at the given position by the given value.
117        // There must be an existing value at the given position.
118        // @arg value must be in network byte order
119        // @arg pos location the value must be in.
120        void set(const TYPE& value, uint32_t pos) {
121            CHECK_LT(pos, mTotalNumTableEntries * mEntryCapacity);
122
123            typename List<TYPE *>::iterator it = mTableEntryList.begin();
124            uint32_t iterations = (pos / (mElementCapacity * mEntryCapacity));
125            while (it != mTableEntryList.end() && iterations > 0) {
126                ++it;
127                --iterations;
128            }
129            CHECK(it != mTableEntryList.end());
130            CHECK_EQ(iterations, 0);
131
132            (*it)[(pos % (mElementCapacity * mEntryCapacity))] = value;
133        }
134
135        // Get the value at the given position by the given value.
136        // @arg value the retrieved value at the position in network byte order.
137        // @arg pos location the value must be in.
138        // @return true if a value is found.
139        bool get(TYPE& value, uint32_t pos) const {
140            if (pos >= mTotalNumTableEntries * mEntryCapacity) {
141                return false;
142            }
143
144            typename List<TYPE *>::iterator it = mTableEntryList.begin();
145            uint32_t iterations = (pos / (mElementCapacity * mEntryCapacity));
146            while (it != mTableEntryList.end() && iterations > 0) {
147                ++it;
148                --iterations;
149            }
150            CHECK(it != mTableEntryList.end());
151            CHECK_EQ(iterations, 0);
152
153            value = (*it)[(pos % (mElementCapacity * mEntryCapacity))];
154            return true;
155        }
156
157        // Store a single value.
158        // @arg value must be in network byte order.
159        void add(const TYPE& value) {
160            CHECK_LT(mNumValuesInCurrEntry, mElementCapacity);
161            uint32_t nEntries = mTotalNumTableEntries % mElementCapacity;
162            uint32_t nValues  = mNumValuesInCurrEntry % mEntryCapacity;
163            if (nEntries == 0 && nValues == 0) {
164                mCurrTableEntriesElement = new TYPE[mEntryCapacity * mElementCapacity];
165                CHECK(mCurrTableEntriesElement != NULL);
166                mTableEntryList.push_back(mCurrTableEntriesElement);
167            }
168
169            uint32_t pos = nEntries * mEntryCapacity + nValues;
170            mCurrTableEntriesElement[pos] = value;
171
172            ++mNumValuesInCurrEntry;
173            if ((mNumValuesInCurrEntry % mEntryCapacity) == 0) {
174                ++mTotalNumTableEntries;
175                mNumValuesInCurrEntry = 0;
176            }
177        }
178
179        // Write out the table entries:
180        // 1. the number of entries goes first
181        // 2. followed by the values in the table enties in order
182        // @arg writer the writer to actual write to the storage
183        void write(MPEG4Writer *writer) const {
184            CHECK_EQ(mNumValuesInCurrEntry % mEntryCapacity, 0);
185            uint32_t nEntries = mTotalNumTableEntries;
186            writer->writeInt32(nEntries);
187            for (typename List<TYPE *>::iterator it = mTableEntryList.begin();
188                it != mTableEntryList.end(); ++it) {
189                CHECK_GT(nEntries, 0);
190                if (nEntries >= mElementCapacity) {
191                    writer->write(*it, sizeof(TYPE) * mEntryCapacity, mElementCapacity);
192                    nEntries -= mElementCapacity;
193                } else {
194                    writer->write(*it, sizeof(TYPE) * mEntryCapacity, nEntries);
195                    break;
196                }
197            }
198        }
199
200        // Return the number of entries in the table.
201        uint32_t count() const { return mTotalNumTableEntries; }
202
203    private:
204        uint32_t         mElementCapacity;  // # entries in an element
205        uint32_t         mEntryCapacity;    // # of values in each entry
206        uint32_t         mTotalNumTableEntries;
207        uint32_t         mNumValuesInCurrEntry;  // up to mEntryCapacity
208        TYPE             *mCurrTableEntriesElement;
209        mutable List<TYPE *>     mTableEntryList;
210
211        DISALLOW_EVIL_CONSTRUCTORS(ListTableEntries);
212    };
213
214
215
216    MPEG4Writer *mOwner;
217    sp<MetaData> mMeta;
218    sp<MediaSource> mSource;
219    volatile bool mDone;
220    volatile bool mPaused;
221    volatile bool mResumed;
222    volatile bool mStarted;
223    bool mIsAvc;
224    bool mIsAudio;
225    bool mIsMPEG4;
226    int32_t mTrackId;
227    int64_t mTrackDurationUs;
228    int64_t mMaxChunkDurationUs;
229
230    int64_t mEstimatedTrackSizeBytes;
231    int64_t mMdatSizeBytes;
232    int32_t mTimeScale;
233
234    pthread_t mThread;
235
236
237    List<MediaBuffer *> mChunkSamples;
238
239    bool                mSamplesHaveSameSize;
240    ListTableEntries<uint32_t> *mStszTableEntries;
241
242    ListTableEntries<uint32_t> *mStcoTableEntries;
243    ListTableEntries<off64_t> *mCo64TableEntries;
244    ListTableEntries<uint32_t> *mStscTableEntries;
245    ListTableEntries<uint32_t> *mStssTableEntries;
246    ListTableEntries<uint32_t> *mSttsTableEntries;
247    ListTableEntries<uint32_t> *mCttsTableEntries;
248
249    int64_t mMinCttsOffsetTimeUs;
250    int64_t mMaxCttsOffsetTimeUs;
251
252    // Sequence parameter set or picture parameter set
253    struct AVCParamSet {
254        AVCParamSet(uint16_t length, const uint8_t *data)
255            : mLength(length), mData(data) {}
256
257        uint16_t mLength;
258        const uint8_t *mData;
259    };
260    List<AVCParamSet> mSeqParamSets;
261    List<AVCParamSet> mPicParamSets;
262    uint8_t mProfileIdc;
263    uint8_t mProfileCompatible;
264    uint8_t mLevelIdc;
265
266    void *mCodecSpecificData;
267    size_t mCodecSpecificDataSize;
268    bool mGotAllCodecSpecificData;
269    bool mTrackingProgressStatus;
270
271    bool mReachedEOS;
272    int64_t mStartTimestampUs;
273    int64_t mStartTimeRealUs;
274    int64_t mFirstSampleTimeRealUs;
275    int64_t mPreviousTrackTimeUs;
276    int64_t mTrackEveryTimeDurationUs;
277
278    // Update the audio track's drift information.
279    void updateDriftTime(const sp<MetaData>& meta);
280
281    int32_t getStartTimeOffsetScaledTime() const;
282
283    static void *ThreadWrapper(void *me);
284    status_t threadEntry();
285
286    const uint8_t *parseParamSet(
287        const uint8_t *data, size_t length, int type, size_t *paramSetLen);
288
289    status_t makeAVCCodecSpecificData(const uint8_t *data, size_t size);
290    status_t copyAVCCodecSpecificData(const uint8_t *data, size_t size);
291    status_t parseAVCCodecSpecificData(const uint8_t *data, size_t size);
292
293    // Track authoring progress status
294    void trackProgressStatus(int64_t timeUs, status_t err = OK);
295    void initTrackingProgressStatus(MetaData *params);
296
297    void getCodecSpecificDataFromInputFormatIfPossible();
298
299    // Determine the track time scale
300    // If it is an audio track, try to use the sampling rate as
301    // the time scale; however, if user chooses the overwrite
302    // value, the user-supplied time scale will be used.
303    void setTimeScale();
304
305    // Simple validation on the codec specific data
306    status_t checkCodecSpecificData() const;
307    int32_t mRotation;
308
309    void updateTrackSizeEstimate();
310    void addOneStscTableEntry(size_t chunkId, size_t sampleId);
311    void addOneStssTableEntry(size_t sampleId);
312
313    // Duration is time scale based
314    void addOneSttsTableEntry(size_t sampleCount, int32_t timescaledDur);
315    void addOneCttsTableEntry(size_t sampleCount, int32_t timescaledDur);
316
317    bool isTrackMalFormed() const;
318    void sendTrackSummary(bool hasMultipleTracks);
319
320    // Write the boxes
321    void writeStcoBox(bool use32BitOffset);
322    void writeStscBox();
323    void writeStszBox();
324    void writeStssBox();
325    void writeSttsBox();
326    void writeCttsBox();
327    void writeD263Box();
328    void writePaspBox();
329    void writeAvccBox();
330    void writeUrlBox();
331    void writeDrefBox();
332    void writeDinfBox();
333    void writeDamrBox();
334    void writeMdhdBox(uint32_t now);
335    void writeSmhdBox();
336    void writeVmhdBox();
337    void writeHdlrBox();
338    void writeTkhdBox(uint32_t now);
339    void writeMp4aEsdsBox();
340    void writeMp4vEsdsBox();
341    void writeAudioFourCCBox();
342    void writeVideoFourCCBox();
343    void writeStblBox(bool use32BitOffset);
344
345    Track(const Track &);
346    Track &operator=(const Track &);
347};
348
349MPEG4Writer::MPEG4Writer(int fd)
350    : mFd(dup(fd)),
351      mInitCheck(mFd < 0? NO_INIT: OK),
352      mIsRealTimeRecording(true),
353      mUse4ByteNalLength(true),
354      mUse32BitOffset(true),
355      mIsFileSizeLimitExplicitlyRequested(false),
356      mPaused(false),
357      mStarted(false),
358      mWriterThreadStarted(false),
359      mOffset(0),
360      mMdatOffset(0),
361      mEstimatedMoovBoxSize(0),
362      mInterleaveDurationUs(1000000),
363      mLatitudex10000(0),
364      mLongitudex10000(0),
365      mAreGeoTagsAvailable(false),
366      mMetaKeys(new AMessage()),
367      mStartTimeOffsetMs(-1) {
368}
369
370MPEG4Writer::~MPEG4Writer() {
371    reset();
372
373    while (!mTracks.empty()) {
374        List<Track *>::iterator it = mTracks.begin();
375        delete *it;
376        (*it) = NULL;
377        mTracks.erase(it);
378    }
379    mTracks.clear();
380}
381
382status_t MPEG4Writer::dump(
383        int fd, const Vector<String16>& args) {
384    const size_t SIZE = 256;
385    char buffer[SIZE];
386    String8 result;
387    snprintf(buffer, SIZE, "   MPEG4Writer %p\n", this);
388    result.append(buffer);
389    snprintf(buffer, SIZE, "     mStarted: %s\n", mStarted? "true": "false");
390    result.append(buffer);
391    ::write(fd, result.string(), result.size());
392    for (List<Track *>::iterator it = mTracks.begin();
393         it != mTracks.end(); ++it) {
394        (*it)->dump(fd, args);
395    }
396    return OK;
397}
398
399status_t MPEG4Writer::Track::dump(
400        int fd, const Vector<String16>& /* args */) const {
401    const size_t SIZE = 256;
402    char buffer[SIZE];
403    String8 result;
404    snprintf(buffer, SIZE, "     %s track\n", mIsAudio? "Audio": "Video");
405    result.append(buffer);
406    snprintf(buffer, SIZE, "       reached EOS: %s\n",
407            mReachedEOS? "true": "false");
408    result.append(buffer);
409    snprintf(buffer, SIZE, "       frames encoded : %d\n", mStszTableEntries->count());
410    result.append(buffer);
411    snprintf(buffer, SIZE, "       duration encoded : %" PRId64 " us\n", mTrackDurationUs);
412    result.append(buffer);
413    ::write(fd, result.string(), result.size());
414    return OK;
415}
416
417status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
418    Mutex::Autolock l(mLock);
419    if (mStarted) {
420        ALOGE("Attempt to add source AFTER recording is started");
421        return UNKNOWN_ERROR;
422    }
423
424    // At most 2 tracks can be supported.
425    if (mTracks.size() >= 2) {
426        ALOGE("Too many tracks (%zu) to add", mTracks.size());
427        return ERROR_UNSUPPORTED;
428    }
429
430    CHECK(source.get() != NULL);
431
432    // A track of type other than video or audio is not supported.
433    const char *mime;
434    source->getFormat()->findCString(kKeyMIMEType, &mime);
435    bool isAudio = !strncasecmp(mime, "audio/", 6);
436    bool isVideo = !strncasecmp(mime, "video/", 6);
437    if (!isAudio && !isVideo) {
438        ALOGE("Track (%s) other than video or audio is not supported",
439            mime);
440        return ERROR_UNSUPPORTED;
441    }
442
443    // At this point, we know the track to be added is either
444    // video or audio. Thus, we only need to check whether it
445    // is an audio track or not (if it is not, then it must be
446    // a video track).
447
448    // No more than one video or one audio track is supported.
449    for (List<Track*>::iterator it = mTracks.begin();
450         it != mTracks.end(); ++it) {
451        if ((*it)->isAudio() == isAudio) {
452            ALOGE("%s track already exists", isAudio? "Audio": "Video");
453            return ERROR_UNSUPPORTED;
454        }
455    }
456
457    // This is the first track of either audio or video.
458    // Go ahead to add the track.
459    Track *track = new Track(this, source, 1 + mTracks.size());
460    mTracks.push_back(track);
461
462    return OK;
463}
464
465status_t MPEG4Writer::startTracks(MetaData *params) {
466    if (mTracks.empty()) {
467        ALOGE("No source added");
468        return INVALID_OPERATION;
469    }
470
471    for (List<Track *>::iterator it = mTracks.begin();
472         it != mTracks.end(); ++it) {
473        status_t err = (*it)->start(params);
474
475        if (err != OK) {
476            for (List<Track *>::iterator it2 = mTracks.begin();
477                 it2 != it; ++it2) {
478                (*it2)->stop();
479            }
480
481            return err;
482        }
483    }
484    return OK;
485}
486
487int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) {
488    // This implementation is highly experimental/heurisitic.
489    //
490    // Statistical analysis shows that metadata usually accounts
491    // for a small portion of the total file size, usually < 0.6%.
492
493    // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2,
494    // where 1MB is the common file size limit for MMS application.
495    // The default MAX _MOOV_BOX_SIZE value is based on about 3
496    // minute video recording with a bit rate about 3 Mbps, because
497    // statistics also show that most of the video captured are going
498    // to be less than 3 minutes.
499
500    // If the estimation is wrong, we will pay the price of wasting
501    // some reserved space. This should not happen so often statistically.
502    static const int32_t factor = mUse32BitOffset? 1: 2;
503    static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024;  // 3 KB
504    static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000);
505    int64_t size = MIN_MOOV_BOX_SIZE;
506
507    // Max file size limit is set
508    if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
509        size = mMaxFileSizeLimitBytes * 6 / 1000;
510    }
511
512    // Max file duration limit is set
513    if (mMaxFileDurationLimitUs != 0) {
514        if (bitRate > 0) {
515            int64_t size2 =
516                ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000);
517            if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
518                // When both file size and duration limits are set,
519                // we use the smaller limit of the two.
520                if (size > size2) {
521                    size = size2;
522                }
523            } else {
524                // Only max file duration limit is set
525                size = size2;
526            }
527        }
528    }
529
530    if (size < MIN_MOOV_BOX_SIZE) {
531        size = MIN_MOOV_BOX_SIZE;
532    }
533
534    // Any long duration recording will be probably end up with
535    // non-streamable mp4 file.
536    if (size > MAX_MOOV_BOX_SIZE) {
537        size = MAX_MOOV_BOX_SIZE;
538    }
539
540    ALOGI("limits: %" PRId64 "/%" PRId64 " bytes/us, bit rate: %d bps and the"
541         " estimated moov size %" PRId64 " bytes",
542         mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size);
543    return factor * size;
544}
545
546status_t MPEG4Writer::start(MetaData *param) {
547    if (mInitCheck != OK) {
548        return UNKNOWN_ERROR;
549    }
550
551    /*
552     * Check mMaxFileSizeLimitBytes at the beginning
553     * since mMaxFileSizeLimitBytes may be implicitly
554     * changed later for 32-bit file offset even if
555     * user does not ask to set it explicitly.
556     */
557    if (mMaxFileSizeLimitBytes != 0) {
558        mIsFileSizeLimitExplicitlyRequested = true;
559    }
560
561    int32_t use64BitOffset;
562    if (param &&
563        param->findInt32(kKey64BitFileOffset, &use64BitOffset) &&
564        use64BitOffset) {
565        mUse32BitOffset = false;
566    }
567
568    if (mUse32BitOffset) {
569        // Implicit 32 bit file size limit
570        if (mMaxFileSizeLimitBytes == 0) {
571            mMaxFileSizeLimitBytes = kMax32BitFileSize;
572        }
573
574        // If file size is set to be larger than the 32 bit file
575        // size limit, treat it as an error.
576        if (mMaxFileSizeLimitBytes > kMax32BitFileSize) {
577            ALOGW("32-bit file size limit (%" PRId64 " bytes) too big. "
578                 "It is changed to %" PRId64 " bytes",
579                mMaxFileSizeLimitBytes, kMax32BitFileSize);
580            mMaxFileSizeLimitBytes = kMax32BitFileSize;
581        }
582    }
583
584    int32_t use2ByteNalLength;
585    if (param &&
586        param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) &&
587        use2ByteNalLength) {
588        mUse4ByteNalLength = false;
589    }
590
591    int32_t isRealTimeRecording;
592    if (param && param->findInt32(kKeyRealTimeRecording, &isRealTimeRecording)) {
593        mIsRealTimeRecording = isRealTimeRecording;
594    }
595
596    mStartTimestampUs = -1;
597
598    if (mStarted) {
599        if (mPaused) {
600            mPaused = false;
601            return startTracks(param);
602        }
603        return OK;
604    }
605
606    if (!param ||
607        !param->findInt32(kKeyTimeScale, &mTimeScale)) {
608        mTimeScale = 1000;
609    }
610    CHECK_GT(mTimeScale, 0);
611    ALOGV("movie time scale: %d", mTimeScale);
612
613    /*
614     * When the requested file size limit is small, the priority
615     * is to meet the file size limit requirement, rather than
616     * to make the file streamable. mStreamableFile does not tell
617     * whether the actual recorded file is streamable or not.
618     */
619    mStreamableFile =
620        (mMaxFileSizeLimitBytes != 0 &&
621         mMaxFileSizeLimitBytes >= kMinStreamableFileSizeInBytes);
622
623    /*
624     * mWriteMoovBoxToMemory is true if the amount of data in moov box is
625     * smaller than the reserved free space at the beginning of a file, AND
626     * when the content of moov box is constructed. Note that video/audio
627     * frame data is always written to the file but not in the memory.
628     *
629     * Before stop()/reset() is called, mWriteMoovBoxToMemory is always
630     * false. When reset() is called at the end of a recording session,
631     * Moov box needs to be constructed.
632     *
633     * 1) Right before a moov box is constructed, mWriteMoovBoxToMemory
634     * to set to mStreamableFile so that if
635     * the file is intended to be streamable, it is set to true;
636     * otherwise, it is set to false. When the value is set to false,
637     * all the content of the moov box is written immediately to
638     * the end of the file. When the value is set to true, all the
639     * content of the moov box is written to an in-memory cache,
640     * mMoovBoxBuffer, util the following condition happens. Note
641     * that the size of the in-memory cache is the same as the
642     * reserved free space at the beginning of the file.
643     *
644     * 2) While the data of the moov box is written to an in-memory
645     * cache, the data size is checked against the reserved space.
646     * If the data size surpasses the reserved space, subsequent moov
647     * data could no longer be hold in the in-memory cache. This also
648     * indicates that the reserved space was too small. At this point,
649     * _all_ moov data must be written to the end of the file.
650     * mWriteMoovBoxToMemory must be set to false to direct the write
651     * to the file.
652     *
653     * 3) If the data size in moov box is smaller than the reserved
654     * space after moov box is completely constructed, the in-memory
655     * cache copy of the moov box is written to the reserved free
656     * space. Thus, immediately after the moov is completedly
657     * constructed, mWriteMoovBoxToMemory is always set to false.
658     */
659    mWriteMoovBoxToMemory = false;
660    mMoovBoxBuffer = NULL;
661    mMoovBoxBufferOffset = 0;
662
663    writeFtypBox(param);
664
665    mFreeBoxOffset = mOffset;
666
667    if (mEstimatedMoovBoxSize == 0) {
668        int32_t bitRate = -1;
669        if (param) {
670            param->findInt32(kKeyBitRate, &bitRate);
671        }
672        mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate);
673    }
674    CHECK_GE(mEstimatedMoovBoxSize, 8);
675    if (mStreamableFile) {
676        // Reserve a 'free' box only for streamable file
677        lseek64(mFd, mFreeBoxOffset, SEEK_SET);
678        writeInt32(mEstimatedMoovBoxSize);
679        write("free", 4);
680        mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize;
681    } else {
682        mMdatOffset = mOffset;
683    }
684
685    mOffset = mMdatOffset;
686    lseek64(mFd, mMdatOffset, SEEK_SET);
687    if (mUse32BitOffset) {
688        write("????mdat", 8);
689    } else {
690        write("\x00\x00\x00\x01mdat????????", 16);
691    }
692
693    status_t err = startWriterThread();
694    if (err != OK) {
695        return err;
696    }
697
698    err = startTracks(param);
699    if (err != OK) {
700        return err;
701    }
702
703    mStarted = true;
704    return OK;
705}
706
707bool MPEG4Writer::use32BitFileOffset() const {
708    return mUse32BitOffset;
709}
710
711status_t MPEG4Writer::pause() {
712    if (mInitCheck != OK) {
713        return OK;
714    }
715    mPaused = true;
716    status_t err = OK;
717    for (List<Track *>::iterator it = mTracks.begin();
718         it != mTracks.end(); ++it) {
719        status_t status = (*it)->pause();
720        if (status != OK) {
721            err = status;
722        }
723    }
724    return err;
725}
726
727void MPEG4Writer::stopWriterThread() {
728    ALOGD("Stopping writer thread");
729    if (!mWriterThreadStarted) {
730        return;
731    }
732
733    {
734        Mutex::Autolock autolock(mLock);
735
736        mDone = true;
737        mChunkReadyCondition.signal();
738    }
739
740    void *dummy;
741    pthread_join(mThread, &dummy);
742    mWriterThreadStarted = false;
743    ALOGD("Writer thread stopped");
744}
745
746/*
747 * MP4 file standard defines a composition matrix:
748 * | a  b  u |
749 * | c  d  v |
750 * | x  y  w |
751 *
752 * the element in the matrix is stored in the following
753 * order: {a, b, u, c, d, v, x, y, w},
754 * where a, b, c, d, x, and y is in 16.16 format, while
755 * u, v and w is in 2.30 format.
756 */
757void MPEG4Writer::writeCompositionMatrix(int degrees) {
758    ALOGV("writeCompositionMatrix");
759    uint32_t a = 0x00010000;
760    uint32_t b = 0;
761    uint32_t c = 0;
762    uint32_t d = 0x00010000;
763    switch (degrees) {
764        case 0:
765            break;
766        case 90:
767            a = 0;
768            b = 0x00010000;
769            c = 0xFFFF0000;
770            d = 0;
771            break;
772        case 180:
773            a = 0xFFFF0000;
774            d = 0xFFFF0000;
775            break;
776        case 270:
777            a = 0;
778            b = 0xFFFF0000;
779            c = 0x00010000;
780            d = 0;
781            break;
782        default:
783            CHECK(!"Should never reach this unknown rotation");
784            break;
785    }
786
787    writeInt32(a);           // a
788    writeInt32(b);           // b
789    writeInt32(0);           // u
790    writeInt32(c);           // c
791    writeInt32(d);           // d
792    writeInt32(0);           // v
793    writeInt32(0);           // x
794    writeInt32(0);           // y
795    writeInt32(0x40000000);  // w
796}
797
798void MPEG4Writer::release() {
799    close(mFd);
800    mFd = -1;
801    mInitCheck = NO_INIT;
802    mStarted = false;
803}
804
805status_t MPEG4Writer::reset() {
806    if (mInitCheck != OK) {
807        return OK;
808    } else {
809        if (!mWriterThreadStarted ||
810            !mStarted) {
811            if (mWriterThreadStarted) {
812                stopWriterThread();
813            }
814            release();
815            return OK;
816        }
817    }
818
819    status_t err = OK;
820    int64_t maxDurationUs = 0;
821    int64_t minDurationUs = 0x7fffffffffffffffLL;
822    for (List<Track *>::iterator it = mTracks.begin();
823         it != mTracks.end(); ++it) {
824        status_t status = (*it)->stop();
825        if (err == OK && status != OK) {
826            err = status;
827        }
828
829        int64_t durationUs = (*it)->getDurationUs();
830        if (durationUs > maxDurationUs) {
831            maxDurationUs = durationUs;
832        }
833        if (durationUs < minDurationUs) {
834            minDurationUs = durationUs;
835        }
836    }
837
838    if (mTracks.size() > 1) {
839        ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us",
840            minDurationUs, maxDurationUs);
841    }
842
843    stopWriterThread();
844
845    // Do not write out movie header on error.
846    if (err != OK) {
847        release();
848        return err;
849    }
850
851    // Fix up the size of the 'mdat' chunk.
852    if (mUse32BitOffset) {
853        lseek64(mFd, mMdatOffset, SEEK_SET);
854        uint32_t size = htonl(static_cast<uint32_t>(mOffset - mMdatOffset));
855        ::write(mFd, &size, 4);
856    } else {
857        lseek64(mFd, mMdatOffset + 8, SEEK_SET);
858        uint64_t size = mOffset - mMdatOffset;
859        size = hton64(size);
860        ::write(mFd, &size, 8);
861    }
862    lseek64(mFd, mOffset, SEEK_SET);
863
864    // Construct moov box now
865    mMoovBoxBufferOffset = 0;
866    mWriteMoovBoxToMemory = mStreamableFile;
867    if (mWriteMoovBoxToMemory) {
868        // There is no need to allocate in-memory cache
869        // for moov box if the file is not streamable.
870
871        mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
872        CHECK(mMoovBoxBuffer != NULL);
873    }
874    writeMoovBox(maxDurationUs);
875
876    // mWriteMoovBoxToMemory could be set to false in
877    // MPEG4Writer::write() method
878    if (mWriteMoovBoxToMemory) {
879        mWriteMoovBoxToMemory = false;
880        // Content of the moov box is saved in the cache, and the in-memory
881        // moov box needs to be written to the file in a single shot.
882
883        CHECK_LE(mMoovBoxBufferOffset + 8, mEstimatedMoovBoxSize);
884
885        // Moov box
886        lseek64(mFd, mFreeBoxOffset, SEEK_SET);
887        mOffset = mFreeBoxOffset;
888        write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset);
889
890        // Free box
891        lseek64(mFd, mOffset, SEEK_SET);
892        writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset);
893        write("free", 4);
894    } else {
895        ALOGI("The mp4 file will not be streamable.");
896    }
897
898    // Free in-memory cache for moov box
899    if (mMoovBoxBuffer != NULL) {
900        free(mMoovBoxBuffer);
901        mMoovBoxBuffer = NULL;
902        mMoovBoxBufferOffset = 0;
903    }
904
905    CHECK(mBoxes.empty());
906
907    release();
908    return err;
909}
910
911uint32_t MPEG4Writer::getMpeg4Time() {
912    time_t now = time(NULL);
913    // MP4 file uses time counting seconds since midnight, Jan. 1, 1904
914    // while time function returns Unix epoch values which starts
915    // at 1970-01-01. Lets add the number of seconds between them
916    uint32_t mpeg4Time = now + (66 * 365 + 17) * (24 * 60 * 60);
917    return mpeg4Time;
918}
919
920void MPEG4Writer::writeMvhdBox(int64_t durationUs) {
921    uint32_t now = getMpeg4Time();
922    beginBox("mvhd");
923    writeInt32(0);             // version=0, flags=0
924    writeInt32(now);           // creation time
925    writeInt32(now);           // modification time
926    writeInt32(mTimeScale);    // mvhd timescale
927    int32_t duration = (durationUs * mTimeScale + 5E5) / 1E6;
928    writeInt32(duration);
929    writeInt32(0x10000);       // rate: 1.0
930    writeInt16(0x100);         // volume
931    writeInt16(0);             // reserved
932    writeInt32(0);             // reserved
933    writeInt32(0);             // reserved
934    writeCompositionMatrix(0); // matrix
935    writeInt32(0);             // predefined
936    writeInt32(0);             // predefined
937    writeInt32(0);             // predefined
938    writeInt32(0);             // predefined
939    writeInt32(0);             // predefined
940    writeInt32(0);             // predefined
941    writeInt32(mTracks.size() + 1);  // nextTrackID
942    endBox();  // mvhd
943}
944
945void MPEG4Writer::writeMoovBox(int64_t durationUs) {
946    beginBox("moov");
947    writeMvhdBox(durationUs);
948    if (mAreGeoTagsAvailable) {
949        writeUdtaBox();
950    }
951    writeMetaBox();
952    int32_t id = 1;
953    for (List<Track *>::iterator it = mTracks.begin();
954        it != mTracks.end(); ++it, ++id) {
955        (*it)->writeTrackHeader(mUse32BitOffset);
956    }
957    endBox();  // moov
958}
959
960void MPEG4Writer::writeFtypBox(MetaData *param) {
961    beginBox("ftyp");
962
963    int32_t fileType;
964    if (param && param->findInt32(kKeyFileType, &fileType) &&
965        fileType != OUTPUT_FORMAT_MPEG_4) {
966        writeFourcc("3gp4");
967        writeInt32(0);
968        writeFourcc("isom");
969        writeFourcc("3gp4");
970    } else {
971        writeFourcc("mp42");
972        writeInt32(0);
973        writeFourcc("isom");
974        writeFourcc("mp42");
975    }
976
977    endBox();
978}
979
980static bool isTestModeEnabled() {
981#if (PROPERTY_VALUE_MAX < 5)
982#error "PROPERTY_VALUE_MAX must be at least 5"
983#endif
984
985    // Test mode is enabled only if rw.media.record.test system
986    // property is enabled.
987    char value[PROPERTY_VALUE_MAX];
988    if (property_get("rw.media.record.test", value, NULL) &&
989        (!strcasecmp(value, "true") || !strcasecmp(value, "1"))) {
990        return true;
991    }
992    return false;
993}
994
995void MPEG4Writer::sendSessionSummary() {
996    // Send session summary only if test mode is enabled
997    if (!isTestModeEnabled()) {
998        return;
999    }
1000
1001    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
1002         it != mChunkInfos.end(); ++it) {
1003        int trackNum = it->mTrack->getTrackId() << 28;
1004        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
1005                trackNum | MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS,
1006                it->mMaxInterChunkDurUs);
1007    }
1008}
1009
1010status_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) {
1011    mInterleaveDurationUs = durationUs;
1012    return OK;
1013}
1014
1015void MPEG4Writer::lock() {
1016    mLock.lock();
1017}
1018
1019void MPEG4Writer::unlock() {
1020    mLock.unlock();
1021}
1022
1023off64_t MPEG4Writer::addSample_l(MediaBuffer *buffer) {
1024    off64_t old_offset = mOffset;
1025
1026    ::write(mFd,
1027          (const uint8_t *)buffer->data() + buffer->range_offset(),
1028          buffer->range_length());
1029
1030    mOffset += buffer->range_length();
1031
1032    return old_offset;
1033}
1034
1035static void StripStartcode(MediaBuffer *buffer) {
1036    if (buffer->range_length() < 4) {
1037        return;
1038    }
1039
1040    const uint8_t *ptr =
1041        (const uint8_t *)buffer->data() + buffer->range_offset();
1042
1043    if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
1044        buffer->set_range(
1045                buffer->range_offset() + 4, buffer->range_length() - 4);
1046    }
1047}
1048
1049off64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
1050    off64_t old_offset = mOffset;
1051
1052    size_t length = buffer->range_length();
1053
1054    if (mUse4ByteNalLength) {
1055        uint8_t x = length >> 24;
1056        ::write(mFd, &x, 1);
1057        x = (length >> 16) & 0xff;
1058        ::write(mFd, &x, 1);
1059        x = (length >> 8) & 0xff;
1060        ::write(mFd, &x, 1);
1061        x = length & 0xff;
1062        ::write(mFd, &x, 1);
1063
1064        ::write(mFd,
1065              (const uint8_t *)buffer->data() + buffer->range_offset(),
1066              length);
1067
1068        mOffset += length + 4;
1069    } else {
1070        CHECK_LT(length, 65536);
1071
1072        uint8_t x = length >> 8;
1073        ::write(mFd, &x, 1);
1074        x = length & 0xff;
1075        ::write(mFd, &x, 1);
1076        ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length);
1077        mOffset += length + 2;
1078    }
1079
1080    return old_offset;
1081}
1082
1083size_t MPEG4Writer::write(
1084        const void *ptr, size_t size, size_t nmemb) {
1085
1086    const size_t bytes = size * nmemb;
1087    if (mWriteMoovBoxToMemory) {
1088
1089        off64_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes;
1090        if (moovBoxSize > mEstimatedMoovBoxSize) {
1091            // The reserved moov box at the beginning of the file
1092            // is not big enough. Moov box should be written to
1093            // the end of the file from now on, but not to the
1094            // in-memory cache.
1095
1096            // We write partial moov box that is in the memory to
1097            // the file first.
1098            for (List<off64_t>::iterator it = mBoxes.begin();
1099                 it != mBoxes.end(); ++it) {
1100                (*it) += mOffset;
1101            }
1102            lseek64(mFd, mOffset, SEEK_SET);
1103            ::write(mFd, mMoovBoxBuffer, mMoovBoxBufferOffset);
1104            ::write(mFd, ptr, bytes);
1105            mOffset += (bytes + mMoovBoxBufferOffset);
1106
1107            // All subsequent moov box content will be written
1108            // to the end of the file.
1109            mWriteMoovBoxToMemory = false;
1110        } else {
1111            memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes);
1112            mMoovBoxBufferOffset += bytes;
1113        }
1114    } else {
1115        ::write(mFd, ptr, size * nmemb);
1116        mOffset += bytes;
1117    }
1118    return bytes;
1119}
1120
1121void MPEG4Writer::beginBox(uint32_t id) {
1122    mBoxes.push_back(mWriteMoovBoxToMemory?
1123            mMoovBoxBufferOffset: mOffset);
1124
1125    writeInt32(0);
1126    writeInt32(id);
1127}
1128
1129void MPEG4Writer::beginBox(const char *fourcc) {
1130    CHECK_EQ(strlen(fourcc), 4);
1131
1132    mBoxes.push_back(mWriteMoovBoxToMemory?
1133            mMoovBoxBufferOffset: mOffset);
1134
1135    writeInt32(0);
1136    writeFourcc(fourcc);
1137}
1138
1139void MPEG4Writer::endBox() {
1140    CHECK(!mBoxes.empty());
1141
1142    off64_t offset = *--mBoxes.end();
1143    mBoxes.erase(--mBoxes.end());
1144
1145    if (mWriteMoovBoxToMemory) {
1146       int32_t x = htonl(mMoovBoxBufferOffset - offset);
1147       memcpy(mMoovBoxBuffer + offset, &x, 4);
1148    } else {
1149        lseek64(mFd, offset, SEEK_SET);
1150        writeInt32(mOffset - offset);
1151        mOffset -= 4;
1152        lseek64(mFd, mOffset, SEEK_SET);
1153    }
1154}
1155
1156void MPEG4Writer::writeInt8(int8_t x) {
1157    write(&x, 1, 1);
1158}
1159
1160void MPEG4Writer::writeInt16(int16_t x) {
1161    x = htons(x);
1162    write(&x, 1, 2);
1163}
1164
1165void MPEG4Writer::writeInt32(int32_t x) {
1166    x = htonl(x);
1167    write(&x, 1, 4);
1168}
1169
1170void MPEG4Writer::writeInt64(int64_t x) {
1171    x = hton64(x);
1172    write(&x, 1, 8);
1173}
1174
1175void MPEG4Writer::writeCString(const char *s) {
1176    size_t n = strlen(s);
1177    write(s, 1, n + 1);
1178}
1179
1180void MPEG4Writer::writeFourcc(const char *s) {
1181    CHECK_EQ(strlen(s), 4);
1182    write(s, 1, 4);
1183}
1184
1185
1186// Written in +/-DD.DDDD format
1187void MPEG4Writer::writeLatitude(int degreex10000) {
1188    bool isNegative = (degreex10000 < 0);
1189    char sign = isNegative? '-': '+';
1190
1191    // Handle the whole part
1192    char str[9];
1193    int wholePart = degreex10000 / 10000;
1194    if (wholePart == 0) {
1195        snprintf(str, 5, "%c%.2d.", sign, wholePart);
1196    } else {
1197        snprintf(str, 5, "%+.2d.", wholePart);
1198    }
1199
1200    // Handle the fractional part
1201    int fractionalPart = degreex10000 - (wholePart * 10000);
1202    if (fractionalPart < 0) {
1203        fractionalPart = -fractionalPart;
1204    }
1205    snprintf(&str[4], 5, "%.4d", fractionalPart);
1206
1207    // Do not write the null terminator
1208    write(str, 1, 8);
1209}
1210
1211// Written in +/- DDD.DDDD format
1212void MPEG4Writer::writeLongitude(int degreex10000) {
1213    bool isNegative = (degreex10000 < 0);
1214    char sign = isNegative? '-': '+';
1215
1216    // Handle the whole part
1217    char str[10];
1218    int wholePart = degreex10000 / 10000;
1219    if (wholePart == 0) {
1220        snprintf(str, 6, "%c%.3d.", sign, wholePart);
1221    } else {
1222        snprintf(str, 6, "%+.3d.", wholePart);
1223    }
1224
1225    // Handle the fractional part
1226    int fractionalPart = degreex10000 - (wholePart * 10000);
1227    if (fractionalPart < 0) {
1228        fractionalPart = -fractionalPart;
1229    }
1230    snprintf(&str[5], 5, "%.4d", fractionalPart);
1231
1232    // Do not write the null terminator
1233    write(str, 1, 9);
1234}
1235
1236/*
1237 * Geodata is stored according to ISO-6709 standard.
1238 * latitudex10000 is latitude in degrees times 10000, and
1239 * longitudex10000 is longitude in degrees times 10000.
1240 * The range for the latitude is in [-90, +90], and
1241 * The range for the longitude is in [-180, +180]
1242 */
1243status_t MPEG4Writer::setGeoData(int latitudex10000, int longitudex10000) {
1244    // Is latitude or longitude out of range?
1245    if (latitudex10000 < -900000 || latitudex10000 > 900000 ||
1246        longitudex10000 < -1800000 || longitudex10000 > 1800000) {
1247        return BAD_VALUE;
1248    }
1249
1250    mLatitudex10000 = latitudex10000;
1251    mLongitudex10000 = longitudex10000;
1252    mAreGeoTagsAvailable = true;
1253    return OK;
1254}
1255
1256status_t MPEG4Writer::setCaptureRate(float captureFps) {
1257    if (captureFps <= 0.0f) {
1258        return BAD_VALUE;
1259    }
1260
1261    mMetaKeys->setFloat("com.android.capture.fps", captureFps);
1262    return OK;
1263}
1264
1265void MPEG4Writer::write(const void *data, size_t size) {
1266    write(data, 1, size);
1267}
1268
1269bool MPEG4Writer::isFileStreamable() const {
1270    return mStreamableFile;
1271}
1272
1273bool MPEG4Writer::exceedsFileSizeLimit() {
1274    // No limit
1275    if (mMaxFileSizeLimitBytes == 0) {
1276        return false;
1277    }
1278
1279    int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize);
1280    for (List<Track *>::iterator it = mTracks.begin();
1281         it != mTracks.end(); ++it) {
1282        nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
1283    }
1284
1285    if (!mStreamableFile) {
1286        // Add 1024 bytes as error tolerance
1287        return nTotalBytesEstimate + 1024 >= mMaxFileSizeLimitBytes;
1288    }
1289    // Be conservative in the estimate: do not exceed 95% of
1290    // the target file limit. For small target file size limit, though,
1291    // this will not help.
1292    return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100);
1293}
1294
1295bool MPEG4Writer::exceedsFileDurationLimit() {
1296    // No limit
1297    if (mMaxFileDurationLimitUs == 0) {
1298        return false;
1299    }
1300
1301    for (List<Track *>::iterator it = mTracks.begin();
1302         it != mTracks.end(); ++it) {
1303        if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) {
1304            return true;
1305        }
1306    }
1307    return false;
1308}
1309
1310bool MPEG4Writer::reachedEOS() {
1311    bool allDone = true;
1312    for (List<Track *>::iterator it = mTracks.begin();
1313         it != mTracks.end(); ++it) {
1314        if (!(*it)->reachedEOS()) {
1315            allDone = false;
1316            break;
1317        }
1318    }
1319
1320    return allDone;
1321}
1322
1323void MPEG4Writer::setStartTimestampUs(int64_t timeUs) {
1324    ALOGI("setStartTimestampUs: %" PRId64, timeUs);
1325    CHECK_GE(timeUs, 0ll);
1326    Mutex::Autolock autoLock(mLock);
1327    if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) {
1328        mStartTimestampUs = timeUs;
1329        ALOGI("Earliest track starting time: %" PRId64, mStartTimestampUs);
1330    }
1331}
1332
1333int64_t MPEG4Writer::getStartTimestampUs() {
1334    Mutex::Autolock autoLock(mLock);
1335    return mStartTimestampUs;
1336}
1337
1338size_t MPEG4Writer::numTracks() {
1339    Mutex::Autolock autolock(mLock);
1340    return mTracks.size();
1341}
1342
1343////////////////////////////////////////////////////////////////////////////////
1344
1345MPEG4Writer::Track::Track(
1346        MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId)
1347    : mOwner(owner),
1348      mMeta(source->getFormat()),
1349      mSource(source),
1350      mDone(false),
1351      mPaused(false),
1352      mResumed(false),
1353      mStarted(false),
1354      mTrackId(trackId),
1355      mTrackDurationUs(0),
1356      mEstimatedTrackSizeBytes(0),
1357      mSamplesHaveSameSize(true),
1358      mStszTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
1359      mStcoTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
1360      mCo64TableEntries(new ListTableEntries<off64_t>(1000, 1)),
1361      mStscTableEntries(new ListTableEntries<uint32_t>(1000, 3)),
1362      mStssTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
1363      mSttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)),
1364      mCttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)),
1365      mCodecSpecificData(NULL),
1366      mCodecSpecificDataSize(0),
1367      mGotAllCodecSpecificData(false),
1368      mReachedEOS(false),
1369      mRotation(0) {
1370    getCodecSpecificDataFromInputFormatIfPossible();
1371
1372    const char *mime;
1373    mMeta->findCString(kKeyMIMEType, &mime);
1374    mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
1375    mIsAudio = !strncasecmp(mime, "audio/", 6);
1376    mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
1377               !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
1378
1379    setTimeScale();
1380}
1381
1382void MPEG4Writer::Track::updateTrackSizeEstimate() {
1383
1384    uint32_t stcoBoxCount = (mOwner->use32BitFileOffset()
1385                            ? mStcoTableEntries->count()
1386                            : mCo64TableEntries->count());
1387    int64_t stcoBoxSizeBytes = stcoBoxCount * 4;
1388    int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mStszTableEntries->count() * 4);
1389
1390    mEstimatedTrackSizeBytes = mMdatSizeBytes;  // media data size
1391    if (!mOwner->isFileStreamable()) {
1392        // Reserved free space is not large enough to hold
1393        // all meta data and thus wasted.
1394        mEstimatedTrackSizeBytes += mStscTableEntries->count() * 12 +  // stsc box size
1395                                    mStssTableEntries->count() * 4 +   // stss box size
1396                                    mSttsTableEntries->count() * 8 +   // stts box size
1397                                    mCttsTableEntries->count() * 8 +   // ctts box size
1398                                    stcoBoxSizeBytes +           // stco box size
1399                                    stszBoxSizeBytes;            // stsz box size
1400    }
1401}
1402
1403void MPEG4Writer::Track::addOneStscTableEntry(
1404        size_t chunkId, size_t sampleId) {
1405
1406        mStscTableEntries->add(htonl(chunkId));
1407        mStscTableEntries->add(htonl(sampleId));
1408        mStscTableEntries->add(htonl(1));
1409}
1410
1411void MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) {
1412    mStssTableEntries->add(htonl(sampleId));
1413}
1414
1415void MPEG4Writer::Track::addOneSttsTableEntry(
1416        size_t sampleCount, int32_t duration) {
1417
1418    if (duration == 0) {
1419        ALOGW("0-duration samples found: %zu", sampleCount);
1420    }
1421    mSttsTableEntries->add(htonl(sampleCount));
1422    mSttsTableEntries->add(htonl(duration));
1423}
1424
1425void MPEG4Writer::Track::addOneCttsTableEntry(
1426        size_t sampleCount, int32_t duration) {
1427
1428    if (mIsAudio) {
1429        return;
1430    }
1431    mCttsTableEntries->add(htonl(sampleCount));
1432    mCttsTableEntries->add(htonl(duration));
1433}
1434
1435void MPEG4Writer::Track::addChunkOffset(off64_t offset) {
1436    if (mOwner->use32BitFileOffset()) {
1437        uint32_t value = offset;
1438        mStcoTableEntries->add(htonl(value));
1439    } else {
1440        mCo64TableEntries->add(hton64(offset));
1441    }
1442}
1443
1444void MPEG4Writer::Track::setTimeScale() {
1445    ALOGV("setTimeScale");
1446    // Default time scale
1447    mTimeScale = 90000;
1448
1449    if (mIsAudio) {
1450        // Use the sampling rate as the default time scale for audio track.
1451        int32_t sampleRate;
1452        bool success = mMeta->findInt32(kKeySampleRate, &sampleRate);
1453        CHECK(success);
1454        mTimeScale = sampleRate;
1455    }
1456
1457    // If someone would like to overwrite the timescale, use user-supplied value.
1458    int32_t timeScale;
1459    if (mMeta->findInt32(kKeyTimeScale, &timeScale)) {
1460        mTimeScale = timeScale;
1461    }
1462
1463    CHECK_GT(mTimeScale, 0);
1464}
1465
1466void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
1467    const char *mime;
1468    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
1469
1470    if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
1471        uint32_t type;
1472        const void *data;
1473        size_t size;
1474        if (mMeta->findData(kKeyAVCC, &type, &data, &size)) {
1475            mCodecSpecificData = malloc(size);
1476            mCodecSpecificDataSize = size;
1477            memcpy(mCodecSpecificData, data, size);
1478            mGotAllCodecSpecificData = true;
1479        }
1480    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
1481            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
1482        uint32_t type;
1483        const void *data;
1484        size_t size;
1485        if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
1486            ESDS esds(data, size);
1487            if (esds.getCodecSpecificInfo(&data, &size) == OK) {
1488                mCodecSpecificData = malloc(size);
1489                mCodecSpecificDataSize = size;
1490                memcpy(mCodecSpecificData, data, size);
1491                mGotAllCodecSpecificData = true;
1492            }
1493        }
1494    }
1495}
1496
1497MPEG4Writer::Track::~Track() {
1498    stop();
1499
1500    delete mStszTableEntries;
1501    delete mStcoTableEntries;
1502    delete mCo64TableEntries;
1503    delete mStscTableEntries;
1504    delete mSttsTableEntries;
1505    delete mStssTableEntries;
1506    delete mCttsTableEntries;
1507
1508    mStszTableEntries = NULL;
1509    mStcoTableEntries = NULL;
1510    mCo64TableEntries = NULL;
1511    mStscTableEntries = NULL;
1512    mSttsTableEntries = NULL;
1513    mStssTableEntries = NULL;
1514    mCttsTableEntries = NULL;
1515
1516    if (mCodecSpecificData != NULL) {
1517        free(mCodecSpecificData);
1518        mCodecSpecificData = NULL;
1519    }
1520}
1521
1522void MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) {
1523    ALOGV("initTrackingProgressStatus");
1524    mPreviousTrackTimeUs = -1;
1525    mTrackingProgressStatus = false;
1526    mTrackEveryTimeDurationUs = 0;
1527    {
1528        int64_t timeUs;
1529        if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) {
1530            ALOGV("Receive request to track progress status for every %" PRId64 " us", timeUs);
1531            mTrackEveryTimeDurationUs = timeUs;
1532            mTrackingProgressStatus = true;
1533        }
1534    }
1535}
1536
1537// static
1538void *MPEG4Writer::ThreadWrapper(void *me) {
1539    ALOGV("ThreadWrapper: %p", me);
1540    MPEG4Writer *writer = static_cast<MPEG4Writer *>(me);
1541    writer->threadFunc();
1542    return NULL;
1543}
1544
1545void MPEG4Writer::bufferChunk(const Chunk& chunk) {
1546    ALOGV("bufferChunk: %p", chunk.mTrack);
1547    Mutex::Autolock autolock(mLock);
1548    CHECK_EQ(mDone, false);
1549
1550    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
1551         it != mChunkInfos.end(); ++it) {
1552
1553        if (chunk.mTrack == it->mTrack) {  // Found owner
1554            it->mChunks.push_back(chunk);
1555            mChunkReadyCondition.signal();
1556            return;
1557        }
1558    }
1559
1560    CHECK(!"Received a chunk for a unknown track");
1561}
1562
1563void MPEG4Writer::writeChunkToFile(Chunk* chunk) {
1564    ALOGV("writeChunkToFile: %" PRId64 " from %s track",
1565        chunk->mTimeStampUs, chunk->mTrack->isAudio()? "audio": "video");
1566
1567    int32_t isFirstSample = true;
1568    while (!chunk->mSamples.empty()) {
1569        List<MediaBuffer *>::iterator it = chunk->mSamples.begin();
1570
1571        off64_t offset = chunk->mTrack->isAvc()
1572                                ? addLengthPrefixedSample_l(*it)
1573                                : addSample_l(*it);
1574
1575        if (isFirstSample) {
1576            chunk->mTrack->addChunkOffset(offset);
1577            isFirstSample = false;
1578        }
1579
1580        (*it)->release();
1581        (*it) = NULL;
1582        chunk->mSamples.erase(it);
1583    }
1584    chunk->mSamples.clear();
1585}
1586
1587void MPEG4Writer::writeAllChunks() {
1588    ALOGV("writeAllChunks");
1589    size_t outstandingChunks = 0;
1590    Chunk chunk;
1591    while (findChunkToWrite(&chunk)) {
1592        writeChunkToFile(&chunk);
1593        ++outstandingChunks;
1594    }
1595
1596    sendSessionSummary();
1597
1598    mChunkInfos.clear();
1599    ALOGD("%zu chunks are written in the last batch", outstandingChunks);
1600}
1601
1602bool MPEG4Writer::findChunkToWrite(Chunk *chunk) {
1603    ALOGV("findChunkToWrite");
1604
1605    int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL;
1606    Track *track = NULL;
1607    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
1608         it != mChunkInfos.end(); ++it) {
1609        if (!it->mChunks.empty()) {
1610            List<Chunk>::iterator chunkIt = it->mChunks.begin();
1611            if (chunkIt->mTimeStampUs < minTimestampUs) {
1612                minTimestampUs = chunkIt->mTimeStampUs;
1613                track = it->mTrack;
1614            }
1615        }
1616    }
1617
1618    if (track == NULL) {
1619        ALOGV("Nothing to be written after all");
1620        return false;
1621    }
1622
1623    if (mIsFirstChunk) {
1624        mIsFirstChunk = false;
1625    }
1626
1627    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
1628         it != mChunkInfos.end(); ++it) {
1629        if (it->mTrack == track) {
1630            *chunk = *(it->mChunks.begin());
1631            it->mChunks.erase(it->mChunks.begin());
1632            CHECK_EQ(chunk->mTrack, track);
1633
1634            int64_t interChunkTimeUs =
1635                chunk->mTimeStampUs - it->mPrevChunkTimestampUs;
1636            if (interChunkTimeUs > it->mPrevChunkTimestampUs) {
1637                it->mMaxInterChunkDurUs = interChunkTimeUs;
1638            }
1639
1640            return true;
1641        }
1642    }
1643
1644    return false;
1645}
1646
1647void MPEG4Writer::threadFunc() {
1648    ALOGV("threadFunc");
1649
1650    prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0);
1651
1652    Mutex::Autolock autoLock(mLock);
1653    while (!mDone) {
1654        Chunk chunk;
1655        bool chunkFound = false;
1656
1657        while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) {
1658            mChunkReadyCondition.wait(mLock);
1659        }
1660
1661        // In real time recording mode, write without holding the lock in order
1662        // to reduce the blocking time for media track threads.
1663        // Otherwise, hold the lock until the existing chunks get written to the
1664        // file.
1665        if (chunkFound) {
1666            if (mIsRealTimeRecording) {
1667                mLock.unlock();
1668            }
1669            writeChunkToFile(&chunk);
1670            if (mIsRealTimeRecording) {
1671                mLock.lock();
1672            }
1673        }
1674    }
1675
1676    writeAllChunks();
1677}
1678
1679status_t MPEG4Writer::startWriterThread() {
1680    ALOGV("startWriterThread");
1681
1682    mDone = false;
1683    mIsFirstChunk = true;
1684    mDriftTimeUs = 0;
1685    for (List<Track *>::iterator it = mTracks.begin();
1686         it != mTracks.end(); ++it) {
1687        ChunkInfo info;
1688        info.mTrack = *it;
1689        info.mPrevChunkTimestampUs = 0;
1690        info.mMaxInterChunkDurUs = 0;
1691        mChunkInfos.push_back(info);
1692    }
1693
1694    pthread_attr_t attr;
1695    pthread_attr_init(&attr);
1696    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1697    pthread_create(&mThread, &attr, ThreadWrapper, this);
1698    pthread_attr_destroy(&attr);
1699    mWriterThreadStarted = true;
1700    return OK;
1701}
1702
1703
1704status_t MPEG4Writer::Track::start(MetaData *params) {
1705    if (!mDone && mPaused) {
1706        mPaused = false;
1707        mResumed = true;
1708        return OK;
1709    }
1710
1711    int64_t startTimeUs;
1712    if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) {
1713        startTimeUs = 0;
1714    }
1715    mStartTimeRealUs = startTimeUs;
1716
1717    int32_t rotationDegrees;
1718    if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) {
1719        mRotation = rotationDegrees;
1720    }
1721
1722    initTrackingProgressStatus(params);
1723
1724    sp<MetaData> meta = new MetaData;
1725    if (mOwner->isRealTimeRecording() && mOwner->numTracks() > 1) {
1726        /*
1727         * This extra delay of accepting incoming audio/video signals
1728         * helps to align a/v start time at the beginning of a recording
1729         * session, and it also helps eliminate the "recording" sound for
1730         * camcorder applications.
1731         *
1732         * If client does not set the start time offset, we fall back to
1733         * use the default initial delay value.
1734         */
1735        int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL;
1736        if (startTimeOffsetUs < 0) {  // Start time offset was not set
1737            startTimeOffsetUs = kInitialDelayTimeUs;
1738        }
1739        startTimeUs += startTimeOffsetUs;
1740        ALOGI("Start time offset: %" PRId64 " us", startTimeOffsetUs);
1741    }
1742
1743    meta->setInt64(kKeyTime, startTimeUs);
1744
1745    status_t err = mSource->start(meta.get());
1746    if (err != OK) {
1747        mDone = mReachedEOS = true;
1748        return err;
1749    }
1750
1751    pthread_attr_t attr;
1752    pthread_attr_init(&attr);
1753    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1754
1755    mDone = false;
1756    mStarted = true;
1757    mTrackDurationUs = 0;
1758    mReachedEOS = false;
1759    mEstimatedTrackSizeBytes = 0;
1760    mMdatSizeBytes = 0;
1761    mMaxChunkDurationUs = 0;
1762
1763    pthread_create(&mThread, &attr, ThreadWrapper, this);
1764    pthread_attr_destroy(&attr);
1765
1766    return OK;
1767}
1768
1769status_t MPEG4Writer::Track::pause() {
1770    mPaused = true;
1771    return OK;
1772}
1773
1774status_t MPEG4Writer::Track::stop() {
1775    ALOGD("%s track stopping", mIsAudio? "Audio": "Video");
1776    if (!mStarted) {
1777        ALOGE("Stop() called but track is not started");
1778        return ERROR_END_OF_STREAM;
1779    }
1780
1781    if (mDone) {
1782        return OK;
1783    }
1784    mDone = true;
1785
1786    ALOGD("%s track source stopping", mIsAudio? "Audio": "Video");
1787    mSource->stop();
1788    ALOGD("%s track source stopped", mIsAudio? "Audio": "Video");
1789
1790    void *dummy;
1791    pthread_join(mThread, &dummy);
1792    status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
1793
1794    ALOGD("%s track stopped", mIsAudio? "Audio": "Video");
1795    return err;
1796}
1797
1798bool MPEG4Writer::Track::reachedEOS() {
1799    return mReachedEOS;
1800}
1801
1802// static
1803void *MPEG4Writer::Track::ThreadWrapper(void *me) {
1804    Track *track = static_cast<Track *>(me);
1805
1806    status_t err = track->threadEntry();
1807    return (void *)(uintptr_t)err;
1808}
1809
1810static void getNalUnitType(uint8_t byte, uint8_t* type) {
1811    ALOGV("getNalUnitType: %d", byte);
1812
1813    // nal_unit_type: 5-bit unsigned integer
1814    *type = (byte & 0x1F);
1815}
1816
1817static const uint8_t *findNextStartCode(
1818        const uint8_t *data, size_t length) {
1819
1820    ALOGV("findNextStartCode: %p %zu", data, length);
1821
1822    size_t bytesLeft = length;
1823    while (bytesLeft > 4  &&
1824            memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) {
1825        --bytesLeft;
1826    }
1827    if (bytesLeft <= 4) {
1828        bytesLeft = 0; // Last parameter set
1829    }
1830    return &data[length - bytesLeft];
1831}
1832
1833const uint8_t *MPEG4Writer::Track::parseParamSet(
1834        const uint8_t *data, size_t length, int type, size_t *paramSetLen) {
1835
1836    ALOGV("parseParamSet");
1837    CHECK(type == kNalUnitTypeSeqParamSet ||
1838          type == kNalUnitTypePicParamSet);
1839
1840    const uint8_t *nextStartCode = findNextStartCode(data, length);
1841    *paramSetLen = nextStartCode - data;
1842    if (*paramSetLen == 0) {
1843        ALOGE("Param set is malformed, since its length is 0");
1844        return NULL;
1845    }
1846
1847    AVCParamSet paramSet(*paramSetLen, data);
1848    if (type == kNalUnitTypeSeqParamSet) {
1849        if (*paramSetLen < 4) {
1850            ALOGE("Seq parameter set malformed");
1851            return NULL;
1852        }
1853        if (mSeqParamSets.empty()) {
1854            mProfileIdc = data[1];
1855            mProfileCompatible = data[2];
1856            mLevelIdc = data[3];
1857        } else {
1858            if (mProfileIdc != data[1] ||
1859                mProfileCompatible != data[2] ||
1860                mLevelIdc != data[3]) {
1861                ALOGE("Inconsistent profile/level found in seq parameter sets");
1862                return NULL;
1863            }
1864        }
1865        mSeqParamSets.push_back(paramSet);
1866    } else {
1867        mPicParamSets.push_back(paramSet);
1868    }
1869    return nextStartCode;
1870}
1871
1872status_t MPEG4Writer::Track::copyAVCCodecSpecificData(
1873        const uint8_t *data, size_t size) {
1874    ALOGV("copyAVCCodecSpecificData");
1875
1876    // 2 bytes for each of the parameter set length field
1877    // plus the 7 bytes for the header
1878    if (size < 4 + 7) {
1879        ALOGE("Codec specific data length too short: %zu", size);
1880        return ERROR_MALFORMED;
1881    }
1882
1883    mCodecSpecificDataSize = size;
1884    mCodecSpecificData = malloc(size);
1885    memcpy(mCodecSpecificData, data, size);
1886    return OK;
1887}
1888
1889status_t MPEG4Writer::Track::parseAVCCodecSpecificData(
1890        const uint8_t *data, size_t size) {
1891
1892    ALOGV("parseAVCCodecSpecificData");
1893    // Data starts with a start code.
1894    // SPS and PPS are separated with start codes.
1895    // Also, SPS must come before PPS
1896    uint8_t type = kNalUnitTypeSeqParamSet;
1897    bool gotSps = false;
1898    bool gotPps = false;
1899    const uint8_t *tmp = data;
1900    const uint8_t *nextStartCode = data;
1901    size_t bytesLeft = size;
1902    size_t paramSetLen = 0;
1903    mCodecSpecificDataSize = 0;
1904    while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) {
1905        getNalUnitType(*(tmp + 4), &type);
1906        if (type == kNalUnitTypeSeqParamSet) {
1907            if (gotPps) {
1908                ALOGE("SPS must come before PPS");
1909                return ERROR_MALFORMED;
1910            }
1911            if (!gotSps) {
1912                gotSps = true;
1913            }
1914            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
1915        } else if (type == kNalUnitTypePicParamSet) {
1916            if (!gotSps) {
1917                ALOGE("SPS must come before PPS");
1918                return ERROR_MALFORMED;
1919            }
1920            if (!gotPps) {
1921                gotPps = true;
1922            }
1923            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
1924        } else {
1925            ALOGE("Only SPS and PPS Nal units are expected");
1926            return ERROR_MALFORMED;
1927        }
1928
1929        if (nextStartCode == NULL) {
1930            return ERROR_MALFORMED;
1931        }
1932
1933        // Move on to find the next parameter set
1934        bytesLeft -= nextStartCode - tmp;
1935        tmp = nextStartCode;
1936        mCodecSpecificDataSize += (2 + paramSetLen);
1937    }
1938
1939    {
1940        // Check on the number of seq parameter sets
1941        size_t nSeqParamSets = mSeqParamSets.size();
1942        if (nSeqParamSets == 0) {
1943            ALOGE("Cound not find sequence parameter set");
1944            return ERROR_MALFORMED;
1945        }
1946
1947        if (nSeqParamSets > 0x1F) {
1948            ALOGE("Too many seq parameter sets (%zu) found", nSeqParamSets);
1949            return ERROR_MALFORMED;
1950        }
1951    }
1952
1953    {
1954        // Check on the number of pic parameter sets
1955        size_t nPicParamSets = mPicParamSets.size();
1956        if (nPicParamSets == 0) {
1957            ALOGE("Cound not find picture parameter set");
1958            return ERROR_MALFORMED;
1959        }
1960        if (nPicParamSets > 0xFF) {
1961            ALOGE("Too many pic parameter sets (%zd) found", nPicParamSets);
1962            return ERROR_MALFORMED;
1963        }
1964    }
1965// FIXME:
1966// Add chromat_format_idc, bit depth values, etc for AVC/h264 high profile and above
1967// and remove #if 0
1968#if 0
1969    {
1970        // Check on the profiles
1971        // These profiles requires additional parameter set extensions
1972        if (mProfileIdc == 100 || mProfileIdc == 110 ||
1973            mProfileIdc == 122 || mProfileIdc == 144) {
1974            ALOGE("Sorry, no support for profile_idc: %d!", mProfileIdc);
1975            return BAD_VALUE;
1976        }
1977    }
1978#endif
1979    return OK;
1980}
1981
1982status_t MPEG4Writer::Track::makeAVCCodecSpecificData(
1983        const uint8_t *data, size_t size) {
1984
1985    if (mCodecSpecificData != NULL) {
1986        ALOGE("Already have codec specific data");
1987        return ERROR_MALFORMED;
1988    }
1989
1990    if (size < 4) {
1991        ALOGE("Codec specific data length too short: %zu", size);
1992        return ERROR_MALFORMED;
1993    }
1994
1995    // Data is in the form of AVCCodecSpecificData
1996    if (memcmp("\x00\x00\x00\x01", data, 4)) {
1997        return copyAVCCodecSpecificData(data, size);
1998    }
1999
2000    if (parseAVCCodecSpecificData(data, size) != OK) {
2001        return ERROR_MALFORMED;
2002    }
2003
2004    // ISO 14496-15: AVC file format
2005    mCodecSpecificDataSize += 7;  // 7 more bytes in the header
2006    mCodecSpecificData = malloc(mCodecSpecificDataSize);
2007    uint8_t *header = (uint8_t *)mCodecSpecificData;
2008    header[0] = 1;                     // version
2009    header[1] = mProfileIdc;           // profile indication
2010    header[2] = mProfileCompatible;    // profile compatibility
2011    header[3] = mLevelIdc;
2012
2013    // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne
2014    if (mOwner->useNalLengthFour()) {
2015        header[4] = 0xfc | 3;  // length size == 4 bytes
2016    } else {
2017        header[4] = 0xfc | 1;  // length size == 2 bytes
2018    }
2019
2020    // 3-bit '111' followed by 5-bit numSequenceParameterSets
2021    int nSequenceParamSets = mSeqParamSets.size();
2022    header[5] = 0xe0 | nSequenceParamSets;
2023    header += 6;
2024    for (List<AVCParamSet>::iterator it = mSeqParamSets.begin();
2025         it != mSeqParamSets.end(); ++it) {
2026        // 16-bit sequence parameter set length
2027        uint16_t seqParamSetLength = it->mLength;
2028        header[0] = seqParamSetLength >> 8;
2029        header[1] = seqParamSetLength & 0xff;
2030
2031        // SPS NAL unit (sequence parameter length bytes)
2032        memcpy(&header[2], it->mData, seqParamSetLength);
2033        header += (2 + seqParamSetLength);
2034    }
2035
2036    // 8-bit nPictureParameterSets
2037    int nPictureParamSets = mPicParamSets.size();
2038    header[0] = nPictureParamSets;
2039    header += 1;
2040    for (List<AVCParamSet>::iterator it = mPicParamSets.begin();
2041         it != mPicParamSets.end(); ++it) {
2042        // 16-bit picture parameter set length
2043        uint16_t picParamSetLength = it->mLength;
2044        header[0] = picParamSetLength >> 8;
2045        header[1] = picParamSetLength & 0xff;
2046
2047        // PPS Nal unit (picture parameter set length bytes)
2048        memcpy(&header[2], it->mData, picParamSetLength);
2049        header += (2 + picParamSetLength);
2050    }
2051
2052    return OK;
2053}
2054
2055/*
2056 * Updates the drift time from the audio track so that
2057 * the video track can get the updated drift time information
2058 * from the file writer. The fluctuation of the drift time of the audio
2059 * encoding path is smoothed out with a simple filter by giving a larger
2060 * weight to more recently drift time. The filter coefficients, 0.5 and 0.5,
2061 * are heuristically determined.
2062 */
2063void MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) {
2064    int64_t driftTimeUs = 0;
2065    if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) {
2066        int64_t prevDriftTimeUs = mOwner->getDriftTimeUs();
2067        int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1;
2068        mOwner->setDriftTimeUs(timeUs);
2069    }
2070}
2071
2072status_t MPEG4Writer::Track::threadEntry() {
2073    int32_t count = 0;
2074    const int64_t interleaveDurationUs = mOwner->interleaveDuration();
2075    const bool hasMultipleTracks = (mOwner->numTracks() > 1);
2076    int64_t chunkTimestampUs = 0;
2077    int32_t nChunks = 0;
2078    int32_t nZeroLengthFrames = 0;
2079    int64_t lastTimestampUs = 0;      // Previous sample time stamp
2080    int64_t lastDurationUs = 0;       // Between the previous two samples
2081    int64_t currDurationTicks = 0;    // Timescale based ticks
2082    int64_t lastDurationTicks = 0;    // Timescale based ticks
2083    int32_t sampleCount = 1;          // Sample count in the current stts table entry
2084    uint32_t previousSampleSize = 0;  // Size of the previous sample
2085    int64_t previousPausedDurationUs = 0;
2086    int64_t timestampUs = 0;
2087    int64_t cttsOffsetTimeUs = 0;
2088    int64_t currCttsOffsetTimeTicks = 0;   // Timescale based ticks
2089    int64_t lastCttsOffsetTimeTicks = -1;  // Timescale based ticks
2090    int32_t cttsSampleCount = 0;           // Sample count in the current ctts table entry
2091    uint32_t lastSamplesPerChunk = 0;
2092
2093    if (mIsAudio) {
2094        prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
2095    } else {
2096        prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0);
2097    }
2098
2099    if (mOwner->isRealTimeRecording()) {
2100        androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
2101    }
2102
2103    sp<MetaData> meta_data;
2104
2105    status_t err = OK;
2106    MediaBuffer *buffer;
2107    const char *trackName = mIsAudio ? "Audio" : "Video";
2108    while (!mDone && (err = mSource->read(&buffer)) == OK) {
2109        if (buffer->range_length() == 0) {
2110            buffer->release();
2111            buffer = NULL;
2112            ++nZeroLengthFrames;
2113            continue;
2114        }
2115
2116        // If the codec specific data has not been received yet, delay pause.
2117        // After the codec specific data is received, discard what we received
2118        // when the track is to be paused.
2119        if (mPaused && !mResumed) {
2120            buffer->release();
2121            buffer = NULL;
2122            continue;
2123        }
2124
2125        ++count;
2126
2127        int32_t isCodecConfig;
2128        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
2129                && isCodecConfig) {
2130            CHECK(!mGotAllCodecSpecificData);
2131
2132            if (mIsAvc) {
2133                status_t err = makeAVCCodecSpecificData(
2134                        (const uint8_t *)buffer->data()
2135                            + buffer->range_offset(),
2136                        buffer->range_length());
2137                CHECK_EQ((status_t)OK, err);
2138            } else if (mIsMPEG4) {
2139                mCodecSpecificDataSize = buffer->range_length();
2140                mCodecSpecificData = malloc(mCodecSpecificDataSize);
2141                memcpy(mCodecSpecificData,
2142                        (const uint8_t *)buffer->data()
2143                            + buffer->range_offset(),
2144                       buffer->range_length());
2145            }
2146
2147            buffer->release();
2148            buffer = NULL;
2149
2150            mGotAllCodecSpecificData = true;
2151            continue;
2152        }
2153
2154        // Make a deep copy of the MediaBuffer and Metadata and release
2155        // the original as soon as we can
2156        MediaBuffer *copy = new MediaBuffer(buffer->range_length());
2157        memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(),
2158                buffer->range_length());
2159        copy->set_range(0, buffer->range_length());
2160        meta_data = new MetaData(*buffer->meta_data().get());
2161        buffer->release();
2162        buffer = NULL;
2163
2164        if (mIsAvc) StripStartcode(copy);
2165
2166        size_t sampleSize = copy->range_length();
2167        if (mIsAvc) {
2168            if (mOwner->useNalLengthFour()) {
2169                sampleSize += 4;
2170            } else {
2171                sampleSize += 2;
2172            }
2173        }
2174
2175        // Max file size or duration handling
2176        mMdatSizeBytes += sampleSize;
2177        updateTrackSizeEstimate();
2178
2179        if (mOwner->exceedsFileSizeLimit()) {
2180            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
2181            break;
2182        }
2183        if (mOwner->exceedsFileDurationLimit()) {
2184            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
2185            break;
2186        }
2187
2188
2189        int32_t isSync = false;
2190        meta_data->findInt32(kKeyIsSyncFrame, &isSync);
2191        CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
2192
2193////////////////////////////////////////////////////////////////////////////////
2194        if (mStszTableEntries->count() == 0) {
2195            mFirstSampleTimeRealUs = systemTime() / 1000;
2196            mStartTimestampUs = timestampUs;
2197            mOwner->setStartTimestampUs(mStartTimestampUs);
2198            previousPausedDurationUs = mStartTimestampUs;
2199        }
2200
2201        if (mResumed) {
2202            int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
2203            if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) {
2204                copy->release();
2205                return ERROR_MALFORMED;
2206            }
2207
2208            int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
2209            if (WARN_UNLESS(pausedDurationUs >= lastDurationUs, "for %s track", trackName)) {
2210                copy->release();
2211                return ERROR_MALFORMED;
2212            }
2213
2214            previousPausedDurationUs += pausedDurationUs - lastDurationUs;
2215            mResumed = false;
2216        }
2217
2218        timestampUs -= previousPausedDurationUs;
2219        if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
2220            copy->release();
2221            return ERROR_MALFORMED;
2222        }
2223
2224        if (!mIsAudio) {
2225            /*
2226             * Composition time: timestampUs
2227             * Decoding time: decodingTimeUs
2228             * Composition time offset = composition time - decoding time
2229             */
2230            int64_t decodingTimeUs;
2231            CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs));
2232            decodingTimeUs -= previousPausedDurationUs;
2233            cttsOffsetTimeUs =
2234                    timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
2235            if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) {
2236                copy->release();
2237                return ERROR_MALFORMED;
2238            }
2239
2240            timestampUs = decodingTimeUs;
2241            ALOGV("decoding time: %" PRId64 " and ctts offset time: %" PRId64,
2242                timestampUs, cttsOffsetTimeUs);
2243
2244            // Update ctts box table if necessary
2245            currCttsOffsetTimeTicks =
2246                    (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL;
2247            if (WARN_UNLESS(currCttsOffsetTimeTicks <= 0x0FFFFFFFFLL, "for %s track", trackName)) {
2248                copy->release();
2249                return ERROR_MALFORMED;
2250            }
2251
2252            if (mStszTableEntries->count() == 0) {
2253                // Force the first ctts table entry to have one single entry
2254                // so that we can do adjustment for the initial track start
2255                // time offset easily in writeCttsBox().
2256                lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
2257                addOneCttsTableEntry(1, currCttsOffsetTimeTicks);
2258                cttsSampleCount = 0;      // No sample in ctts box is pending
2259            } else {
2260                if (currCttsOffsetTimeTicks != lastCttsOffsetTimeTicks) {
2261                    addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
2262                    lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
2263                    cttsSampleCount = 1;  // One sample in ctts box is pending
2264                } else {
2265                    ++cttsSampleCount;
2266                }
2267            }
2268
2269            // Update ctts time offset range
2270            if (mStszTableEntries->count() == 0) {
2271                mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2272                mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2273            } else {
2274                if (currCttsOffsetTimeTicks > mMaxCttsOffsetTimeUs) {
2275                    mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2276                } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTimeUs) {
2277                    mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2278                }
2279            }
2280
2281        }
2282
2283        if (mOwner->isRealTimeRecording()) {
2284            if (mIsAudio) {
2285                updateDriftTime(meta_data);
2286            }
2287        }
2288
2289        if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
2290            copy->release();
2291            return ERROR_MALFORMED;
2292        }
2293
2294        ALOGV("%s media time stamp: %" PRId64 " and previous paused duration %" PRId64,
2295                trackName, timestampUs, previousPausedDurationUs);
2296        if (timestampUs > mTrackDurationUs) {
2297            mTrackDurationUs = timestampUs;
2298        }
2299
2300        // We need to use the time scale based ticks, rather than the
2301        // timestamp itself to determine whether we have to use a new
2302        // stts entry, since we may have rounding errors.
2303        // The calculation is intended to reduce the accumulated
2304        // rounding errors.
2305        currDurationTicks =
2306            ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
2307                (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
2308        if (currDurationTicks < 0ll) {
2309            ALOGE("timestampUs %" PRId64 " < lastTimestampUs %" PRId64 " for %s track",
2310                timestampUs, lastTimestampUs, trackName);
2311            copy->release();
2312            return UNKNOWN_ERROR;
2313        }
2314
2315        // if the duration is different for this sample, see if it is close enough to the previous
2316        // duration that we can fudge it and use the same value, to avoid filling the stts table
2317        // with lots of near-identical entries.
2318        // "close enough" here means that the current duration needs to be adjusted by less
2319        // than 0.1 milliseconds
2320        if (lastDurationTicks && (currDurationTicks != lastDurationTicks)) {
2321            int64_t deltaUs = ((lastDurationTicks - currDurationTicks) * 1000000LL
2322                    + (mTimeScale / 2)) / mTimeScale;
2323            if (deltaUs > -100 && deltaUs < 100) {
2324                // use previous ticks, and adjust timestamp as if it was actually that number
2325                // of ticks
2326                currDurationTicks = lastDurationTicks;
2327                timestampUs += deltaUs;
2328            }
2329        }
2330
2331        mStszTableEntries->add(htonl(sampleSize));
2332        if (mStszTableEntries->count() > 2) {
2333
2334            // Force the first sample to have its own stts entry so that
2335            // we can adjust its value later to maintain the A/V sync.
2336            if (mStszTableEntries->count() == 3 || currDurationTicks != lastDurationTicks) {
2337                addOneSttsTableEntry(sampleCount, lastDurationTicks);
2338                sampleCount = 1;
2339            } else {
2340                ++sampleCount;
2341            }
2342
2343        }
2344        if (mSamplesHaveSameSize) {
2345            if (mStszTableEntries->count() >= 2 && previousSampleSize != sampleSize) {
2346                mSamplesHaveSameSize = false;
2347            }
2348            previousSampleSize = sampleSize;
2349        }
2350        ALOGV("%s timestampUs/lastTimestampUs: %" PRId64 "/%" PRId64,
2351                trackName, timestampUs, lastTimestampUs);
2352        lastDurationUs = timestampUs - lastTimestampUs;
2353        lastDurationTicks = currDurationTicks;
2354        lastTimestampUs = timestampUs;
2355
2356        if (isSync != 0) {
2357            addOneStssTableEntry(mStszTableEntries->count());
2358        }
2359
2360        if (mTrackingProgressStatus) {
2361            if (mPreviousTrackTimeUs <= 0) {
2362                mPreviousTrackTimeUs = mStartTimestampUs;
2363            }
2364            trackProgressStatus(timestampUs);
2365        }
2366        if (!hasMultipleTracks) {
2367            off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy)
2368                                 : mOwner->addSample_l(copy);
2369
2370            uint32_t count = (mOwner->use32BitFileOffset()
2371                        ? mStcoTableEntries->count()
2372                        : mCo64TableEntries->count());
2373
2374            if (count == 0) {
2375                addChunkOffset(offset);
2376            }
2377            copy->release();
2378            copy = NULL;
2379            continue;
2380        }
2381
2382        mChunkSamples.push_back(copy);
2383        if (interleaveDurationUs == 0) {
2384            addOneStscTableEntry(++nChunks, 1);
2385            bufferChunk(timestampUs);
2386        } else {
2387            if (chunkTimestampUs == 0) {
2388                chunkTimestampUs = timestampUs;
2389            } else {
2390                int64_t chunkDurationUs = timestampUs - chunkTimestampUs;
2391                if (chunkDurationUs > interleaveDurationUs) {
2392                    if (chunkDurationUs > mMaxChunkDurationUs) {
2393                        mMaxChunkDurationUs = chunkDurationUs;
2394                    }
2395                    ++nChunks;
2396                    if (nChunks == 1 ||  // First chunk
2397                        lastSamplesPerChunk != mChunkSamples.size()) {
2398                        lastSamplesPerChunk = mChunkSamples.size();
2399                        addOneStscTableEntry(nChunks, lastSamplesPerChunk);
2400                    }
2401                    bufferChunk(timestampUs);
2402                    chunkTimestampUs = timestampUs;
2403                }
2404            }
2405        }
2406
2407    }
2408
2409    if (isTrackMalFormed()) {
2410        err = ERROR_MALFORMED;
2411    }
2412
2413    mOwner->trackProgressStatus(mTrackId, -1, err);
2414
2415    // Last chunk
2416    if (!hasMultipleTracks) {
2417        addOneStscTableEntry(1, mStszTableEntries->count());
2418    } else if (!mChunkSamples.empty()) {
2419        addOneStscTableEntry(++nChunks, mChunkSamples.size());
2420        bufferChunk(timestampUs);
2421    }
2422
2423    // We don't really know how long the last frame lasts, since
2424    // there is no frame time after it, just repeat the previous
2425    // frame's duration.
2426    if (mStszTableEntries->count() == 1) {
2427        lastDurationUs = 0;  // A single sample's duration
2428        lastDurationTicks = 0;
2429    } else {
2430        ++sampleCount;  // Count for the last sample
2431    }
2432
2433    if (mStszTableEntries->count() <= 2) {
2434        addOneSttsTableEntry(1, lastDurationTicks);
2435        if (sampleCount - 1 > 0) {
2436            addOneSttsTableEntry(sampleCount - 1, lastDurationTicks);
2437        }
2438    } else {
2439        addOneSttsTableEntry(sampleCount, lastDurationTicks);
2440    }
2441
2442    // The last ctts box may not have been written yet, and this
2443    // is to make sure that we write out the last ctts box.
2444    if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) {
2445        if (cttsSampleCount > 0) {
2446            addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
2447        }
2448    }
2449
2450    mTrackDurationUs += lastDurationUs;
2451    mReachedEOS = true;
2452
2453    sendTrackSummary(hasMultipleTracks);
2454
2455    ALOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s",
2456            count, nZeroLengthFrames, mStszTableEntries->count(), trackName);
2457    if (mIsAudio) {
2458        ALOGI("Audio track drift time: %" PRId64 " us", mOwner->getDriftTimeUs());
2459    }
2460
2461    if (err == ERROR_END_OF_STREAM) {
2462        return OK;
2463    }
2464    return err;
2465}
2466
2467bool MPEG4Writer::Track::isTrackMalFormed() const {
2468    if (mStszTableEntries->count() == 0) {                      // no samples written
2469        ALOGE("The number of recorded samples is 0");
2470        return true;
2471    }
2472
2473    if (!mIsAudio && mStssTableEntries->count() == 0) {  // no sync frames for video
2474        ALOGE("There are no sync frames for video track");
2475        return true;
2476    }
2477
2478    if (OK != checkCodecSpecificData()) {         // no codec specific data
2479        return true;
2480    }
2481
2482    return false;
2483}
2484
2485void MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) {
2486
2487    // Send track summary only if test mode is enabled.
2488    if (!isTestModeEnabled()) {
2489        return;
2490    }
2491
2492    int trackNum = (mTrackId << 28);
2493
2494    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2495                    trackNum | MEDIA_RECORDER_TRACK_INFO_TYPE,
2496                    mIsAudio? 0: 1);
2497
2498    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2499                    trackNum | MEDIA_RECORDER_TRACK_INFO_DURATION_MS,
2500                    mTrackDurationUs / 1000);
2501
2502    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2503                    trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES,
2504                    mStszTableEntries->count());
2505
2506    {
2507        // The system delay time excluding the requested initial delay that
2508        // is used to eliminate the recording sound.
2509        int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL;
2510        if (startTimeOffsetUs < 0) {  // Start time offset was not set
2511            startTimeOffsetUs = kInitialDelayTimeUs;
2512        }
2513        int64_t initialDelayUs =
2514            mFirstSampleTimeRealUs - mStartTimeRealUs - startTimeOffsetUs;
2515
2516        mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2517                    trackNum | MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS,
2518                    (initialDelayUs) / 1000);
2519    }
2520
2521    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2522                    trackNum | MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES,
2523                    mMdatSizeBytes / 1024);
2524
2525    if (hasMultipleTracks) {
2526        mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2527                    trackNum | MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS,
2528                    mMaxChunkDurationUs / 1000);
2529
2530        int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
2531        if (mStartTimestampUs != moovStartTimeUs) {
2532            int64_t startTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
2533            mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2534                    trackNum | MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS,
2535                    startTimeOffsetUs / 1000);
2536        }
2537    }
2538}
2539
2540void MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) {
2541    ALOGV("trackProgressStatus: %" PRId64 " us", timeUs);
2542
2543    if (mTrackEveryTimeDurationUs > 0 &&
2544        timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) {
2545        ALOGV("Fire time tracking progress status at %" PRId64 " us", timeUs);
2546        mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err);
2547        mPreviousTrackTimeUs = timeUs;
2548    }
2549}
2550
2551void MPEG4Writer::trackProgressStatus(
2552        size_t trackId, int64_t timeUs, status_t err) {
2553    Mutex::Autolock lock(mLock);
2554    int32_t trackNum = (trackId << 28);
2555
2556    // Error notification
2557    // Do not consider ERROR_END_OF_STREAM an error
2558    if (err != OK && err != ERROR_END_OF_STREAM) {
2559        notify(MEDIA_RECORDER_TRACK_EVENT_ERROR,
2560               trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL,
2561               err);
2562        return;
2563    }
2564
2565    if (timeUs == -1) {
2566        // Send completion notification
2567        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2568               trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS,
2569               err);
2570    } else {
2571        // Send progress status
2572        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2573               trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME,
2574               timeUs / 1000);
2575    }
2576}
2577
2578void MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) {
2579    ALOGV("setDriftTimeUs: %" PRId64 " us", driftTimeUs);
2580    Mutex::Autolock autolock(mLock);
2581    mDriftTimeUs = driftTimeUs;
2582}
2583
2584int64_t MPEG4Writer::getDriftTimeUs() {
2585    ALOGV("getDriftTimeUs: %" PRId64 " us", mDriftTimeUs);
2586    Mutex::Autolock autolock(mLock);
2587    return mDriftTimeUs;
2588}
2589
2590bool MPEG4Writer::isRealTimeRecording() const {
2591    return mIsRealTimeRecording;
2592}
2593
2594bool MPEG4Writer::useNalLengthFour() {
2595    return mUse4ByteNalLength;
2596}
2597
2598void MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
2599    ALOGV("bufferChunk");
2600
2601    Chunk chunk(this, timestampUs, mChunkSamples);
2602    mOwner->bufferChunk(chunk);
2603    mChunkSamples.clear();
2604}
2605
2606int64_t MPEG4Writer::Track::getDurationUs() const {
2607    return mTrackDurationUs;
2608}
2609
2610int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
2611    return mEstimatedTrackSizeBytes;
2612}
2613
2614status_t MPEG4Writer::Track::checkCodecSpecificData() const {
2615    const char *mime;
2616    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
2617    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) ||
2618        !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
2619        !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2620        if (!mCodecSpecificData ||
2621            mCodecSpecificDataSize <= 0) {
2622            ALOGE("Missing codec specific data");
2623            return ERROR_MALFORMED;
2624        }
2625    } else {
2626        if (mCodecSpecificData ||
2627            mCodecSpecificDataSize > 0) {
2628            ALOGE("Unexepected codec specific data found");
2629            return ERROR_MALFORMED;
2630        }
2631    }
2632    return OK;
2633}
2634
2635void MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) {
2636
2637    ALOGV("%s track time scale: %d",
2638        mIsAudio? "Audio": "Video", mTimeScale);
2639
2640    uint32_t now = getMpeg4Time();
2641    mOwner->beginBox("trak");
2642        writeTkhdBox(now);
2643        mOwner->beginBox("mdia");
2644            writeMdhdBox(now);
2645            writeHdlrBox();
2646            mOwner->beginBox("minf");
2647                if (mIsAudio) {
2648                    writeSmhdBox();
2649                } else {
2650                    writeVmhdBox();
2651                }
2652                writeDinfBox();
2653                writeStblBox(use32BitOffset);
2654            mOwner->endBox();  // minf
2655        mOwner->endBox();  // mdia
2656    mOwner->endBox();  // trak
2657}
2658
2659void MPEG4Writer::Track::writeStblBox(bool use32BitOffset) {
2660    mOwner->beginBox("stbl");
2661    mOwner->beginBox("stsd");
2662    mOwner->writeInt32(0);               // version=0, flags=0
2663    mOwner->writeInt32(1);               // entry count
2664    if (mIsAudio) {
2665        writeAudioFourCCBox();
2666    } else {
2667        writeVideoFourCCBox();
2668    }
2669    mOwner->endBox();  // stsd
2670    writeSttsBox();
2671    writeCttsBox();
2672    if (!mIsAudio) {
2673        writeStssBox();
2674    }
2675    writeStszBox();
2676    writeStscBox();
2677    writeStcoBox(use32BitOffset);
2678    mOwner->endBox();  // stbl
2679}
2680
2681void MPEG4Writer::Track::writeVideoFourCCBox() {
2682    const char *mime;
2683    bool success = mMeta->findCString(kKeyMIMEType, &mime);
2684    CHECK(success);
2685    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2686        mOwner->beginBox("mp4v");
2687    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2688        mOwner->beginBox("s263");
2689    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2690        mOwner->beginBox("avc1");
2691    } else {
2692        ALOGE("Unknown mime type '%s'.", mime);
2693        CHECK(!"should not be here, unknown mime type.");
2694    }
2695
2696    mOwner->writeInt32(0);           // reserved
2697    mOwner->writeInt16(0);           // reserved
2698    mOwner->writeInt16(1);           // data ref index
2699    mOwner->writeInt16(0);           // predefined
2700    mOwner->writeInt16(0);           // reserved
2701    mOwner->writeInt32(0);           // predefined
2702    mOwner->writeInt32(0);           // predefined
2703    mOwner->writeInt32(0);           // predefined
2704
2705    int32_t width, height;
2706    success = mMeta->findInt32(kKeyWidth, &width);
2707    success = success && mMeta->findInt32(kKeyHeight, &height);
2708    CHECK(success);
2709
2710    mOwner->writeInt16(width);
2711    mOwner->writeInt16(height);
2712    mOwner->writeInt32(0x480000);    // horiz resolution
2713    mOwner->writeInt32(0x480000);    // vert resolution
2714    mOwner->writeInt32(0);           // reserved
2715    mOwner->writeInt16(1);           // frame count
2716    mOwner->writeInt8(0);            // compressor string length
2717    mOwner->write("                               ", 31);
2718    mOwner->writeInt16(0x18);        // depth
2719    mOwner->writeInt16(-1);          // predefined
2720
2721    CHECK_LT(23 + mCodecSpecificDataSize, 128);
2722
2723    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2724        writeMp4vEsdsBox();
2725    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2726        writeD263Box();
2727    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2728        writeAvccBox();
2729    }
2730
2731    writePaspBox();
2732    mOwner->endBox();  // mp4v, s263 or avc1
2733}
2734
2735void MPEG4Writer::Track::writeAudioFourCCBox() {
2736    const char *mime;
2737    bool success = mMeta->findCString(kKeyMIMEType, &mime);
2738    CHECK(success);
2739    const char *fourcc = NULL;
2740    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
2741        fourcc = "samr";
2742    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2743        fourcc = "sawb";
2744    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2745        fourcc = "mp4a";
2746    } else {
2747        ALOGE("Unknown mime type '%s'.", mime);
2748        CHECK(!"should not be here, unknown mime type.");
2749    }
2750
2751    mOwner->beginBox(fourcc);        // audio format
2752    mOwner->writeInt32(0);           // reserved
2753    mOwner->writeInt16(0);           // reserved
2754    mOwner->writeInt16(0x1);         // data ref index
2755    mOwner->writeInt32(0);           // reserved
2756    mOwner->writeInt32(0);           // reserved
2757    int32_t nChannels;
2758    CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels));
2759    mOwner->writeInt16(nChannels);   // channel count
2760    mOwner->writeInt16(16);          // sample size
2761    mOwner->writeInt16(0);           // predefined
2762    mOwner->writeInt16(0);           // reserved
2763
2764    int32_t samplerate;
2765    success = mMeta->findInt32(kKeySampleRate, &samplerate);
2766    CHECK(success);
2767    mOwner->writeInt32(samplerate << 16);
2768    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2769        writeMp4aEsdsBox();
2770    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) ||
2771               !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2772        writeDamrBox();
2773    }
2774    mOwner->endBox();
2775}
2776
2777void MPEG4Writer::Track::writeMp4aEsdsBox() {
2778    mOwner->beginBox("esds");
2779    CHECK(mCodecSpecificData);
2780    CHECK_GT(mCodecSpecificDataSize, 0);
2781
2782    // Make sure all sizes encode to a single byte.
2783    CHECK_LT(mCodecSpecificDataSize + 23, 128);
2784
2785    mOwner->writeInt32(0);     // version=0, flags=0
2786    mOwner->writeInt8(0x03);   // ES_DescrTag
2787    mOwner->writeInt8(23 + mCodecSpecificDataSize);
2788    mOwner->writeInt16(0x0000);// ES_ID
2789    mOwner->writeInt8(0x00);
2790
2791    mOwner->writeInt8(0x04);   // DecoderConfigDescrTag
2792    mOwner->writeInt8(15 + mCodecSpecificDataSize);
2793    mOwner->writeInt8(0x40);   // objectTypeIndication ISO/IEC 14492-2
2794    mOwner->writeInt8(0x15);   // streamType AudioStream
2795
2796    mOwner->writeInt16(0x03);  // XXX
2797    mOwner->writeInt8(0x00);   // buffer size 24-bit
2798    mOwner->writeInt32(96000); // max bit rate
2799    mOwner->writeInt32(96000); // avg bit rate
2800
2801    mOwner->writeInt8(0x05);   // DecoderSpecificInfoTag
2802    mOwner->writeInt8(mCodecSpecificDataSize);
2803    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2804
2805    static const uint8_t kData2[] = {
2806        0x06,  // SLConfigDescriptorTag
2807        0x01,
2808        0x02
2809    };
2810    mOwner->write(kData2, sizeof(kData2));
2811
2812    mOwner->endBox();  // esds
2813}
2814
2815void MPEG4Writer::Track::writeMp4vEsdsBox() {
2816    CHECK(mCodecSpecificData);
2817    CHECK_GT(mCodecSpecificDataSize, 0);
2818    mOwner->beginBox("esds");
2819
2820    mOwner->writeInt32(0);    // version=0, flags=0
2821
2822    mOwner->writeInt8(0x03);  // ES_DescrTag
2823    mOwner->writeInt8(23 + mCodecSpecificDataSize);
2824    mOwner->writeInt16(0x0000);  // ES_ID
2825    mOwner->writeInt8(0x1f);
2826
2827    mOwner->writeInt8(0x04);  // DecoderConfigDescrTag
2828    mOwner->writeInt8(15 + mCodecSpecificDataSize);
2829    mOwner->writeInt8(0x20);  // objectTypeIndication ISO/IEC 14492-2
2830    mOwner->writeInt8(0x11);  // streamType VisualStream
2831
2832    static const uint8_t kData[] = {
2833        0x01, 0x77, 0x00,
2834        0x00, 0x03, 0xe8, 0x00,
2835        0x00, 0x03, 0xe8, 0x00
2836    };
2837    mOwner->write(kData, sizeof(kData));
2838
2839    mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
2840
2841    mOwner->writeInt8(mCodecSpecificDataSize);
2842    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2843
2844    static const uint8_t kData2[] = {
2845        0x06,  // SLConfigDescriptorTag
2846        0x01,
2847        0x02
2848    };
2849    mOwner->write(kData2, sizeof(kData2));
2850
2851    mOwner->endBox();  // esds
2852}
2853
2854void MPEG4Writer::Track::writeTkhdBox(uint32_t now) {
2855    mOwner->beginBox("tkhd");
2856    // Flags = 7 to indicate that the track is enabled, and
2857    // part of the presentation
2858    mOwner->writeInt32(0x07);          // version=0, flags=7
2859    mOwner->writeInt32(now);           // creation time
2860    mOwner->writeInt32(now);           // modification time
2861    mOwner->writeInt32(mTrackId);      // track id starts with 1
2862    mOwner->writeInt32(0);             // reserved
2863    int64_t trakDurationUs = getDurationUs();
2864    int32_t mvhdTimeScale = mOwner->getTimeScale();
2865    int32_t tkhdDuration =
2866        (trakDurationUs * mvhdTimeScale + 5E5) / 1E6;
2867    mOwner->writeInt32(tkhdDuration);  // in mvhd timescale
2868    mOwner->writeInt32(0);             // reserved
2869    mOwner->writeInt32(0);             // reserved
2870    mOwner->writeInt16(0);             // layer
2871    mOwner->writeInt16(0);             // alternate group
2872    mOwner->writeInt16(mIsAudio ? 0x100 : 0);  // volume
2873    mOwner->writeInt16(0);             // reserved
2874
2875    mOwner->writeCompositionMatrix(mRotation);       // matrix
2876
2877    if (mIsAudio) {
2878        mOwner->writeInt32(0);
2879        mOwner->writeInt32(0);
2880    } else {
2881        int32_t width, height;
2882        bool success = mMeta->findInt32(kKeyWidth, &width);
2883        success = success && mMeta->findInt32(kKeyHeight, &height);
2884        CHECK(success);
2885
2886        mOwner->writeInt32(width << 16);   // 32-bit fixed-point value
2887        mOwner->writeInt32(height << 16);  // 32-bit fixed-point value
2888    }
2889    mOwner->endBox();  // tkhd
2890}
2891
2892void MPEG4Writer::Track::writeVmhdBox() {
2893    mOwner->beginBox("vmhd");
2894    mOwner->writeInt32(0x01);        // version=0, flags=1
2895    mOwner->writeInt16(0);           // graphics mode
2896    mOwner->writeInt16(0);           // opcolor
2897    mOwner->writeInt16(0);
2898    mOwner->writeInt16(0);
2899    mOwner->endBox();
2900}
2901
2902void MPEG4Writer::Track::writeSmhdBox() {
2903    mOwner->beginBox("smhd");
2904    mOwner->writeInt32(0);           // version=0, flags=0
2905    mOwner->writeInt16(0);           // balance
2906    mOwner->writeInt16(0);           // reserved
2907    mOwner->endBox();
2908}
2909
2910void MPEG4Writer::Track::writeHdlrBox() {
2911    mOwner->beginBox("hdlr");
2912    mOwner->writeInt32(0);             // version=0, flags=0
2913    mOwner->writeInt32(0);             // component type: should be mhlr
2914    mOwner->writeFourcc(mIsAudio ? "soun" : "vide");  // component subtype
2915    mOwner->writeInt32(0);             // reserved
2916    mOwner->writeInt32(0);             // reserved
2917    mOwner->writeInt32(0);             // reserved
2918    // Removing "r" for the name string just makes the string 4 byte aligned
2919    mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle");  // name
2920    mOwner->endBox();
2921}
2922
2923void MPEG4Writer::Track::writeMdhdBox(uint32_t now) {
2924    int64_t trakDurationUs = getDurationUs();
2925    mOwner->beginBox("mdhd");
2926    mOwner->writeInt32(0);             // version=0, flags=0
2927    mOwner->writeInt32(now);           // creation time
2928    mOwner->writeInt32(now);           // modification time
2929    mOwner->writeInt32(mTimeScale);    // media timescale
2930    int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6;
2931    mOwner->writeInt32(mdhdDuration);  // use media timescale
2932    // Language follows the three letter standard ISO-639-2/T
2933    // 'e', 'n', 'g' for "English", for instance.
2934    // Each character is packed as the difference between its ASCII value and 0x60.
2935    // For "English", these are 00101, 01110, 00111.
2936    // XXX: Where is the padding bit located: 0x15C7?
2937    mOwner->writeInt16(0);             // language code
2938    mOwner->writeInt16(0);             // predefined
2939    mOwner->endBox();
2940}
2941
2942void MPEG4Writer::Track::writeDamrBox() {
2943    // 3gpp2 Spec AMRSampleEntry fields
2944    mOwner->beginBox("damr");
2945    mOwner->writeCString("   ");  // vendor: 4 bytes
2946    mOwner->writeInt8(0);         // decoder version
2947    mOwner->writeInt16(0x83FF);   // mode set: all enabled
2948    mOwner->writeInt8(0);         // mode change period
2949    mOwner->writeInt8(1);         // frames per sample
2950    mOwner->endBox();
2951}
2952
2953void MPEG4Writer::Track::writeUrlBox() {
2954    // The table index here refers to the sample description index
2955    // in the sample table entries.
2956    mOwner->beginBox("url ");
2957    mOwner->writeInt32(1);  // version=0, flags=1 (self-contained)
2958    mOwner->endBox();  // url
2959}
2960
2961void MPEG4Writer::Track::writeDrefBox() {
2962    mOwner->beginBox("dref");
2963    mOwner->writeInt32(0);  // version=0, flags=0
2964    mOwner->writeInt32(1);  // entry count (either url or urn)
2965    writeUrlBox();
2966    mOwner->endBox();  // dref
2967}
2968
2969void MPEG4Writer::Track::writeDinfBox() {
2970    mOwner->beginBox("dinf");
2971    writeDrefBox();
2972    mOwner->endBox();  // dinf
2973}
2974
2975void MPEG4Writer::Track::writeAvccBox() {
2976    CHECK(mCodecSpecificData);
2977    CHECK_GE(mCodecSpecificDataSize, 5);
2978
2979    // Patch avcc's lengthSize field to match the number
2980    // of bytes we use to indicate the size of a nal unit.
2981    uint8_t *ptr = (uint8_t *)mCodecSpecificData;
2982    ptr[4] = (ptr[4] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1);
2983    mOwner->beginBox("avcC");
2984    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2985    mOwner->endBox();  // avcC
2986}
2987
2988void MPEG4Writer::Track::writeD263Box() {
2989    mOwner->beginBox("d263");
2990    mOwner->writeInt32(0);  // vendor
2991    mOwner->writeInt8(0);   // decoder version
2992    mOwner->writeInt8(10);  // level: 10
2993    mOwner->writeInt8(0);   // profile: 0
2994    mOwner->endBox();  // d263
2995}
2996
2997// This is useful if the pixel is not square
2998void MPEG4Writer::Track::writePaspBox() {
2999    mOwner->beginBox("pasp");
3000    mOwner->writeInt32(1 << 16);  // hspacing
3001    mOwner->writeInt32(1 << 16);  // vspacing
3002    mOwner->endBox();  // pasp
3003}
3004
3005int32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const {
3006    int64_t trackStartTimeOffsetUs = 0;
3007    int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
3008    if (mStartTimestampUs != moovStartTimeUs) {
3009        CHECK_GT(mStartTimestampUs, moovStartTimeUs);
3010        trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
3011    }
3012    return (trackStartTimeOffsetUs *  mTimeScale + 500000LL) / 1000000LL;
3013}
3014
3015void MPEG4Writer::Track::writeSttsBox() {
3016    mOwner->beginBox("stts");
3017    mOwner->writeInt32(0);  // version=0, flags=0
3018    uint32_t duration;
3019    CHECK(mSttsTableEntries->get(duration, 1));
3020    duration = htonl(duration);  // Back to host byte order
3021    mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1);
3022    mSttsTableEntries->write(mOwner);
3023    mOwner->endBox();  // stts
3024}
3025
3026void MPEG4Writer::Track::writeCttsBox() {
3027    if (mIsAudio) {  // ctts is not for audio
3028        return;
3029    }
3030
3031    // There is no B frame at all
3032    if (mMinCttsOffsetTimeUs == mMaxCttsOffsetTimeUs) {
3033        return;
3034    }
3035
3036    // Do not write ctts box when there is no need to have it.
3037    if (mCttsTableEntries->count() == 0) {
3038        return;
3039    }
3040
3041    ALOGV("ctts box has %d entries with range [%" PRId64 ", %" PRId64 "]",
3042            mCttsTableEntries->count(), mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs);
3043
3044    mOwner->beginBox("ctts");
3045    mOwner->writeInt32(0);  // version=0, flags=0
3046    uint32_t duration;
3047    CHECK(mCttsTableEntries->get(duration, 1));
3048    duration = htonl(duration);  // Back host byte order
3049    mCttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime() - mMinCttsOffsetTimeUs), 1);
3050    mCttsTableEntries->write(mOwner);
3051    mOwner->endBox();  // ctts
3052}
3053
3054void MPEG4Writer::Track::writeStssBox() {
3055    mOwner->beginBox("stss");
3056    mOwner->writeInt32(0);  // version=0, flags=0
3057    mStssTableEntries->write(mOwner);
3058    mOwner->endBox();  // stss
3059}
3060
3061void MPEG4Writer::Track::writeStszBox() {
3062    mOwner->beginBox("stsz");
3063    mOwner->writeInt32(0);  // version=0, flags=0
3064    mOwner->writeInt32(0);
3065    mStszTableEntries->write(mOwner);
3066    mOwner->endBox();  // stsz
3067}
3068
3069void MPEG4Writer::Track::writeStscBox() {
3070    mOwner->beginBox("stsc");
3071    mOwner->writeInt32(0);  // version=0, flags=0
3072    mStscTableEntries->write(mOwner);
3073    mOwner->endBox();  // stsc
3074}
3075
3076void MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) {
3077    mOwner->beginBox(use32BitOffset? "stco": "co64");
3078    mOwner->writeInt32(0);  // version=0, flags=0
3079    if (use32BitOffset) {
3080        mStcoTableEntries->write(mOwner);
3081    } else {
3082        mCo64TableEntries->write(mOwner);
3083    }
3084    mOwner->endBox();  // stco or co64
3085}
3086
3087void MPEG4Writer::writeUdtaBox() {
3088    beginBox("udta");
3089    writeGeoDataBox();
3090    endBox();
3091}
3092
3093void MPEG4Writer::writeHdlr() {
3094    beginBox("hdlr");
3095    writeInt32(0); // Version, Flags
3096    writeInt32(0); // Predefined
3097    writeFourcc("mdta");
3098    writeInt32(0); // Reserved[0]
3099    writeInt32(0); // Reserved[1]
3100    writeInt32(0); // Reserved[2]
3101    writeInt8(0);  // Name (empty)
3102    endBox();
3103}
3104
3105void MPEG4Writer::writeKeys() {
3106    size_t count = mMetaKeys->countEntries();
3107
3108    beginBox("keys");
3109    writeInt32(0);     // Version, Flags
3110    writeInt32(count); // Entry_count
3111    for (size_t i = 0; i < count; i++) {
3112        AMessage::Type type;
3113        const char *key = mMetaKeys->getEntryNameAt(i, &type);
3114        size_t n = strlen(key);
3115        writeInt32(n + 8);
3116        writeFourcc("mdta");
3117        write(key, n); // write without the \0
3118    }
3119    endBox();
3120}
3121
3122void MPEG4Writer::writeIlst() {
3123    size_t count = mMetaKeys->countEntries();
3124
3125    // meta data key types
3126    static const int32_t kKeyType_BE32Float = 23;
3127    static const int32_t kKeyType_BE32SignedInteger = 67;
3128    static const int32_t kKeyType_BE32UnsignedInteger = 77;
3129
3130    beginBox("ilst");
3131    for (size_t i = 0; i < count; i++) {
3132        beginBox(i + 1); // key id (1-based)
3133        beginBox("data");
3134        AMessage::Type type;
3135        const char *key = mMetaKeys->getEntryNameAt(i, &type);
3136        switch (type) {
3137            case AMessage::kTypeFloat:
3138            {
3139                float val;
3140                CHECK(mMetaKeys->findFloat(key, &val));
3141                writeInt32(kKeyType_BE32Float);
3142                writeInt32(*reinterpret_cast<int32_t *>(&val));
3143                break;
3144            }
3145
3146            case AMessage::kTypeInt32:
3147            {
3148                int32_t val;
3149                CHECK(mMetaKeys->findInt32(key, &val));
3150                writeInt32(kKeyType_BE32SignedInteger);
3151                writeInt32(val);
3152                break;
3153            }
3154
3155            default:
3156            {
3157                ALOGW("Unsupported key type, writing 0 instead");
3158                writeInt32(kKeyType_BE32UnsignedInteger);
3159                writeInt32(0);
3160                break;
3161            }
3162        }
3163        endBox(); // data
3164        endBox(); // key id
3165    }
3166    endBox(); // ilst
3167}
3168
3169void MPEG4Writer::writeMetaBox() {
3170    size_t count = mMetaKeys->countEntries();
3171    if (count == 0) {
3172        return;
3173    }
3174
3175    beginBox("meta");
3176    writeHdlr();
3177    writeKeys();
3178    writeIlst();
3179    endBox();
3180}
3181
3182
3183/*
3184 * Geodata is stored according to ISO-6709 standard.
3185 */
3186void MPEG4Writer::writeGeoDataBox() {
3187    beginBox("\xA9xyz");
3188    /*
3189     * For historical reasons, any user data start
3190     * with "\0xA9", must be followed by its assoicated
3191     * language code.
3192     * 0x0012: text string length
3193     * 0x15c7: lang (locale) code: en
3194     */
3195    writeInt32(0x001215c7);
3196    writeLatitude(mLatitudex10000);
3197    writeLongitude(mLongitudex10000);
3198    writeInt8(0x2F);
3199    endBox();
3200}
3201
3202}  // namespace android
3203