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