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