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