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