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