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