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