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