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