MPEG4Writer.cpp revision 7c4820d23b68f748b8dfff3d4bb5b13e9d4811a8
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}
845
846status_t MPEG4Writer::reset() {
847    if (mInitCheck != OK) {
848        return OK;
849    } else {
850        if (!mWriterThreadStarted ||
851            !mStarted) {
852            if (mWriterThreadStarted) {
853                stopWriterThread();
854            }
855            release();
856            return OK;
857        }
858    }
859
860    status_t err = OK;
861    int64_t maxDurationUs = 0;
862    int64_t minDurationUs = 0x7fffffffffffffffLL;
863    for (List<Track *>::iterator it = mTracks.begin();
864         it != mTracks.end(); ++it) {
865        status_t status = (*it)->stop();
866        if (err == OK && status != OK) {
867            err = status;
868        }
869
870        int64_t durationUs = (*it)->getDurationUs();
871        if (durationUs > maxDurationUs) {
872            maxDurationUs = durationUs;
873        }
874        if (durationUs < minDurationUs) {
875            minDurationUs = durationUs;
876        }
877    }
878
879    if (mTracks.size() > 1) {
880        ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us",
881            minDurationUs, maxDurationUs);
882    }
883
884    stopWriterThread();
885
886    // Do not write out movie header on error.
887    if (err != OK) {
888        release();
889        return err;
890    }
891
892    // Fix up the size of the 'mdat' chunk.
893    if (mUse32BitOffset) {
894        lseek64(mFd, mMdatOffset, SEEK_SET);
895        uint32_t size = htonl(static_cast<uint32_t>(mOffset - mMdatOffset));
896        ::write(mFd, &size, 4);
897    } else {
898        lseek64(mFd, mMdatOffset + 8, SEEK_SET);
899        uint64_t size = mOffset - mMdatOffset;
900        size = hton64(size);
901        ::write(mFd, &size, 8);
902    }
903    lseek64(mFd, mOffset, SEEK_SET);
904
905    // Construct moov box now
906    mMoovBoxBufferOffset = 0;
907    mWriteMoovBoxToMemory = mStreamableFile;
908    if (mWriteMoovBoxToMemory) {
909        // There is no need to allocate in-memory cache
910        // for moov box if the file is not streamable.
911
912        mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
913        CHECK(mMoovBoxBuffer != NULL);
914    }
915    writeMoovBox(maxDurationUs);
916
917    // mWriteMoovBoxToMemory could be set to false in
918    // MPEG4Writer::write() method
919    if (mWriteMoovBoxToMemory) {
920        mWriteMoovBoxToMemory = false;
921        // Content of the moov box is saved in the cache, and the in-memory
922        // moov box needs to be written to the file in a single shot.
923
924        CHECK_LE(mMoovBoxBufferOffset + 8, mEstimatedMoovBoxSize);
925
926        // Moov box
927        lseek64(mFd, mFreeBoxOffset, SEEK_SET);
928        mOffset = mFreeBoxOffset;
929        write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset);
930
931        // Free box
932        lseek64(mFd, mOffset, SEEK_SET);
933        writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset);
934        write("free", 4);
935    } else {
936        ALOGI("The mp4 file will not be streamable.");
937    }
938
939    // Free in-memory cache for moov box
940    if (mMoovBoxBuffer != NULL) {
941        free(mMoovBoxBuffer);
942        mMoovBoxBuffer = NULL;
943        mMoovBoxBufferOffset = 0;
944    }
945
946    CHECK(mBoxes.empty());
947
948    release();
949    return err;
950}
951
952uint32_t MPEG4Writer::getMpeg4Time() {
953    time_t now = time(NULL);
954    // MP4 file uses time counting seconds since midnight, Jan. 1, 1904
955    // while time function returns Unix epoch values which starts
956    // at 1970-01-01. Lets add the number of seconds between them
957    uint32_t mpeg4Time = now + (66 * 365 + 17) * (24 * 60 * 60);
958    return mpeg4Time;
959}
960
961void MPEG4Writer::writeMvhdBox(int64_t durationUs) {
962    uint32_t now = getMpeg4Time();
963    beginBox("mvhd");
964    writeInt32(0);             // version=0, flags=0
965    writeInt32(now);           // creation time
966    writeInt32(now);           // modification time
967    writeInt32(mTimeScale);    // mvhd timescale
968    int32_t duration = (durationUs * mTimeScale + 5E5) / 1E6;
969    writeInt32(duration);
970    writeInt32(0x10000);       // rate: 1.0
971    writeInt16(0x100);         // volume
972    writeInt16(0);             // reserved
973    writeInt32(0);             // reserved
974    writeInt32(0);             // reserved
975    writeCompositionMatrix(0); // matrix
976    writeInt32(0);             // predefined
977    writeInt32(0);             // predefined
978    writeInt32(0);             // predefined
979    writeInt32(0);             // predefined
980    writeInt32(0);             // predefined
981    writeInt32(0);             // predefined
982    writeInt32(mTracks.size() + 1);  // nextTrackID
983    endBox();  // mvhd
984}
985
986void MPEG4Writer::writeMoovBox(int64_t durationUs) {
987    beginBox("moov");
988    writeMvhdBox(durationUs);
989    if (mAreGeoTagsAvailable) {
990        writeUdtaBox();
991    }
992    writeMetaBox();
993    int32_t id = 1;
994    for (List<Track *>::iterator it = mTracks.begin();
995        it != mTracks.end(); ++it, ++id) {
996        (*it)->writeTrackHeader(mUse32BitOffset);
997    }
998    endBox();  // moov
999}
1000
1001void MPEG4Writer::writeFtypBox(MetaData *param) {
1002    beginBox("ftyp");
1003
1004    int32_t fileType;
1005    if (param && param->findInt32(kKeyFileType, &fileType) &&
1006        fileType != OUTPUT_FORMAT_MPEG_4) {
1007        writeFourcc("3gp4");
1008        writeInt32(0);
1009        writeFourcc("isom");
1010        writeFourcc("3gp4");
1011    } else {
1012        writeFourcc("mp42");
1013        writeInt32(0);
1014        writeFourcc("isom");
1015        writeFourcc("mp42");
1016    }
1017
1018    endBox();
1019}
1020
1021static bool isTestModeEnabled() {
1022#if (PROPERTY_VALUE_MAX < 5)
1023#error "PROPERTY_VALUE_MAX must be at least 5"
1024#endif
1025
1026    // Test mode is enabled only if rw.media.record.test system
1027    // property is enabled.
1028    char value[PROPERTY_VALUE_MAX];
1029    if (property_get("rw.media.record.test", value, NULL) &&
1030        (!strcasecmp(value, "true") || !strcasecmp(value, "1"))) {
1031        return true;
1032    }
1033    return false;
1034}
1035
1036void MPEG4Writer::sendSessionSummary() {
1037    // Send session summary only if test mode is enabled
1038    if (!isTestModeEnabled()) {
1039        return;
1040    }
1041
1042    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
1043         it != mChunkInfos.end(); ++it) {
1044        int trackNum = it->mTrack->getTrackId() << 28;
1045        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
1046                trackNum | MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS,
1047                it->mMaxInterChunkDurUs);
1048    }
1049}
1050
1051status_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) {
1052    mInterleaveDurationUs = durationUs;
1053    return OK;
1054}
1055
1056void MPEG4Writer::lock() {
1057    mLock.lock();
1058}
1059
1060void MPEG4Writer::unlock() {
1061    mLock.unlock();
1062}
1063
1064off64_t MPEG4Writer::addSample_l(MediaBuffer *buffer) {
1065    off64_t old_offset = mOffset;
1066
1067    ::write(mFd,
1068          (const uint8_t *)buffer->data() + buffer->range_offset(),
1069          buffer->range_length());
1070
1071    mOffset += buffer->range_length();
1072
1073    return old_offset;
1074}
1075
1076static void StripStartcode(MediaBuffer *buffer) {
1077    if (buffer->range_length() < 4) {
1078        return;
1079    }
1080
1081    const uint8_t *ptr =
1082        (const uint8_t *)buffer->data() + buffer->range_offset();
1083
1084    if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
1085        buffer->set_range(
1086                buffer->range_offset() + 4, buffer->range_length() - 4);
1087    }
1088}
1089
1090off64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
1091    off64_t old_offset = mOffset;
1092
1093    size_t length = buffer->range_length();
1094
1095    if (mUse4ByteNalLength) {
1096        uint8_t x = length >> 24;
1097        ::write(mFd, &x, 1);
1098        x = (length >> 16) & 0xff;
1099        ::write(mFd, &x, 1);
1100        x = (length >> 8) & 0xff;
1101        ::write(mFd, &x, 1);
1102        x = length & 0xff;
1103        ::write(mFd, &x, 1);
1104
1105        ::write(mFd,
1106              (const uint8_t *)buffer->data() + buffer->range_offset(),
1107              length);
1108
1109        mOffset += length + 4;
1110    } else {
1111        CHECK_LT(length, 65536);
1112
1113        uint8_t x = length >> 8;
1114        ::write(mFd, &x, 1);
1115        x = length & 0xff;
1116        ::write(mFd, &x, 1);
1117        ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length);
1118        mOffset += length + 2;
1119    }
1120
1121    return old_offset;
1122}
1123
1124size_t MPEG4Writer::write(
1125        const void *ptr, size_t size, size_t nmemb) {
1126
1127    const size_t bytes = size * nmemb;
1128    if (mWriteMoovBoxToMemory) {
1129
1130        off64_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes;
1131        if (moovBoxSize > mEstimatedMoovBoxSize) {
1132            // The reserved moov box at the beginning of the file
1133            // is not big enough. Moov box should be written to
1134            // the end of the file from now on, but not to the
1135            // in-memory cache.
1136
1137            // We write partial moov box that is in the memory to
1138            // the file first.
1139            for (List<off64_t>::iterator it = mBoxes.begin();
1140                 it != mBoxes.end(); ++it) {
1141                (*it) += mOffset;
1142            }
1143            lseek64(mFd, mOffset, SEEK_SET);
1144            ::write(mFd, mMoovBoxBuffer, mMoovBoxBufferOffset);
1145            ::write(mFd, ptr, bytes);
1146            mOffset += (bytes + mMoovBoxBufferOffset);
1147
1148            // All subsequent moov box content will be written
1149            // to the end of the file.
1150            mWriteMoovBoxToMemory = false;
1151        } else {
1152            memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes);
1153            mMoovBoxBufferOffset += bytes;
1154        }
1155    } else {
1156        ::write(mFd, ptr, size * nmemb);
1157        mOffset += bytes;
1158    }
1159    return bytes;
1160}
1161
1162void MPEG4Writer::beginBox(uint32_t id) {
1163    mBoxes.push_back(mWriteMoovBoxToMemory?
1164            mMoovBoxBufferOffset: mOffset);
1165
1166    writeInt32(0);
1167    writeInt32(id);
1168}
1169
1170void MPEG4Writer::beginBox(const char *fourcc) {
1171    CHECK_EQ(strlen(fourcc), 4);
1172
1173    mBoxes.push_back(mWriteMoovBoxToMemory?
1174            mMoovBoxBufferOffset: mOffset);
1175
1176    writeInt32(0);
1177    writeFourcc(fourcc);
1178}
1179
1180void MPEG4Writer::endBox() {
1181    CHECK(!mBoxes.empty());
1182
1183    off64_t offset = *--mBoxes.end();
1184    mBoxes.erase(--mBoxes.end());
1185
1186    if (mWriteMoovBoxToMemory) {
1187       int32_t x = htonl(mMoovBoxBufferOffset - offset);
1188       memcpy(mMoovBoxBuffer + offset, &x, 4);
1189    } else {
1190        lseek64(mFd, offset, SEEK_SET);
1191        writeInt32(mOffset - offset);
1192        mOffset -= 4;
1193        lseek64(mFd, mOffset, SEEK_SET);
1194    }
1195}
1196
1197void MPEG4Writer::writeInt8(int8_t x) {
1198    write(&x, 1, 1);
1199}
1200
1201void MPEG4Writer::writeInt16(int16_t x) {
1202    x = htons(x);
1203    write(&x, 1, 2);
1204}
1205
1206void MPEG4Writer::writeInt32(int32_t x) {
1207    x = htonl(x);
1208    write(&x, 1, 4);
1209}
1210
1211void MPEG4Writer::writeInt64(int64_t x) {
1212    x = hton64(x);
1213    write(&x, 1, 8);
1214}
1215
1216void MPEG4Writer::writeCString(const char *s) {
1217    size_t n = strlen(s);
1218    write(s, 1, n + 1);
1219}
1220
1221void MPEG4Writer::writeFourcc(const char *s) {
1222    CHECK_EQ(strlen(s), 4);
1223    write(s, 1, 4);
1224}
1225
1226
1227// Written in +/-DD.DDDD format
1228void MPEG4Writer::writeLatitude(int degreex10000) {
1229    bool isNegative = (degreex10000 < 0);
1230    char sign = isNegative? '-': '+';
1231
1232    // Handle the whole part
1233    char str[9];
1234    int wholePart = degreex10000 / 10000;
1235    if (wholePart == 0) {
1236        snprintf(str, 5, "%c%.2d.", sign, wholePart);
1237    } else {
1238        snprintf(str, 5, "%+.2d.", wholePart);
1239    }
1240
1241    // Handle the fractional part
1242    int fractionalPart = degreex10000 - (wholePart * 10000);
1243    if (fractionalPart < 0) {
1244        fractionalPart = -fractionalPart;
1245    }
1246    snprintf(&str[4], 5, "%.4d", fractionalPart);
1247
1248    // Do not write the null terminator
1249    write(str, 1, 8);
1250}
1251
1252// Written in +/- DDD.DDDD format
1253void MPEG4Writer::writeLongitude(int degreex10000) {
1254    bool isNegative = (degreex10000 < 0);
1255    char sign = isNegative? '-': '+';
1256
1257    // Handle the whole part
1258    char str[10];
1259    int wholePart = degreex10000 / 10000;
1260    if (wholePart == 0) {
1261        snprintf(str, 6, "%c%.3d.", sign, wholePart);
1262    } else {
1263        snprintf(str, 6, "%+.3d.", wholePart);
1264    }
1265
1266    // Handle the fractional part
1267    int fractionalPart = degreex10000 - (wholePart * 10000);
1268    if (fractionalPart < 0) {
1269        fractionalPart = -fractionalPart;
1270    }
1271    snprintf(&str[5], 5, "%.4d", fractionalPart);
1272
1273    // Do not write the null terminator
1274    write(str, 1, 9);
1275}
1276
1277/*
1278 * Geodata is stored according to ISO-6709 standard.
1279 * latitudex10000 is latitude in degrees times 10000, and
1280 * longitudex10000 is longitude in degrees times 10000.
1281 * The range for the latitude is in [-90, +90], and
1282 * The range for the longitude is in [-180, +180]
1283 */
1284status_t MPEG4Writer::setGeoData(int latitudex10000, int longitudex10000) {
1285    // Is latitude or longitude out of range?
1286    if (latitudex10000 < -900000 || latitudex10000 > 900000 ||
1287        longitudex10000 < -1800000 || longitudex10000 > 1800000) {
1288        return BAD_VALUE;
1289    }
1290
1291    mLatitudex10000 = latitudex10000;
1292    mLongitudex10000 = longitudex10000;
1293    mAreGeoTagsAvailable = true;
1294    mMoovExtraSize += 30;
1295    return OK;
1296}
1297
1298status_t MPEG4Writer::setCaptureRate(float captureFps) {
1299    if (captureFps <= 0.0f) {
1300        return BAD_VALUE;
1301    }
1302
1303    mMetaKeys->setFloat(kMetaKey_CaptureFps, captureFps);
1304    mMoovExtraSize += sizeof(kMetaKey_CaptureFps) + 4 + 32;
1305
1306    return OK;
1307}
1308
1309void MPEG4Writer::write(const void *data, size_t size) {
1310    write(data, 1, size);
1311}
1312
1313bool MPEG4Writer::isFileStreamable() const {
1314    return mStreamableFile;
1315}
1316
1317bool MPEG4Writer::exceedsFileSizeLimit() {
1318    // No limit
1319    if (mMaxFileSizeLimitBytes == 0) {
1320        return false;
1321    }
1322
1323    int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize);
1324    for (List<Track *>::iterator it = mTracks.begin();
1325         it != mTracks.end(); ++it) {
1326        nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
1327    }
1328
1329    if (!mStreamableFile) {
1330        // Add 1024 bytes as error tolerance
1331        return nTotalBytesEstimate + 1024 >= mMaxFileSizeLimitBytes;
1332    }
1333    // Be conservative in the estimate: do not exceed 95% of
1334    // the target file limit. For small target file size limit, though,
1335    // this will not help.
1336    return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100);
1337}
1338
1339bool MPEG4Writer::exceedsFileDurationLimit() {
1340    // No limit
1341    if (mMaxFileDurationLimitUs == 0) {
1342        return false;
1343    }
1344
1345    for (List<Track *>::iterator it = mTracks.begin();
1346         it != mTracks.end(); ++it) {
1347        if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) {
1348            return true;
1349        }
1350    }
1351    return false;
1352}
1353
1354bool MPEG4Writer::reachedEOS() {
1355    bool allDone = true;
1356    for (List<Track *>::iterator it = mTracks.begin();
1357         it != mTracks.end(); ++it) {
1358        if (!(*it)->reachedEOS()) {
1359            allDone = false;
1360            break;
1361        }
1362    }
1363
1364    return allDone;
1365}
1366
1367void MPEG4Writer::setStartTimestampUs(int64_t timeUs) {
1368    ALOGI("setStartTimestampUs: %" PRId64, timeUs);
1369    CHECK_GE(timeUs, 0ll);
1370    Mutex::Autolock autoLock(mLock);
1371    if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) {
1372        mStartTimestampUs = timeUs;
1373        ALOGI("Earliest track starting time: %" PRId64, mStartTimestampUs);
1374    }
1375}
1376
1377int64_t MPEG4Writer::getStartTimestampUs() {
1378    Mutex::Autolock autoLock(mLock);
1379    return mStartTimestampUs;
1380}
1381
1382size_t MPEG4Writer::numTracks() {
1383    Mutex::Autolock autolock(mLock);
1384    return mTracks.size();
1385}
1386
1387////////////////////////////////////////////////////////////////////////////////
1388
1389MPEG4Writer::Track::Track(
1390        MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId)
1391    : mOwner(owner),
1392      mMeta(source->getFormat()),
1393      mSource(source),
1394      mDone(false),
1395      mPaused(false),
1396      mResumed(false),
1397      mStarted(false),
1398      mTrackId(trackId),
1399      mTrackDurationUs(0),
1400      mEstimatedTrackSizeBytes(0),
1401      mSamplesHaveSameSize(true),
1402      mStszTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
1403      mStcoTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
1404      mCo64TableEntries(new ListTableEntries<off64_t>(1000, 1)),
1405      mStscTableEntries(new ListTableEntries<uint32_t>(1000, 3)),
1406      mStssTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
1407      mSttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)),
1408      mCttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)),
1409      mCodecSpecificData(NULL),
1410      mCodecSpecificDataSize(0),
1411      mGotAllCodecSpecificData(false),
1412      mReachedEOS(false),
1413      mRotation(0) {
1414    getCodecSpecificDataFromInputFormatIfPossible();
1415
1416    const char *mime;
1417    mMeta->findCString(kKeyMIMEType, &mime);
1418    mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
1419    mIsAudio = !strncasecmp(mime, "audio/", 6);
1420    mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
1421               !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
1422
1423    setTimeScale();
1424}
1425
1426void MPEG4Writer::Track::updateTrackSizeEstimate() {
1427
1428    uint32_t stcoBoxCount = (mOwner->use32BitFileOffset()
1429                            ? mStcoTableEntries->count()
1430                            : mCo64TableEntries->count());
1431    int64_t stcoBoxSizeBytes = stcoBoxCount * 4;
1432    int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mStszTableEntries->count() * 4);
1433
1434    mEstimatedTrackSizeBytes = mMdatSizeBytes;  // media data size
1435    if (!mOwner->isFileStreamable()) {
1436        // Reserved free space is not large enough to hold
1437        // all meta data and thus wasted.
1438        mEstimatedTrackSizeBytes += mStscTableEntries->count() * 12 +  // stsc box size
1439                                    mStssTableEntries->count() * 4 +   // stss box size
1440                                    mSttsTableEntries->count() * 8 +   // stts box size
1441                                    mCttsTableEntries->count() * 8 +   // ctts box size
1442                                    stcoBoxSizeBytes +           // stco box size
1443                                    stszBoxSizeBytes;            // stsz box size
1444    }
1445}
1446
1447void MPEG4Writer::Track::addOneStscTableEntry(
1448        size_t chunkId, size_t sampleId) {
1449
1450        mStscTableEntries->add(htonl(chunkId));
1451        mStscTableEntries->add(htonl(sampleId));
1452        mStscTableEntries->add(htonl(1));
1453}
1454
1455void MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) {
1456    mStssTableEntries->add(htonl(sampleId));
1457}
1458
1459void MPEG4Writer::Track::addOneSttsTableEntry(
1460        size_t sampleCount, int32_t duration) {
1461
1462    if (duration == 0) {
1463        ALOGW("0-duration samples found: %zu", sampleCount);
1464    }
1465    mSttsTableEntries->add(htonl(sampleCount));
1466    mSttsTableEntries->add(htonl(duration));
1467}
1468
1469void MPEG4Writer::Track::addOneCttsTableEntry(
1470        size_t sampleCount, int32_t duration) {
1471
1472    if (mIsAudio) {
1473        return;
1474    }
1475    mCttsTableEntries->add(htonl(sampleCount));
1476    mCttsTableEntries->add(htonl(duration));
1477}
1478
1479void MPEG4Writer::Track::addChunkOffset(off64_t offset) {
1480    if (mOwner->use32BitFileOffset()) {
1481        uint32_t value = offset;
1482        mStcoTableEntries->add(htonl(value));
1483    } else {
1484        mCo64TableEntries->add(hton64(offset));
1485    }
1486}
1487
1488void MPEG4Writer::Track::setTimeScale() {
1489    ALOGV("setTimeScale");
1490    // Default time scale
1491    mTimeScale = 90000;
1492
1493    if (mIsAudio) {
1494        // Use the sampling rate as the default time scale for audio track.
1495        int32_t sampleRate;
1496        bool success = mMeta->findInt32(kKeySampleRate, &sampleRate);
1497        CHECK(success);
1498        mTimeScale = sampleRate;
1499    }
1500
1501    // If someone would like to overwrite the timescale, use user-supplied value.
1502    int32_t timeScale;
1503    if (mMeta->findInt32(kKeyTimeScale, &timeScale)) {
1504        mTimeScale = timeScale;
1505    }
1506
1507    CHECK_GT(mTimeScale, 0);
1508}
1509
1510void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
1511    const char *mime;
1512    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
1513
1514    if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
1515        uint32_t type;
1516        const void *data;
1517        size_t size;
1518        if (mMeta->findData(kKeyAVCC, &type, &data, &size)) {
1519            mCodecSpecificData = malloc(size);
1520            mCodecSpecificDataSize = size;
1521            memcpy(mCodecSpecificData, data, size);
1522            mGotAllCodecSpecificData = true;
1523        }
1524    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
1525            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
1526        uint32_t type;
1527        const void *data;
1528        size_t size;
1529        if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
1530            ESDS esds(data, size);
1531            if (esds.getCodecSpecificInfo(&data, &size) == OK) {
1532                mCodecSpecificData = malloc(size);
1533                mCodecSpecificDataSize = size;
1534                memcpy(mCodecSpecificData, data, size);
1535                mGotAllCodecSpecificData = true;
1536            }
1537        }
1538    }
1539}
1540
1541MPEG4Writer::Track::~Track() {
1542    stop();
1543
1544    delete mStszTableEntries;
1545    delete mStcoTableEntries;
1546    delete mCo64TableEntries;
1547    delete mStscTableEntries;
1548    delete mSttsTableEntries;
1549    delete mStssTableEntries;
1550    delete mCttsTableEntries;
1551
1552    mStszTableEntries = NULL;
1553    mStcoTableEntries = NULL;
1554    mCo64TableEntries = NULL;
1555    mStscTableEntries = NULL;
1556    mSttsTableEntries = NULL;
1557    mStssTableEntries = NULL;
1558    mCttsTableEntries = NULL;
1559
1560    if (mCodecSpecificData != NULL) {
1561        free(mCodecSpecificData);
1562        mCodecSpecificData = NULL;
1563    }
1564}
1565
1566void MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) {
1567    ALOGV("initTrackingProgressStatus");
1568    mPreviousTrackTimeUs = -1;
1569    mTrackingProgressStatus = false;
1570    mTrackEveryTimeDurationUs = 0;
1571    {
1572        int64_t timeUs;
1573        if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) {
1574            ALOGV("Receive request to track progress status for every %" PRId64 " us", timeUs);
1575            mTrackEveryTimeDurationUs = timeUs;
1576            mTrackingProgressStatus = true;
1577        }
1578    }
1579}
1580
1581// static
1582void *MPEG4Writer::ThreadWrapper(void *me) {
1583    ALOGV("ThreadWrapper: %p", me);
1584    MPEG4Writer *writer = static_cast<MPEG4Writer *>(me);
1585    writer->threadFunc();
1586    return NULL;
1587}
1588
1589void MPEG4Writer::bufferChunk(const Chunk& chunk) {
1590    ALOGV("bufferChunk: %p", chunk.mTrack);
1591    Mutex::Autolock autolock(mLock);
1592    CHECK_EQ(mDone, false);
1593
1594    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
1595         it != mChunkInfos.end(); ++it) {
1596
1597        if (chunk.mTrack == it->mTrack) {  // Found owner
1598            it->mChunks.push_back(chunk);
1599            mChunkReadyCondition.signal();
1600            return;
1601        }
1602    }
1603
1604    CHECK(!"Received a chunk for a unknown track");
1605}
1606
1607void MPEG4Writer::writeChunkToFile(Chunk* chunk) {
1608    ALOGV("writeChunkToFile: %" PRId64 " from %s track",
1609        chunk->mTimeStampUs, chunk->mTrack->isAudio()? "audio": "video");
1610
1611    int32_t isFirstSample = true;
1612    while (!chunk->mSamples.empty()) {
1613        List<MediaBuffer *>::iterator it = chunk->mSamples.begin();
1614
1615        off64_t offset = chunk->mTrack->isAvc()
1616                                ? addLengthPrefixedSample_l(*it)
1617                                : addSample_l(*it);
1618
1619        if (isFirstSample) {
1620            chunk->mTrack->addChunkOffset(offset);
1621            isFirstSample = false;
1622        }
1623
1624        (*it)->release();
1625        (*it) = NULL;
1626        chunk->mSamples.erase(it);
1627    }
1628    chunk->mSamples.clear();
1629}
1630
1631void MPEG4Writer::writeAllChunks() {
1632    ALOGV("writeAllChunks");
1633    size_t outstandingChunks = 0;
1634    Chunk chunk;
1635    while (findChunkToWrite(&chunk)) {
1636        writeChunkToFile(&chunk);
1637        ++outstandingChunks;
1638    }
1639
1640    sendSessionSummary();
1641
1642    mChunkInfos.clear();
1643    ALOGD("%zu chunks are written in the last batch", outstandingChunks);
1644}
1645
1646bool MPEG4Writer::findChunkToWrite(Chunk *chunk) {
1647    ALOGV("findChunkToWrite");
1648
1649    int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL;
1650    Track *track = NULL;
1651    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
1652         it != mChunkInfos.end(); ++it) {
1653        if (!it->mChunks.empty()) {
1654            List<Chunk>::iterator chunkIt = it->mChunks.begin();
1655            if (chunkIt->mTimeStampUs < minTimestampUs) {
1656                minTimestampUs = chunkIt->mTimeStampUs;
1657                track = it->mTrack;
1658            }
1659        }
1660    }
1661
1662    if (track == NULL) {
1663        ALOGV("Nothing to be written after all");
1664        return false;
1665    }
1666
1667    if (mIsFirstChunk) {
1668        mIsFirstChunk = false;
1669    }
1670
1671    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
1672         it != mChunkInfos.end(); ++it) {
1673        if (it->mTrack == track) {
1674            *chunk = *(it->mChunks.begin());
1675            it->mChunks.erase(it->mChunks.begin());
1676            CHECK_EQ(chunk->mTrack, track);
1677
1678            int64_t interChunkTimeUs =
1679                chunk->mTimeStampUs - it->mPrevChunkTimestampUs;
1680            if (interChunkTimeUs > it->mPrevChunkTimestampUs) {
1681                it->mMaxInterChunkDurUs = interChunkTimeUs;
1682            }
1683
1684            return true;
1685        }
1686    }
1687
1688    return false;
1689}
1690
1691void MPEG4Writer::threadFunc() {
1692    ALOGV("threadFunc");
1693
1694    prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0);
1695
1696    Mutex::Autolock autoLock(mLock);
1697    while (!mDone) {
1698        Chunk chunk;
1699        bool chunkFound = false;
1700
1701        while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) {
1702            mChunkReadyCondition.wait(mLock);
1703        }
1704
1705        // In real time recording mode, write without holding the lock in order
1706        // to reduce the blocking time for media track threads.
1707        // Otherwise, hold the lock until the existing chunks get written to the
1708        // file.
1709        if (chunkFound) {
1710            if (mIsRealTimeRecording) {
1711                mLock.unlock();
1712            }
1713            writeChunkToFile(&chunk);
1714            if (mIsRealTimeRecording) {
1715                mLock.lock();
1716            }
1717        }
1718    }
1719
1720    writeAllChunks();
1721}
1722
1723status_t MPEG4Writer::startWriterThread() {
1724    ALOGV("startWriterThread");
1725
1726    mDone = false;
1727    mIsFirstChunk = true;
1728    mDriftTimeUs = 0;
1729    for (List<Track *>::iterator it = mTracks.begin();
1730         it != mTracks.end(); ++it) {
1731        ChunkInfo info;
1732        info.mTrack = *it;
1733        info.mPrevChunkTimestampUs = 0;
1734        info.mMaxInterChunkDurUs = 0;
1735        mChunkInfos.push_back(info);
1736    }
1737
1738    pthread_attr_t attr;
1739    pthread_attr_init(&attr);
1740    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1741    pthread_create(&mThread, &attr, ThreadWrapper, this);
1742    pthread_attr_destroy(&attr);
1743    mWriterThreadStarted = true;
1744    return OK;
1745}
1746
1747
1748status_t MPEG4Writer::Track::start(MetaData *params) {
1749    if (!mDone && mPaused) {
1750        mPaused = false;
1751        mResumed = true;
1752        return OK;
1753    }
1754
1755    int64_t startTimeUs;
1756    if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) {
1757        startTimeUs = 0;
1758    }
1759    mStartTimeRealUs = startTimeUs;
1760
1761    int32_t rotationDegrees;
1762    if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) {
1763        mRotation = rotationDegrees;
1764    }
1765
1766    initTrackingProgressStatus(params);
1767
1768    sp<MetaData> meta = new MetaData;
1769    if (mOwner->isRealTimeRecording() && mOwner->numTracks() > 1) {
1770        /*
1771         * This extra delay of accepting incoming audio/video signals
1772         * helps to align a/v start time at the beginning of a recording
1773         * session, and it also helps eliminate the "recording" sound for
1774         * camcorder applications.
1775         *
1776         * If client does not set the start time offset, we fall back to
1777         * use the default initial delay value.
1778         */
1779        int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL;
1780        if (startTimeOffsetUs < 0) {  // Start time offset was not set
1781            startTimeOffsetUs = kInitialDelayTimeUs;
1782        }
1783        startTimeUs += startTimeOffsetUs;
1784        ALOGI("Start time offset: %" PRId64 " us", startTimeOffsetUs);
1785    }
1786
1787    meta->setInt64(kKeyTime, startTimeUs);
1788
1789    status_t err = mSource->start(meta.get());
1790    if (err != OK) {
1791        mDone = mReachedEOS = true;
1792        return err;
1793    }
1794
1795    pthread_attr_t attr;
1796    pthread_attr_init(&attr);
1797    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1798
1799    mDone = false;
1800    mStarted = true;
1801    mTrackDurationUs = 0;
1802    mReachedEOS = false;
1803    mEstimatedTrackSizeBytes = 0;
1804    mMdatSizeBytes = 0;
1805    mMaxChunkDurationUs = 0;
1806
1807    pthread_create(&mThread, &attr, ThreadWrapper, this);
1808    pthread_attr_destroy(&attr);
1809
1810    return OK;
1811}
1812
1813status_t MPEG4Writer::Track::pause() {
1814    mPaused = true;
1815    return OK;
1816}
1817
1818status_t MPEG4Writer::Track::stop() {
1819    ALOGD("%s track stopping", mIsAudio? "Audio": "Video");
1820    if (!mStarted) {
1821        ALOGE("Stop() called but track is not started");
1822        return ERROR_END_OF_STREAM;
1823    }
1824
1825    if (mDone) {
1826        return OK;
1827    }
1828    mDone = true;
1829
1830    ALOGD("%s track source stopping", mIsAudio? "Audio": "Video");
1831    mSource->stop();
1832    ALOGD("%s track source stopped", mIsAudio? "Audio": "Video");
1833
1834    void *dummy;
1835    pthread_join(mThread, &dummy);
1836    status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
1837
1838    ALOGD("%s track stopped", mIsAudio? "Audio": "Video");
1839    return err;
1840}
1841
1842bool MPEG4Writer::Track::reachedEOS() {
1843    return mReachedEOS;
1844}
1845
1846// static
1847void *MPEG4Writer::Track::ThreadWrapper(void *me) {
1848    Track *track = static_cast<Track *>(me);
1849
1850    status_t err = track->threadEntry();
1851    return (void *)(uintptr_t)err;
1852}
1853
1854static void getNalUnitType(uint8_t byte, uint8_t* type) {
1855    ALOGV("getNalUnitType: %d", byte);
1856
1857    // nal_unit_type: 5-bit unsigned integer
1858    *type = (byte & 0x1F);
1859}
1860
1861static const uint8_t *findNextStartCode(
1862        const uint8_t *data, size_t length) {
1863
1864    ALOGV("findNextStartCode: %p %zu", data, length);
1865
1866    size_t bytesLeft = length;
1867    while (bytesLeft > 4  &&
1868            memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) {
1869        --bytesLeft;
1870    }
1871    if (bytesLeft <= 4) {
1872        bytesLeft = 0; // Last parameter set
1873    }
1874    return &data[length - bytesLeft];
1875}
1876
1877const uint8_t *MPEG4Writer::Track::parseParamSet(
1878        const uint8_t *data, size_t length, int type, size_t *paramSetLen) {
1879
1880    ALOGV("parseParamSet");
1881    CHECK(type == kNalUnitTypeSeqParamSet ||
1882          type == kNalUnitTypePicParamSet);
1883
1884    const uint8_t *nextStartCode = findNextStartCode(data, length);
1885    *paramSetLen = nextStartCode - data;
1886    if (*paramSetLen == 0) {
1887        ALOGE("Param set is malformed, since its length is 0");
1888        return NULL;
1889    }
1890
1891    AVCParamSet paramSet(*paramSetLen, data);
1892    if (type == kNalUnitTypeSeqParamSet) {
1893        if (*paramSetLen < 4) {
1894            ALOGE("Seq parameter set malformed");
1895            return NULL;
1896        }
1897        if (mSeqParamSets.empty()) {
1898            mProfileIdc = data[1];
1899            mProfileCompatible = data[2];
1900            mLevelIdc = data[3];
1901        } else {
1902            if (mProfileIdc != data[1] ||
1903                mProfileCompatible != data[2] ||
1904                mLevelIdc != data[3]) {
1905                ALOGE("Inconsistent profile/level found in seq parameter sets");
1906                return NULL;
1907            }
1908        }
1909        mSeqParamSets.push_back(paramSet);
1910    } else {
1911        mPicParamSets.push_back(paramSet);
1912    }
1913    return nextStartCode;
1914}
1915
1916status_t MPEG4Writer::Track::copyAVCCodecSpecificData(
1917        const uint8_t *data, size_t size) {
1918    ALOGV("copyAVCCodecSpecificData");
1919
1920    // 2 bytes for each of the parameter set length field
1921    // plus the 7 bytes for the header
1922    if (size < 4 + 7) {
1923        ALOGE("Codec specific data length too short: %zu", size);
1924        return ERROR_MALFORMED;
1925    }
1926
1927    mCodecSpecificDataSize = size;
1928    mCodecSpecificData = malloc(size);
1929    memcpy(mCodecSpecificData, data, size);
1930    return OK;
1931}
1932
1933status_t MPEG4Writer::Track::parseAVCCodecSpecificData(
1934        const uint8_t *data, size_t size) {
1935
1936    ALOGV("parseAVCCodecSpecificData");
1937    // Data starts with a start code.
1938    // SPS and PPS are separated with start codes.
1939    // Also, SPS must come before PPS
1940    uint8_t type = kNalUnitTypeSeqParamSet;
1941    bool gotSps = false;
1942    bool gotPps = false;
1943    const uint8_t *tmp = data;
1944    const uint8_t *nextStartCode = data;
1945    size_t bytesLeft = size;
1946    size_t paramSetLen = 0;
1947    mCodecSpecificDataSize = 0;
1948    while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) {
1949        getNalUnitType(*(tmp + 4), &type);
1950        if (type == kNalUnitTypeSeqParamSet) {
1951            if (gotPps) {
1952                ALOGE("SPS must come before PPS");
1953                return ERROR_MALFORMED;
1954            }
1955            if (!gotSps) {
1956                gotSps = true;
1957            }
1958            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
1959        } else if (type == kNalUnitTypePicParamSet) {
1960            if (!gotSps) {
1961                ALOGE("SPS must come before PPS");
1962                return ERROR_MALFORMED;
1963            }
1964            if (!gotPps) {
1965                gotPps = true;
1966            }
1967            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
1968        } else {
1969            ALOGE("Only SPS and PPS Nal units are expected");
1970            return ERROR_MALFORMED;
1971        }
1972
1973        if (nextStartCode == NULL) {
1974            return ERROR_MALFORMED;
1975        }
1976
1977        // Move on to find the next parameter set
1978        bytesLeft -= nextStartCode - tmp;
1979        tmp = nextStartCode;
1980        mCodecSpecificDataSize += (2 + paramSetLen);
1981    }
1982
1983    {
1984        // Check on the number of seq parameter sets
1985        size_t nSeqParamSets = mSeqParamSets.size();
1986        if (nSeqParamSets == 0) {
1987            ALOGE("Cound not find sequence parameter set");
1988            return ERROR_MALFORMED;
1989        }
1990
1991        if (nSeqParamSets > 0x1F) {
1992            ALOGE("Too many seq parameter sets (%zu) found", nSeqParamSets);
1993            return ERROR_MALFORMED;
1994        }
1995    }
1996
1997    {
1998        // Check on the number of pic parameter sets
1999        size_t nPicParamSets = mPicParamSets.size();
2000        if (nPicParamSets == 0) {
2001            ALOGE("Cound not find picture parameter set");
2002            return ERROR_MALFORMED;
2003        }
2004        if (nPicParamSets > 0xFF) {
2005            ALOGE("Too many pic parameter sets (%zd) found", nPicParamSets);
2006            return ERROR_MALFORMED;
2007        }
2008    }
2009// FIXME:
2010// Add chromat_format_idc, bit depth values, etc for AVC/h264 high profile and above
2011// and remove #if 0
2012#if 0
2013    {
2014        // Check on the profiles
2015        // These profiles requires additional parameter set extensions
2016        if (mProfileIdc == 100 || mProfileIdc == 110 ||
2017            mProfileIdc == 122 || mProfileIdc == 144) {
2018            ALOGE("Sorry, no support for profile_idc: %d!", mProfileIdc);
2019            return BAD_VALUE;
2020        }
2021    }
2022#endif
2023    return OK;
2024}
2025
2026status_t MPEG4Writer::Track::makeAVCCodecSpecificData(
2027        const uint8_t *data, size_t size) {
2028
2029    if (mCodecSpecificData != NULL) {
2030        ALOGE("Already have codec specific data");
2031        return ERROR_MALFORMED;
2032    }
2033
2034    if (size < 4) {
2035        ALOGE("Codec specific data length too short: %zu", size);
2036        return ERROR_MALFORMED;
2037    }
2038
2039    // Data is in the form of AVCCodecSpecificData
2040    if (memcmp("\x00\x00\x00\x01", data, 4)) {
2041        return copyAVCCodecSpecificData(data, size);
2042    }
2043
2044    if (parseAVCCodecSpecificData(data, size) != OK) {
2045        return ERROR_MALFORMED;
2046    }
2047
2048    // ISO 14496-15: AVC file format
2049    mCodecSpecificDataSize += 7;  // 7 more bytes in the header
2050    mCodecSpecificData = malloc(mCodecSpecificDataSize);
2051    uint8_t *header = (uint8_t *)mCodecSpecificData;
2052    header[0] = 1;                     // version
2053    header[1] = mProfileIdc;           // profile indication
2054    header[2] = mProfileCompatible;    // profile compatibility
2055    header[3] = mLevelIdc;
2056
2057    // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne
2058    if (mOwner->useNalLengthFour()) {
2059        header[4] = 0xfc | 3;  // length size == 4 bytes
2060    } else {
2061        header[4] = 0xfc | 1;  // length size == 2 bytes
2062    }
2063
2064    // 3-bit '111' followed by 5-bit numSequenceParameterSets
2065    int nSequenceParamSets = mSeqParamSets.size();
2066    header[5] = 0xe0 | nSequenceParamSets;
2067    header += 6;
2068    for (List<AVCParamSet>::iterator it = mSeqParamSets.begin();
2069         it != mSeqParamSets.end(); ++it) {
2070        // 16-bit sequence parameter set length
2071        uint16_t seqParamSetLength = it->mLength;
2072        header[0] = seqParamSetLength >> 8;
2073        header[1] = seqParamSetLength & 0xff;
2074
2075        // SPS NAL unit (sequence parameter length bytes)
2076        memcpy(&header[2], it->mData, seqParamSetLength);
2077        header += (2 + seqParamSetLength);
2078    }
2079
2080    // 8-bit nPictureParameterSets
2081    int nPictureParamSets = mPicParamSets.size();
2082    header[0] = nPictureParamSets;
2083    header += 1;
2084    for (List<AVCParamSet>::iterator it = mPicParamSets.begin();
2085         it != mPicParamSets.end(); ++it) {
2086        // 16-bit picture parameter set length
2087        uint16_t picParamSetLength = it->mLength;
2088        header[0] = picParamSetLength >> 8;
2089        header[1] = picParamSetLength & 0xff;
2090
2091        // PPS Nal unit (picture parameter set length bytes)
2092        memcpy(&header[2], it->mData, picParamSetLength);
2093        header += (2 + picParamSetLength);
2094    }
2095
2096    return OK;
2097}
2098
2099/*
2100 * Updates the drift time from the audio track so that
2101 * the video track can get the updated drift time information
2102 * from the file writer. The fluctuation of the drift time of the audio
2103 * encoding path is smoothed out with a simple filter by giving a larger
2104 * weight to more recently drift time. The filter coefficients, 0.5 and 0.5,
2105 * are heuristically determined.
2106 */
2107void MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) {
2108    int64_t driftTimeUs = 0;
2109    if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) {
2110        int64_t prevDriftTimeUs = mOwner->getDriftTimeUs();
2111        int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1;
2112        mOwner->setDriftTimeUs(timeUs);
2113    }
2114}
2115
2116status_t MPEG4Writer::Track::threadEntry() {
2117    int32_t count = 0;
2118    const int64_t interleaveDurationUs = mOwner->interleaveDuration();
2119    const bool hasMultipleTracks = (mOwner->numTracks() > 1);
2120    int64_t chunkTimestampUs = 0;
2121    int32_t nChunks = 0;
2122    int32_t nZeroLengthFrames = 0;
2123    int64_t lastTimestampUs = 0;      // Previous sample time stamp
2124    int64_t lastDurationUs = 0;       // Between the previous two samples
2125    int64_t currDurationTicks = 0;    // Timescale based ticks
2126    int64_t lastDurationTicks = 0;    // Timescale based ticks
2127    int32_t sampleCount = 1;          // Sample count in the current stts table entry
2128    uint32_t previousSampleSize = 0;  // Size of the previous sample
2129    int64_t previousPausedDurationUs = 0;
2130    int64_t timestampUs = 0;
2131    int64_t cttsOffsetTimeUs = 0;
2132    int64_t currCttsOffsetTimeTicks = 0;   // Timescale based ticks
2133    int64_t lastCttsOffsetTimeTicks = -1;  // Timescale based ticks
2134    int32_t cttsSampleCount = 0;           // Sample count in the current ctts table entry
2135    uint32_t lastSamplesPerChunk = 0;
2136
2137    if (mIsAudio) {
2138        prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
2139    } else {
2140        prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0);
2141    }
2142
2143    if (mOwner->isRealTimeRecording()) {
2144        androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
2145    }
2146
2147    sp<MetaData> meta_data;
2148
2149    status_t err = OK;
2150    MediaBuffer *buffer;
2151    const char *trackName = mIsAudio ? "Audio" : "Video";
2152    while (!mDone && (err = mSource->read(&buffer)) == OK) {
2153        if (buffer->range_length() == 0) {
2154            buffer->release();
2155            buffer = NULL;
2156            ++nZeroLengthFrames;
2157            continue;
2158        }
2159
2160        // If the codec specific data has not been received yet, delay pause.
2161        // After the codec specific data is received, discard what we received
2162        // when the track is to be paused.
2163        if (mPaused && !mResumed) {
2164            buffer->release();
2165            buffer = NULL;
2166            continue;
2167        }
2168
2169        ++count;
2170
2171        int32_t isCodecConfig;
2172        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
2173                && isCodecConfig) {
2174            CHECK(!mGotAllCodecSpecificData);
2175
2176            if (mIsAvc) {
2177                status_t err = makeAVCCodecSpecificData(
2178                        (const uint8_t *)buffer->data()
2179                            + buffer->range_offset(),
2180                        buffer->range_length());
2181                CHECK_EQ((status_t)OK, err);
2182            } else if (mIsMPEG4) {
2183                mCodecSpecificDataSize = buffer->range_length();
2184                mCodecSpecificData = malloc(mCodecSpecificDataSize);
2185                memcpy(mCodecSpecificData,
2186                        (const uint8_t *)buffer->data()
2187                            + buffer->range_offset(),
2188                       buffer->range_length());
2189            }
2190
2191            buffer->release();
2192            buffer = NULL;
2193
2194            mGotAllCodecSpecificData = true;
2195            continue;
2196        }
2197
2198        // Make a deep copy of the MediaBuffer and Metadata and release
2199        // the original as soon as we can
2200        MediaBuffer *copy = new MediaBuffer(buffer->range_length());
2201        memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(),
2202                buffer->range_length());
2203        copy->set_range(0, buffer->range_length());
2204        meta_data = new MetaData(*buffer->meta_data().get());
2205        buffer->release();
2206        buffer = NULL;
2207
2208        if (mIsAvc) StripStartcode(copy);
2209
2210        size_t sampleSize = copy->range_length();
2211        if (mIsAvc) {
2212            if (mOwner->useNalLengthFour()) {
2213                sampleSize += 4;
2214            } else {
2215                sampleSize += 2;
2216            }
2217        }
2218
2219        // Max file size or duration handling
2220        mMdatSizeBytes += sampleSize;
2221        updateTrackSizeEstimate();
2222
2223        if (mOwner->exceedsFileSizeLimit()) {
2224            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
2225            break;
2226        }
2227        if (mOwner->exceedsFileDurationLimit()) {
2228            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
2229            break;
2230        }
2231
2232
2233        int32_t isSync = false;
2234        meta_data->findInt32(kKeyIsSyncFrame, &isSync);
2235        CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
2236
2237////////////////////////////////////////////////////////////////////////////////
2238        if (mStszTableEntries->count() == 0) {
2239            mFirstSampleTimeRealUs = systemTime() / 1000;
2240            mStartTimestampUs = timestampUs;
2241            mOwner->setStartTimestampUs(mStartTimestampUs);
2242            previousPausedDurationUs = mStartTimestampUs;
2243        }
2244
2245        if (mResumed) {
2246            int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
2247            if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) {
2248                copy->release();
2249                return ERROR_MALFORMED;
2250            }
2251
2252            int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
2253            if (WARN_UNLESS(pausedDurationUs >= lastDurationUs, "for %s track", trackName)) {
2254                copy->release();
2255                return ERROR_MALFORMED;
2256            }
2257
2258            previousPausedDurationUs += pausedDurationUs - lastDurationUs;
2259            mResumed = false;
2260        }
2261
2262        timestampUs -= previousPausedDurationUs;
2263        if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
2264            copy->release();
2265            return ERROR_MALFORMED;
2266        }
2267
2268        if (!mIsAudio) {
2269            /*
2270             * Composition time: timestampUs
2271             * Decoding time: decodingTimeUs
2272             * Composition time offset = composition time - decoding time
2273             */
2274            int64_t decodingTimeUs;
2275            CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs));
2276            decodingTimeUs -= previousPausedDurationUs;
2277            cttsOffsetTimeUs =
2278                    timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
2279            if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) {
2280                copy->release();
2281                return ERROR_MALFORMED;
2282            }
2283
2284            timestampUs = decodingTimeUs;
2285            ALOGV("decoding time: %" PRId64 " and ctts offset time: %" PRId64,
2286                timestampUs, cttsOffsetTimeUs);
2287
2288            // Update ctts box table if necessary
2289            currCttsOffsetTimeTicks =
2290                    (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL;
2291            if (WARN_UNLESS(currCttsOffsetTimeTicks <= 0x0FFFFFFFFLL, "for %s track", trackName)) {
2292                copy->release();
2293                return ERROR_MALFORMED;
2294            }
2295
2296            if (mStszTableEntries->count() == 0) {
2297                // Force the first ctts table entry to have one single entry
2298                // so that we can do adjustment for the initial track start
2299                // time offset easily in writeCttsBox().
2300                lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
2301                addOneCttsTableEntry(1, currCttsOffsetTimeTicks);
2302                cttsSampleCount = 0;      // No sample in ctts box is pending
2303            } else {
2304                if (currCttsOffsetTimeTicks != lastCttsOffsetTimeTicks) {
2305                    addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
2306                    lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
2307                    cttsSampleCount = 1;  // One sample in ctts box is pending
2308                } else {
2309                    ++cttsSampleCount;
2310                }
2311            }
2312
2313            // Update ctts time offset range
2314            if (mStszTableEntries->count() == 0) {
2315                mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2316                mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2317            } else {
2318                if (currCttsOffsetTimeTicks > mMaxCttsOffsetTimeUs) {
2319                    mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2320                } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTimeUs) {
2321                    mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2322                }
2323            }
2324
2325        }
2326
2327        if (mOwner->isRealTimeRecording()) {
2328            if (mIsAudio) {
2329                updateDriftTime(meta_data);
2330            }
2331        }
2332
2333        if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
2334            copy->release();
2335            return ERROR_MALFORMED;
2336        }
2337
2338        ALOGV("%s media time stamp: %" PRId64 " and previous paused duration %" PRId64,
2339                trackName, timestampUs, previousPausedDurationUs);
2340        if (timestampUs > mTrackDurationUs) {
2341            mTrackDurationUs = timestampUs;
2342        }
2343
2344        // We need to use the time scale based ticks, rather than the
2345        // timestamp itself to determine whether we have to use a new
2346        // stts entry, since we may have rounding errors.
2347        // The calculation is intended to reduce the accumulated
2348        // rounding errors.
2349        currDurationTicks =
2350            ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
2351                (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
2352        if (currDurationTicks < 0ll) {
2353            ALOGE("timestampUs %" PRId64 " < lastTimestampUs %" PRId64 " for %s track",
2354                timestampUs, lastTimestampUs, trackName);
2355            copy->release();
2356            return UNKNOWN_ERROR;
2357        }
2358
2359        // if the duration is different for this sample, see if it is close enough to the previous
2360        // duration that we can fudge it and use the same value, to avoid filling the stts table
2361        // with lots of near-identical entries.
2362        // "close enough" here means that the current duration needs to be adjusted by less
2363        // than 0.1 milliseconds
2364        if (lastDurationTicks && (currDurationTicks != lastDurationTicks)) {
2365            int64_t deltaUs = ((lastDurationTicks - currDurationTicks) * 1000000LL
2366                    + (mTimeScale / 2)) / mTimeScale;
2367            if (deltaUs > -100 && deltaUs < 100) {
2368                // use previous ticks, and adjust timestamp as if it was actually that number
2369                // of ticks
2370                currDurationTicks = lastDurationTicks;
2371                timestampUs += deltaUs;
2372            }
2373        }
2374
2375        mStszTableEntries->add(htonl(sampleSize));
2376        if (mStszTableEntries->count() > 2) {
2377
2378            // Force the first sample to have its own stts entry so that
2379            // we can adjust its value later to maintain the A/V sync.
2380            if (mStszTableEntries->count() == 3 || currDurationTicks != lastDurationTicks) {
2381                addOneSttsTableEntry(sampleCount, lastDurationTicks);
2382                sampleCount = 1;
2383            } else {
2384                ++sampleCount;
2385            }
2386
2387        }
2388        if (mSamplesHaveSameSize) {
2389            if (mStszTableEntries->count() >= 2 && previousSampleSize != sampleSize) {
2390                mSamplesHaveSameSize = false;
2391            }
2392            previousSampleSize = sampleSize;
2393        }
2394        ALOGV("%s timestampUs/lastTimestampUs: %" PRId64 "/%" PRId64,
2395                trackName, timestampUs, lastTimestampUs);
2396        lastDurationUs = timestampUs - lastTimestampUs;
2397        lastDurationTicks = currDurationTicks;
2398        lastTimestampUs = timestampUs;
2399
2400        if (isSync != 0) {
2401            addOneStssTableEntry(mStszTableEntries->count());
2402        }
2403
2404        if (mTrackingProgressStatus) {
2405            if (mPreviousTrackTimeUs <= 0) {
2406                mPreviousTrackTimeUs = mStartTimestampUs;
2407            }
2408            trackProgressStatus(timestampUs);
2409        }
2410        if (!hasMultipleTracks) {
2411            off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy)
2412                                 : mOwner->addSample_l(copy);
2413
2414            uint32_t count = (mOwner->use32BitFileOffset()
2415                        ? mStcoTableEntries->count()
2416                        : mCo64TableEntries->count());
2417
2418            if (count == 0) {
2419                addChunkOffset(offset);
2420            }
2421            copy->release();
2422            copy = NULL;
2423            continue;
2424        }
2425
2426        mChunkSamples.push_back(copy);
2427        if (interleaveDurationUs == 0) {
2428            addOneStscTableEntry(++nChunks, 1);
2429            bufferChunk(timestampUs);
2430        } else {
2431            if (chunkTimestampUs == 0) {
2432                chunkTimestampUs = timestampUs;
2433            } else {
2434                int64_t chunkDurationUs = timestampUs - chunkTimestampUs;
2435                if (chunkDurationUs > interleaveDurationUs) {
2436                    if (chunkDurationUs > mMaxChunkDurationUs) {
2437                        mMaxChunkDurationUs = chunkDurationUs;
2438                    }
2439                    ++nChunks;
2440                    if (nChunks == 1 ||  // First chunk
2441                        lastSamplesPerChunk != mChunkSamples.size()) {
2442                        lastSamplesPerChunk = mChunkSamples.size();
2443                        addOneStscTableEntry(nChunks, lastSamplesPerChunk);
2444                    }
2445                    bufferChunk(timestampUs);
2446                    chunkTimestampUs = timestampUs;
2447                }
2448            }
2449        }
2450
2451    }
2452
2453    if (isTrackMalFormed()) {
2454        err = ERROR_MALFORMED;
2455    }
2456
2457    mOwner->trackProgressStatus(mTrackId, -1, err);
2458
2459    // Last chunk
2460    if (!hasMultipleTracks) {
2461        addOneStscTableEntry(1, mStszTableEntries->count());
2462    } else if (!mChunkSamples.empty()) {
2463        addOneStscTableEntry(++nChunks, mChunkSamples.size());
2464        bufferChunk(timestampUs);
2465    }
2466
2467    // We don't really know how long the last frame lasts, since
2468    // there is no frame time after it, just repeat the previous
2469    // frame's duration.
2470    if (mStszTableEntries->count() == 1) {
2471        lastDurationUs = 0;  // A single sample's duration
2472        lastDurationTicks = 0;
2473    } else {
2474        ++sampleCount;  // Count for the last sample
2475    }
2476
2477    if (mStszTableEntries->count() <= 2) {
2478        addOneSttsTableEntry(1, lastDurationTicks);
2479        if (sampleCount - 1 > 0) {
2480            addOneSttsTableEntry(sampleCount - 1, lastDurationTicks);
2481        }
2482    } else {
2483        addOneSttsTableEntry(sampleCount, lastDurationTicks);
2484    }
2485
2486    // The last ctts box may not have been written yet, and this
2487    // is to make sure that we write out the last ctts box.
2488    if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) {
2489        if (cttsSampleCount > 0) {
2490            addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
2491        }
2492    }
2493
2494    mTrackDurationUs += lastDurationUs;
2495    mReachedEOS = true;
2496
2497    sendTrackSummary(hasMultipleTracks);
2498
2499    ALOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s",
2500            count, nZeroLengthFrames, mStszTableEntries->count(), trackName);
2501    if (mIsAudio) {
2502        ALOGI("Audio track drift time: %" PRId64 " us", mOwner->getDriftTimeUs());
2503    }
2504
2505    if (err == ERROR_END_OF_STREAM) {
2506        return OK;
2507    }
2508    return err;
2509}
2510
2511bool MPEG4Writer::Track::isTrackMalFormed() const {
2512    if (mStszTableEntries->count() == 0) {                      // no samples written
2513        ALOGE("The number of recorded samples is 0");
2514        return true;
2515    }
2516
2517    if (!mIsAudio && mStssTableEntries->count() == 0) {  // no sync frames for video
2518        ALOGE("There are no sync frames for video track");
2519        return true;
2520    }
2521
2522    if (OK != checkCodecSpecificData()) {         // no codec specific data
2523        return true;
2524    }
2525
2526    return false;
2527}
2528
2529void MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) {
2530
2531    // Send track summary only if test mode is enabled.
2532    if (!isTestModeEnabled()) {
2533        return;
2534    }
2535
2536    int trackNum = (mTrackId << 28);
2537
2538    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2539                    trackNum | MEDIA_RECORDER_TRACK_INFO_TYPE,
2540                    mIsAudio? 0: 1);
2541
2542    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2543                    trackNum | MEDIA_RECORDER_TRACK_INFO_DURATION_MS,
2544                    mTrackDurationUs / 1000);
2545
2546    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2547                    trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES,
2548                    mStszTableEntries->count());
2549
2550    {
2551        // The system delay time excluding the requested initial delay that
2552        // is used to eliminate the recording sound.
2553        int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL;
2554        if (startTimeOffsetUs < 0) {  // Start time offset was not set
2555            startTimeOffsetUs = kInitialDelayTimeUs;
2556        }
2557        int64_t initialDelayUs =
2558            mFirstSampleTimeRealUs - mStartTimeRealUs - startTimeOffsetUs;
2559
2560        mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2561                    trackNum | MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS,
2562                    (initialDelayUs) / 1000);
2563    }
2564
2565    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2566                    trackNum | MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES,
2567                    mMdatSizeBytes / 1024);
2568
2569    if (hasMultipleTracks) {
2570        mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2571                    trackNum | MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS,
2572                    mMaxChunkDurationUs / 1000);
2573
2574        int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
2575        if (mStartTimestampUs != moovStartTimeUs) {
2576            int64_t startTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
2577            mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2578                    trackNum | MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS,
2579                    startTimeOffsetUs / 1000);
2580        }
2581    }
2582}
2583
2584void MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) {
2585    ALOGV("trackProgressStatus: %" PRId64 " us", timeUs);
2586
2587    if (mTrackEveryTimeDurationUs > 0 &&
2588        timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) {
2589        ALOGV("Fire time tracking progress status at %" PRId64 " us", timeUs);
2590        mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err);
2591        mPreviousTrackTimeUs = timeUs;
2592    }
2593}
2594
2595void MPEG4Writer::trackProgressStatus(
2596        size_t trackId, int64_t timeUs, status_t err) {
2597    Mutex::Autolock lock(mLock);
2598    int32_t trackNum = (trackId << 28);
2599
2600    // Error notification
2601    // Do not consider ERROR_END_OF_STREAM an error
2602    if (err != OK && err != ERROR_END_OF_STREAM) {
2603        notify(MEDIA_RECORDER_TRACK_EVENT_ERROR,
2604               trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL,
2605               err);
2606        return;
2607    }
2608
2609    if (timeUs == -1) {
2610        // Send completion notification
2611        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2612               trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS,
2613               err);
2614    } else {
2615        // Send progress status
2616        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2617               trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME,
2618               timeUs / 1000);
2619    }
2620}
2621
2622void MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) {
2623    ALOGV("setDriftTimeUs: %" PRId64 " us", driftTimeUs);
2624    Mutex::Autolock autolock(mLock);
2625    mDriftTimeUs = driftTimeUs;
2626}
2627
2628int64_t MPEG4Writer::getDriftTimeUs() {
2629    ALOGV("getDriftTimeUs: %" PRId64 " us", mDriftTimeUs);
2630    Mutex::Autolock autolock(mLock);
2631    return mDriftTimeUs;
2632}
2633
2634bool MPEG4Writer::isRealTimeRecording() const {
2635    return mIsRealTimeRecording;
2636}
2637
2638bool MPEG4Writer::useNalLengthFour() {
2639    return mUse4ByteNalLength;
2640}
2641
2642void MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
2643    ALOGV("bufferChunk");
2644
2645    Chunk chunk(this, timestampUs, mChunkSamples);
2646    mOwner->bufferChunk(chunk);
2647    mChunkSamples.clear();
2648}
2649
2650int64_t MPEG4Writer::Track::getDurationUs() const {
2651    return mTrackDurationUs;
2652}
2653
2654int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
2655    return mEstimatedTrackSizeBytes;
2656}
2657
2658status_t MPEG4Writer::Track::checkCodecSpecificData() const {
2659    const char *mime;
2660    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
2661    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) ||
2662        !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
2663        !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2664        if (!mCodecSpecificData ||
2665            mCodecSpecificDataSize <= 0) {
2666            ALOGE("Missing codec specific data");
2667            return ERROR_MALFORMED;
2668        }
2669    } else {
2670        if (mCodecSpecificData ||
2671            mCodecSpecificDataSize > 0) {
2672            ALOGE("Unexepected codec specific data found");
2673            return ERROR_MALFORMED;
2674        }
2675    }
2676    return OK;
2677}
2678
2679void MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) {
2680
2681    ALOGV("%s track time scale: %d",
2682        mIsAudio? "Audio": "Video", mTimeScale);
2683
2684    uint32_t now = getMpeg4Time();
2685    mOwner->beginBox("trak");
2686        writeTkhdBox(now);
2687        mOwner->beginBox("mdia");
2688            writeMdhdBox(now);
2689            writeHdlrBox();
2690            mOwner->beginBox("minf");
2691                if (mIsAudio) {
2692                    writeSmhdBox();
2693                } else {
2694                    writeVmhdBox();
2695                }
2696                writeDinfBox();
2697                writeStblBox(use32BitOffset);
2698            mOwner->endBox();  // minf
2699        mOwner->endBox();  // mdia
2700    mOwner->endBox();  // trak
2701}
2702
2703void MPEG4Writer::Track::writeStblBox(bool use32BitOffset) {
2704    mOwner->beginBox("stbl");
2705    mOwner->beginBox("stsd");
2706    mOwner->writeInt32(0);               // version=0, flags=0
2707    mOwner->writeInt32(1);               // entry count
2708    if (mIsAudio) {
2709        writeAudioFourCCBox();
2710    } else {
2711        writeVideoFourCCBox();
2712    }
2713    mOwner->endBox();  // stsd
2714    writeSttsBox();
2715    writeCttsBox();
2716    if (!mIsAudio) {
2717        writeStssBox();
2718    }
2719    writeStszBox();
2720    writeStscBox();
2721    writeStcoBox(use32BitOffset);
2722    mOwner->endBox();  // stbl
2723}
2724
2725void MPEG4Writer::Track::writeVideoFourCCBox() {
2726    const char *mime;
2727    bool success = mMeta->findCString(kKeyMIMEType, &mime);
2728    CHECK(success);
2729    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2730        mOwner->beginBox("mp4v");
2731    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2732        mOwner->beginBox("s263");
2733    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2734        mOwner->beginBox("avc1");
2735    } else {
2736        ALOGE("Unknown mime type '%s'.", mime);
2737        CHECK(!"should not be here, unknown mime type.");
2738    }
2739
2740    mOwner->writeInt32(0);           // reserved
2741    mOwner->writeInt16(0);           // reserved
2742    mOwner->writeInt16(1);           // data ref index
2743    mOwner->writeInt16(0);           // predefined
2744    mOwner->writeInt16(0);           // reserved
2745    mOwner->writeInt32(0);           // predefined
2746    mOwner->writeInt32(0);           // predefined
2747    mOwner->writeInt32(0);           // predefined
2748
2749    int32_t width, height;
2750    success = mMeta->findInt32(kKeyWidth, &width);
2751    success = success && mMeta->findInt32(kKeyHeight, &height);
2752    CHECK(success);
2753
2754    mOwner->writeInt16(width);
2755    mOwner->writeInt16(height);
2756    mOwner->writeInt32(0x480000);    // horiz resolution
2757    mOwner->writeInt32(0x480000);    // vert resolution
2758    mOwner->writeInt32(0);           // reserved
2759    mOwner->writeInt16(1);           // frame count
2760    mOwner->writeInt8(0);            // compressor string length
2761    mOwner->write("                               ", 31);
2762    mOwner->writeInt16(0x18);        // depth
2763    mOwner->writeInt16(-1);          // predefined
2764
2765    CHECK_LT(23 + mCodecSpecificDataSize, 128);
2766
2767    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2768        writeMp4vEsdsBox();
2769    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2770        writeD263Box();
2771    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2772        writeAvccBox();
2773    }
2774
2775    writePaspBox();
2776    mOwner->endBox();  // mp4v, s263 or avc1
2777}
2778
2779void MPEG4Writer::Track::writeAudioFourCCBox() {
2780    const char *mime;
2781    bool success = mMeta->findCString(kKeyMIMEType, &mime);
2782    CHECK(success);
2783    const char *fourcc = NULL;
2784    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
2785        fourcc = "samr";
2786    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2787        fourcc = "sawb";
2788    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2789        fourcc = "mp4a";
2790    } else {
2791        ALOGE("Unknown mime type '%s'.", mime);
2792        CHECK(!"should not be here, unknown mime type.");
2793    }
2794
2795    mOwner->beginBox(fourcc);        // audio format
2796    mOwner->writeInt32(0);           // reserved
2797    mOwner->writeInt16(0);           // reserved
2798    mOwner->writeInt16(0x1);         // data ref index
2799    mOwner->writeInt32(0);           // reserved
2800    mOwner->writeInt32(0);           // reserved
2801    int32_t nChannels;
2802    CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels));
2803    mOwner->writeInt16(nChannels);   // channel count
2804    mOwner->writeInt16(16);          // sample size
2805    mOwner->writeInt16(0);           // predefined
2806    mOwner->writeInt16(0);           // reserved
2807
2808    int32_t samplerate;
2809    success = mMeta->findInt32(kKeySampleRate, &samplerate);
2810    CHECK(success);
2811    mOwner->writeInt32(samplerate << 16);
2812    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2813        writeMp4aEsdsBox();
2814    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) ||
2815               !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2816        writeDamrBox();
2817    }
2818    mOwner->endBox();
2819}
2820
2821void MPEG4Writer::Track::writeMp4aEsdsBox() {
2822    mOwner->beginBox("esds");
2823    CHECK(mCodecSpecificData);
2824    CHECK_GT(mCodecSpecificDataSize, 0);
2825
2826    // Make sure all sizes encode to a single byte.
2827    CHECK_LT(mCodecSpecificDataSize + 23, 128);
2828
2829    mOwner->writeInt32(0);     // version=0, flags=0
2830    mOwner->writeInt8(0x03);   // ES_DescrTag
2831    mOwner->writeInt8(23 + mCodecSpecificDataSize);
2832    mOwner->writeInt16(0x0000);// ES_ID
2833    mOwner->writeInt8(0x00);
2834
2835    mOwner->writeInt8(0x04);   // DecoderConfigDescrTag
2836    mOwner->writeInt8(15 + mCodecSpecificDataSize);
2837    mOwner->writeInt8(0x40);   // objectTypeIndication ISO/IEC 14492-2
2838    mOwner->writeInt8(0x15);   // streamType AudioStream
2839
2840    mOwner->writeInt16(0x03);  // XXX
2841    mOwner->writeInt8(0x00);   // buffer size 24-bit
2842    mOwner->writeInt32(96000); // max bit rate
2843    mOwner->writeInt32(96000); // avg bit rate
2844
2845    mOwner->writeInt8(0x05);   // DecoderSpecificInfoTag
2846    mOwner->writeInt8(mCodecSpecificDataSize);
2847    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2848
2849    static const uint8_t kData2[] = {
2850        0x06,  // SLConfigDescriptorTag
2851        0x01,
2852        0x02
2853    };
2854    mOwner->write(kData2, sizeof(kData2));
2855
2856    mOwner->endBox();  // esds
2857}
2858
2859void MPEG4Writer::Track::writeMp4vEsdsBox() {
2860    CHECK(mCodecSpecificData);
2861    CHECK_GT(mCodecSpecificDataSize, 0);
2862    mOwner->beginBox("esds");
2863
2864    mOwner->writeInt32(0);    // version=0, flags=0
2865
2866    mOwner->writeInt8(0x03);  // ES_DescrTag
2867    mOwner->writeInt8(23 + mCodecSpecificDataSize);
2868    mOwner->writeInt16(0x0000);  // ES_ID
2869    mOwner->writeInt8(0x1f);
2870
2871    mOwner->writeInt8(0x04);  // DecoderConfigDescrTag
2872    mOwner->writeInt8(15 + mCodecSpecificDataSize);
2873    mOwner->writeInt8(0x20);  // objectTypeIndication ISO/IEC 14492-2
2874    mOwner->writeInt8(0x11);  // streamType VisualStream
2875
2876    static const uint8_t kData[] = {
2877        0x01, 0x77, 0x00,
2878        0x00, 0x03, 0xe8, 0x00,
2879        0x00, 0x03, 0xe8, 0x00
2880    };
2881    mOwner->write(kData, sizeof(kData));
2882
2883    mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
2884
2885    mOwner->writeInt8(mCodecSpecificDataSize);
2886    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2887
2888    static const uint8_t kData2[] = {
2889        0x06,  // SLConfigDescriptorTag
2890        0x01,
2891        0x02
2892    };
2893    mOwner->write(kData2, sizeof(kData2));
2894
2895    mOwner->endBox();  // esds
2896}
2897
2898void MPEG4Writer::Track::writeTkhdBox(uint32_t now) {
2899    mOwner->beginBox("tkhd");
2900    // Flags = 7 to indicate that the track is enabled, and
2901    // part of the presentation
2902    mOwner->writeInt32(0x07);          // version=0, flags=7
2903    mOwner->writeInt32(now);           // creation time
2904    mOwner->writeInt32(now);           // modification time
2905    mOwner->writeInt32(mTrackId);      // track id starts with 1
2906    mOwner->writeInt32(0);             // reserved
2907    int64_t trakDurationUs = getDurationUs();
2908    int32_t mvhdTimeScale = mOwner->getTimeScale();
2909    int32_t tkhdDuration =
2910        (trakDurationUs * mvhdTimeScale + 5E5) / 1E6;
2911    mOwner->writeInt32(tkhdDuration);  // in mvhd timescale
2912    mOwner->writeInt32(0);             // reserved
2913    mOwner->writeInt32(0);             // reserved
2914    mOwner->writeInt16(0);             // layer
2915    mOwner->writeInt16(0);             // alternate group
2916    mOwner->writeInt16(mIsAudio ? 0x100 : 0);  // volume
2917    mOwner->writeInt16(0);             // reserved
2918
2919    mOwner->writeCompositionMatrix(mRotation);       // matrix
2920
2921    if (mIsAudio) {
2922        mOwner->writeInt32(0);
2923        mOwner->writeInt32(0);
2924    } else {
2925        int32_t width, height;
2926        bool success = mMeta->findInt32(kKeyWidth, &width);
2927        success = success && mMeta->findInt32(kKeyHeight, &height);
2928        CHECK(success);
2929
2930        mOwner->writeInt32(width << 16);   // 32-bit fixed-point value
2931        mOwner->writeInt32(height << 16);  // 32-bit fixed-point value
2932    }
2933    mOwner->endBox();  // tkhd
2934}
2935
2936void MPEG4Writer::Track::writeVmhdBox() {
2937    mOwner->beginBox("vmhd");
2938    mOwner->writeInt32(0x01);        // version=0, flags=1
2939    mOwner->writeInt16(0);           // graphics mode
2940    mOwner->writeInt16(0);           // opcolor
2941    mOwner->writeInt16(0);
2942    mOwner->writeInt16(0);
2943    mOwner->endBox();
2944}
2945
2946void MPEG4Writer::Track::writeSmhdBox() {
2947    mOwner->beginBox("smhd");
2948    mOwner->writeInt32(0);           // version=0, flags=0
2949    mOwner->writeInt16(0);           // balance
2950    mOwner->writeInt16(0);           // reserved
2951    mOwner->endBox();
2952}
2953
2954void MPEG4Writer::Track::writeHdlrBox() {
2955    mOwner->beginBox("hdlr");
2956    mOwner->writeInt32(0);             // version=0, flags=0
2957    mOwner->writeInt32(0);             // component type: should be mhlr
2958    mOwner->writeFourcc(mIsAudio ? "soun" : "vide");  // component subtype
2959    mOwner->writeInt32(0);             // reserved
2960    mOwner->writeInt32(0);             // reserved
2961    mOwner->writeInt32(0);             // reserved
2962    // Removing "r" for the name string just makes the string 4 byte aligned
2963    mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle");  // name
2964    mOwner->endBox();
2965}
2966
2967void MPEG4Writer::Track::writeMdhdBox(uint32_t now) {
2968    int64_t trakDurationUs = getDurationUs();
2969    mOwner->beginBox("mdhd");
2970    mOwner->writeInt32(0);             // version=0, flags=0
2971    mOwner->writeInt32(now);           // creation time
2972    mOwner->writeInt32(now);           // modification time
2973    mOwner->writeInt32(mTimeScale);    // media timescale
2974    int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6;
2975    mOwner->writeInt32(mdhdDuration);  // use media timescale
2976    // Language follows the three letter standard ISO-639-2/T
2977    // 'e', 'n', 'g' for "English", for instance.
2978    // Each character is packed as the difference between its ASCII value and 0x60.
2979    // For "English", these are 00101, 01110, 00111.
2980    // XXX: Where is the padding bit located: 0x15C7?
2981    mOwner->writeInt16(0);             // language code
2982    mOwner->writeInt16(0);             // predefined
2983    mOwner->endBox();
2984}
2985
2986void MPEG4Writer::Track::writeDamrBox() {
2987    // 3gpp2 Spec AMRSampleEntry fields
2988    mOwner->beginBox("damr");
2989    mOwner->writeCString("   ");  // vendor: 4 bytes
2990    mOwner->writeInt8(0);         // decoder version
2991    mOwner->writeInt16(0x83FF);   // mode set: all enabled
2992    mOwner->writeInt8(0);         // mode change period
2993    mOwner->writeInt8(1);         // frames per sample
2994    mOwner->endBox();
2995}
2996
2997void MPEG4Writer::Track::writeUrlBox() {
2998    // The table index here refers to the sample description index
2999    // in the sample table entries.
3000    mOwner->beginBox("url ");
3001    mOwner->writeInt32(1);  // version=0, flags=1 (self-contained)
3002    mOwner->endBox();  // url
3003}
3004
3005void MPEG4Writer::Track::writeDrefBox() {
3006    mOwner->beginBox("dref");
3007    mOwner->writeInt32(0);  // version=0, flags=0
3008    mOwner->writeInt32(1);  // entry count (either url or urn)
3009    writeUrlBox();
3010    mOwner->endBox();  // dref
3011}
3012
3013void MPEG4Writer::Track::writeDinfBox() {
3014    mOwner->beginBox("dinf");
3015    writeDrefBox();
3016    mOwner->endBox();  // dinf
3017}
3018
3019void MPEG4Writer::Track::writeAvccBox() {
3020    CHECK(mCodecSpecificData);
3021    CHECK_GE(mCodecSpecificDataSize, 5);
3022
3023    // Patch avcc's lengthSize field to match the number
3024    // of bytes we use to indicate the size of a nal unit.
3025    uint8_t *ptr = (uint8_t *)mCodecSpecificData;
3026    ptr[4] = (ptr[4] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1);
3027    mOwner->beginBox("avcC");
3028    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
3029    mOwner->endBox();  // avcC
3030}
3031
3032void MPEG4Writer::Track::writeD263Box() {
3033    mOwner->beginBox("d263");
3034    mOwner->writeInt32(0);  // vendor
3035    mOwner->writeInt8(0);   // decoder version
3036    mOwner->writeInt8(10);  // level: 10
3037    mOwner->writeInt8(0);   // profile: 0
3038    mOwner->endBox();  // d263
3039}
3040
3041// This is useful if the pixel is not square
3042void MPEG4Writer::Track::writePaspBox() {
3043    mOwner->beginBox("pasp");
3044    mOwner->writeInt32(1 << 16);  // hspacing
3045    mOwner->writeInt32(1 << 16);  // vspacing
3046    mOwner->endBox();  // pasp
3047}
3048
3049int32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const {
3050    int64_t trackStartTimeOffsetUs = 0;
3051    int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
3052    if (mStartTimestampUs != moovStartTimeUs) {
3053        CHECK_GT(mStartTimestampUs, moovStartTimeUs);
3054        trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
3055    }
3056    return (trackStartTimeOffsetUs *  mTimeScale + 500000LL) / 1000000LL;
3057}
3058
3059void MPEG4Writer::Track::writeSttsBox() {
3060    mOwner->beginBox("stts");
3061    mOwner->writeInt32(0);  // version=0, flags=0
3062    uint32_t duration;
3063    CHECK(mSttsTableEntries->get(duration, 1));
3064    duration = htonl(duration);  // Back to host byte order
3065    mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1);
3066    mSttsTableEntries->write(mOwner);
3067    mOwner->endBox();  // stts
3068}
3069
3070void MPEG4Writer::Track::writeCttsBox() {
3071    if (mIsAudio) {  // ctts is not for audio
3072        return;
3073    }
3074
3075    // There is no B frame at all
3076    if (mMinCttsOffsetTimeUs == mMaxCttsOffsetTimeUs) {
3077        return;
3078    }
3079
3080    // Do not write ctts box when there is no need to have it.
3081    if (mCttsTableEntries->count() == 0) {
3082        return;
3083    }
3084
3085    ALOGV("ctts box has %d entries with range [%" PRId64 ", %" PRId64 "]",
3086            mCttsTableEntries->count(), mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs);
3087
3088    mOwner->beginBox("ctts");
3089    mOwner->writeInt32(0);  // version=0, flags=0
3090    uint32_t duration;
3091    CHECK(mCttsTableEntries->get(duration, 1));
3092    duration = htonl(duration);  // Back host byte order
3093    mCttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime() - mMinCttsOffsetTimeUs), 1);
3094    mCttsTableEntries->write(mOwner);
3095    mOwner->endBox();  // ctts
3096}
3097
3098void MPEG4Writer::Track::writeStssBox() {
3099    mOwner->beginBox("stss");
3100    mOwner->writeInt32(0);  // version=0, flags=0
3101    mStssTableEntries->write(mOwner);
3102    mOwner->endBox();  // stss
3103}
3104
3105void MPEG4Writer::Track::writeStszBox() {
3106    mOwner->beginBox("stsz");
3107    mOwner->writeInt32(0);  // version=0, flags=0
3108    mOwner->writeInt32(0);
3109    mStszTableEntries->write(mOwner);
3110    mOwner->endBox();  // stsz
3111}
3112
3113void MPEG4Writer::Track::writeStscBox() {
3114    mOwner->beginBox("stsc");
3115    mOwner->writeInt32(0);  // version=0, flags=0
3116    mStscTableEntries->write(mOwner);
3117    mOwner->endBox();  // stsc
3118}
3119
3120void MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) {
3121    mOwner->beginBox(use32BitOffset? "stco": "co64");
3122    mOwner->writeInt32(0);  // version=0, flags=0
3123    if (use32BitOffset) {
3124        mStcoTableEntries->write(mOwner);
3125    } else {
3126        mCo64TableEntries->write(mOwner);
3127    }
3128    mOwner->endBox();  // stco or co64
3129}
3130
3131void MPEG4Writer::writeUdtaBox() {
3132    beginBox("udta");
3133    writeGeoDataBox();
3134    endBox();
3135}
3136
3137void MPEG4Writer::writeHdlr() {
3138    beginBox("hdlr");
3139    writeInt32(0); // Version, Flags
3140    writeInt32(0); // Predefined
3141    writeFourcc("mdta");
3142    writeInt32(0); // Reserved[0]
3143    writeInt32(0); // Reserved[1]
3144    writeInt32(0); // Reserved[2]
3145    writeInt8(0);  // Name (empty)
3146    endBox();
3147}
3148
3149void MPEG4Writer::writeKeys() {
3150    size_t count = mMetaKeys->countEntries();
3151
3152    beginBox("keys");
3153    writeInt32(0);     // Version, Flags
3154    writeInt32(count); // Entry_count
3155    for (size_t i = 0; i < count; i++) {
3156        AMessage::Type type;
3157        const char *key = mMetaKeys->getEntryNameAt(i, &type);
3158        size_t n = strlen(key);
3159        writeInt32(n + 8);
3160        writeFourcc("mdta");
3161        write(key, n); // write without the \0
3162    }
3163    endBox();
3164}
3165
3166void MPEG4Writer::writeIlst() {
3167    size_t count = mMetaKeys->countEntries();
3168
3169    beginBox("ilst");
3170    for (size_t i = 0; i < count; i++) {
3171        beginBox(i + 1); // key id (1-based)
3172        beginBox("data");
3173        AMessage::Type type;
3174        const char *key = mMetaKeys->getEntryNameAt(i, &type);
3175        switch (type) {
3176            case AMessage::kTypeString:
3177            {
3178                AString val;
3179                CHECK(mMetaKeys->findString(key, &val));
3180                writeInt32(1); // type = UTF8
3181                writeInt32(0); // default country/language
3182                write(val.c_str(), strlen(val.c_str())); // write without \0
3183                break;
3184            }
3185
3186            case AMessage::kTypeFloat:
3187            {
3188                float val;
3189                CHECK(mMetaKeys->findFloat(key, &val));
3190                writeInt32(23); // type = float32
3191                writeInt32(0);  // default country/language
3192                writeInt32(*reinterpret_cast<int32_t *>(&val));
3193                break;
3194            }
3195
3196            case AMessage::kTypeInt32:
3197            {
3198                int32_t val;
3199                CHECK(mMetaKeys->findInt32(key, &val));
3200                writeInt32(67); // type = signed int32
3201                writeInt32(0);  // default country/language
3202                writeInt32(val);
3203                break;
3204            }
3205
3206            default:
3207            {
3208                ALOGW("Unsupported key type, writing 0 instead");
3209                writeInt32(77); // type = unsigned int32
3210                writeInt32(0);  // default country/language
3211                writeInt32(0);
3212                break;
3213            }
3214        }
3215        endBox(); // data
3216        endBox(); // key id
3217    }
3218    endBox(); // ilst
3219}
3220
3221void MPEG4Writer::writeMetaBox() {
3222    size_t count = mMetaKeys->countEntries();
3223    if (count == 0) {
3224        return;
3225    }
3226
3227    beginBox("meta");
3228    writeHdlr();
3229    writeKeys();
3230    writeIlst();
3231    endBox();
3232}
3233
3234/*
3235 * Geodata is stored according to ISO-6709 standard.
3236 */
3237void MPEG4Writer::writeGeoDataBox() {
3238    beginBox("\xA9xyz");
3239    /*
3240     * For historical reasons, any user data start
3241     * with "\0xA9", must be followed by its assoicated
3242     * language code.
3243     * 0x0012: text string length
3244     * 0x15c7: lang (locale) code: en
3245     */
3246    writeInt32(0x001215c7);
3247    writeLatitude(mLatitudex10000);
3248    writeLongitude(mLongitudex10000);
3249    writeInt8(0x2F);
3250    endBox();
3251}
3252
3253}  // namespace android
3254