MPEG4Writer.cpp revision 56eab8ec67058fe06d6014c56600021e2b965c9e
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    // Rotation angle in HEIF is CCW, framework angle is CW.
1966    int32_t heifRotation = 0;
1967    switch(mRotation) {
1968        case 90: heifRotation = 3; break;
1969        case 180: heifRotation = 2; break;
1970        case 270: heifRotation = 1; break;
1971        default: break; // don't set if invalid
1972    }
1973
1974    bool hasGrid = (mNumTiles > 1);
1975
1976    if (mProperties.empty()) {
1977        mProperties.push_back(mOwner->addProperty_l({
1978            .type = FOURCC('h', 'v', 'c', 'C'),
1979            .hvcc = ABuffer::CreateAsCopy(mCodecSpecificData, mCodecSpecificDataSize)
1980        }));
1981
1982        mProperties.push_back(mOwner->addProperty_l({
1983            .type = FOURCC('i', 's', 'p', 'e'),
1984            .width = hasGrid ? mGridWidth : mWidth,
1985            .height = hasGrid ? mGridHeight : mHeight,
1986        }));
1987
1988        if (!hasGrid && heifRotation > 0) {
1989            mProperties.push_back(mOwner->addProperty_l({
1990                .type = FOURCC('i', 'r', 'o', 't'),
1991                .rotation = heifRotation,
1992            }));
1993        }
1994    }
1995
1996    uint16_t itemId = mOwner->addItem_l({
1997        .itemType = "hvc1",
1998        .isPrimary = hasGrid ? false : (mIsPrimary != 0),
1999        .isHidden = hasGrid,
2000        .offset = (uint32_t)offset,
2001        .size = (uint32_t)size,
2002        .properties = mProperties,
2003    });
2004
2005    mTileIndex++;
2006    if (hasGrid) {
2007        mDimgRefs.push_back(itemId);
2008
2009        if (mTileIndex == mNumTiles) {
2010            mProperties.clear();
2011            mProperties.push_back(mOwner->addProperty_l({
2012                .type = FOURCC('i', 's', 'p', 'e'),
2013                .width = mWidth,
2014                .height = mHeight,
2015            }));
2016            if (heifRotation > 0) {
2017                mProperties.push_back(mOwner->addProperty_l({
2018                    .type = FOURCC('i', 'r', 'o', 't'),
2019                    .rotation = heifRotation,
2020                }));
2021            }
2022            mOwner->addItem_l({
2023                .itemType = "grid",
2024                .isPrimary = (mIsPrimary != 0),
2025                .isHidden = false,
2026                .rows = (uint32_t)mGridRows,
2027                .cols = (uint32_t)mGridCols,
2028                .width = (uint32_t)mWidth,
2029                .height = (uint32_t)mHeight,
2030                .properties = mProperties,
2031                .dimgRefs = mDimgRefs,
2032            });
2033        }
2034    }
2035}
2036
2037void MPEG4Writer::Track::setTimeScale() {
2038    ALOGV("setTimeScale");
2039    // Default time scale
2040    mTimeScale = 90000;
2041
2042    if (mIsAudio) {
2043        // Use the sampling rate as the default time scale for audio track.
2044        int32_t sampleRate;
2045        bool success = mMeta->findInt32(kKeySampleRate, &sampleRate);
2046        CHECK(success);
2047        mTimeScale = sampleRate;
2048    }
2049
2050    // If someone would like to overwrite the timescale, use user-supplied value.
2051    int32_t timeScale;
2052    if (mMeta->findInt32(kKeyTimeScale, &timeScale)) {
2053        mTimeScale = timeScale;
2054    }
2055
2056    CHECK_GT(mTimeScale, 0);
2057}
2058
2059void MPEG4Writer::onMessageReceived(const sp<AMessage> &msg) {
2060    switch (msg->what()) {
2061        case kWhatSwitch:
2062        {
2063            finishCurrentSession();
2064            mLock.lock();
2065            int fd = mNextFd;
2066            mNextFd = -1;
2067            mLock.unlock();
2068            initInternal(fd, false /*isFirstSession*/);
2069            start(mStartMeta.get());
2070            mSwitchPending = false;
2071            notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED, 0);
2072            break;
2073        }
2074        default:
2075        TRESPASS();
2076    }
2077}
2078
2079void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
2080    const char *mime;
2081
2082    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
2083
2084    uint32_t type;
2085    const void *data = NULL;
2086    size_t size = 0;
2087    if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
2088        mMeta->findData(kKeyAVCC, &type, &data, &size);
2089    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC) ||
2090               !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
2091        mMeta->findData(kKeyHVCC, &type, &data, &size);
2092    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
2093            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
2094        if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
2095            ESDS esds(data, size);
2096            if (esds.getCodecSpecificInfo(&data, &size) == OK &&
2097                    data != NULL &&
2098                    copyCodecSpecificData((uint8_t*)data, size) == OK) {
2099                mGotAllCodecSpecificData = true;
2100            }
2101            return;
2102        }
2103    }
2104    if (data != NULL && copyCodecSpecificData((uint8_t *)data, size) == OK) {
2105        mGotAllCodecSpecificData = true;
2106    }
2107}
2108
2109MPEG4Writer::Track::~Track() {
2110    stop();
2111
2112    delete mStszTableEntries;
2113    delete mStcoTableEntries;
2114    delete mCo64TableEntries;
2115    delete mStscTableEntries;
2116    delete mSttsTableEntries;
2117    delete mStssTableEntries;
2118    delete mCttsTableEntries;
2119
2120    mStszTableEntries = NULL;
2121    mStcoTableEntries = NULL;
2122    mCo64TableEntries = NULL;
2123    mStscTableEntries = NULL;
2124    mSttsTableEntries = NULL;
2125    mStssTableEntries = NULL;
2126    mCttsTableEntries = NULL;
2127
2128    if (mCodecSpecificData != NULL) {
2129        free(mCodecSpecificData);
2130        mCodecSpecificData = NULL;
2131    }
2132}
2133
2134void MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) {
2135    ALOGV("initTrackingProgressStatus");
2136    mPreviousTrackTimeUs = -1;
2137    mTrackingProgressStatus = false;
2138    mTrackEveryTimeDurationUs = 0;
2139    {
2140        int64_t timeUs;
2141        if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) {
2142            ALOGV("Receive request to track progress status for every %" PRId64 " us", timeUs);
2143            mTrackEveryTimeDurationUs = timeUs;
2144            mTrackingProgressStatus = true;
2145        }
2146    }
2147}
2148
2149// static
2150void *MPEG4Writer::ThreadWrapper(void *me) {
2151    ALOGV("ThreadWrapper: %p", me);
2152    MPEG4Writer *writer = static_cast<MPEG4Writer *>(me);
2153    writer->threadFunc();
2154    return NULL;
2155}
2156
2157void MPEG4Writer::bufferChunk(const Chunk& chunk) {
2158    ALOGV("bufferChunk: %p", chunk.mTrack);
2159    Mutex::Autolock autolock(mLock);
2160    CHECK_EQ(mDone, false);
2161
2162    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
2163         it != mChunkInfos.end(); ++it) {
2164
2165        if (chunk.mTrack == it->mTrack) {  // Found owner
2166            it->mChunks.push_back(chunk);
2167            mChunkReadyCondition.signal();
2168            return;
2169        }
2170    }
2171
2172    CHECK(!"Received a chunk for a unknown track");
2173}
2174
2175void MPEG4Writer::writeChunkToFile(Chunk* chunk) {
2176    ALOGV("writeChunkToFile: %" PRId64 " from %s track",
2177        chunk->mTimeStampUs, chunk->mTrack->getTrackType());
2178
2179    int32_t isFirstSample = true;
2180    bool usePrefix = chunk->mTrack->usePrefix();
2181    while (!chunk->mSamples.empty()) {
2182        List<MediaBuffer *>::iterator it = chunk->mSamples.begin();
2183
2184        size_t bytesWritten;
2185        off64_t offset = addSample_l(*it, usePrefix, &bytesWritten);
2186
2187        if (chunk->mTrack->isHeic()) {
2188            chunk->mTrack->addItemOffsetAndSize(offset, bytesWritten);
2189        } else if (isFirstSample) {
2190            chunk->mTrack->addChunkOffset(offset);
2191            isFirstSample = false;
2192        }
2193
2194        (*it)->release();
2195        (*it) = NULL;
2196        chunk->mSamples.erase(it);
2197    }
2198    chunk->mSamples.clear();
2199}
2200
2201void MPEG4Writer::writeAllChunks() {
2202    ALOGV("writeAllChunks");
2203    size_t outstandingChunks = 0;
2204    Chunk chunk;
2205    while (findChunkToWrite(&chunk)) {
2206        writeChunkToFile(&chunk);
2207        ++outstandingChunks;
2208    }
2209
2210    sendSessionSummary();
2211
2212    mChunkInfos.clear();
2213    ALOGD("%zu chunks are written in the last batch", outstandingChunks);
2214}
2215
2216bool MPEG4Writer::findChunkToWrite(Chunk *chunk) {
2217    ALOGV("findChunkToWrite");
2218
2219    int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL;
2220    Track *track = NULL;
2221    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
2222         it != mChunkInfos.end(); ++it) {
2223        if (!it->mChunks.empty()) {
2224            List<Chunk>::iterator chunkIt = it->mChunks.begin();
2225            if (chunkIt->mTimeStampUs < minTimestampUs) {
2226                minTimestampUs = chunkIt->mTimeStampUs;
2227                track = it->mTrack;
2228            }
2229        }
2230    }
2231
2232    if (track == NULL) {
2233        ALOGV("Nothing to be written after all");
2234        return false;
2235    }
2236
2237    if (mIsFirstChunk) {
2238        mIsFirstChunk = false;
2239    }
2240
2241    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
2242         it != mChunkInfos.end(); ++it) {
2243        if (it->mTrack == track) {
2244            *chunk = *(it->mChunks.begin());
2245            it->mChunks.erase(it->mChunks.begin());
2246            CHECK_EQ(chunk->mTrack, track);
2247
2248            int64_t interChunkTimeUs =
2249                chunk->mTimeStampUs - it->mPrevChunkTimestampUs;
2250            if (interChunkTimeUs > it->mPrevChunkTimestampUs) {
2251                it->mMaxInterChunkDurUs = interChunkTimeUs;
2252            }
2253
2254            return true;
2255        }
2256    }
2257
2258    return false;
2259}
2260
2261void MPEG4Writer::threadFunc() {
2262    ALOGV("threadFunc");
2263
2264    prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0);
2265
2266    Mutex::Autolock autoLock(mLock);
2267    while (!mDone) {
2268        Chunk chunk;
2269        bool chunkFound = false;
2270
2271        while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) {
2272            mChunkReadyCondition.wait(mLock);
2273        }
2274
2275        // In real time recording mode, write without holding the lock in order
2276        // to reduce the blocking time for media track threads.
2277        // Otherwise, hold the lock until the existing chunks get written to the
2278        // file.
2279        if (chunkFound) {
2280            if (mIsRealTimeRecording) {
2281                mLock.unlock();
2282            }
2283            writeChunkToFile(&chunk);
2284            if (mIsRealTimeRecording) {
2285                mLock.lock();
2286            }
2287        }
2288    }
2289
2290    writeAllChunks();
2291}
2292
2293status_t MPEG4Writer::startWriterThread() {
2294    ALOGV("startWriterThread");
2295
2296    mDone = false;
2297    mIsFirstChunk = true;
2298    mDriftTimeUs = 0;
2299    for (List<Track *>::iterator it = mTracks.begin();
2300         it != mTracks.end(); ++it) {
2301        ChunkInfo info;
2302        info.mTrack = *it;
2303        info.mPrevChunkTimestampUs = 0;
2304        info.mMaxInterChunkDurUs = 0;
2305        mChunkInfos.push_back(info);
2306    }
2307
2308    pthread_attr_t attr;
2309    pthread_attr_init(&attr);
2310    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
2311    pthread_create(&mThread, &attr, ThreadWrapper, this);
2312    pthread_attr_destroy(&attr);
2313    mWriterThreadStarted = true;
2314    return OK;
2315}
2316
2317
2318status_t MPEG4Writer::Track::start(MetaData *params) {
2319    if (!mDone && mPaused) {
2320        mPaused = false;
2321        mResumed = true;
2322        return OK;
2323    }
2324
2325    int64_t startTimeUs;
2326    if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) {
2327        startTimeUs = 0;
2328    }
2329    mStartTimeRealUs = startTimeUs;
2330
2331    int32_t rotationDegrees;
2332    if ((mIsVideo || mIsHeic) && params &&
2333            params->findInt32(kKeyRotation, &rotationDegrees)) {
2334        mRotation = rotationDegrees;
2335    }
2336
2337    initTrackingProgressStatus(params);
2338
2339    sp<MetaData> meta = new MetaData;
2340    if (mOwner->isRealTimeRecording() && mOwner->numTracks() > 1) {
2341        /*
2342         * This extra delay of accepting incoming audio/video signals
2343         * helps to align a/v start time at the beginning of a recording
2344         * session, and it also helps eliminate the "recording" sound for
2345         * camcorder applications.
2346         *
2347         * If client does not set the start time offset, we fall back to
2348         * use the default initial delay value.
2349         */
2350        int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL;
2351        if (startTimeOffsetUs < 0) {  // Start time offset was not set
2352            startTimeOffsetUs = kInitialDelayTimeUs;
2353        }
2354        startTimeUs += startTimeOffsetUs;
2355        ALOGI("Start time offset: %" PRId64 " us", startTimeOffsetUs);
2356    }
2357
2358    meta->setInt64(kKeyTime, startTimeUs);
2359
2360    status_t err = mSource->start(meta.get());
2361    if (err != OK) {
2362        mDone = mReachedEOS = true;
2363        return err;
2364    }
2365
2366    pthread_attr_t attr;
2367    pthread_attr_init(&attr);
2368    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
2369
2370    mDone = false;
2371    mStarted = true;
2372    mTrackDurationUs = 0;
2373    mReachedEOS = false;
2374    mEstimatedTrackSizeBytes = 0;
2375    mMdatSizeBytes = 0;
2376    mMaxChunkDurationUs = 0;
2377    mLastDecodingTimeUs = -1;
2378
2379    pthread_create(&mThread, &attr, ThreadWrapper, this);
2380    pthread_attr_destroy(&attr);
2381
2382    return OK;
2383}
2384
2385status_t MPEG4Writer::Track::pause() {
2386    mPaused = true;
2387    return OK;
2388}
2389
2390status_t MPEG4Writer::Track::stop(bool stopSource) {
2391    ALOGD("%s track stopping. %s source", getTrackType(), stopSource ? "Stop" : "Not Stop");
2392    if (!mStarted) {
2393        ALOGE("Stop() called but track is not started");
2394        return ERROR_END_OF_STREAM;
2395    }
2396
2397    if (mDone) {
2398        return OK;
2399    }
2400
2401    if (stopSource) {
2402        ALOGD("%s track source stopping", getTrackType());
2403        mSource->stop();
2404        ALOGD("%s track source stopped", getTrackType());
2405    }
2406
2407    // Set mDone to be true after sucessfully stop mSource as mSource may be still outputting
2408    // buffers to the writer.
2409    mDone = true;
2410
2411    void *dummy;
2412    pthread_join(mThread, &dummy);
2413    status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
2414
2415    ALOGD("%s track stopped. %s source", getTrackType(), stopSource ? "Stop" : "Not Stop");
2416    return err;
2417}
2418
2419bool MPEG4Writer::Track::reachedEOS() {
2420    return mReachedEOS;
2421}
2422
2423// static
2424void *MPEG4Writer::Track::ThreadWrapper(void *me) {
2425    Track *track = static_cast<Track *>(me);
2426
2427    status_t err = track->threadEntry();
2428    return (void *)(uintptr_t)err;
2429}
2430
2431static void getNalUnitType(uint8_t byte, uint8_t* type) {
2432    ALOGV("getNalUnitType: %d", byte);
2433
2434    // nal_unit_type: 5-bit unsigned integer
2435    *type = (byte & 0x1F);
2436}
2437
2438const uint8_t *MPEG4Writer::Track::parseParamSet(
2439        const uint8_t *data, size_t length, int type, size_t *paramSetLen) {
2440
2441    ALOGV("parseParamSet");
2442    CHECK(type == kNalUnitTypeSeqParamSet ||
2443          type == kNalUnitTypePicParamSet);
2444
2445    const uint8_t *nextStartCode = findNextNalStartCode(data, length);
2446    *paramSetLen = nextStartCode - data;
2447    if (*paramSetLen == 0) {
2448        ALOGE("Param set is malformed, since its length is 0");
2449        return NULL;
2450    }
2451
2452    AVCParamSet paramSet(*paramSetLen, data);
2453    if (type == kNalUnitTypeSeqParamSet) {
2454        if (*paramSetLen < 4) {
2455            ALOGE("Seq parameter set malformed");
2456            return NULL;
2457        }
2458        if (mSeqParamSets.empty()) {
2459            mProfileIdc = data[1];
2460            mProfileCompatible = data[2];
2461            mLevelIdc = data[3];
2462        } else {
2463            if (mProfileIdc != data[1] ||
2464                mProfileCompatible != data[2] ||
2465                mLevelIdc != data[3]) {
2466                // COULD DO: set profile/level to the lowest required to support all SPSs
2467                ALOGE("Inconsistent profile/level found in seq parameter sets");
2468                return NULL;
2469            }
2470        }
2471        mSeqParamSets.push_back(paramSet);
2472    } else {
2473        mPicParamSets.push_back(paramSet);
2474    }
2475    return nextStartCode;
2476}
2477
2478status_t MPEG4Writer::Track::copyAVCCodecSpecificData(
2479        const uint8_t *data, size_t size) {
2480    ALOGV("copyAVCCodecSpecificData");
2481
2482    // 2 bytes for each of the parameter set length field
2483    // plus the 7 bytes for the header
2484    return copyCodecSpecificData(data, size, 4 + 7);
2485}
2486
2487status_t MPEG4Writer::Track::copyHEVCCodecSpecificData(
2488        const uint8_t *data, size_t size) {
2489    ALOGV("copyHEVCCodecSpecificData");
2490
2491    // Min length of HEVC CSD is 23. (ISO/IEC 14496-15:2014 Chapter 8.3.3.1.2)
2492    return copyCodecSpecificData(data, size, 23);
2493}
2494
2495status_t MPEG4Writer::Track::copyCodecSpecificData(
2496        const uint8_t *data, size_t size, size_t minLength) {
2497    if (size < minLength) {
2498        ALOGE("Codec specific data length too short: %zu", size);
2499        return ERROR_MALFORMED;
2500    }
2501
2502    mCodecSpecificData = malloc(size);
2503    if (mCodecSpecificData == NULL) {
2504        ALOGE("Failed allocating codec specific data");
2505        return NO_MEMORY;
2506    }
2507    mCodecSpecificDataSize = size;
2508    memcpy(mCodecSpecificData, data, size);
2509    return OK;
2510}
2511
2512status_t MPEG4Writer::Track::parseAVCCodecSpecificData(
2513        const uint8_t *data, size_t size) {
2514
2515    ALOGV("parseAVCCodecSpecificData");
2516    // Data starts with a start code.
2517    // SPS and PPS are separated with start codes.
2518    // Also, SPS must come before PPS
2519    uint8_t type = kNalUnitTypeSeqParamSet;
2520    bool gotSps = false;
2521    bool gotPps = false;
2522    const uint8_t *tmp = data;
2523    const uint8_t *nextStartCode = data;
2524    size_t bytesLeft = size;
2525    size_t paramSetLen = 0;
2526    mCodecSpecificDataSize = 0;
2527    while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) {
2528        getNalUnitType(*(tmp + 4), &type);
2529        if (type == kNalUnitTypeSeqParamSet) {
2530            if (gotPps) {
2531                ALOGE("SPS must come before PPS");
2532                return ERROR_MALFORMED;
2533            }
2534            if (!gotSps) {
2535                gotSps = true;
2536            }
2537            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
2538        } else if (type == kNalUnitTypePicParamSet) {
2539            if (!gotSps) {
2540                ALOGE("SPS must come before PPS");
2541                return ERROR_MALFORMED;
2542            }
2543            if (!gotPps) {
2544                gotPps = true;
2545            }
2546            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
2547        } else {
2548            ALOGE("Only SPS and PPS Nal units are expected");
2549            return ERROR_MALFORMED;
2550        }
2551
2552        if (nextStartCode == NULL) {
2553            return ERROR_MALFORMED;
2554        }
2555
2556        // Move on to find the next parameter set
2557        bytesLeft -= nextStartCode - tmp;
2558        tmp = nextStartCode;
2559        mCodecSpecificDataSize += (2 + paramSetLen);
2560    }
2561
2562    {
2563        // Check on the number of seq parameter sets
2564        size_t nSeqParamSets = mSeqParamSets.size();
2565        if (nSeqParamSets == 0) {
2566            ALOGE("Cound not find sequence parameter set");
2567            return ERROR_MALFORMED;
2568        }
2569
2570        if (nSeqParamSets > 0x1F) {
2571            ALOGE("Too many seq parameter sets (%zu) found", nSeqParamSets);
2572            return ERROR_MALFORMED;
2573        }
2574    }
2575
2576    {
2577        // Check on the number of pic parameter sets
2578        size_t nPicParamSets = mPicParamSets.size();
2579        if (nPicParamSets == 0) {
2580            ALOGE("Cound not find picture parameter set");
2581            return ERROR_MALFORMED;
2582        }
2583        if (nPicParamSets > 0xFF) {
2584            ALOGE("Too many pic parameter sets (%zd) found", nPicParamSets);
2585            return ERROR_MALFORMED;
2586        }
2587    }
2588// FIXME:
2589// Add chromat_format_idc, bit depth values, etc for AVC/h264 high profile and above
2590// and remove #if 0
2591#if 0
2592    {
2593        // Check on the profiles
2594        // These profiles requires additional parameter set extensions
2595        if (mProfileIdc == 100 || mProfileIdc == 110 ||
2596            mProfileIdc == 122 || mProfileIdc == 144) {
2597            ALOGE("Sorry, no support for profile_idc: %d!", mProfileIdc);
2598            return BAD_VALUE;
2599        }
2600    }
2601#endif
2602    return OK;
2603}
2604
2605status_t MPEG4Writer::Track::makeAVCCodecSpecificData(
2606        const uint8_t *data, size_t size) {
2607
2608    if (mCodecSpecificData != NULL) {
2609        ALOGE("Already have codec specific data");
2610        return ERROR_MALFORMED;
2611    }
2612
2613    if (size < 4) {
2614        ALOGE("Codec specific data length too short: %zu", size);
2615        return ERROR_MALFORMED;
2616    }
2617
2618    // Data is in the form of AVCCodecSpecificData
2619    if (memcmp("\x00\x00\x00\x01", data, 4)) {
2620        return copyAVCCodecSpecificData(data, size);
2621    }
2622
2623    if (parseAVCCodecSpecificData(data, size) != OK) {
2624        return ERROR_MALFORMED;
2625    }
2626
2627    // ISO 14496-15: AVC file format
2628    mCodecSpecificDataSize += 7;  // 7 more bytes in the header
2629    mCodecSpecificData = malloc(mCodecSpecificDataSize);
2630    if (mCodecSpecificData == NULL) {
2631        mCodecSpecificDataSize = 0;
2632        ALOGE("Failed allocating codec specific data");
2633        return NO_MEMORY;
2634    }
2635    uint8_t *header = (uint8_t *)mCodecSpecificData;
2636    header[0] = 1;                     // version
2637    header[1] = mProfileIdc;           // profile indication
2638    header[2] = mProfileCompatible;    // profile compatibility
2639    header[3] = mLevelIdc;
2640
2641    // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne
2642    if (mOwner->useNalLengthFour()) {
2643        header[4] = 0xfc | 3;  // length size == 4 bytes
2644    } else {
2645        header[4] = 0xfc | 1;  // length size == 2 bytes
2646    }
2647
2648    // 3-bit '111' followed by 5-bit numSequenceParameterSets
2649    int nSequenceParamSets = mSeqParamSets.size();
2650    header[5] = 0xe0 | nSequenceParamSets;
2651    header += 6;
2652    for (List<AVCParamSet>::iterator it = mSeqParamSets.begin();
2653         it != mSeqParamSets.end(); ++it) {
2654        // 16-bit sequence parameter set length
2655        uint16_t seqParamSetLength = it->mLength;
2656        header[0] = seqParamSetLength >> 8;
2657        header[1] = seqParamSetLength & 0xff;
2658
2659        // SPS NAL unit (sequence parameter length bytes)
2660        memcpy(&header[2], it->mData, seqParamSetLength);
2661        header += (2 + seqParamSetLength);
2662    }
2663
2664    // 8-bit nPictureParameterSets
2665    int nPictureParamSets = mPicParamSets.size();
2666    header[0] = nPictureParamSets;
2667    header += 1;
2668    for (List<AVCParamSet>::iterator it = mPicParamSets.begin();
2669         it != mPicParamSets.end(); ++it) {
2670        // 16-bit picture parameter set length
2671        uint16_t picParamSetLength = it->mLength;
2672        header[0] = picParamSetLength >> 8;
2673        header[1] = picParamSetLength & 0xff;
2674
2675        // PPS Nal unit (picture parameter set length bytes)
2676        memcpy(&header[2], it->mData, picParamSetLength);
2677        header += (2 + picParamSetLength);
2678    }
2679
2680    return OK;
2681}
2682
2683
2684status_t MPEG4Writer::Track::parseHEVCCodecSpecificData(
2685        const uint8_t *data, size_t size, HevcParameterSets &paramSets) {
2686
2687    ALOGV("parseHEVCCodecSpecificData");
2688    const uint8_t *tmp = data;
2689    const uint8_t *nextStartCode = data;
2690    size_t bytesLeft = size;
2691    while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) {
2692        nextStartCode = findNextNalStartCode(tmp + 4, bytesLeft - 4);
2693        status_t err = paramSets.addNalUnit(tmp + 4, (nextStartCode - tmp) - 4);
2694        if (err != OK) {
2695            return ERROR_MALFORMED;
2696        }
2697
2698        // Move on to find the next parameter set
2699        bytesLeft -= nextStartCode - tmp;
2700        tmp = nextStartCode;
2701    }
2702
2703    size_t csdSize = 23;
2704    const size_t numNalUnits = paramSets.getNumNalUnits();
2705    for (size_t i = 0; i < ARRAY_SIZE(kMandatoryHevcNalUnitTypes); ++i) {
2706        int type = kMandatoryHevcNalUnitTypes[i];
2707        size_t numParamSets = paramSets.getNumNalUnitsOfType(type);
2708        if (numParamSets == 0) {
2709            ALOGE("Cound not find NAL unit of type %d", type);
2710            return ERROR_MALFORMED;
2711        }
2712    }
2713    for (size_t i = 0; i < ARRAY_SIZE(kHevcNalUnitTypes); ++i) {
2714        int type = kHevcNalUnitTypes[i];
2715        size_t numParamSets = paramSets.getNumNalUnitsOfType(type);
2716        if (numParamSets > 0xffff) {
2717            ALOGE("Too many seq parameter sets (%zu) found", numParamSets);
2718            return ERROR_MALFORMED;
2719        }
2720        csdSize += 3;
2721        for (size_t j = 0; j < numNalUnits; ++j) {
2722            if (paramSets.getType(j) != type) {
2723                continue;
2724            }
2725            csdSize += 2 + paramSets.getSize(j);
2726        }
2727    }
2728    mCodecSpecificDataSize = csdSize;
2729    return OK;
2730}
2731
2732status_t MPEG4Writer::Track::makeHEVCCodecSpecificData(
2733        const uint8_t *data, size_t size) {
2734
2735    if (mCodecSpecificData != NULL) {
2736        ALOGE("Already have codec specific data");
2737        return ERROR_MALFORMED;
2738    }
2739
2740    if (size < 4) {
2741        ALOGE("Codec specific data length too short: %zu", size);
2742        return ERROR_MALFORMED;
2743    }
2744
2745    // Data is in the form of HEVCCodecSpecificData
2746    if (memcmp("\x00\x00\x00\x01", data, 4)) {
2747        return copyHEVCCodecSpecificData(data, size);
2748    }
2749
2750    HevcParameterSets paramSets;
2751    if (parseHEVCCodecSpecificData(data, size, paramSets) != OK) {
2752        ALOGE("failed parsing codec specific data");
2753        return ERROR_MALFORMED;
2754    }
2755
2756    mCodecSpecificData = malloc(mCodecSpecificDataSize);
2757    if (mCodecSpecificData == NULL) {
2758        mCodecSpecificDataSize = 0;
2759        ALOGE("Failed allocating codec specific data");
2760        return NO_MEMORY;
2761    }
2762    status_t err = paramSets.makeHvcc((uint8_t *)mCodecSpecificData,
2763            &mCodecSpecificDataSize, mOwner->useNalLengthFour() ? 4 : 2);
2764    if (err != OK) {
2765        ALOGE("failed constructing HVCC atom");
2766        return err;
2767    }
2768
2769    return OK;
2770}
2771
2772/*
2773 * Updates the drift time from the audio track so that
2774 * the video track can get the updated drift time information
2775 * from the file writer. The fluctuation of the drift time of the audio
2776 * encoding path is smoothed out with a simple filter by giving a larger
2777 * weight to more recently drift time. The filter coefficients, 0.5 and 0.5,
2778 * are heuristically determined.
2779 */
2780void MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) {
2781    int64_t driftTimeUs = 0;
2782    if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) {
2783        int64_t prevDriftTimeUs = mOwner->getDriftTimeUs();
2784        int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1;
2785        mOwner->setDriftTimeUs(timeUs);
2786    }
2787}
2788
2789void MPEG4Writer::Track::dumpTimeStamps() {
2790    ALOGE("Dumping %s track's last 10 frames timestamp and frame type ", getTrackType());
2791    std::string timeStampString;
2792    for (std::list<TimestampDebugHelperEntry>::iterator entry = mTimestampDebugHelper.begin();
2793            entry != mTimestampDebugHelper.end(); ++entry) {
2794        timeStampString += "(" + std::to_string(entry->pts)+
2795                "us, " + std::to_string(entry->dts) + "us " + entry->frameType + ") ";
2796    }
2797    ALOGE("%s", timeStampString.c_str());
2798}
2799
2800status_t MPEG4Writer::Track::threadEntry() {
2801    int32_t count = 0;
2802    const int64_t interleaveDurationUs = mOwner->interleaveDuration();
2803    const bool hasMultipleTracks = (mOwner->numTracks() > 1);
2804    int64_t chunkTimestampUs = 0;
2805    int32_t nChunks = 0;
2806    int32_t nActualFrames = 0;        // frames containing non-CSD data (non-0 length)
2807    int32_t nZeroLengthFrames = 0;
2808    int64_t lastTimestampUs = 0;      // Previous sample time stamp
2809    int64_t lastDurationUs = 0;       // Between the previous two samples
2810    int64_t currDurationTicks = 0;    // Timescale based ticks
2811    int64_t lastDurationTicks = 0;    // Timescale based ticks
2812    int32_t sampleCount = 1;          // Sample count in the current stts table entry
2813    uint32_t previousSampleSize = 0;  // Size of the previous sample
2814    int64_t previousPausedDurationUs = 0;
2815    int64_t timestampUs = 0;
2816    int64_t cttsOffsetTimeUs = 0;
2817    int64_t currCttsOffsetTimeTicks = 0;   // Timescale based ticks
2818    int64_t lastCttsOffsetTimeTicks = -1;  // Timescale based ticks
2819    int32_t cttsSampleCount = 0;           // Sample count in the current ctts table entry
2820    uint32_t lastSamplesPerChunk = 0;
2821
2822    if (mIsAudio) {
2823        prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
2824    } else if (mIsVideo) {
2825        prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0);
2826    } else {
2827        prctl(PR_SET_NAME, (unsigned long)"MetadataTrackEncoding", 0, 0, 0);
2828    }
2829
2830    if (mOwner->isRealTimeRecording()) {
2831        androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
2832    }
2833
2834    sp<MetaData> meta_data;
2835
2836    status_t err = OK;
2837    MediaBufferBase *buffer;
2838    const char *trackName = getTrackType();
2839    while (!mDone && (err = mSource->read(&buffer)) == OK) {
2840        if (buffer->range_length() == 0) {
2841            buffer->release();
2842            buffer = NULL;
2843            ++nZeroLengthFrames;
2844            continue;
2845        }
2846
2847        // If the codec specific data has not been received yet, delay pause.
2848        // After the codec specific data is received, discard what we received
2849        // when the track is to be paused.
2850        if (mPaused && !mResumed) {
2851            buffer->release();
2852            buffer = NULL;
2853            continue;
2854        }
2855
2856        ++count;
2857
2858        int32_t isCodecConfig;
2859        if (buffer->meta_data().findInt32(kKeyIsCodecConfig, &isCodecConfig)
2860                && isCodecConfig) {
2861            // if config format (at track addition) already had CSD, keep that
2862            // UNLESS we have not received any frames yet.
2863            // TODO: for now the entire CSD has to come in one frame for encoders, even though
2864            // they need to be spread out for decoders.
2865            if (mGotAllCodecSpecificData && nActualFrames > 0) {
2866                ALOGI("ignoring additional CSD for video track after first frame");
2867            } else {
2868                mMeta = mSource->getFormat(); // get output format after format change
2869                status_t err;
2870                if (mIsAvc) {
2871                    err = makeAVCCodecSpecificData(
2872                            (const uint8_t *)buffer->data()
2873                                + buffer->range_offset(),
2874                            buffer->range_length());
2875                } else if (mIsHevc || mIsHeic) {
2876                    err = makeHEVCCodecSpecificData(
2877                            (const uint8_t *)buffer->data()
2878                                + buffer->range_offset(),
2879                            buffer->range_length());
2880                } else if (mIsMPEG4) {
2881                    copyCodecSpecificData((const uint8_t *)buffer->data() + buffer->range_offset(),
2882                            buffer->range_length());
2883                }
2884            }
2885
2886            buffer->release();
2887            buffer = NULL;
2888            if (OK != err) {
2889                mSource->stop();
2890                mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_ERROR,
2891                       mTrackId | MEDIA_RECORDER_TRACK_ERROR_GENERAL, err);
2892                break;
2893            }
2894
2895            mGotAllCodecSpecificData = true;
2896            continue;
2897        }
2898
2899        // Per-frame metadata sample's size must be smaller than max allowed.
2900        if (!mIsVideo && !mIsAudio && !mIsHeic &&
2901                buffer->range_length() >= kMaxMetadataSize) {
2902            ALOGW("Buffer size is %zu. Maximum metadata buffer size is %lld for %s track",
2903                    buffer->range_length(), (long long)kMaxMetadataSize, trackName);
2904            buffer->release();
2905            mSource->stop();
2906            mIsMalformed = true;
2907            break;
2908        }
2909
2910        ++nActualFrames;
2911
2912        // Make a deep copy of the MediaBuffer and Metadata and release
2913        // the original as soon as we can
2914        MediaBuffer *copy = new MediaBuffer(buffer->range_length());
2915        memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(),
2916                buffer->range_length());
2917        copy->set_range(0, buffer->range_length());
2918        meta_data = new MetaData(buffer->meta_data());
2919        buffer->release();
2920        buffer = NULL;
2921
2922        if (usePrefix()) StripStartcode(copy);
2923
2924        size_t sampleSize = copy->range_length();
2925        if (usePrefix()) {
2926            if (mOwner->useNalLengthFour()) {
2927                sampleSize += 4;
2928            } else {
2929                sampleSize += 2;
2930            }
2931        }
2932
2933        // Max file size or duration handling
2934        mMdatSizeBytes += sampleSize;
2935        updateTrackSizeEstimate();
2936
2937        if (mOwner->exceedsFileSizeLimit()) {
2938            if (mOwner->switchFd() != OK) {
2939                ALOGW("Recorded file size exceeds limit %" PRId64 "bytes",
2940                        mOwner->mMaxFileSizeLimitBytes);
2941                mSource->stop();
2942                mOwner->notify(
2943                        MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
2944            } else {
2945                ALOGV("%s Current recorded file size exceeds limit %" PRId64 "bytes. Switching output",
2946                        getTrackType(), mOwner->mMaxFileSizeLimitBytes);
2947            }
2948            copy->release();
2949            break;
2950        }
2951
2952        if (mOwner->exceedsFileDurationLimit()) {
2953            ALOGW("Recorded file duration exceeds limit %" PRId64 "microseconds",
2954                    mOwner->mMaxFileDurationLimitUs);
2955            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
2956            copy->release();
2957            mSource->stop();
2958            break;
2959        }
2960
2961        if (mOwner->approachingFileSizeLimit()) {
2962            mOwner->notifyApproachingLimit();
2963        }
2964
2965        int32_t isSync = false;
2966        meta_data->findInt32(kKeyIsSyncFrame, &isSync);
2967        CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
2968
2969        // For video, skip the first several non-key frames until getting the first key frame.
2970        if (mIsVideo && !mGotStartKeyFrame && !isSync) {
2971            ALOGD("Video skip non-key frame");
2972            copy->release();
2973            continue;
2974        }
2975        if (mIsVideo && isSync) {
2976            mGotStartKeyFrame = true;
2977        }
2978////////////////////////////////////////////////////////////////////////////////
2979
2980        if (!mIsHeic) {
2981            if (mStszTableEntries->count() == 0) {
2982                mFirstSampleTimeRealUs = systemTime() / 1000;
2983                mStartTimestampUs = timestampUs;
2984                mOwner->setStartTimestampUs(mStartTimestampUs);
2985                previousPausedDurationUs = mStartTimestampUs;
2986            }
2987
2988            if (mResumed) {
2989                int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
2990                if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) {
2991                    copy->release();
2992                    mSource->stop();
2993                    mIsMalformed = true;
2994                    break;
2995                }
2996
2997                int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
2998                if (WARN_UNLESS(pausedDurationUs >= lastDurationUs, "for %s track", trackName)) {
2999                    copy->release();
3000                    mSource->stop();
3001                    mIsMalformed = true;
3002                    break;
3003                }
3004
3005                previousPausedDurationUs += pausedDurationUs - lastDurationUs;
3006                mResumed = false;
3007            }
3008            TimestampDebugHelperEntry timestampDebugEntry;
3009            timestampUs -= previousPausedDurationUs;
3010            timestampDebugEntry.pts = timestampUs;
3011            if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
3012                copy->release();
3013                mSource->stop();
3014                mIsMalformed = true;
3015                break;
3016            }
3017
3018            if (mIsVideo) {
3019                /*
3020                 * Composition time: timestampUs
3021                 * Decoding time: decodingTimeUs
3022                 * Composition time offset = composition time - decoding time
3023                 */
3024                int64_t decodingTimeUs;
3025                CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs));
3026                decodingTimeUs -= previousPausedDurationUs;
3027
3028                // ensure non-negative, monotonic decoding time
3029                if (mLastDecodingTimeUs < 0) {
3030                    decodingTimeUs = std::max((int64_t)0, decodingTimeUs);
3031                } else {
3032                    // increase decoding time by at least the larger vaule of 1 tick and
3033                    // 0.1 milliseconds. This needs to take into account the possible
3034                    // delta adjustment in DurationTicks in below.
3035                    decodingTimeUs = std::max(mLastDecodingTimeUs +
3036                            std::max(100, divUp(1000000, mTimeScale)), decodingTimeUs);
3037                }
3038
3039                mLastDecodingTimeUs = decodingTimeUs;
3040                timestampDebugEntry.dts = decodingTimeUs;
3041                timestampDebugEntry.frameType = isSync ? "Key frame" : "Non-Key frame";
3042                // Insert the timestamp into the mTimestampDebugHelper
3043                if (mTimestampDebugHelper.size() >= kTimestampDebugCount) {
3044                    mTimestampDebugHelper.pop_front();
3045                }
3046                mTimestampDebugHelper.push_back(timestampDebugEntry);
3047
3048                cttsOffsetTimeUs =
3049                        timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
3050                if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) {
3051                    copy->release();
3052                    mSource->stop();
3053                    mIsMalformed = true;
3054                    break;
3055                }
3056
3057                timestampUs = decodingTimeUs;
3058                ALOGV("decoding time: %" PRId64 " and ctts offset time: %" PRId64,
3059                    timestampUs, cttsOffsetTimeUs);
3060
3061                // Update ctts box table if necessary
3062                currCttsOffsetTimeTicks =
3063                        (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL;
3064                if (WARN_UNLESS(currCttsOffsetTimeTicks <= 0x0FFFFFFFFLL, "for %s track", trackName)) {
3065                    copy->release();
3066                    mSource->stop();
3067                    mIsMalformed = true;
3068                    break;
3069                }
3070
3071                if (mStszTableEntries->count() == 0) {
3072                    // Force the first ctts table entry to have one single entry
3073                    // so that we can do adjustment for the initial track start
3074                    // time offset easily in writeCttsBox().
3075                    lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
3076                    addOneCttsTableEntry(1, currCttsOffsetTimeTicks);
3077                    cttsSampleCount = 0;      // No sample in ctts box is pending
3078                } else {
3079                    if (currCttsOffsetTimeTicks != lastCttsOffsetTimeTicks) {
3080                        addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
3081                        lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
3082                        cttsSampleCount = 1;  // One sample in ctts box is pending
3083                    } else {
3084                        ++cttsSampleCount;
3085                    }
3086                }
3087
3088                // Update ctts time offset range
3089                if (mStszTableEntries->count() == 0) {
3090                    mMinCttsOffsetTicks = currCttsOffsetTimeTicks;
3091                    mMaxCttsOffsetTicks = currCttsOffsetTimeTicks;
3092                } else {
3093                    if (currCttsOffsetTimeTicks > mMaxCttsOffsetTicks) {
3094                        mMaxCttsOffsetTicks = currCttsOffsetTimeTicks;
3095                    } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTicks) {
3096                        mMinCttsOffsetTicks = currCttsOffsetTimeTicks;
3097                        mMinCttsOffsetTimeUs = cttsOffsetTimeUs;
3098                    }
3099                }
3100            }
3101
3102            if (mOwner->isRealTimeRecording()) {
3103                if (mIsAudio) {
3104                    updateDriftTime(meta_data);
3105                }
3106            }
3107
3108            if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
3109                copy->release();
3110                mSource->stop();
3111                mIsMalformed = true;
3112                break;
3113            }
3114
3115            ALOGV("%s media time stamp: %" PRId64 " and previous paused duration %" PRId64,
3116                    trackName, timestampUs, previousPausedDurationUs);
3117            if (timestampUs > mTrackDurationUs) {
3118                mTrackDurationUs = timestampUs;
3119            }
3120
3121            // We need to use the time scale based ticks, rather than the
3122            // timestamp itself to determine whether we have to use a new
3123            // stts entry, since we may have rounding errors.
3124            // The calculation is intended to reduce the accumulated
3125            // rounding errors.
3126            currDurationTicks =
3127                ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
3128                    (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
3129            if (currDurationTicks < 0ll) {
3130                ALOGE("do not support out of order frames (timestamp: %lld < last: %lld for %s track",
3131                        (long long)timestampUs, (long long)lastTimestampUs, trackName);
3132                copy->release();
3133                mSource->stop();
3134                mIsMalformed = true;
3135                break;
3136            }
3137
3138            // if the duration is different for this sample, see if it is close enough to the previous
3139            // duration that we can fudge it and use the same value, to avoid filling the stts table
3140            // with lots of near-identical entries.
3141            // "close enough" here means that the current duration needs to be adjusted by less
3142            // than 0.1 milliseconds
3143            if (lastDurationTicks && (currDurationTicks != lastDurationTicks)) {
3144                int64_t deltaUs = ((lastDurationTicks - currDurationTicks) * 1000000LL
3145                        + (mTimeScale / 2)) / mTimeScale;
3146                if (deltaUs > -100 && deltaUs < 100) {
3147                    // use previous ticks, and adjust timestamp as if it was actually that number
3148                    // of ticks
3149                    currDurationTicks = lastDurationTicks;
3150                    timestampUs += deltaUs;
3151                }
3152            }
3153            mStszTableEntries->add(htonl(sampleSize));
3154            if (mStszTableEntries->count() > 2) {
3155
3156                // Force the first sample to have its own stts entry so that
3157                // we can adjust its value later to maintain the A/V sync.
3158                if (mStszTableEntries->count() == 3 || currDurationTicks != lastDurationTicks) {
3159                    addOneSttsTableEntry(sampleCount, lastDurationTicks);
3160                    sampleCount = 1;
3161                } else {
3162                    ++sampleCount;
3163                }
3164
3165            }
3166            if (mSamplesHaveSameSize) {
3167                if (mStszTableEntries->count() >= 2 && previousSampleSize != sampleSize) {
3168                    mSamplesHaveSameSize = false;
3169                }
3170                previousSampleSize = sampleSize;
3171            }
3172            ALOGV("%s timestampUs/lastTimestampUs: %" PRId64 "/%" PRId64,
3173                    trackName, timestampUs, lastTimestampUs);
3174            lastDurationUs = timestampUs - lastTimestampUs;
3175            lastDurationTicks = currDurationTicks;
3176            lastTimestampUs = timestampUs;
3177
3178            if (isSync != 0) {
3179                addOneStssTableEntry(mStszTableEntries->count());
3180            }
3181
3182            if (mTrackingProgressStatus) {
3183                if (mPreviousTrackTimeUs <= 0) {
3184                    mPreviousTrackTimeUs = mStartTimestampUs;
3185                }
3186                trackProgressStatus(timestampUs);
3187            }
3188        }
3189        if (!hasMultipleTracks) {
3190            size_t bytesWritten;
3191            off64_t offset = mOwner->addSample_l(copy, usePrefix(), &bytesWritten);
3192
3193            if (mIsHeic) {
3194                addItemOffsetAndSize(offset, bytesWritten);
3195            } else {
3196                uint32_t count = (mOwner->use32BitFileOffset()
3197                            ? mStcoTableEntries->count()
3198                            : mCo64TableEntries->count());
3199
3200                if (count == 0) {
3201                    addChunkOffset(offset);
3202                }
3203            }
3204            copy->release();
3205            copy = NULL;
3206            continue;
3207        }
3208
3209        mChunkSamples.push_back(copy);
3210        if (mIsHeic) {
3211            bufferChunk(0 /*timestampUs*/);
3212            ++nChunks;
3213        } else if (interleaveDurationUs == 0) {
3214            addOneStscTableEntry(++nChunks, 1);
3215            bufferChunk(timestampUs);
3216        } else {
3217            if (chunkTimestampUs == 0) {
3218                chunkTimestampUs = timestampUs;
3219            } else {
3220                int64_t chunkDurationUs = timestampUs - chunkTimestampUs;
3221                if (chunkDurationUs > interleaveDurationUs) {
3222                    if (chunkDurationUs > mMaxChunkDurationUs) {
3223                        mMaxChunkDurationUs = chunkDurationUs;
3224                    }
3225                    ++nChunks;
3226                    if (nChunks == 1 ||  // First chunk
3227                        lastSamplesPerChunk != mChunkSamples.size()) {
3228                        lastSamplesPerChunk = mChunkSamples.size();
3229                        addOneStscTableEntry(nChunks, lastSamplesPerChunk);
3230                    }
3231                    bufferChunk(timestampUs);
3232                    chunkTimestampUs = timestampUs;
3233                }
3234            }
3235        }
3236
3237    }
3238
3239    if (isTrackMalFormed()) {
3240        dumpTimeStamps();
3241        err = ERROR_MALFORMED;
3242    }
3243
3244    mOwner->trackProgressStatus(mTrackId, -1, err);
3245
3246    if (mIsHeic) {
3247        if (!mChunkSamples.empty()) {
3248            bufferChunk(0);
3249            ++nChunks;
3250        }
3251    } else {
3252        // Last chunk
3253        if (!hasMultipleTracks) {
3254            addOneStscTableEntry(1, mStszTableEntries->count());
3255        } else if (!mChunkSamples.empty()) {
3256            addOneStscTableEntry(++nChunks, mChunkSamples.size());
3257            bufferChunk(timestampUs);
3258        }
3259
3260        // We don't really know how long the last frame lasts, since
3261        // there is no frame time after it, just repeat the previous
3262        // frame's duration.
3263        if (mStszTableEntries->count() == 1) {
3264            lastDurationUs = 0;  // A single sample's duration
3265            lastDurationTicks = 0;
3266        } else {
3267            ++sampleCount;  // Count for the last sample
3268        }
3269
3270        if (mStszTableEntries->count() <= 2) {
3271            addOneSttsTableEntry(1, lastDurationTicks);
3272            if (sampleCount - 1 > 0) {
3273                addOneSttsTableEntry(sampleCount - 1, lastDurationTicks);
3274            }
3275        } else {
3276            addOneSttsTableEntry(sampleCount, lastDurationTicks);
3277        }
3278
3279        // The last ctts box may not have been written yet, and this
3280        // is to make sure that we write out the last ctts box.
3281        if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) {
3282            if (cttsSampleCount > 0) {
3283                addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
3284            }
3285        }
3286
3287        mTrackDurationUs += lastDurationUs;
3288    }
3289    mReachedEOS = true;
3290
3291    sendTrackSummary(hasMultipleTracks);
3292
3293    ALOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s",
3294            count, nZeroLengthFrames, mStszTableEntries->count(), trackName);
3295    if (mIsAudio) {
3296        ALOGI("Audio track drift time: %" PRId64 " us", mOwner->getDriftTimeUs());
3297    }
3298
3299    if (err == ERROR_END_OF_STREAM) {
3300        return OK;
3301    }
3302    return err;
3303}
3304
3305bool MPEG4Writer::Track::isTrackMalFormed() const {
3306    if (mIsMalformed) {
3307        return true;
3308    }
3309
3310    if (!mIsHeic && mStszTableEntries->count() == 0) {  // no samples written
3311        ALOGE("The number of recorded samples is 0");
3312        return true;
3313    }
3314
3315    if (mIsVideo && mStssTableEntries->count() == 0) {  // no sync frames for video
3316        ALOGE("There are no sync frames for video track");
3317        return true;
3318    }
3319
3320    if (OK != checkCodecSpecificData()) {         // no codec specific data
3321        return true;
3322    }
3323
3324    return false;
3325}
3326
3327void MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) {
3328
3329    // Send track summary only if test mode is enabled.
3330    if (!isTestModeEnabled()) {
3331        return;
3332    }
3333
3334    int trackNum = (mTrackId << 28);
3335
3336    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
3337                    trackNum | MEDIA_RECORDER_TRACK_INFO_TYPE,
3338                    mIsAudio ? 0: 1);
3339
3340    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
3341                    trackNum | MEDIA_RECORDER_TRACK_INFO_DURATION_MS,
3342                    mTrackDurationUs / 1000);
3343
3344    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
3345                    trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES,
3346                    mStszTableEntries->count());
3347
3348    {
3349        // The system delay time excluding the requested initial delay that
3350        // is used to eliminate the recording sound.
3351        int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL;
3352        if (startTimeOffsetUs < 0) {  // Start time offset was not set
3353            startTimeOffsetUs = kInitialDelayTimeUs;
3354        }
3355        int64_t initialDelayUs =
3356            mFirstSampleTimeRealUs - mStartTimeRealUs - startTimeOffsetUs;
3357
3358        mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
3359                    trackNum | MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS,
3360                    (initialDelayUs) / 1000);
3361    }
3362
3363    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
3364                    trackNum | MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES,
3365                    mMdatSizeBytes / 1024);
3366
3367    if (hasMultipleTracks) {
3368        mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
3369                    trackNum | MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS,
3370                    mMaxChunkDurationUs / 1000);
3371
3372        int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
3373        if (mStartTimestampUs != moovStartTimeUs) {
3374            int64_t startTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
3375            mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
3376                    trackNum | MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS,
3377                    startTimeOffsetUs / 1000);
3378        }
3379    }
3380}
3381
3382void MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) {
3383    ALOGV("trackProgressStatus: %" PRId64 " us", timeUs);
3384
3385    if (mTrackEveryTimeDurationUs > 0 &&
3386        timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) {
3387        ALOGV("Fire time tracking progress status at %" PRId64 " us", timeUs);
3388        mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err);
3389        mPreviousTrackTimeUs = timeUs;
3390    }
3391}
3392
3393void MPEG4Writer::trackProgressStatus(
3394        size_t trackId, int64_t timeUs, status_t err) {
3395    Mutex::Autolock lock(mLock);
3396    int32_t trackNum = (trackId << 28);
3397
3398    // Error notification
3399    // Do not consider ERROR_END_OF_STREAM an error
3400    if (err != OK && err != ERROR_END_OF_STREAM) {
3401        notify(MEDIA_RECORDER_TRACK_EVENT_ERROR,
3402               trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL,
3403               err);
3404        return;
3405    }
3406
3407    if (timeUs == -1) {
3408        // Send completion notification
3409        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
3410               trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS,
3411               err);
3412    } else {
3413        // Send progress status
3414        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
3415               trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME,
3416               timeUs / 1000);
3417    }
3418}
3419
3420void MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) {
3421    ALOGV("setDriftTimeUs: %" PRId64 " us", driftTimeUs);
3422    Mutex::Autolock autolock(mLock);
3423    mDriftTimeUs = driftTimeUs;
3424}
3425
3426int64_t MPEG4Writer::getDriftTimeUs() {
3427    ALOGV("getDriftTimeUs: %" PRId64 " us", mDriftTimeUs);
3428    Mutex::Autolock autolock(mLock);
3429    return mDriftTimeUs;
3430}
3431
3432bool MPEG4Writer::isRealTimeRecording() const {
3433    return mIsRealTimeRecording;
3434}
3435
3436bool MPEG4Writer::useNalLengthFour() {
3437    return mUse4ByteNalLength;
3438}
3439
3440void MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
3441    ALOGV("bufferChunk");
3442
3443    Chunk chunk(this, timestampUs, mChunkSamples);
3444    mOwner->bufferChunk(chunk);
3445    mChunkSamples.clear();
3446}
3447
3448int64_t MPEG4Writer::Track::getDurationUs() const {
3449    return mTrackDurationUs + getStartTimeOffsetTimeUs();
3450}
3451
3452int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
3453    return mEstimatedTrackSizeBytes;
3454}
3455
3456int32_t MPEG4Writer::Track::getMetaSizeIncrease() const {
3457    CHECK(mIsHeic);
3458
3459    int32_t grid = (mNumTiles > 1);
3460
3461    // Note that the rotation angle is in the file meta, and we don't have
3462    // it until start, so here the calculation has to assume rotation.
3463
3464    // increase to ipco
3465    int32_t increase = 20 * (grid + 1)              // 'ispe' property
3466                     + (8 + mCodecSpecificDataSize) // 'hvcC' property
3467                     + 9;                           // 'irot' property (worst case)
3468
3469    // increase to iref and idat
3470    if (grid) {
3471        increase += (8 + 2 + 2 + mNumTiles * 2)  // 'dimg' in iref
3472                  + 12;                          // ImageGrid in 'idat' (worst case)
3473    }
3474
3475    // increase to iloc, iinf and ipma
3476    increase += (16             // increase to 'iloc'
3477              + 21              // increase to 'iinf'
3478              + (3 + 2 * 2))    // increase to 'ipma' (worst case, 2 props x 2 bytes)
3479              * (mNumTiles + grid);
3480
3481    // adjust to ipma:
3482    // if rotation is present and only one tile, it could ref 3 properties
3483    if (!grid) {
3484        increase += 2;
3485    }
3486
3487    return increase;
3488}
3489
3490status_t MPEG4Writer::Track::checkCodecSpecificData() const {
3491    const char *mime;
3492    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
3493    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) ||
3494        !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
3495        !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime) ||
3496        !strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime) ||
3497        !strcasecmp(MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC, mime)) {
3498        if (!mCodecSpecificData ||
3499            mCodecSpecificDataSize <= 0) {
3500            ALOGE("Missing codec specific data");
3501            return ERROR_MALFORMED;
3502        }
3503    } else {
3504        if (mCodecSpecificData ||
3505            mCodecSpecificDataSize > 0) {
3506            ALOGE("Unexepected codec specific data found");
3507            return ERROR_MALFORMED;
3508        }
3509    }
3510    return OK;
3511}
3512
3513const char *MPEG4Writer::Track::getTrackType() const {
3514    return mIsAudio ? "Audio" :
3515           mIsVideo ? "Video" :
3516           mIsHeic  ? "Image" :
3517                      "Metadata";
3518}
3519
3520void MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) {
3521    uint32_t now = getMpeg4Time();
3522    mOwner->beginBox("trak");
3523        writeTkhdBox(now);
3524        mOwner->beginBox("mdia");
3525            writeMdhdBox(now);
3526            writeHdlrBox();
3527            mOwner->beginBox("minf");
3528                if (mIsAudio) {
3529                    writeSmhdBox();
3530                } else if (mIsVideo) {
3531                    writeVmhdBox();
3532                } else {
3533                    writeNmhdBox();
3534                }
3535                writeDinfBox();
3536                writeStblBox(use32BitOffset);
3537            mOwner->endBox();  // minf
3538        mOwner->endBox();  // mdia
3539    mOwner->endBox();  // trak
3540}
3541
3542int64_t MPEG4Writer::Track::getMinCttsOffsetTimeUs() {
3543    // For video tracks with ctts table, this should return the minimum ctts
3544    // offset in the table. For non-video tracks or video tracks without ctts
3545    // table, this will return kMaxCttsOffsetTimeUs.
3546    if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) {
3547        return kMaxCttsOffsetTimeUs;
3548    }
3549    return mMinCttsOffsetTimeUs;
3550}
3551
3552void MPEG4Writer::Track::writeStblBox(bool use32BitOffset) {
3553    mOwner->beginBox("stbl");
3554    mOwner->beginBox("stsd");
3555    mOwner->writeInt32(0);               // version=0, flags=0
3556    mOwner->writeInt32(1);               // entry count
3557    if (mIsAudio) {
3558        writeAudioFourCCBox();
3559    } else if (mIsVideo) {
3560        writeVideoFourCCBox();
3561    } else {
3562        writeMetadataFourCCBox();
3563    }
3564    mOwner->endBox();  // stsd
3565    writeSttsBox();
3566    if (mIsVideo) {
3567        writeCttsBox();
3568        writeStssBox();
3569    }
3570    writeStszBox();
3571    writeStscBox();
3572    writeStcoBox(use32BitOffset);
3573    mOwner->endBox();  // stbl
3574}
3575
3576void MPEG4Writer::Track::writeMetadataFourCCBox() {
3577    const char *mime;
3578    bool success = mMeta->findCString(kKeyMIMEType, &mime);
3579    CHECK(success);
3580    const char *fourcc = getFourCCForMime(mime);
3581    if (fourcc == NULL) {
3582        ALOGE("Unknown mime type '%s'.", mime);
3583        TRESPASS();
3584    }
3585    mOwner->beginBox(fourcc);    // TextMetaDataSampleEntry
3586    mOwner->writeCString(mime);  // metadata mime_format
3587    mOwner->endBox(); // mett
3588}
3589
3590void MPEG4Writer::Track::writeVideoFourCCBox() {
3591    const char *mime;
3592    bool success = mMeta->findCString(kKeyMIMEType, &mime);
3593    CHECK(success);
3594    const char *fourcc = getFourCCForMime(mime);
3595    if (fourcc == NULL) {
3596        ALOGE("Unknown mime type '%s'.", mime);
3597        TRESPASS();
3598    }
3599
3600    mOwner->beginBox(fourcc);        // video format
3601    mOwner->writeInt32(0);           // reserved
3602    mOwner->writeInt16(0);           // reserved
3603    mOwner->writeInt16(1);           // data ref index
3604    mOwner->writeInt16(0);           // predefined
3605    mOwner->writeInt16(0);           // reserved
3606    mOwner->writeInt32(0);           // predefined
3607    mOwner->writeInt32(0);           // predefined
3608    mOwner->writeInt32(0);           // predefined
3609
3610    int32_t width, height;
3611    success = mMeta->findInt32(kKeyWidth, &width);
3612    success = success && mMeta->findInt32(kKeyHeight, &height);
3613    CHECK(success);
3614
3615    mOwner->writeInt16(width);
3616    mOwner->writeInt16(height);
3617    mOwner->writeInt32(0x480000);    // horiz resolution
3618    mOwner->writeInt32(0x480000);    // vert resolution
3619    mOwner->writeInt32(0);           // reserved
3620    mOwner->writeInt16(1);           // frame count
3621    mOwner->writeInt8(0);            // compressor string length
3622    mOwner->write("                               ", 31);
3623    mOwner->writeInt16(0x18);        // depth
3624    mOwner->writeInt16(-1);          // predefined
3625
3626    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
3627        writeMp4vEsdsBox();
3628    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
3629        writeD263Box();
3630    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
3631        writeAvccBox();
3632    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
3633        writeHvccBox();
3634    }
3635
3636    writePaspBox();
3637    writeColrBox();
3638    mOwner->endBox();  // mp4v, s263 or avc1
3639}
3640
3641void MPEG4Writer::Track::writeColrBox() {
3642    ColorAspects aspects;
3643    memset(&aspects, 0, sizeof(aspects));
3644    // TRICKY: using | instead of || because we want to execute all findInt32-s
3645    if (mMeta->findInt32(kKeyColorPrimaries, (int32_t*)&aspects.mPrimaries)
3646            | mMeta->findInt32(kKeyTransferFunction, (int32_t*)&aspects.mTransfer)
3647            | mMeta->findInt32(kKeyColorMatrix, (int32_t*)&aspects.mMatrixCoeffs)
3648            | mMeta->findInt32(kKeyColorRange, (int32_t*)&aspects.mRange)) {
3649        int32_t primaries, transfer, coeffs;
3650        bool fullRange;
3651        ColorUtils::convertCodecColorAspectsToIsoAspects(
3652                aspects, &primaries, &transfer, &coeffs, &fullRange);
3653        mOwner->beginBox("colr");
3654        mOwner->writeFourcc("nclx");
3655        mOwner->writeInt16(primaries);
3656        mOwner->writeInt16(transfer);
3657        mOwner->writeInt16(coeffs);
3658        mOwner->writeInt8(int8_t(fullRange ? 0x80 : 0x0));
3659        mOwner->endBox(); // colr
3660    }
3661}
3662
3663void MPEG4Writer::Track::writeAudioFourCCBox() {
3664    const char *mime;
3665    bool success = mMeta->findCString(kKeyMIMEType, &mime);
3666    CHECK(success);
3667    const char *fourcc = getFourCCForMime(mime);
3668    if (fourcc == NULL) {
3669        ALOGE("Unknown mime type '%s'.", mime);
3670        TRESPASS();
3671    }
3672
3673    mOwner->beginBox(fourcc);        // audio format
3674    mOwner->writeInt32(0);           // reserved
3675    mOwner->writeInt16(0);           // reserved
3676    mOwner->writeInt16(0x1);         // data ref index
3677    mOwner->writeInt32(0);           // reserved
3678    mOwner->writeInt32(0);           // reserved
3679    int32_t nChannels;
3680    CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels));
3681    mOwner->writeInt16(nChannels);   // channel count
3682    mOwner->writeInt16(16);          // sample size
3683    mOwner->writeInt16(0);           // predefined
3684    mOwner->writeInt16(0);           // reserved
3685
3686    int32_t samplerate;
3687    success = mMeta->findInt32(kKeySampleRate, &samplerate);
3688    CHECK(success);
3689    mOwner->writeInt32(samplerate << 16);
3690    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
3691        writeMp4aEsdsBox();
3692    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) ||
3693               !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
3694        writeDamrBox();
3695    }
3696    mOwner->endBox();
3697}
3698
3699void MPEG4Writer::Track::writeMp4aEsdsBox() {
3700    mOwner->beginBox("esds");
3701    CHECK(mCodecSpecificData);
3702    CHECK_GT(mCodecSpecificDataSize, 0u);
3703
3704    // Make sure all sizes encode to a single byte.
3705    CHECK_LT(mCodecSpecificDataSize + 23, 128u);
3706
3707    mOwner->writeInt32(0);     // version=0, flags=0
3708    mOwner->writeInt8(0x03);   // ES_DescrTag
3709    mOwner->writeInt8(23 + mCodecSpecificDataSize);
3710    mOwner->writeInt16(0x0000);// ES_ID
3711    mOwner->writeInt8(0x00);
3712
3713    mOwner->writeInt8(0x04);   // DecoderConfigDescrTag
3714    mOwner->writeInt8(15 + mCodecSpecificDataSize);
3715    mOwner->writeInt8(0x40);   // objectTypeIndication ISO/IEC 14492-2
3716    mOwner->writeInt8(0x15);   // streamType AudioStream
3717
3718    mOwner->writeInt16(0x03);  // XXX
3719    mOwner->writeInt8(0x00);   // buffer size 24-bit (0x300)
3720
3721    int32_t avgBitrate = 0;
3722    (void)mMeta->findInt32(kKeyBitRate, &avgBitrate);
3723    int32_t maxBitrate = 0;
3724    (void)mMeta->findInt32(kKeyMaxBitRate, &maxBitrate);
3725    mOwner->writeInt32(maxBitrate);
3726    mOwner->writeInt32(avgBitrate);
3727
3728    mOwner->writeInt8(0x05);   // DecoderSpecificInfoTag
3729    mOwner->writeInt8(mCodecSpecificDataSize);
3730    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
3731
3732    static const uint8_t kData2[] = {
3733        0x06,  // SLConfigDescriptorTag
3734        0x01,
3735        0x02
3736    };
3737    mOwner->write(kData2, sizeof(kData2));
3738
3739    mOwner->endBox();  // esds
3740}
3741
3742void MPEG4Writer::Track::writeMp4vEsdsBox() {
3743    CHECK(mCodecSpecificData);
3744    CHECK_GT(mCodecSpecificDataSize, 0u);
3745
3746    // Make sure all sizes encode to a single byte.
3747    CHECK_LT(23 + mCodecSpecificDataSize, 128u);
3748
3749    mOwner->beginBox("esds");
3750
3751    mOwner->writeInt32(0);    // version=0, flags=0
3752
3753    mOwner->writeInt8(0x03);  // ES_DescrTag
3754    mOwner->writeInt8(23 + mCodecSpecificDataSize);
3755    mOwner->writeInt16(0x0000);  // ES_ID
3756    mOwner->writeInt8(0x1f);
3757
3758    mOwner->writeInt8(0x04);  // DecoderConfigDescrTag
3759    mOwner->writeInt8(15 + mCodecSpecificDataSize);
3760    mOwner->writeInt8(0x20);  // objectTypeIndication ISO/IEC 14492-2
3761    mOwner->writeInt8(0x11);  // streamType VisualStream
3762
3763    static const uint8_t kData[] = {
3764        0x01, 0x77, 0x00, // buffer size 96000 bytes
3765    };
3766    mOwner->write(kData, sizeof(kData));
3767
3768    int32_t avgBitrate = 0;
3769    (void)mMeta->findInt32(kKeyBitRate, &avgBitrate);
3770    int32_t maxBitrate = 0;
3771    (void)mMeta->findInt32(kKeyMaxBitRate, &maxBitrate);
3772    mOwner->writeInt32(maxBitrate);
3773    mOwner->writeInt32(avgBitrate);
3774
3775    mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
3776
3777    mOwner->writeInt8(mCodecSpecificDataSize);
3778    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
3779
3780    static const uint8_t kData2[] = {
3781        0x06,  // SLConfigDescriptorTag
3782        0x01,
3783        0x02
3784    };
3785    mOwner->write(kData2, sizeof(kData2));
3786
3787    mOwner->endBox();  // esds
3788}
3789
3790void MPEG4Writer::Track::writeTkhdBox(uint32_t now) {
3791    mOwner->beginBox("tkhd");
3792    // Flags = 7 to indicate that the track is enabled, and
3793    // part of the presentation
3794    mOwner->writeInt32(0x07);          // version=0, flags=7
3795    mOwner->writeInt32(now);           // creation time
3796    mOwner->writeInt32(now);           // modification time
3797    mOwner->writeInt32(mTrackId);      // track id starts with 1
3798    mOwner->writeInt32(0);             // reserved
3799    int64_t trakDurationUs = getDurationUs();
3800    int32_t mvhdTimeScale = mOwner->getTimeScale();
3801    int32_t tkhdDuration =
3802        (trakDurationUs * mvhdTimeScale + 5E5) / 1E6;
3803    mOwner->writeInt32(tkhdDuration);  // in mvhd timescale
3804    mOwner->writeInt32(0);             // reserved
3805    mOwner->writeInt32(0);             // reserved
3806    mOwner->writeInt16(0);             // layer
3807    mOwner->writeInt16(0);             // alternate group
3808    mOwner->writeInt16(mIsAudio ? 0x100 : 0);  // volume
3809    mOwner->writeInt16(0);             // reserved
3810
3811    mOwner->writeCompositionMatrix(mRotation);       // matrix
3812
3813    if (!mIsVideo) {
3814        mOwner->writeInt32(0);
3815        mOwner->writeInt32(0);
3816    } else {
3817        int32_t width, height;
3818        bool success = mMeta->findInt32(kKeyDisplayWidth, &width);
3819        success = success && mMeta->findInt32(kKeyDisplayHeight, &height);
3820
3821        // Use width/height if display width/height are not present.
3822        if (!success) {
3823            success = mMeta->findInt32(kKeyWidth, &width);
3824            success = success && mMeta->findInt32(kKeyHeight, &height);
3825        }
3826        CHECK(success);
3827
3828        mOwner->writeInt32(width << 16);   // 32-bit fixed-point value
3829        mOwner->writeInt32(height << 16);  // 32-bit fixed-point value
3830    }
3831    mOwner->endBox();  // tkhd
3832}
3833
3834void MPEG4Writer::Track::writeVmhdBox() {
3835    mOwner->beginBox("vmhd");
3836    mOwner->writeInt32(0x01);        // version=0, flags=1
3837    mOwner->writeInt16(0);           // graphics mode
3838    mOwner->writeInt16(0);           // opcolor
3839    mOwner->writeInt16(0);
3840    mOwner->writeInt16(0);
3841    mOwner->endBox();
3842}
3843
3844void MPEG4Writer::Track::writeSmhdBox() {
3845    mOwner->beginBox("smhd");
3846    mOwner->writeInt32(0);           // version=0, flags=0
3847    mOwner->writeInt16(0);           // balance
3848    mOwner->writeInt16(0);           // reserved
3849    mOwner->endBox();
3850}
3851
3852void MPEG4Writer::Track::writeNmhdBox() {
3853    mOwner->beginBox("nmhd");
3854    mOwner->writeInt32(0);           // version=0, flags=0
3855    mOwner->endBox();
3856}
3857
3858void MPEG4Writer::Track::writeHdlrBox() {
3859    mOwner->beginBox("hdlr");
3860    mOwner->writeInt32(0);             // version=0, flags=0
3861    mOwner->writeInt32(0);             // component type: should be mhlr
3862    mOwner->writeFourcc(mIsAudio ? "soun" : (mIsVideo ? "vide" : "meta"));  // component subtype
3863    mOwner->writeInt32(0);             // reserved
3864    mOwner->writeInt32(0);             // reserved
3865    mOwner->writeInt32(0);             // reserved
3866    // Removing "r" for the name string just makes the string 4 byte aligned
3867    mOwner->writeCString(mIsAudio ? "SoundHandle": (mIsVideo ? "VideoHandle" : "MetadHandle"));
3868    mOwner->endBox();
3869}
3870
3871void MPEG4Writer::Track::writeMdhdBox(uint32_t now) {
3872    int64_t trakDurationUs = getDurationUs();
3873    int64_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6;
3874    mOwner->beginBox("mdhd");
3875
3876    if (mdhdDuration > UINT32_MAX) {
3877        mOwner->writeInt32((1 << 24));            // version=1, flags=0
3878        mOwner->writeInt64((int64_t)now);         // creation time
3879        mOwner->writeInt64((int64_t)now);         // modification time
3880        mOwner->writeInt32(mTimeScale);           // media timescale
3881        mOwner->writeInt64(mdhdDuration);         // media timescale
3882    } else {
3883        mOwner->writeInt32(0);                      // version=0, flags=0
3884        mOwner->writeInt32(now);                    // creation time
3885        mOwner->writeInt32(now);                    // modification time
3886        mOwner->writeInt32(mTimeScale);             // media timescale
3887        mOwner->writeInt32((int32_t)mdhdDuration);  // use media timescale
3888    }
3889    // Language follows the three letter standard ISO-639-2/T
3890    // 'e', 'n', 'g' for "English", for instance.
3891    // Each character is packed as the difference between its ASCII value and 0x60.
3892    // For "English", these are 00101, 01110, 00111.
3893    // XXX: Where is the padding bit located: 0x15C7?
3894    const char *lang = NULL;
3895    int16_t langCode = 0;
3896    if (mMeta->findCString(kKeyMediaLanguage, &lang) && lang && strnlen(lang, 3) > 2) {
3897        langCode = ((lang[0] & 0x1f) << 10) | ((lang[1] & 0x1f) << 5) | (lang[2] & 0x1f);
3898    }
3899    mOwner->writeInt16(langCode);      // language code
3900    mOwner->writeInt16(0);             // predefined
3901    mOwner->endBox();
3902}
3903
3904void MPEG4Writer::Track::writeDamrBox() {
3905    // 3gpp2 Spec AMRSampleEntry fields
3906    mOwner->beginBox("damr");
3907    mOwner->writeCString("   ");  // vendor: 4 bytes
3908    mOwner->writeInt8(0);         // decoder version
3909    mOwner->writeInt16(0x83FF);   // mode set: all enabled
3910    mOwner->writeInt8(0);         // mode change period
3911    mOwner->writeInt8(1);         // frames per sample
3912    mOwner->endBox();
3913}
3914
3915void MPEG4Writer::Track::writeUrlBox() {
3916    // The table index here refers to the sample description index
3917    // in the sample table entries.
3918    mOwner->beginBox("url ");
3919    mOwner->writeInt32(1);  // version=0, flags=1 (self-contained)
3920    mOwner->endBox();  // url
3921}
3922
3923void MPEG4Writer::Track::writeDrefBox() {
3924    mOwner->beginBox("dref");
3925    mOwner->writeInt32(0);  // version=0, flags=0
3926    mOwner->writeInt32(1);  // entry count (either url or urn)
3927    writeUrlBox();
3928    mOwner->endBox();  // dref
3929}
3930
3931void MPEG4Writer::Track::writeDinfBox() {
3932    mOwner->beginBox("dinf");
3933    writeDrefBox();
3934    mOwner->endBox();  // dinf
3935}
3936
3937void MPEG4Writer::Track::writeAvccBox() {
3938    CHECK(mCodecSpecificData);
3939    CHECK_GE(mCodecSpecificDataSize, 5u);
3940
3941    // Patch avcc's lengthSize field to match the number
3942    // of bytes we use to indicate the size of a nal unit.
3943    uint8_t *ptr = (uint8_t *)mCodecSpecificData;
3944    ptr[4] = (ptr[4] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1);
3945    mOwner->beginBox("avcC");
3946    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
3947    mOwner->endBox();  // avcC
3948}
3949
3950
3951void MPEG4Writer::Track::writeHvccBox() {
3952    CHECK(mCodecSpecificData);
3953    CHECK_GE(mCodecSpecificDataSize, 5u);
3954
3955    // Patch avcc's lengthSize field to match the number
3956    // of bytes we use to indicate the size of a nal unit.
3957    uint8_t *ptr = (uint8_t *)mCodecSpecificData;
3958    ptr[21] = (ptr[21] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1);
3959    mOwner->beginBox("hvcC");
3960    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
3961    mOwner->endBox();  // hvcC
3962}
3963
3964void MPEG4Writer::Track::writeD263Box() {
3965    mOwner->beginBox("d263");
3966    mOwner->writeInt32(0);  // vendor
3967    mOwner->writeInt8(0);   // decoder version
3968    mOwner->writeInt8(10);  // level: 10
3969    mOwner->writeInt8(0);   // profile: 0
3970    mOwner->endBox();  // d263
3971}
3972
3973// This is useful if the pixel is not square
3974void MPEG4Writer::Track::writePaspBox() {
3975    mOwner->beginBox("pasp");
3976    mOwner->writeInt32(1 << 16);  // hspacing
3977    mOwner->writeInt32(1 << 16);  // vspacing
3978    mOwner->endBox();  // pasp
3979}
3980
3981int64_t MPEG4Writer::Track::getStartTimeOffsetTimeUs() const {
3982    int64_t trackStartTimeOffsetUs = 0;
3983    int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
3984    if (mStartTimestampUs != -1 && mStartTimestampUs != moovStartTimeUs) {
3985        CHECK_GT(mStartTimestampUs, moovStartTimeUs);
3986        trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
3987    }
3988    return trackStartTimeOffsetUs;
3989}
3990
3991int32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const {
3992    return (getStartTimeOffsetTimeUs() * mTimeScale + 500000LL) / 1000000LL;
3993}
3994
3995void MPEG4Writer::Track::writeSttsBox() {
3996    mOwner->beginBox("stts");
3997    mOwner->writeInt32(0);  // version=0, flags=0
3998    if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) {
3999        // For non-vdeio tracks or video tracks without ctts table,
4000        // adjust duration of first sample for tracks to account for
4001        // first sample not starting at the media start time.
4002        // TODO: consider signaling this using some offset
4003        // as this is not quite correct.
4004        uint32_t duration;
4005        CHECK(mSttsTableEntries->get(duration, 1));
4006        duration = htonl(duration);  // Back to host byte order
4007        mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1);
4008    }
4009    mSttsTableEntries->write(mOwner);
4010    mOwner->endBox();  // stts
4011}
4012
4013void MPEG4Writer::Track::writeCttsBox() {
4014    // There is no B frame at all
4015    if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) {
4016        return;
4017    }
4018
4019    // Do not write ctts box when there is no need to have it.
4020    if (mCttsTableEntries->count() == 0) {
4021        return;
4022    }
4023
4024    ALOGV("ctts box has %d entries with range [%" PRId64 ", %" PRId64 "]",
4025            mCttsTableEntries->count(), mMinCttsOffsetTicks, mMaxCttsOffsetTicks);
4026
4027    mOwner->beginBox("ctts");
4028    mOwner->writeInt32(0);  // version=0, flags=0
4029    int64_t deltaTimeUs = kMaxCttsOffsetTimeUs - getStartTimeOffsetTimeUs();
4030    int64_t delta = (deltaTimeUs * mTimeScale + 500000LL) / 1000000LL;
4031    mCttsTableEntries->adjustEntries([delta](size_t /* ix */, uint32_t (&value)[2]) {
4032        // entries are <count, ctts> pairs; adjust only ctts
4033        uint32_t duration = htonl(value[1]); // back to host byte order
4034        // Prevent overflow and underflow
4035        if (delta > duration) {
4036            duration = 0;
4037        } else if (delta < 0 && UINT32_MAX + delta < duration) {
4038            duration = UINT32_MAX;
4039        } else {
4040            duration -= delta;
4041        }
4042        value[1] = htonl(duration);
4043    });
4044    mCttsTableEntries->write(mOwner);
4045    mOwner->endBox();  // ctts
4046}
4047
4048void MPEG4Writer::Track::writeStssBox() {
4049    mOwner->beginBox("stss");
4050    mOwner->writeInt32(0);  // version=0, flags=0
4051    mStssTableEntries->write(mOwner);
4052    mOwner->endBox();  // stss
4053}
4054
4055void MPEG4Writer::Track::writeStszBox() {
4056    mOwner->beginBox("stsz");
4057    mOwner->writeInt32(0);  // version=0, flags=0
4058    mOwner->writeInt32(0);
4059    mStszTableEntries->write(mOwner);
4060    mOwner->endBox();  // stsz
4061}
4062
4063void MPEG4Writer::Track::writeStscBox() {
4064    mOwner->beginBox("stsc");
4065    mOwner->writeInt32(0);  // version=0, flags=0
4066    mStscTableEntries->write(mOwner);
4067    mOwner->endBox();  // stsc
4068}
4069
4070void MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) {
4071    mOwner->beginBox(use32BitOffset? "stco": "co64");
4072    mOwner->writeInt32(0);  // version=0, flags=0
4073    if (use32BitOffset) {
4074        mStcoTableEntries->write(mOwner);
4075    } else {
4076        mCo64TableEntries->write(mOwner);
4077    }
4078    mOwner->endBox();  // stco or co64
4079}
4080
4081void MPEG4Writer::writeUdtaBox() {
4082    beginBox("udta");
4083    writeGeoDataBox();
4084    endBox();
4085}
4086
4087void MPEG4Writer::writeHdlr(const char *handlerType) {
4088    beginBox("hdlr");
4089    writeInt32(0); // Version, Flags
4090    writeInt32(0); // Predefined
4091    writeFourcc(handlerType);
4092    writeInt32(0); // Reserved[0]
4093    writeInt32(0); // Reserved[1]
4094    writeInt32(0); // Reserved[2]
4095    writeInt8(0);  // Name (empty)
4096    endBox();
4097}
4098
4099void MPEG4Writer::writeKeys() {
4100    size_t count = mMetaKeys->countEntries();
4101
4102    beginBox("keys");
4103    writeInt32(0);     // Version, Flags
4104    writeInt32(count); // Entry_count
4105    for (size_t i = 0; i < count; i++) {
4106        AMessage::Type type;
4107        const char *key = mMetaKeys->getEntryNameAt(i, &type);
4108        size_t n = strlen(key);
4109        writeInt32(n + 8);
4110        writeFourcc("mdta");
4111        write(key, n); // write without the \0
4112    }
4113    endBox();
4114}
4115
4116void MPEG4Writer::writeIlst() {
4117    size_t count = mMetaKeys->countEntries();
4118
4119    beginBox("ilst");
4120    for (size_t i = 0; i < count; i++) {
4121        beginBox(i + 1); // key id (1-based)
4122        beginBox("data");
4123        AMessage::Type type;
4124        const char *key = mMetaKeys->getEntryNameAt(i, &type);
4125        switch (type) {
4126            case AMessage::kTypeString:
4127            {
4128                AString val;
4129                CHECK(mMetaKeys->findString(key, &val));
4130                writeInt32(1); // type = UTF8
4131                writeInt32(0); // default country/language
4132                write(val.c_str(), strlen(val.c_str())); // write without \0
4133                break;
4134            }
4135
4136            case AMessage::kTypeFloat:
4137            {
4138                float val;
4139                CHECK(mMetaKeys->findFloat(key, &val));
4140                writeInt32(23); // type = float32
4141                writeInt32(0);  // default country/language
4142                writeInt32(*reinterpret_cast<int32_t *>(&val));
4143                break;
4144            }
4145
4146            case AMessage::kTypeInt32:
4147            {
4148                int32_t val;
4149                CHECK(mMetaKeys->findInt32(key, &val));
4150                writeInt32(67); // type = signed int32
4151                writeInt32(0);  // default country/language
4152                writeInt32(val);
4153                break;
4154            }
4155
4156            default:
4157            {
4158                ALOGW("Unsupported key type, writing 0 instead");
4159                writeInt32(77); // type = unsigned int32
4160                writeInt32(0);  // default country/language
4161                writeInt32(0);
4162                break;
4163            }
4164        }
4165        endBox(); // data
4166        endBox(); // key id
4167    }
4168    endBox(); // ilst
4169}
4170
4171void MPEG4Writer::writeMoovLevelMetaBox() {
4172    size_t count = mMetaKeys->countEntries();
4173    if (count == 0) {
4174        return;
4175    }
4176
4177    beginBox("meta");
4178    writeHdlr("mdta");
4179    writeKeys();
4180    writeIlst();
4181    endBox();
4182}
4183
4184void MPEG4Writer::writeIlocBox() {
4185    beginBox("iloc");
4186    // Use version 1 to allow construction method 1 that refers to
4187    // data in idat box inside meta box.
4188    writeInt32(0x01000000); // Version = 1, Flags = 0
4189    writeInt16(0x4400);     // offset_size = length_size = 4
4190                            // base_offset_size = index_size = 0
4191
4192    // 16-bit item_count
4193    size_t itemCount = mItems.size();
4194    if (itemCount > 65535) {
4195        ALOGW("Dropping excess items: itemCount %zu", itemCount);
4196        itemCount = 65535;
4197    }
4198    writeInt16((uint16_t)itemCount);
4199
4200    for (size_t i = 0; i < itemCount; i++) {
4201        writeInt16(mItems[i].itemId);
4202        bool isGrid = mItems[i].isGrid();
4203
4204        writeInt16(isGrid ? 1 : 0); // construction_method
4205        writeInt16(0); // data_reference_index = 0
4206        writeInt16(1); // extent_count = 1
4207
4208        if (isGrid) {
4209            // offset into the 'idat' box
4210            writeInt32(mNumGrids++ * 8);
4211            writeInt32(8);
4212        } else {
4213            writeInt32(mItems[i].offset);
4214            writeInt32(mItems[i].size);
4215        }
4216    }
4217    endBox();
4218}
4219
4220void MPEG4Writer::writeInfeBox(
4221        uint16_t itemId, const char *itemType, uint32_t flags) {
4222    beginBox("infe");
4223    writeInt32(0x02000000 | flags); // Version = 2, Flags = 0
4224    writeInt16(itemId);
4225    writeInt16(0);          //item_protection_index = 0
4226    writeFourcc(itemType);
4227    writeCString("");       // item_name
4228    endBox();
4229}
4230
4231void MPEG4Writer::writeIinfBox() {
4232    beginBox("iinf");
4233    writeInt32(0);          // Version = 0, Flags = 0
4234
4235    // 16-bit item_count
4236    size_t itemCount = mItems.size();
4237    if (itemCount > 65535) {
4238        ALOGW("Dropping excess items: itemCount %zu", itemCount);
4239        itemCount = 65535;
4240    }
4241
4242    writeInt16((uint16_t)itemCount);
4243    for (size_t i = 0; i < itemCount; i++) {
4244        writeInfeBox(mItems[i].itemId, mItems[i].itemType,
4245                mItems[i].isHidden ? 1 : 0);
4246    }
4247
4248    endBox();
4249}
4250
4251void MPEG4Writer::writeIdatBox() {
4252    beginBox("idat");
4253
4254    for (size_t i = 0; i < mItems.size(); i++) {
4255        if (mItems[i].isGrid()) {
4256            writeInt8(0); // version
4257            // flags == 1 means 32-bit width,height
4258            int8_t flags = (mItems[i].width > 65535 || mItems[i].height > 65535);
4259            writeInt8(flags);
4260            writeInt8(mItems[i].rows - 1);
4261            writeInt8(mItems[i].cols - 1);
4262            if (flags) {
4263                writeInt32(mItems[i].width);
4264                writeInt32(mItems[i].height);
4265            } else {
4266                writeInt16((uint16_t)mItems[i].width);
4267                writeInt16((uint16_t)mItems[i].height);
4268            }
4269        }
4270    }
4271
4272    endBox();
4273}
4274
4275void MPEG4Writer::writeIrefBox() {
4276    beginBox("iref");
4277    writeInt32(0);          // Version = 0, Flags = 0
4278    {
4279        for (size_t i = 0; i < mItems.size(); i++) {
4280            if (!mItems[i].isGrid()) {
4281                continue;
4282            }
4283            beginBox("dimg");
4284            writeInt16(mItems[i].itemId);
4285            size_t refCount = mItems[i].dimgRefs.size();
4286            if (refCount > 65535) {
4287                ALOGW("too many entries in dimg");
4288                refCount = 65535;
4289            }
4290            writeInt16((uint16_t)refCount);
4291            for (size_t refIndex = 0; refIndex < refCount; refIndex++) {
4292                writeInt16(mItems[i].dimgRefs[refIndex]);
4293            }
4294            endBox();
4295        }
4296    }
4297    endBox();
4298}
4299
4300void MPEG4Writer::writePitmBox() {
4301    beginBox("pitm");
4302    writeInt32(0);          // Version = 0, Flags = 0
4303    writeInt16(mPrimaryItemId);
4304    endBox();
4305}
4306
4307void MPEG4Writer::writeIpcoBox() {
4308    beginBox("ipco");
4309    size_t numProperties = mProperties.size();
4310    if (numProperties > 32767) {
4311        ALOGW("Dropping excess properties: numProperties %zu", numProperties);
4312        numProperties = 32767;
4313    }
4314    for (size_t propIndex = 0; propIndex < numProperties; propIndex++) {
4315        switch (mProperties[propIndex].type) {
4316            case FOURCC('h', 'v', 'c', 'C'):
4317            {
4318                beginBox("hvcC");
4319                sp<ABuffer> hvcc = mProperties[propIndex].hvcc;
4320                // Patch avcc's lengthSize field to match the number
4321                // of bytes we use to indicate the size of a nal unit.
4322                uint8_t *ptr = (uint8_t *)hvcc->data();
4323                ptr[21] = (ptr[21] & 0xfc) | (useNalLengthFour() ? 3 : 1);
4324                write(hvcc->data(), hvcc->size());
4325                endBox();
4326                break;
4327            }
4328            case FOURCC('i', 's', 'p', 'e'):
4329            {
4330                beginBox("ispe");
4331                writeInt32(0); // Version = 0, Flags = 0
4332                writeInt32(mProperties[propIndex].width);
4333                writeInt32(mProperties[propIndex].height);
4334                endBox();
4335                break;
4336            }
4337            case FOURCC('i', 'r', 'o', 't'):
4338            {
4339                beginBox("irot");
4340                writeInt8(mProperties[propIndex].rotation);
4341                endBox();
4342                break;
4343            }
4344            default:
4345                ALOGW("Skipping unrecognized property: type 0x%08x",
4346                        mProperties[propIndex].type);
4347        }
4348    }
4349    endBox();
4350}
4351
4352void MPEG4Writer::writeIpmaBox() {
4353    beginBox("ipma");
4354    uint32_t flags = (mProperties.size() > 127) ? 1 : 0;
4355    writeInt32(flags); // Version = 0
4356
4357    writeInt32(mAssociationEntryCount);
4358    for (size_t itemIndex = 0; itemIndex < mItems.size(); itemIndex++) {
4359        const Vector<uint16_t> &properties = mItems[itemIndex].properties;
4360        if (properties.empty()) {
4361            continue;
4362        }
4363        writeInt16(mItems[itemIndex].itemId);
4364
4365        size_t entryCount = properties.size();
4366        if (entryCount > 255) {
4367            ALOGW("Dropping excess associations: entryCount %zu", entryCount);
4368            entryCount = 255;
4369        }
4370        writeInt8((uint8_t)entryCount);
4371        for (size_t propIndex = 0; propIndex < entryCount; propIndex++) {
4372            if (flags & 1) {
4373                writeInt16((1 << 15) | properties[propIndex]);
4374            } else {
4375                writeInt8((1 << 7) | properties[propIndex]);
4376            }
4377        }
4378    }
4379    endBox();
4380}
4381
4382void MPEG4Writer::writeIprpBox() {
4383    beginBox("iprp");
4384    writeIpcoBox();
4385    writeIpmaBox();
4386    endBox();
4387}
4388
4389void MPEG4Writer::writeFileLevelMetaBox() {
4390    if (mItems.empty()) {
4391        ALOGE("no valid item was found");
4392        return;
4393    }
4394
4395    // patch up the mPrimaryItemId and count items with prop associations
4396    uint16_t firstVisibleItemId = 0;
4397    for (size_t index = 0; index < mItems.size(); index++) {
4398        if (mItems[index].isPrimary) {
4399            mPrimaryItemId = mItems[index].itemId;
4400        } else if (!firstVisibleItemId && !mItems[index].isHidden) {
4401            firstVisibleItemId = mItems[index].itemId;
4402        }
4403
4404        if (!mItems[index].properties.empty()) {
4405            mAssociationEntryCount++;
4406        }
4407    }
4408
4409    if (mPrimaryItemId == 0) {
4410        if (firstVisibleItemId > 0) {
4411            ALOGW("didn't find primary, using first visible item");
4412            mPrimaryItemId = firstVisibleItemId;
4413        } else {
4414            ALOGW("no primary and no visible item, using first item");
4415            mPrimaryItemId = mItems[0].itemId;
4416        }
4417    }
4418
4419    beginBox("meta");
4420    writeInt32(0); // Version = 0, Flags = 0
4421    writeHdlr("pict");
4422    writeIlocBox();
4423    writeIinfBox();
4424    writePitmBox();
4425    writeIprpBox();
4426    if (mNumGrids > 0) {
4427        writeIdatBox();
4428        writeIrefBox();
4429    }
4430    endBox();
4431}
4432
4433uint16_t MPEG4Writer::addProperty_l(const ItemProperty &prop) {
4434    char typeStr[5];
4435    MakeFourCCString(prop.type, typeStr);
4436    ALOGV("addProperty_l: %s", typeStr);
4437
4438    mProperties.push_back(prop);
4439
4440    // returning 1-based property index
4441    return mProperties.size();
4442}
4443
4444uint16_t MPEG4Writer::addItem_l(const ItemInfo &info) {
4445    ALOGV("addItem_l: type %s, offset %u, size %u",
4446            info.itemType, info.offset, info.size);
4447
4448    size_t index = mItems.size();
4449    mItems.push_back(info);
4450
4451    // make the item id start at 10000
4452    mItems.editItemAt(index).itemId = index + 10000;
4453
4454#if (LOG_NDEBUG==0)
4455    if (!info.properties.empty()) {
4456        AString str;
4457        for (size_t i = 0; i < info.properties.size(); i++) {
4458            if (i > 0) {
4459                str.append(", ");
4460            }
4461            str.append(info.properties[i]);
4462        }
4463        ALOGV("addItem_l: id %d, properties: %s", mItems[index].itemId, str.c_str());
4464    }
4465#endif // (LOG_NDEBUG==0)
4466
4467    return mItems[index].itemId;
4468}
4469
4470/*
4471 * Geodata is stored according to ISO-6709 standard.
4472 */
4473void MPEG4Writer::writeGeoDataBox() {
4474    beginBox("\xA9xyz");
4475    /*
4476     * For historical reasons, any user data start
4477     * with "\0xA9", must be followed by its assoicated
4478     * language code.
4479     * 0x0012: text string length
4480     * 0x15c7: lang (locale) code: en
4481     */
4482    writeInt32(0x001215c7);
4483    writeLatitude(mLatitudex10000);
4484    writeLongitude(mLongitudex10000);
4485    writeInt8(0x2F);
4486    endBox();
4487}
4488
4489}  // namespace android
4490