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