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