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