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