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