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