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