• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "MPEG4Writer"
19 
20 #include <algorithm>
21 
22 #include <arpa/inet.h>
23 #include <fcntl.h>
24 #include <inttypes.h>
25 #include <pthread.h>
26 #include <sys/prctl.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 
31 #include <utils/Log.h>
32 
33 #include <functional>
34 
35 #include <media/stagefright/foundation/ADebug.h>
36 #include <media/stagefright/foundation/AMessage.h>
37 #include <media/stagefright/foundation/AUtils.h>
38 #include <media/stagefright/foundation/ColorUtils.h>
39 #include <media/stagefright/MPEG4Writer.h>
40 #include <media/stagefright/MediaBuffer.h>
41 #include <media/stagefright/MetaData.h>
42 #include <media/stagefright/MediaDefs.h>
43 #include <media/stagefright/MediaErrors.h>
44 #include <media/stagefright/MediaSource.h>
45 #include <media/stagefright/Utils.h>
46 #include <media/mediarecorder.h>
47 #include <cutils/properties.h>
48 
49 #include "include/ESDS.h"
50 #include "include/HevcUtils.h"
51 #include "include/avc_utils.h"
52 
53 #ifndef __predict_false
54 #define __predict_false(exp) __builtin_expect((exp) != 0, 0)
55 #endif
56 
57 #define WARN_UNLESS(condition, message, ...) \
58 ( (__predict_false(condition)) ? false : ({ \
59     ALOGW("Condition %s failed "  message, #condition, ##__VA_ARGS__); \
60     true; \
61 }))
62 
63 namespace android {
64 
65 static const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024;
66 static const int64_t kMax32BitFileSize = 0x00ffffffffLL; // 2^32-1 : max FAT32
67                                                          // filesystem file size
68                                                          // used by most SD cards
69 static const uint8_t kNalUnitTypeSeqParamSet = 0x07;
70 static const uint8_t kNalUnitTypePicParamSet = 0x08;
71 static const int64_t kInitialDelayTimeUs     = 700000LL;
72 
73 static const char kMetaKey_Version[]    = "com.android.version";
74 #ifdef SHOW_MODEL_BUILD
75 static const char kMetaKey_Model[]      = "com.android.model";
76 static const char kMetaKey_Build[]      = "com.android.build";
77 #endif
78 static const char kMetaKey_CaptureFps[] = "com.android.capture.fps";
79 static const char kMetaKey_TemporalLayerCount[] = "com.android.video.temporal_layers_count";
80 
81 static const uint8_t kMandatoryHevcNalUnitTypes[3] = {
82     kHevcNalUnitTypeVps,
83     kHevcNalUnitTypeSps,
84     kHevcNalUnitTypePps,
85 };
86 static const uint8_t kHevcNalUnitTypes[5] = {
87     kHevcNalUnitTypeVps,
88     kHevcNalUnitTypeSps,
89     kHevcNalUnitTypePps,
90     kHevcNalUnitTypePrefixSei,
91     kHevcNalUnitTypeSuffixSei,
92 };
93 /* uncomment to include model and build in meta */
94 //#define SHOW_MODEL_BUILD 1
95 
96 class MPEG4Writer::Track {
97 public:
98     Track(MPEG4Writer *owner, const sp<IMediaSource> &source, size_t trackId);
99 
100     ~Track();
101 
102     status_t start(MetaData *params);
103     status_t stop();
104     status_t pause();
105     bool reachedEOS();
106 
107     int64_t getDurationUs() const;
108     int64_t getEstimatedTrackSizeBytes() const;
109     void writeTrackHeader(bool use32BitOffset = true);
110     void bufferChunk(int64_t timestampUs);
isAvc() const111     bool isAvc() const { return mIsAvc; }
isHevc() const112     bool isHevc() const { return mIsHevc; }
isAudio() const113     bool isAudio() const { return mIsAudio; }
isMPEG4() const114     bool isMPEG4() const { return mIsMPEG4; }
115     void addChunkOffset(off64_t offset);
getTrackId() const116     int32_t getTrackId() const { return mTrackId; }
117     status_t dump(int fd, const Vector<String16>& args) const;
118     static const char *getFourCCForMime(const char *mime);
119 
120 private:
121     enum {
122         kMaxCttsOffsetTimeUs = 1000000LL,  // 1 second
123         kSampleArraySize = 1000,
124     };
125 
126     // A helper class to handle faster write box with table entries
127     template<class TYPE, unsigned ENTRY_SIZE>
128     // ENTRY_SIZE: # of values in each entry
129     struct ListTableEntries {
130         static_assert(ENTRY_SIZE > 0, "ENTRY_SIZE must be positive");
ListTableEntriesandroid::MPEG4Writer::Track::ListTableEntries131         ListTableEntries(uint32_t elementCapacity)
132             : mElementCapacity(elementCapacity),
133             mTotalNumTableEntries(0),
134             mNumValuesInCurrEntry(0),
135             mCurrTableEntriesElement(NULL) {
136             CHECK_GT(mElementCapacity, 0);
137             // Ensure no integer overflow on allocation in add().
138             CHECK_LT(ENTRY_SIZE, UINT32_MAX / mElementCapacity);
139         }
140 
141         // Free the allocated memory.
~ListTableEntriesandroid::MPEG4Writer::Track::ListTableEntries142         ~ListTableEntries() {
143             while (!mTableEntryList.empty()) {
144                 typename List<TYPE *>::iterator it = mTableEntryList.begin();
145                 delete[] (*it);
146                 mTableEntryList.erase(it);
147             }
148         }
149 
150         // Replace the value at the given position by the given value.
151         // There must be an existing value at the given position.
152         // @arg value must be in network byte order
153         // @arg pos location the value must be in.
setandroid::MPEG4Writer::Track::ListTableEntries154         void set(const TYPE& value, uint32_t pos) {
155             CHECK_LT(pos, mTotalNumTableEntries * ENTRY_SIZE);
156 
157             typename List<TYPE *>::iterator it = mTableEntryList.begin();
158             uint32_t iterations = (pos / (mElementCapacity * ENTRY_SIZE));
159             while (it != mTableEntryList.end() && iterations > 0) {
160                 ++it;
161                 --iterations;
162             }
163             CHECK(it != mTableEntryList.end());
164             CHECK_EQ(iterations, 0);
165 
166             (*it)[(pos % (mElementCapacity * ENTRY_SIZE))] = value;
167         }
168 
169         // Get the value at the given position by the given value.
170         // @arg value the retrieved value at the position in network byte order.
171         // @arg pos location the value must be in.
172         // @return true if a value is found.
getandroid::MPEG4Writer::Track::ListTableEntries173         bool get(TYPE& value, uint32_t pos) const {
174             if (pos >= mTotalNumTableEntries * ENTRY_SIZE) {
175                 return false;
176             }
177 
178             typename List<TYPE *>::iterator it = mTableEntryList.begin();
179             uint32_t iterations = (pos / (mElementCapacity * ENTRY_SIZE));
180             while (it != mTableEntryList.end() && iterations > 0) {
181                 ++it;
182                 --iterations;
183             }
184             CHECK(it != mTableEntryList.end());
185             CHECK_EQ(iterations, 0);
186 
187             value = (*it)[(pos % (mElementCapacity * ENTRY_SIZE))];
188             return true;
189         }
190 
191         // adjusts all values by |adjust(value)|
adjustEntriesandroid::MPEG4Writer::Track::ListTableEntries192         void adjustEntries(
193                 std::function<void(size_t /* ix */, TYPE(& /* entry */)[ENTRY_SIZE])> update) {
194             size_t nEntries = mTotalNumTableEntries + mNumValuesInCurrEntry / ENTRY_SIZE;
195             size_t ix = 0;
196             for (TYPE *entryArray : mTableEntryList) {
197                 size_t num = std::min(nEntries, (size_t)mElementCapacity);
198                 for (size_t i = 0; i < num; ++i) {
199                     update(ix++, (TYPE(&)[ENTRY_SIZE])(*entryArray));
200                     entryArray += ENTRY_SIZE;
201                 }
202                 nEntries -= num;
203             }
204         }
205 
206         // Store a single value.
207         // @arg value must be in network byte order.
addandroid::MPEG4Writer::Track::ListTableEntries208         void add(const TYPE& value) {
209             CHECK_LT(mNumValuesInCurrEntry, mElementCapacity);
210             uint32_t nEntries = mTotalNumTableEntries % mElementCapacity;
211             uint32_t nValues  = mNumValuesInCurrEntry % ENTRY_SIZE;
212             if (nEntries == 0 && nValues == 0) {
213                 mCurrTableEntriesElement = new TYPE[ENTRY_SIZE * mElementCapacity];
214                 CHECK(mCurrTableEntriesElement != NULL);
215                 mTableEntryList.push_back(mCurrTableEntriesElement);
216             }
217 
218             uint32_t pos = nEntries * ENTRY_SIZE + nValues;
219             mCurrTableEntriesElement[pos] = value;
220 
221             ++mNumValuesInCurrEntry;
222             if ((mNumValuesInCurrEntry % ENTRY_SIZE) == 0) {
223                 ++mTotalNumTableEntries;
224                 mNumValuesInCurrEntry = 0;
225             }
226         }
227 
228         // Write out the table entries:
229         // 1. the number of entries goes first
230         // 2. followed by the values in the table enties in order
231         // @arg writer the writer to actual write to the storage
writeandroid::MPEG4Writer::Track::ListTableEntries232         void write(MPEG4Writer *writer) const {
233             CHECK_EQ(mNumValuesInCurrEntry % ENTRY_SIZE, 0);
234             uint32_t nEntries = mTotalNumTableEntries;
235             writer->writeInt32(nEntries);
236             for (typename List<TYPE *>::iterator it = mTableEntryList.begin();
237                 it != mTableEntryList.end(); ++it) {
238                 CHECK_GT(nEntries, 0);
239                 if (nEntries >= mElementCapacity) {
240                     writer->write(*it, sizeof(TYPE) * ENTRY_SIZE, mElementCapacity);
241                     nEntries -= mElementCapacity;
242                 } else {
243                     writer->write(*it, sizeof(TYPE) * ENTRY_SIZE, nEntries);
244                     break;
245                 }
246             }
247         }
248 
249         // Return the number of entries in the table.
countandroid::MPEG4Writer::Track::ListTableEntries250         uint32_t count() const { return mTotalNumTableEntries; }
251 
252     private:
253         uint32_t         mElementCapacity;  // # entries in an element
254         uint32_t         mTotalNumTableEntries;
255         uint32_t         mNumValuesInCurrEntry;  // up to ENTRY_SIZE
256         TYPE             *mCurrTableEntriesElement;
257         mutable List<TYPE *>     mTableEntryList;
258 
259         DISALLOW_EVIL_CONSTRUCTORS(ListTableEntries);
260     };
261 
262 
263 
264     MPEG4Writer *mOwner;
265     sp<MetaData> mMeta;
266     sp<IMediaSource> mSource;
267     volatile bool mDone;
268     volatile bool mPaused;
269     volatile bool mResumed;
270     volatile bool mStarted;
271     bool mIsAvc;
272     bool mIsHevc;
273     bool mIsAudio;
274     bool mIsMPEG4;
275     bool mIsMalformed;
276     int32_t mTrackId;
277     int64_t mTrackDurationUs;
278     int64_t mMaxChunkDurationUs;
279     int64_t mLastDecodingTimeUs;
280 
281     int64_t mEstimatedTrackSizeBytes;
282     int64_t mMdatSizeBytes;
283     int32_t mTimeScale;
284 
285     pthread_t mThread;
286 
287 
288     List<MediaBuffer *> mChunkSamples;
289 
290     bool                mSamplesHaveSameSize;
291     ListTableEntries<uint32_t, 1> *mStszTableEntries;
292 
293     ListTableEntries<uint32_t, 1> *mStcoTableEntries;
294     ListTableEntries<off64_t, 1> *mCo64TableEntries;
295     ListTableEntries<uint32_t, 3> *mStscTableEntries;
296     ListTableEntries<uint32_t, 1> *mStssTableEntries;
297     ListTableEntries<uint32_t, 2> *mSttsTableEntries;
298     ListTableEntries<uint32_t, 2> *mCttsTableEntries;
299 
300     int64_t mMinCttsOffsetTimeUs;
301     int64_t mMaxCttsOffsetTimeUs;
302 
303     // Sequence parameter set or picture parameter set
304     struct AVCParamSet {
AVCParamSetandroid::MPEG4Writer::Track::AVCParamSet305         AVCParamSet(uint16_t length, const uint8_t *data)
306             : mLength(length), mData(data) {}
307 
308         uint16_t mLength;
309         const uint8_t *mData;
310     };
311     List<AVCParamSet> mSeqParamSets;
312     List<AVCParamSet> mPicParamSets;
313     uint8_t mProfileIdc;
314     uint8_t mProfileCompatible;
315     uint8_t mLevelIdc;
316 
317     void *mCodecSpecificData;
318     size_t mCodecSpecificDataSize;
319     bool mGotAllCodecSpecificData;
320     bool mTrackingProgressStatus;
321 
322     bool mReachedEOS;
323     int64_t mStartTimestampUs;
324     int64_t mStartTimeRealUs;
325     int64_t mFirstSampleTimeRealUs;
326     int64_t mPreviousTrackTimeUs;
327     int64_t mTrackEveryTimeDurationUs;
328 
329     // Update the audio track's drift information.
330     void updateDriftTime(const sp<MetaData>& meta);
331 
332     int32_t getStartTimeOffsetScaledTime() const;
333 
334     static void *ThreadWrapper(void *me);
335     status_t threadEntry();
336 
337     const uint8_t *parseParamSet(
338         const uint8_t *data, size_t length, int type, size_t *paramSetLen);
339 
340     status_t copyCodecSpecificData(const uint8_t *data, size_t size, size_t minLength = 0);
341 
342     status_t makeAVCCodecSpecificData(const uint8_t *data, size_t size);
343     status_t copyAVCCodecSpecificData(const uint8_t *data, size_t size);
344     status_t parseAVCCodecSpecificData(const uint8_t *data, size_t size);
345 
346     status_t makeHEVCCodecSpecificData(const uint8_t *data, size_t size);
347     status_t copyHEVCCodecSpecificData(const uint8_t *data, size_t size);
348     status_t parseHEVCCodecSpecificData(
349             const uint8_t *data, size_t size, HevcParameterSets &paramSets);
350 
351     // Track authoring progress status
352     void trackProgressStatus(int64_t timeUs, status_t err = OK);
353     void initTrackingProgressStatus(MetaData *params);
354 
355     void getCodecSpecificDataFromInputFormatIfPossible();
356 
357     // Determine the track time scale
358     // If it is an audio track, try to use the sampling rate as
359     // the time scale; however, if user chooses the overwrite
360     // value, the user-supplied time scale will be used.
361     void setTimeScale();
362 
363     // Simple validation on the codec specific data
364     status_t checkCodecSpecificData() const;
365     int32_t mRotation;
366 
367     void updateTrackSizeEstimate();
368     void addOneStscTableEntry(size_t chunkId, size_t sampleId);
369     void addOneStssTableEntry(size_t sampleId);
370 
371     // Duration is time scale based
372     void addOneSttsTableEntry(size_t sampleCount, int32_t timescaledDur);
373     void addOneCttsTableEntry(size_t sampleCount, int32_t timescaledDur);
374 
375     bool isTrackMalFormed() const;
376     void sendTrackSummary(bool hasMultipleTracks);
377 
378     // Write the boxes
379     void writeStcoBox(bool use32BitOffset);
380     void writeStscBox();
381     void writeStszBox();
382     void writeStssBox();
383     void writeSttsBox();
384     void writeCttsBox();
385     void writeD263Box();
386     void writePaspBox();
387     void writeAvccBox();
388     void writeHvccBox();
389     void writeUrlBox();
390     void writeDrefBox();
391     void writeDinfBox();
392     void writeDamrBox();
393     void writeMdhdBox(uint32_t now);
394     void writeSmhdBox();
395     void writeVmhdBox();
396     void writeHdlrBox();
397     void writeTkhdBox(uint32_t now);
398     void writeColrBox();
399     void writeMp4aEsdsBox();
400     void writeMp4vEsdsBox();
401     void writeAudioFourCCBox();
402     void writeVideoFourCCBox();
403     void writeStblBox(bool use32BitOffset);
404 
405     Track(const Track &);
406     Track &operator=(const Track &);
407 };
408 
MPEG4Writer(int fd)409 MPEG4Writer::MPEG4Writer(int fd)
410     : mFd(dup(fd)),
411       mInitCheck(mFd < 0? NO_INIT: OK),
412       mIsRealTimeRecording(true),
413       mUse4ByteNalLength(true),
414       mUse32BitOffset(true),
415       mIsFileSizeLimitExplicitlyRequested(false),
416       mPaused(false),
417       mStarted(false),
418       mWriterThreadStarted(false),
419       mOffset(0),
420       mMdatOffset(0),
421       mMoovBoxBuffer(NULL),
422       mMoovBoxBufferOffset(0),
423       mWriteMoovBoxToMemory(false),
424       mFreeBoxOffset(0),
425       mStreamableFile(false),
426       mEstimatedMoovBoxSize(0),
427       mMoovExtraSize(0),
428       mInterleaveDurationUs(1000000),
429       mTimeScale(-1),
430       mStartTimestampUs(-1ll),
431       mLatitudex10000(0),
432       mLongitudex10000(0),
433       mAreGeoTagsAvailable(false),
434       mStartTimeOffsetMs(-1),
435       mMetaKeys(new AMessage()) {
436     addDeviceMeta();
437 
438     // Verify mFd is seekable
439     off64_t off = lseek64(mFd, 0, SEEK_SET);
440     if (off < 0) {
441         ALOGE("cannot seek mFd: %s (%d)", strerror(errno), errno);
442         release();
443     }
444 }
445 
~MPEG4Writer()446 MPEG4Writer::~MPEG4Writer() {
447     reset();
448 
449     while (!mTracks.empty()) {
450         List<Track *>::iterator it = mTracks.begin();
451         delete *it;
452         (*it) = NULL;
453         mTracks.erase(it);
454     }
455     mTracks.clear();
456 }
457 
dump(int fd,const Vector<String16> & args)458 status_t MPEG4Writer::dump(
459         int fd, const Vector<String16>& args) {
460     const size_t SIZE = 256;
461     char buffer[SIZE];
462     String8 result;
463     snprintf(buffer, SIZE, "   MPEG4Writer %p\n", this);
464     result.append(buffer);
465     snprintf(buffer, SIZE, "     mStarted: %s\n", mStarted? "true": "false");
466     result.append(buffer);
467     ::write(fd, result.string(), result.size());
468     for (List<Track *>::iterator it = mTracks.begin();
469          it != mTracks.end(); ++it) {
470         (*it)->dump(fd, args);
471     }
472     return OK;
473 }
474 
dump(int fd,const Vector<String16> &) const475 status_t MPEG4Writer::Track::dump(
476         int fd, const Vector<String16>& /* args */) const {
477     const size_t SIZE = 256;
478     char buffer[SIZE];
479     String8 result;
480     snprintf(buffer, SIZE, "     %s track\n", mIsAudio? "Audio": "Video");
481     result.append(buffer);
482     snprintf(buffer, SIZE, "       reached EOS: %s\n",
483             mReachedEOS? "true": "false");
484     result.append(buffer);
485     snprintf(buffer, SIZE, "       frames encoded : %d\n", mStszTableEntries->count());
486     result.append(buffer);
487     snprintf(buffer, SIZE, "       duration encoded : %" PRId64 " us\n", mTrackDurationUs);
488     result.append(buffer);
489     ::write(fd, result.string(), result.size());
490     return OK;
491 }
492 
493 // static
getFourCCForMime(const char * mime)494 const char *MPEG4Writer::Track::getFourCCForMime(const char *mime) {
495     if (mime == NULL) {
496         return NULL;
497     }
498     if (!strncasecmp(mime, "audio/", 6)) {
499         if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
500             return "samr";
501         } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
502             return "sawb";
503         } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
504             return "mp4a";
505         }
506     } else if (!strncasecmp(mime, "video/", 6)) {
507         if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
508             return "mp4v";
509         } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
510             return "s263";
511         } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
512             return "avc1";
513         } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
514             return "hvc1";
515         }
516     } else {
517         ALOGE("Track (%s) other than video or audio is not supported", mime);
518     }
519     return NULL;
520 }
521 
addSource(const sp<IMediaSource> & source)522 status_t MPEG4Writer::addSource(const sp<IMediaSource> &source) {
523     Mutex::Autolock l(mLock);
524     if (mStarted) {
525         ALOGE("Attempt to add source AFTER recording is started");
526         return UNKNOWN_ERROR;
527     }
528 
529     // At most 2 tracks can be supported.
530     if (mTracks.size() >= 2) {
531         ALOGE("Too many tracks (%zu) to add", mTracks.size());
532         return ERROR_UNSUPPORTED;
533     }
534 
535     CHECK(source.get() != NULL);
536 
537     const char *mime;
538     source->getFormat()->findCString(kKeyMIMEType, &mime);
539     bool isAudio = !strncasecmp(mime, "audio/", 6);
540     if (Track::getFourCCForMime(mime) == NULL) {
541         ALOGE("Unsupported mime '%s'", mime);
542         return ERROR_UNSUPPORTED;
543     }
544 
545     // At this point, we know the track to be added is either
546     // video or audio. Thus, we only need to check whether it
547     // is an audio track or not (if it is not, then it must be
548     // a video track).
549 
550     // No more than one video or one audio track is supported.
551     for (List<Track*>::iterator it = mTracks.begin();
552          it != mTracks.end(); ++it) {
553         if ((*it)->isAudio() == isAudio) {
554             ALOGE("%s track already exists", isAudio? "Audio": "Video");
555             return ERROR_UNSUPPORTED;
556         }
557     }
558 
559     // This is the first track of either audio or video.
560     // Go ahead to add the track.
561     Track *track = new Track(this, source, 1 + mTracks.size());
562     mTracks.push_back(track);
563 
564     return OK;
565 }
566 
startTracks(MetaData * params)567 status_t MPEG4Writer::startTracks(MetaData *params) {
568     if (mTracks.empty()) {
569         ALOGE("No source added");
570         return INVALID_OPERATION;
571     }
572 
573     for (List<Track *>::iterator it = mTracks.begin();
574          it != mTracks.end(); ++it) {
575         status_t err = (*it)->start(params);
576 
577         if (err != OK) {
578             for (List<Track *>::iterator it2 = mTracks.begin();
579                  it2 != it; ++it2) {
580                 (*it2)->stop();
581             }
582 
583             return err;
584         }
585     }
586     return OK;
587 }
588 
addDeviceMeta()589 void MPEG4Writer::addDeviceMeta() {
590     // add device info and estimate space in 'moov'
591     char val[PROPERTY_VALUE_MAX];
592     size_t n;
593     // meta size is estimated by adding up the following:
594     // - meta header structures, which occur only once (total 66 bytes)
595     // - size for each key, which consists of a fixed header (32 bytes),
596     //   plus key length and data length.
597     mMoovExtraSize += 66;
598     if (property_get("ro.build.version.release", val, NULL)
599             && (n = strlen(val)) > 0) {
600         mMetaKeys->setString(kMetaKey_Version, val, n + 1);
601         mMoovExtraSize += sizeof(kMetaKey_Version) + n + 32;
602     }
603 #ifdef SHOW_MODEL_BUILD
604     if (property_get("ro.product.model", val, NULL)
605             && (n = strlen(val)) > 0) {
606         mMetaKeys->setString(kMetaKey_Model, val, n + 1);
607         mMoovExtraSize += sizeof(kMetaKey_Model) + n + 32;
608     }
609     if (property_get("ro.build.display.id", val, NULL)
610             && (n = strlen(val)) > 0) {
611         mMetaKeys->setString(kMetaKey_Build, val, n + 1);
612         mMoovExtraSize += sizeof(kMetaKey_Build) + n + 32;
613     }
614 #endif
615 }
616 
estimateMoovBoxSize(int32_t bitRate)617 int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) {
618     // This implementation is highly experimental/heurisitic.
619     //
620     // Statistical analysis shows that metadata usually accounts
621     // for a small portion of the total file size, usually < 0.6%.
622 
623     // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2,
624     // where 1MB is the common file size limit for MMS application.
625     // The default MAX _MOOV_BOX_SIZE value is based on about 3
626     // minute video recording with a bit rate about 3 Mbps, because
627     // statistics also show that most of the video captured are going
628     // to be less than 3 minutes.
629 
630     // If the estimation is wrong, we will pay the price of wasting
631     // some reserved space. This should not happen so often statistically.
632     static const int32_t factor = mUse32BitOffset? 1: 2;
633     static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024;  // 3 KB
634     static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000);
635     int64_t size = MIN_MOOV_BOX_SIZE;
636 
637     // Max file size limit is set
638     if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
639         size = mMaxFileSizeLimitBytes * 6 / 1000;
640     }
641 
642     // Max file duration limit is set
643     if (mMaxFileDurationLimitUs != 0) {
644         if (bitRate > 0) {
645             int64_t size2 =
646                 ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000);
647             if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
648                 // When both file size and duration limits are set,
649                 // we use the smaller limit of the two.
650                 if (size > size2) {
651                     size = size2;
652                 }
653             } else {
654                 // Only max file duration limit is set
655                 size = size2;
656             }
657         }
658     }
659 
660     if (size < MIN_MOOV_BOX_SIZE) {
661         size = MIN_MOOV_BOX_SIZE;
662     }
663 
664     // Any long duration recording will be probably end up with
665     // non-streamable mp4 file.
666     if (size > MAX_MOOV_BOX_SIZE) {
667         size = MAX_MOOV_BOX_SIZE;
668     }
669 
670     // Account for the extra stuff (Geo, meta keys, etc.)
671     size += mMoovExtraSize;
672 
673     ALOGI("limits: %" PRId64 "/%" PRId64 " bytes/us, bit rate: %d bps and the"
674          " estimated moov size %" PRId64 " bytes",
675          mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size);
676     return factor * size;
677 }
678 
start(MetaData * param)679 status_t MPEG4Writer::start(MetaData *param) {
680     if (mInitCheck != OK) {
681         return UNKNOWN_ERROR;
682     }
683 
684     /*
685      * Check mMaxFileSizeLimitBytes at the beginning
686      * since mMaxFileSizeLimitBytes may be implicitly
687      * changed later for 32-bit file offset even if
688      * user does not ask to set it explicitly.
689      */
690     if (mMaxFileSizeLimitBytes != 0) {
691         mIsFileSizeLimitExplicitlyRequested = true;
692     }
693 
694     int32_t use64BitOffset;
695     if (param &&
696         param->findInt32(kKey64BitFileOffset, &use64BitOffset) &&
697         use64BitOffset) {
698         mUse32BitOffset = false;
699     }
700 
701     if (mUse32BitOffset) {
702         // Implicit 32 bit file size limit
703         if (mMaxFileSizeLimitBytes == 0) {
704             mMaxFileSizeLimitBytes = kMax32BitFileSize;
705         }
706 
707         // If file size is set to be larger than the 32 bit file
708         // size limit, treat it as an error.
709         if (mMaxFileSizeLimitBytes > kMax32BitFileSize) {
710             ALOGW("32-bit file size limit (%" PRId64 " bytes) too big. "
711                  "It is changed to %" PRId64 " bytes",
712                 mMaxFileSizeLimitBytes, kMax32BitFileSize);
713             mMaxFileSizeLimitBytes = kMax32BitFileSize;
714         }
715     }
716 
717     int32_t use2ByteNalLength;
718     if (param &&
719         param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) &&
720         use2ByteNalLength) {
721         mUse4ByteNalLength = false;
722     }
723 
724     int32_t isRealTimeRecording;
725     if (param && param->findInt32(kKeyRealTimeRecording, &isRealTimeRecording)) {
726         mIsRealTimeRecording = isRealTimeRecording;
727     }
728 
729     mStartTimestampUs = -1;
730 
731     if (mStarted) {
732         if (mPaused) {
733             mPaused = false;
734             return startTracks(param);
735         }
736         return OK;
737     }
738 
739     if (!param ||
740         !param->findInt32(kKeyTimeScale, &mTimeScale)) {
741         mTimeScale = 1000;
742     }
743     CHECK_GT(mTimeScale, 0);
744     ALOGV("movie time scale: %d", mTimeScale);
745 
746     /*
747      * When the requested file size limit is small, the priority
748      * is to meet the file size limit requirement, rather than
749      * to make the file streamable. mStreamableFile does not tell
750      * whether the actual recorded file is streamable or not.
751      */
752     mStreamableFile =
753         (mMaxFileSizeLimitBytes != 0 &&
754          mMaxFileSizeLimitBytes >= kMinStreamableFileSizeInBytes);
755 
756     /*
757      * mWriteMoovBoxToMemory is true if the amount of data in moov box is
758      * smaller than the reserved free space at the beginning of a file, AND
759      * when the content of moov box is constructed. Note that video/audio
760      * frame data is always written to the file but not in the memory.
761      *
762      * Before stop()/reset() is called, mWriteMoovBoxToMemory is always
763      * false. When reset() is called at the end of a recording session,
764      * Moov box needs to be constructed.
765      *
766      * 1) Right before a moov box is constructed, mWriteMoovBoxToMemory
767      * to set to mStreamableFile so that if
768      * the file is intended to be streamable, it is set to true;
769      * otherwise, it is set to false. When the value is set to false,
770      * all the content of the moov box is written immediately to
771      * the end of the file. When the value is set to true, all the
772      * content of the moov box is written to an in-memory cache,
773      * mMoovBoxBuffer, util the following condition happens. Note
774      * that the size of the in-memory cache is the same as the
775      * reserved free space at the beginning of the file.
776      *
777      * 2) While the data of the moov box is written to an in-memory
778      * cache, the data size is checked against the reserved space.
779      * If the data size surpasses the reserved space, subsequent moov
780      * data could no longer be hold in the in-memory cache. This also
781      * indicates that the reserved space was too small. At this point,
782      * _all_ moov data must be written to the end of the file.
783      * mWriteMoovBoxToMemory must be set to false to direct the write
784      * to the file.
785      *
786      * 3) If the data size in moov box is smaller than the reserved
787      * space after moov box is completely constructed, the in-memory
788      * cache copy of the moov box is written to the reserved free
789      * space. Thus, immediately after the moov is completedly
790      * constructed, mWriteMoovBoxToMemory is always set to false.
791      */
792     mWriteMoovBoxToMemory = false;
793     mMoovBoxBuffer = NULL;
794     mMoovBoxBufferOffset = 0;
795 
796     writeFtypBox(param);
797 
798     mFreeBoxOffset = mOffset;
799 
800     if (mEstimatedMoovBoxSize == 0) {
801         int32_t bitRate = -1;
802         if (param) {
803             param->findInt32(kKeyBitRate, &bitRate);
804         }
805         mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate);
806     }
807     CHECK_GE(mEstimatedMoovBoxSize, 8);
808     if (mStreamableFile) {
809         // Reserve a 'free' box only for streamable file
810         lseek64(mFd, mFreeBoxOffset, SEEK_SET);
811         writeInt32(mEstimatedMoovBoxSize);
812         write("free", 4);
813         mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize;
814     } else {
815         mMdatOffset = mOffset;
816     }
817 
818     mOffset = mMdatOffset;
819     lseek64(mFd, mMdatOffset, SEEK_SET);
820     if (mUse32BitOffset) {
821         write("????mdat", 8);
822     } else {
823         write("\x00\x00\x00\x01mdat????????", 16);
824     }
825 
826     status_t err = startWriterThread();
827     if (err != OK) {
828         return err;
829     }
830 
831     err = startTracks(param);
832     if (err != OK) {
833         return err;
834     }
835 
836     mStarted = true;
837     return OK;
838 }
839 
use32BitFileOffset() const840 bool MPEG4Writer::use32BitFileOffset() const {
841     return mUse32BitOffset;
842 }
843 
pause()844 status_t MPEG4Writer::pause() {
845     if (mInitCheck != OK) {
846         return OK;
847     }
848     mPaused = true;
849     status_t err = OK;
850     for (List<Track *>::iterator it = mTracks.begin();
851          it != mTracks.end(); ++it) {
852         status_t status = (*it)->pause();
853         if (status != OK) {
854             err = status;
855         }
856     }
857     return err;
858 }
859 
stopWriterThread()860 void MPEG4Writer::stopWriterThread() {
861     ALOGD("Stopping writer thread");
862     if (!mWriterThreadStarted) {
863         return;
864     }
865 
866     {
867         Mutex::Autolock autolock(mLock);
868 
869         mDone = true;
870         mChunkReadyCondition.signal();
871     }
872 
873     void *dummy;
874     pthread_join(mThread, &dummy);
875     mWriterThreadStarted = false;
876     ALOGD("Writer thread stopped");
877 }
878 
879 /*
880  * MP4 file standard defines a composition matrix:
881  * | a  b  u |
882  * | c  d  v |
883  * | x  y  w |
884  *
885  * the element in the matrix is stored in the following
886  * order: {a, b, u, c, d, v, x, y, w},
887  * where a, b, c, d, x, and y is in 16.16 format, while
888  * u, v and w is in 2.30 format.
889  */
writeCompositionMatrix(int degrees)890 void MPEG4Writer::writeCompositionMatrix(int degrees) {
891     ALOGV("writeCompositionMatrix");
892     uint32_t a = 0x00010000;
893     uint32_t b = 0;
894     uint32_t c = 0;
895     uint32_t d = 0x00010000;
896     switch (degrees) {
897         case 0:
898             break;
899         case 90:
900             a = 0;
901             b = 0x00010000;
902             c = 0xFFFF0000;
903             d = 0;
904             break;
905         case 180:
906             a = 0xFFFF0000;
907             d = 0xFFFF0000;
908             break;
909         case 270:
910             a = 0;
911             b = 0xFFFF0000;
912             c = 0x00010000;
913             d = 0;
914             break;
915         default:
916             CHECK(!"Should never reach this unknown rotation");
917             break;
918     }
919 
920     writeInt32(a);           // a
921     writeInt32(b);           // b
922     writeInt32(0);           // u
923     writeInt32(c);           // c
924     writeInt32(d);           // d
925     writeInt32(0);           // v
926     writeInt32(0);           // x
927     writeInt32(0);           // y
928     writeInt32(0x40000000);  // w
929 }
930 
release()931 void MPEG4Writer::release() {
932     close(mFd);
933     mFd = -1;
934     mInitCheck = NO_INIT;
935     mStarted = false;
936     free(mMoovBoxBuffer);
937     mMoovBoxBuffer = NULL;
938 }
939 
reset()940 status_t MPEG4Writer::reset() {
941     if (mInitCheck != OK) {
942         return OK;
943     } else {
944         if (!mWriterThreadStarted ||
945             !mStarted) {
946             if (mWriterThreadStarted) {
947                 stopWriterThread();
948             }
949             release();
950             return OK;
951         }
952     }
953 
954     status_t err = OK;
955     int64_t maxDurationUs = 0;
956     int64_t minDurationUs = 0x7fffffffffffffffLL;
957     for (List<Track *>::iterator it = mTracks.begin();
958          it != mTracks.end(); ++it) {
959         status_t status = (*it)->stop();
960         if (err == OK && status != OK) {
961             err = status;
962         }
963 
964         int64_t durationUs = (*it)->getDurationUs();
965         if (durationUs > maxDurationUs) {
966             maxDurationUs = durationUs;
967         }
968         if (durationUs < minDurationUs) {
969             minDurationUs = durationUs;
970         }
971     }
972 
973     if (mTracks.size() > 1) {
974         ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us",
975             minDurationUs, maxDurationUs);
976     }
977 
978     stopWriterThread();
979 
980     // Do not write out movie header on error.
981     if (err != OK) {
982         release();
983         return err;
984     }
985 
986     // Fix up the size of the 'mdat' chunk.
987     if (mUse32BitOffset) {
988         lseek64(mFd, mMdatOffset, SEEK_SET);
989         uint32_t size = htonl(static_cast<uint32_t>(mOffset - mMdatOffset));
990         ::write(mFd, &size, 4);
991     } else {
992         lseek64(mFd, mMdatOffset + 8, SEEK_SET);
993         uint64_t size = mOffset - mMdatOffset;
994         size = hton64(size);
995         ::write(mFd, &size, 8);
996     }
997     lseek64(mFd, mOffset, SEEK_SET);
998 
999     // Construct moov box now
1000     mMoovBoxBufferOffset = 0;
1001     mWriteMoovBoxToMemory = mStreamableFile;
1002     if (mWriteMoovBoxToMemory) {
1003         // There is no need to allocate in-memory cache
1004         // for moov box if the file is not streamable.
1005 
1006         mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
1007         CHECK(mMoovBoxBuffer != NULL);
1008     }
1009     writeMoovBox(maxDurationUs);
1010 
1011     // mWriteMoovBoxToMemory could be set to false in
1012     // MPEG4Writer::write() method
1013     if (mWriteMoovBoxToMemory) {
1014         mWriteMoovBoxToMemory = false;
1015         // Content of the moov box is saved in the cache, and the in-memory
1016         // moov box needs to be written to the file in a single shot.
1017 
1018         CHECK_LE(mMoovBoxBufferOffset + 8, mEstimatedMoovBoxSize);
1019 
1020         // Moov box
1021         lseek64(mFd, mFreeBoxOffset, SEEK_SET);
1022         mOffset = mFreeBoxOffset;
1023         write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset);
1024 
1025         // Free box
1026         lseek64(mFd, mOffset, SEEK_SET);
1027         writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset);
1028         write("free", 4);
1029     } else {
1030         ALOGI("The mp4 file will not be streamable.");
1031     }
1032 
1033     // Free in-memory cache for moov box
1034     if (mMoovBoxBuffer != NULL) {
1035         free(mMoovBoxBuffer);
1036         mMoovBoxBuffer = NULL;
1037         mMoovBoxBufferOffset = 0;
1038     }
1039 
1040     CHECK(mBoxes.empty());
1041 
1042     release();
1043     return err;
1044 }
1045 
getMpeg4Time()1046 uint32_t MPEG4Writer::getMpeg4Time() {
1047     time_t now = time(NULL);
1048     // MP4 file uses time counting seconds since midnight, Jan. 1, 1904
1049     // while time function returns Unix epoch values which starts
1050     // at 1970-01-01. Lets add the number of seconds between them
1051     static const uint32_t delta = (66 * 365 + 17) * (24 * 60 * 60);
1052     if (now < 0 || uint32_t(now) > UINT32_MAX - delta) {
1053         return 0;
1054     }
1055     uint32_t mpeg4Time = uint32_t(now) + delta;
1056     return mpeg4Time;
1057 }
1058 
writeMvhdBox(int64_t durationUs)1059 void MPEG4Writer::writeMvhdBox(int64_t durationUs) {
1060     uint32_t now = getMpeg4Time();
1061     beginBox("mvhd");
1062     writeInt32(0);             // version=0, flags=0
1063     writeInt32(now);           // creation time
1064     writeInt32(now);           // modification time
1065     writeInt32(mTimeScale);    // mvhd timescale
1066     int32_t duration = (durationUs * mTimeScale + 5E5) / 1E6;
1067     writeInt32(duration);
1068     writeInt32(0x10000);       // rate: 1.0
1069     writeInt16(0x100);         // volume
1070     writeInt16(0);             // reserved
1071     writeInt32(0);             // reserved
1072     writeInt32(0);             // reserved
1073     writeCompositionMatrix(0); // matrix
1074     writeInt32(0);             // predefined
1075     writeInt32(0);             // predefined
1076     writeInt32(0);             // predefined
1077     writeInt32(0);             // predefined
1078     writeInt32(0);             // predefined
1079     writeInt32(0);             // predefined
1080     writeInt32(mTracks.size() + 1);  // nextTrackID
1081     endBox();  // mvhd
1082 }
1083 
writeMoovBox(int64_t durationUs)1084 void MPEG4Writer::writeMoovBox(int64_t durationUs) {
1085     beginBox("moov");
1086     writeMvhdBox(durationUs);
1087     if (mAreGeoTagsAvailable) {
1088         writeUdtaBox();
1089     }
1090     writeMetaBox();
1091     int32_t id = 1;
1092     for (List<Track *>::iterator it = mTracks.begin();
1093         it != mTracks.end(); ++it, ++id) {
1094         (*it)->writeTrackHeader(mUse32BitOffset);
1095     }
1096     endBox();  // moov
1097 }
1098 
writeFtypBox(MetaData * param)1099 void MPEG4Writer::writeFtypBox(MetaData *param) {
1100     beginBox("ftyp");
1101 
1102     int32_t fileType;
1103     if (param && param->findInt32(kKeyFileType, &fileType) &&
1104         fileType != OUTPUT_FORMAT_MPEG_4) {
1105         writeFourcc("3gp4");
1106         writeInt32(0);
1107         writeFourcc("isom");
1108         writeFourcc("3gp4");
1109     } else {
1110         writeFourcc("mp42");
1111         writeInt32(0);
1112         writeFourcc("isom");
1113         writeFourcc("mp42");
1114     }
1115 
1116     endBox();
1117 }
1118 
isTestModeEnabled()1119 static bool isTestModeEnabled() {
1120 #if (PROPERTY_VALUE_MAX < 5)
1121 #error "PROPERTY_VALUE_MAX must be at least 5"
1122 #endif
1123 
1124     // Test mode is enabled only if rw.media.record.test system
1125     // property is enabled.
1126     char value[PROPERTY_VALUE_MAX];
1127     if (property_get("rw.media.record.test", value, NULL) &&
1128         (!strcasecmp(value, "true") || !strcasecmp(value, "1"))) {
1129         return true;
1130     }
1131     return false;
1132 }
1133 
sendSessionSummary()1134 void MPEG4Writer::sendSessionSummary() {
1135     // Send session summary only if test mode is enabled
1136     if (!isTestModeEnabled()) {
1137         return;
1138     }
1139 
1140     for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
1141          it != mChunkInfos.end(); ++it) {
1142         int trackNum = it->mTrack->getTrackId() << 28;
1143         notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
1144                 trackNum | MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS,
1145                 it->mMaxInterChunkDurUs);
1146     }
1147 }
1148 
setInterleaveDuration(uint32_t durationUs)1149 status_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) {
1150     mInterleaveDurationUs = durationUs;
1151     return OK;
1152 }
1153 
lock()1154 void MPEG4Writer::lock() {
1155     mLock.lock();
1156 }
1157 
unlock()1158 void MPEG4Writer::unlock() {
1159     mLock.unlock();
1160 }
1161 
addSample_l(MediaBuffer * buffer)1162 off64_t MPEG4Writer::addSample_l(MediaBuffer *buffer) {
1163     off64_t old_offset = mOffset;
1164 
1165     ::write(mFd,
1166           (const uint8_t *)buffer->data() + buffer->range_offset(),
1167           buffer->range_length());
1168 
1169     mOffset += buffer->range_length();
1170 
1171     return old_offset;
1172 }
1173 
StripStartcode(MediaBuffer * buffer)1174 static void StripStartcode(MediaBuffer *buffer) {
1175     if (buffer->range_length() < 4) {
1176         return;
1177     }
1178 
1179     const uint8_t *ptr =
1180         (const uint8_t *)buffer->data() + buffer->range_offset();
1181 
1182     if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
1183         buffer->set_range(
1184                 buffer->range_offset() + 4, buffer->range_length() - 4);
1185     }
1186 }
1187 
addMultipleLengthPrefixedSamples_l(MediaBuffer * buffer)1188 off64_t MPEG4Writer::addMultipleLengthPrefixedSamples_l(MediaBuffer *buffer) {
1189     off64_t old_offset = mOffset;
1190 
1191     const size_t kExtensionNALSearchRange = 64; // bytes to look for non-VCL NALUs
1192 
1193     const uint8_t *dataStart = (const uint8_t *)buffer->data() + buffer->range_offset();
1194     const uint8_t *currentNalStart = dataStart;
1195     const uint8_t *nextNalStart;
1196     const uint8_t *data = dataStart;
1197     size_t nextNalSize;
1198     size_t searchSize = buffer->range_length() > kExtensionNALSearchRange ?
1199                    kExtensionNALSearchRange : buffer->range_length();
1200 
1201     while (getNextNALUnit(&data, &searchSize, &nextNalStart,
1202             &nextNalSize, true) == OK) {
1203         size_t currentNalSize = nextNalStart - currentNalStart - 4 /* strip start-code */;
1204         MediaBuffer *nalBuf = new MediaBuffer((void *)currentNalStart, currentNalSize);
1205         addLengthPrefixedSample_l(nalBuf);
1206         nalBuf->release();
1207 
1208         currentNalStart = nextNalStart;
1209     }
1210 
1211     size_t currentNalOffset = currentNalStart - dataStart;
1212     buffer->set_range(buffer->range_offset() + currentNalOffset,
1213             buffer->range_length() - currentNalOffset);
1214     addLengthPrefixedSample_l(buffer);
1215 
1216     return old_offset;
1217 }
1218 
addLengthPrefixedSample_l(MediaBuffer * buffer)1219 off64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
1220     off64_t old_offset = mOffset;
1221 
1222     size_t length = buffer->range_length();
1223 
1224     if (mUse4ByteNalLength) {
1225         uint8_t x = length >> 24;
1226         ::write(mFd, &x, 1);
1227         x = (length >> 16) & 0xff;
1228         ::write(mFd, &x, 1);
1229         x = (length >> 8) & 0xff;
1230         ::write(mFd, &x, 1);
1231         x = length & 0xff;
1232         ::write(mFd, &x, 1);
1233 
1234         ::write(mFd,
1235               (const uint8_t *)buffer->data() + buffer->range_offset(),
1236               length);
1237 
1238         mOffset += length + 4;
1239     } else {
1240         CHECK_LT(length, 65536);
1241 
1242         uint8_t x = length >> 8;
1243         ::write(mFd, &x, 1);
1244         x = length & 0xff;
1245         ::write(mFd, &x, 1);
1246         ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length);
1247         mOffset += length + 2;
1248     }
1249 
1250     return old_offset;
1251 }
1252 
write(const void * ptr,size_t size,size_t nmemb)1253 size_t MPEG4Writer::write(
1254         const void *ptr, size_t size, size_t nmemb) {
1255 
1256     const size_t bytes = size * nmemb;
1257     if (mWriteMoovBoxToMemory) {
1258 
1259         off64_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes;
1260         if (moovBoxSize > mEstimatedMoovBoxSize) {
1261             // The reserved moov box at the beginning of the file
1262             // is not big enough. Moov box should be written to
1263             // the end of the file from now on, but not to the
1264             // in-memory cache.
1265 
1266             // We write partial moov box that is in the memory to
1267             // the file first.
1268             for (List<off64_t>::iterator it = mBoxes.begin();
1269                  it != mBoxes.end(); ++it) {
1270                 (*it) += mOffset;
1271             }
1272             lseek64(mFd, mOffset, SEEK_SET);
1273             ::write(mFd, mMoovBoxBuffer, mMoovBoxBufferOffset);
1274             ::write(mFd, ptr, bytes);
1275             mOffset += (bytes + mMoovBoxBufferOffset);
1276 
1277             // All subsequent moov box content will be written
1278             // to the end of the file.
1279             mWriteMoovBoxToMemory = false;
1280         } else {
1281             memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes);
1282             mMoovBoxBufferOffset += bytes;
1283         }
1284     } else {
1285         ::write(mFd, ptr, size * nmemb);
1286         mOffset += bytes;
1287     }
1288     return bytes;
1289 }
1290 
beginBox(uint32_t id)1291 void MPEG4Writer::beginBox(uint32_t id) {
1292     mBoxes.push_back(mWriteMoovBoxToMemory?
1293             mMoovBoxBufferOffset: mOffset);
1294 
1295     writeInt32(0);
1296     writeInt32(id);
1297 }
1298 
beginBox(const char * fourcc)1299 void MPEG4Writer::beginBox(const char *fourcc) {
1300     CHECK_EQ(strlen(fourcc), 4);
1301 
1302     mBoxes.push_back(mWriteMoovBoxToMemory?
1303             mMoovBoxBufferOffset: mOffset);
1304 
1305     writeInt32(0);
1306     writeFourcc(fourcc);
1307 }
1308 
endBox()1309 void MPEG4Writer::endBox() {
1310     CHECK(!mBoxes.empty());
1311 
1312     off64_t offset = *--mBoxes.end();
1313     mBoxes.erase(--mBoxes.end());
1314 
1315     if (mWriteMoovBoxToMemory) {
1316        int32_t x = htonl(mMoovBoxBufferOffset - offset);
1317        memcpy(mMoovBoxBuffer + offset, &x, 4);
1318     } else {
1319         lseek64(mFd, offset, SEEK_SET);
1320         writeInt32(mOffset - offset);
1321         mOffset -= 4;
1322         lseek64(mFd, mOffset, SEEK_SET);
1323     }
1324 }
1325 
writeInt8(int8_t x)1326 void MPEG4Writer::writeInt8(int8_t x) {
1327     write(&x, 1, 1);
1328 }
1329 
writeInt16(int16_t x)1330 void MPEG4Writer::writeInt16(int16_t x) {
1331     x = htons(x);
1332     write(&x, 1, 2);
1333 }
1334 
writeInt32(int32_t x)1335 void MPEG4Writer::writeInt32(int32_t x) {
1336     x = htonl(x);
1337     write(&x, 1, 4);
1338 }
1339 
writeInt64(int64_t x)1340 void MPEG4Writer::writeInt64(int64_t x) {
1341     x = hton64(x);
1342     write(&x, 1, 8);
1343 }
1344 
writeCString(const char * s)1345 void MPEG4Writer::writeCString(const char *s) {
1346     size_t n = strlen(s);
1347     write(s, 1, n + 1);
1348 }
1349 
writeFourcc(const char * s)1350 void MPEG4Writer::writeFourcc(const char *s) {
1351     CHECK_EQ(strlen(s), 4);
1352     write(s, 1, 4);
1353 }
1354 
1355 
1356 // Written in +/-DD.DDDD format
writeLatitude(int degreex10000)1357 void MPEG4Writer::writeLatitude(int degreex10000) {
1358     bool isNegative = (degreex10000 < 0);
1359     char sign = isNegative? '-': '+';
1360 
1361     // Handle the whole part
1362     char str[9];
1363     int wholePart = degreex10000 / 10000;
1364     if (wholePart == 0) {
1365         snprintf(str, 5, "%c%.2d.", sign, wholePart);
1366     } else {
1367         snprintf(str, 5, "%+.2d.", wholePart);
1368     }
1369 
1370     // Handle the fractional part
1371     int fractionalPart = degreex10000 - (wholePart * 10000);
1372     if (fractionalPart < 0) {
1373         fractionalPart = -fractionalPart;
1374     }
1375     snprintf(&str[4], 5, "%.4d", fractionalPart);
1376 
1377     // Do not write the null terminator
1378     write(str, 1, 8);
1379 }
1380 
1381 // Written in +/- DDD.DDDD format
writeLongitude(int degreex10000)1382 void MPEG4Writer::writeLongitude(int degreex10000) {
1383     bool isNegative = (degreex10000 < 0);
1384     char sign = isNegative? '-': '+';
1385 
1386     // Handle the whole part
1387     char str[10];
1388     int wholePart = degreex10000 / 10000;
1389     if (wholePart == 0) {
1390         snprintf(str, 6, "%c%.3d.", sign, wholePart);
1391     } else {
1392         snprintf(str, 6, "%+.3d.", wholePart);
1393     }
1394 
1395     // Handle the fractional part
1396     int fractionalPart = degreex10000 - (wholePart * 10000);
1397     if (fractionalPart < 0) {
1398         fractionalPart = -fractionalPart;
1399     }
1400     snprintf(&str[5], 5, "%.4d", fractionalPart);
1401 
1402     // Do not write the null terminator
1403     write(str, 1, 9);
1404 }
1405 
1406 /*
1407  * Geodata is stored according to ISO-6709 standard.
1408  * latitudex10000 is latitude in degrees times 10000, and
1409  * longitudex10000 is longitude in degrees times 10000.
1410  * The range for the latitude is in [-90, +90], and
1411  * The range for the longitude is in [-180, +180]
1412  */
setGeoData(int latitudex10000,int longitudex10000)1413 status_t MPEG4Writer::setGeoData(int latitudex10000, int longitudex10000) {
1414     // Is latitude or longitude out of range?
1415     if (latitudex10000 < -900000 || latitudex10000 > 900000 ||
1416         longitudex10000 < -1800000 || longitudex10000 > 1800000) {
1417         return BAD_VALUE;
1418     }
1419 
1420     mLatitudex10000 = latitudex10000;
1421     mLongitudex10000 = longitudex10000;
1422     mAreGeoTagsAvailable = true;
1423     mMoovExtraSize += 30;
1424     return OK;
1425 }
1426 
setCaptureRate(float captureFps)1427 status_t MPEG4Writer::setCaptureRate(float captureFps) {
1428     if (captureFps <= 0.0f) {
1429         return BAD_VALUE;
1430     }
1431 
1432     mMetaKeys->setFloat(kMetaKey_CaptureFps, captureFps);
1433     mMoovExtraSize += sizeof(kMetaKey_CaptureFps) + 4 + 32;
1434 
1435     return OK;
1436 }
1437 
setTemporalLayerCount(uint32_t layerCount)1438 status_t MPEG4Writer::setTemporalLayerCount(uint32_t layerCount) {
1439     if (layerCount > 9) {
1440         return BAD_VALUE;
1441     }
1442 
1443     if (layerCount > 0) {
1444         mMetaKeys->setInt32(kMetaKey_TemporalLayerCount, layerCount);
1445         mMoovExtraSize += sizeof(kMetaKey_TemporalLayerCount) + 4 + 32;
1446     }
1447 
1448     return OK;
1449 }
1450 
write(const void * data,size_t size)1451 void MPEG4Writer::write(const void *data, size_t size) {
1452     write(data, 1, size);
1453 }
1454 
isFileStreamable() const1455 bool MPEG4Writer::isFileStreamable() const {
1456     return mStreamableFile;
1457 }
1458 
exceedsFileSizeLimit()1459 bool MPEG4Writer::exceedsFileSizeLimit() {
1460     // No limit
1461     if (mMaxFileSizeLimitBytes == 0) {
1462         return false;
1463     }
1464 
1465     int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize);
1466     for (List<Track *>::iterator it = mTracks.begin();
1467          it != mTracks.end(); ++it) {
1468         nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
1469     }
1470 
1471     if (!mStreamableFile) {
1472         // Add 1024 bytes as error tolerance
1473         return nTotalBytesEstimate + 1024 >= mMaxFileSizeLimitBytes;
1474     }
1475     // Be conservative in the estimate: do not exceed 95% of
1476     // the target file limit. For small target file size limit, though,
1477     // this will not help.
1478     return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100);
1479 }
1480 
exceedsFileDurationLimit()1481 bool MPEG4Writer::exceedsFileDurationLimit() {
1482     // No limit
1483     if (mMaxFileDurationLimitUs == 0) {
1484         return false;
1485     }
1486 
1487     for (List<Track *>::iterator it = mTracks.begin();
1488          it != mTracks.end(); ++it) {
1489         if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) {
1490             return true;
1491         }
1492     }
1493     return false;
1494 }
1495 
reachedEOS()1496 bool MPEG4Writer::reachedEOS() {
1497     bool allDone = true;
1498     for (List<Track *>::iterator it = mTracks.begin();
1499          it != mTracks.end(); ++it) {
1500         if (!(*it)->reachedEOS()) {
1501             allDone = false;
1502             break;
1503         }
1504     }
1505 
1506     return allDone;
1507 }
1508 
setStartTimestampUs(int64_t timeUs)1509 void MPEG4Writer::setStartTimestampUs(int64_t timeUs) {
1510     ALOGI("setStartTimestampUs: %" PRId64, timeUs);
1511     CHECK_GE(timeUs, 0ll);
1512     Mutex::Autolock autoLock(mLock);
1513     if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) {
1514         mStartTimestampUs = timeUs;
1515         ALOGI("Earliest track starting time: %" PRId64, mStartTimestampUs);
1516     }
1517 }
1518 
getStartTimestampUs()1519 int64_t MPEG4Writer::getStartTimestampUs() {
1520     Mutex::Autolock autoLock(mLock);
1521     return mStartTimestampUs;
1522 }
1523 
numTracks()1524 size_t MPEG4Writer::numTracks() {
1525     Mutex::Autolock autolock(mLock);
1526     return mTracks.size();
1527 }
1528 
1529 ////////////////////////////////////////////////////////////////////////////////
1530 
Track(MPEG4Writer * owner,const sp<IMediaSource> & source,size_t trackId)1531 MPEG4Writer::Track::Track(
1532         MPEG4Writer *owner, const sp<IMediaSource> &source, size_t trackId)
1533     : mOwner(owner),
1534       mMeta(source->getFormat()),
1535       mSource(source),
1536       mDone(false),
1537       mPaused(false),
1538       mResumed(false),
1539       mStarted(false),
1540       mIsMalformed(false),
1541       mTrackId(trackId),
1542       mTrackDurationUs(0),
1543       mEstimatedTrackSizeBytes(0),
1544       mSamplesHaveSameSize(true),
1545       mStszTableEntries(new ListTableEntries<uint32_t, 1>(1000)),
1546       mStcoTableEntries(new ListTableEntries<uint32_t, 1>(1000)),
1547       mCo64TableEntries(new ListTableEntries<off64_t, 1>(1000)),
1548       mStscTableEntries(new ListTableEntries<uint32_t, 3>(1000)),
1549       mStssTableEntries(new ListTableEntries<uint32_t, 1>(1000)),
1550       mSttsTableEntries(new ListTableEntries<uint32_t, 2>(1000)),
1551       mCttsTableEntries(new ListTableEntries<uint32_t, 2>(1000)),
1552       mCodecSpecificData(NULL),
1553       mCodecSpecificDataSize(0),
1554       mGotAllCodecSpecificData(false),
1555       mReachedEOS(false),
1556       mRotation(0) {
1557     getCodecSpecificDataFromInputFormatIfPossible();
1558 
1559     const char *mime;
1560     mMeta->findCString(kKeyMIMEType, &mime);
1561     mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
1562     mIsHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC);
1563     mIsAudio = !strncasecmp(mime, "audio/", 6);
1564     mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
1565                !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
1566 
1567     // store temporal layer count
1568     if (!mIsAudio) {
1569         int32_t count;
1570         if (mMeta->findInt32(kKeyTemporalLayerCount, &count) && count > 1) {
1571             mOwner->setTemporalLayerCount(count);
1572         }
1573     }
1574 
1575     setTimeScale();
1576 }
1577 
updateTrackSizeEstimate()1578 void MPEG4Writer::Track::updateTrackSizeEstimate() {
1579 
1580     uint32_t stcoBoxCount = (mOwner->use32BitFileOffset()
1581                             ? mStcoTableEntries->count()
1582                             : mCo64TableEntries->count());
1583     int64_t stcoBoxSizeBytes = stcoBoxCount * 4;
1584     int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mStszTableEntries->count() * 4);
1585 
1586     mEstimatedTrackSizeBytes = mMdatSizeBytes;  // media data size
1587     if (!mOwner->isFileStreamable()) {
1588         // Reserved free space is not large enough to hold
1589         // all meta data and thus wasted.
1590         mEstimatedTrackSizeBytes += mStscTableEntries->count() * 12 +  // stsc box size
1591                                     mStssTableEntries->count() * 4 +   // stss box size
1592                                     mSttsTableEntries->count() * 8 +   // stts box size
1593                                     mCttsTableEntries->count() * 8 +   // ctts box size
1594                                     stcoBoxSizeBytes +           // stco box size
1595                                     stszBoxSizeBytes;            // stsz box size
1596     }
1597 }
1598 
addOneStscTableEntry(size_t chunkId,size_t sampleId)1599 void MPEG4Writer::Track::addOneStscTableEntry(
1600         size_t chunkId, size_t sampleId) {
1601 
1602         mStscTableEntries->add(htonl(chunkId));
1603         mStscTableEntries->add(htonl(sampleId));
1604         mStscTableEntries->add(htonl(1));
1605 }
1606 
addOneStssTableEntry(size_t sampleId)1607 void MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) {
1608     mStssTableEntries->add(htonl(sampleId));
1609 }
1610 
addOneSttsTableEntry(size_t sampleCount,int32_t duration)1611 void MPEG4Writer::Track::addOneSttsTableEntry(
1612         size_t sampleCount, int32_t duration) {
1613 
1614     if (duration == 0) {
1615         ALOGW("0-duration samples found: %zu", sampleCount);
1616     }
1617     mSttsTableEntries->add(htonl(sampleCount));
1618     mSttsTableEntries->add(htonl(duration));
1619 }
1620 
addOneCttsTableEntry(size_t sampleCount,int32_t duration)1621 void MPEG4Writer::Track::addOneCttsTableEntry(
1622         size_t sampleCount, int32_t duration) {
1623 
1624     if (mIsAudio) {
1625         return;
1626     }
1627     mCttsTableEntries->add(htonl(sampleCount));
1628     mCttsTableEntries->add(htonl(duration));
1629 }
1630 
addChunkOffset(off64_t offset)1631 void MPEG4Writer::Track::addChunkOffset(off64_t offset) {
1632     if (mOwner->use32BitFileOffset()) {
1633         uint32_t value = offset;
1634         mStcoTableEntries->add(htonl(value));
1635     } else {
1636         mCo64TableEntries->add(hton64(offset));
1637     }
1638 }
1639 
setTimeScale()1640 void MPEG4Writer::Track::setTimeScale() {
1641     ALOGV("setTimeScale");
1642     // Default time scale
1643     mTimeScale = 90000;
1644 
1645     if (mIsAudio) {
1646         // Use the sampling rate as the default time scale for audio track.
1647         int32_t sampleRate;
1648         bool success = mMeta->findInt32(kKeySampleRate, &sampleRate);
1649         CHECK(success);
1650         mTimeScale = sampleRate;
1651     }
1652 
1653     // If someone would like to overwrite the timescale, use user-supplied value.
1654     int32_t timeScale;
1655     if (mMeta->findInt32(kKeyTimeScale, &timeScale)) {
1656         mTimeScale = timeScale;
1657     }
1658 
1659     CHECK_GT(mTimeScale, 0);
1660 }
1661 
getCodecSpecificDataFromInputFormatIfPossible()1662 void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
1663     const char *mime;
1664     CHECK(mMeta->findCString(kKeyMIMEType, &mime));
1665 
1666     uint32_t type;
1667     const void *data = NULL;
1668     size_t size = 0;
1669     if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
1670         mMeta->findData(kKeyAVCC, &type, &data, &size);
1671     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
1672         mMeta->findData(kKeyHVCC, &type, &data, &size);
1673     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
1674             || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
1675         if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
1676             ESDS esds(data, size);
1677             if (esds.getCodecSpecificInfo(&data, &size) != OK) {
1678                 data = NULL;
1679                 size = 0;
1680             }
1681         }
1682     }
1683     if (data != NULL && copyCodecSpecificData((uint8_t *)data, size) == OK) {
1684         mGotAllCodecSpecificData = true;
1685     }
1686 }
1687 
~Track()1688 MPEG4Writer::Track::~Track() {
1689     stop();
1690 
1691     delete mStszTableEntries;
1692     delete mStcoTableEntries;
1693     delete mCo64TableEntries;
1694     delete mStscTableEntries;
1695     delete mSttsTableEntries;
1696     delete mStssTableEntries;
1697     delete mCttsTableEntries;
1698 
1699     mStszTableEntries = NULL;
1700     mStcoTableEntries = NULL;
1701     mCo64TableEntries = NULL;
1702     mStscTableEntries = NULL;
1703     mSttsTableEntries = NULL;
1704     mStssTableEntries = NULL;
1705     mCttsTableEntries = NULL;
1706 
1707     if (mCodecSpecificData != NULL) {
1708         free(mCodecSpecificData);
1709         mCodecSpecificData = NULL;
1710     }
1711 }
1712 
initTrackingProgressStatus(MetaData * params)1713 void MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) {
1714     ALOGV("initTrackingProgressStatus");
1715     mPreviousTrackTimeUs = -1;
1716     mTrackingProgressStatus = false;
1717     mTrackEveryTimeDurationUs = 0;
1718     {
1719         int64_t timeUs;
1720         if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) {
1721             ALOGV("Receive request to track progress status for every %" PRId64 " us", timeUs);
1722             mTrackEveryTimeDurationUs = timeUs;
1723             mTrackingProgressStatus = true;
1724         }
1725     }
1726 }
1727 
1728 // static
ThreadWrapper(void * me)1729 void *MPEG4Writer::ThreadWrapper(void *me) {
1730     ALOGV("ThreadWrapper: %p", me);
1731     MPEG4Writer *writer = static_cast<MPEG4Writer *>(me);
1732     writer->threadFunc();
1733     return NULL;
1734 }
1735 
bufferChunk(const Chunk & chunk)1736 void MPEG4Writer::bufferChunk(const Chunk& chunk) {
1737     ALOGV("bufferChunk: %p", chunk.mTrack);
1738     Mutex::Autolock autolock(mLock);
1739     CHECK_EQ(mDone, false);
1740 
1741     for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
1742          it != mChunkInfos.end(); ++it) {
1743 
1744         if (chunk.mTrack == it->mTrack) {  // Found owner
1745             it->mChunks.push_back(chunk);
1746             mChunkReadyCondition.signal();
1747             return;
1748         }
1749     }
1750 
1751     CHECK(!"Received a chunk for a unknown track");
1752 }
1753 
writeChunkToFile(Chunk * chunk)1754 void MPEG4Writer::writeChunkToFile(Chunk* chunk) {
1755     ALOGV("writeChunkToFile: %" PRId64 " from %s track",
1756         chunk->mTimeStampUs, chunk->mTrack->isAudio()? "audio": "video");
1757 
1758     int32_t isFirstSample = true;
1759     while (!chunk->mSamples.empty()) {
1760         List<MediaBuffer *>::iterator it = chunk->mSamples.begin();
1761 
1762         off64_t offset = (chunk->mTrack->isAvc() || chunk->mTrack->isHevc())
1763                                 ? addMultipleLengthPrefixedSamples_l(*it)
1764                                 : addSample_l(*it);
1765 
1766         if (isFirstSample) {
1767             chunk->mTrack->addChunkOffset(offset);
1768             isFirstSample = false;
1769         }
1770 
1771         (*it)->release();
1772         (*it) = NULL;
1773         chunk->mSamples.erase(it);
1774     }
1775     chunk->mSamples.clear();
1776 }
1777 
writeAllChunks()1778 void MPEG4Writer::writeAllChunks() {
1779     ALOGV("writeAllChunks");
1780     size_t outstandingChunks = 0;
1781     Chunk chunk;
1782     while (findChunkToWrite(&chunk)) {
1783         writeChunkToFile(&chunk);
1784         ++outstandingChunks;
1785     }
1786 
1787     sendSessionSummary();
1788 
1789     mChunkInfos.clear();
1790     ALOGD("%zu chunks are written in the last batch", outstandingChunks);
1791 }
1792 
findChunkToWrite(Chunk * chunk)1793 bool MPEG4Writer::findChunkToWrite(Chunk *chunk) {
1794     ALOGV("findChunkToWrite");
1795 
1796     int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL;
1797     Track *track = NULL;
1798     for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
1799          it != mChunkInfos.end(); ++it) {
1800         if (!it->mChunks.empty()) {
1801             List<Chunk>::iterator chunkIt = it->mChunks.begin();
1802             if (chunkIt->mTimeStampUs < minTimestampUs) {
1803                 minTimestampUs = chunkIt->mTimeStampUs;
1804                 track = it->mTrack;
1805             }
1806         }
1807     }
1808 
1809     if (track == NULL) {
1810         ALOGV("Nothing to be written after all");
1811         return false;
1812     }
1813 
1814     if (mIsFirstChunk) {
1815         mIsFirstChunk = false;
1816     }
1817 
1818     for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
1819          it != mChunkInfos.end(); ++it) {
1820         if (it->mTrack == track) {
1821             *chunk = *(it->mChunks.begin());
1822             it->mChunks.erase(it->mChunks.begin());
1823             CHECK_EQ(chunk->mTrack, track);
1824 
1825             int64_t interChunkTimeUs =
1826                 chunk->mTimeStampUs - it->mPrevChunkTimestampUs;
1827             if (interChunkTimeUs > it->mPrevChunkTimestampUs) {
1828                 it->mMaxInterChunkDurUs = interChunkTimeUs;
1829             }
1830 
1831             return true;
1832         }
1833     }
1834 
1835     return false;
1836 }
1837 
threadFunc()1838 void MPEG4Writer::threadFunc() {
1839     ALOGV("threadFunc");
1840 
1841     prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0);
1842 
1843     Mutex::Autolock autoLock(mLock);
1844     while (!mDone) {
1845         Chunk chunk;
1846         bool chunkFound = false;
1847 
1848         while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) {
1849             mChunkReadyCondition.wait(mLock);
1850         }
1851 
1852         // In real time recording mode, write without holding the lock in order
1853         // to reduce the blocking time for media track threads.
1854         // Otherwise, hold the lock until the existing chunks get written to the
1855         // file.
1856         if (chunkFound) {
1857             if (mIsRealTimeRecording) {
1858                 mLock.unlock();
1859             }
1860             writeChunkToFile(&chunk);
1861             if (mIsRealTimeRecording) {
1862                 mLock.lock();
1863             }
1864         }
1865     }
1866 
1867     writeAllChunks();
1868 }
1869 
startWriterThread()1870 status_t MPEG4Writer::startWriterThread() {
1871     ALOGV("startWriterThread");
1872 
1873     mDone = false;
1874     mIsFirstChunk = true;
1875     mDriftTimeUs = 0;
1876     for (List<Track *>::iterator it = mTracks.begin();
1877          it != mTracks.end(); ++it) {
1878         ChunkInfo info;
1879         info.mTrack = *it;
1880         info.mPrevChunkTimestampUs = 0;
1881         info.mMaxInterChunkDurUs = 0;
1882         mChunkInfos.push_back(info);
1883     }
1884 
1885     pthread_attr_t attr;
1886     pthread_attr_init(&attr);
1887     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1888     pthread_create(&mThread, &attr, ThreadWrapper, this);
1889     pthread_attr_destroy(&attr);
1890     mWriterThreadStarted = true;
1891     return OK;
1892 }
1893 
1894 
start(MetaData * params)1895 status_t MPEG4Writer::Track::start(MetaData *params) {
1896     if (!mDone && mPaused) {
1897         mPaused = false;
1898         mResumed = true;
1899         return OK;
1900     }
1901 
1902     int64_t startTimeUs;
1903     if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) {
1904         startTimeUs = 0;
1905     }
1906     mStartTimeRealUs = startTimeUs;
1907 
1908     int32_t rotationDegrees;
1909     if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) {
1910         mRotation = rotationDegrees;
1911     }
1912 
1913     initTrackingProgressStatus(params);
1914 
1915     sp<MetaData> meta = new MetaData;
1916     if (mOwner->isRealTimeRecording() && mOwner->numTracks() > 1) {
1917         /*
1918          * This extra delay of accepting incoming audio/video signals
1919          * helps to align a/v start time at the beginning of a recording
1920          * session, and it also helps eliminate the "recording" sound for
1921          * camcorder applications.
1922          *
1923          * If client does not set the start time offset, we fall back to
1924          * use the default initial delay value.
1925          */
1926         int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL;
1927         if (startTimeOffsetUs < 0) {  // Start time offset was not set
1928             startTimeOffsetUs = kInitialDelayTimeUs;
1929         }
1930         startTimeUs += startTimeOffsetUs;
1931         ALOGI("Start time offset: %" PRId64 " us", startTimeOffsetUs);
1932     }
1933 
1934     meta->setInt64(kKeyTime, startTimeUs);
1935 
1936     status_t err = mSource->start(meta.get());
1937     if (err != OK) {
1938         mDone = mReachedEOS = true;
1939         return err;
1940     }
1941 
1942     pthread_attr_t attr;
1943     pthread_attr_init(&attr);
1944     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1945 
1946     mDone = false;
1947     mStarted = true;
1948     mTrackDurationUs = 0;
1949     mReachedEOS = false;
1950     mEstimatedTrackSizeBytes = 0;
1951     mMdatSizeBytes = 0;
1952     mMaxChunkDurationUs = 0;
1953     mLastDecodingTimeUs = -1;
1954 
1955     pthread_create(&mThread, &attr, ThreadWrapper, this);
1956     pthread_attr_destroy(&attr);
1957 
1958     return OK;
1959 }
1960 
pause()1961 status_t MPEG4Writer::Track::pause() {
1962     mPaused = true;
1963     return OK;
1964 }
1965 
stop()1966 status_t MPEG4Writer::Track::stop() {
1967     ALOGD("%s track stopping", mIsAudio? "Audio": "Video");
1968     if (!mStarted) {
1969         ALOGE("Stop() called but track is not started");
1970         return ERROR_END_OF_STREAM;
1971     }
1972 
1973     if (mDone) {
1974         return OK;
1975     }
1976     mDone = true;
1977 
1978     ALOGD("%s track source stopping", mIsAudio? "Audio": "Video");
1979     mSource->stop();
1980     ALOGD("%s track source stopped", mIsAudio? "Audio": "Video");
1981 
1982     void *dummy;
1983     pthread_join(mThread, &dummy);
1984     status_t err = static_cast<status_t>(reinterpret_cast<uintptr_t>(dummy));
1985 
1986     ALOGD("%s track stopped", mIsAudio? "Audio": "Video");
1987     return err;
1988 }
1989 
reachedEOS()1990 bool MPEG4Writer::Track::reachedEOS() {
1991     return mReachedEOS;
1992 }
1993 
1994 // static
ThreadWrapper(void * me)1995 void *MPEG4Writer::Track::ThreadWrapper(void *me) {
1996     Track *track = static_cast<Track *>(me);
1997 
1998     status_t err = track->threadEntry();
1999     return (void *)(uintptr_t)err;
2000 }
2001 
getNalUnitType(uint8_t byte,uint8_t * type)2002 static void getNalUnitType(uint8_t byte, uint8_t* type) {
2003     ALOGV("getNalUnitType: %d", byte);
2004 
2005     // nal_unit_type: 5-bit unsigned integer
2006     *type = (byte & 0x1F);
2007 }
2008 
parseParamSet(const uint8_t * data,size_t length,int type,size_t * paramSetLen)2009 const uint8_t *MPEG4Writer::Track::parseParamSet(
2010         const uint8_t *data, size_t length, int type, size_t *paramSetLen) {
2011 
2012     ALOGV("parseParamSet");
2013     CHECK(type == kNalUnitTypeSeqParamSet ||
2014           type == kNalUnitTypePicParamSet);
2015 
2016     const uint8_t *nextStartCode = findNextNalStartCode(data, length);
2017     *paramSetLen = nextStartCode - data;
2018     if (*paramSetLen == 0) {
2019         ALOGE("Param set is malformed, since its length is 0");
2020         return NULL;
2021     }
2022 
2023     AVCParamSet paramSet(*paramSetLen, data);
2024     if (type == kNalUnitTypeSeqParamSet) {
2025         if (*paramSetLen < 4) {
2026             ALOGE("Seq parameter set malformed");
2027             return NULL;
2028         }
2029         if (mSeqParamSets.empty()) {
2030             mProfileIdc = data[1];
2031             mProfileCompatible = data[2];
2032             mLevelIdc = data[3];
2033         } else {
2034             if (mProfileIdc != data[1] ||
2035                 mProfileCompatible != data[2] ||
2036                 mLevelIdc != data[3]) {
2037                 // COULD DO: set profile/level to the lowest required to support all SPSs
2038                 ALOGE("Inconsistent profile/level found in seq parameter sets");
2039                 return NULL;
2040             }
2041         }
2042         mSeqParamSets.push_back(paramSet);
2043     } else {
2044         mPicParamSets.push_back(paramSet);
2045     }
2046     return nextStartCode;
2047 }
2048 
copyAVCCodecSpecificData(const uint8_t * data,size_t size)2049 status_t MPEG4Writer::Track::copyAVCCodecSpecificData(
2050         const uint8_t *data, size_t size) {
2051     ALOGV("copyAVCCodecSpecificData");
2052 
2053     // 2 bytes for each of the parameter set length field
2054     // plus the 7 bytes for the header
2055     return copyCodecSpecificData(data, size, 4 + 7);
2056 }
2057 
copyHEVCCodecSpecificData(const uint8_t * data,size_t size)2058 status_t MPEG4Writer::Track::copyHEVCCodecSpecificData(
2059         const uint8_t *data, size_t size) {
2060     ALOGV("copyHEVCCodecSpecificData");
2061 
2062     // Min length of HEVC CSD is 23. (ISO/IEC 14496-15:2014 Chapter 8.3.3.1.2)
2063     return copyCodecSpecificData(data, size, 23);
2064 }
2065 
copyCodecSpecificData(const uint8_t * data,size_t size,size_t minLength)2066 status_t MPEG4Writer::Track::copyCodecSpecificData(
2067         const uint8_t *data, size_t size, size_t minLength) {
2068     if (size < minLength) {
2069         ALOGE("Codec specific data length too short: %zu", size);
2070         return ERROR_MALFORMED;
2071     }
2072 
2073     mCodecSpecificData = malloc(size);
2074     if (mCodecSpecificData == NULL) {
2075         ALOGE("Failed allocating codec specific data");
2076         return NO_MEMORY;
2077     }
2078     mCodecSpecificDataSize = size;
2079     memcpy(mCodecSpecificData, data, size);
2080     return OK;
2081 }
2082 
parseAVCCodecSpecificData(const uint8_t * data,size_t size)2083 status_t MPEG4Writer::Track::parseAVCCodecSpecificData(
2084         const uint8_t *data, size_t size) {
2085 
2086     ALOGV("parseAVCCodecSpecificData");
2087     // Data starts with a start code.
2088     // SPS and PPS are separated with start codes.
2089     // Also, SPS must come before PPS
2090     uint8_t type = kNalUnitTypeSeqParamSet;
2091     bool gotSps = false;
2092     bool gotPps = false;
2093     const uint8_t *tmp = data;
2094     const uint8_t *nextStartCode = data;
2095     size_t bytesLeft = size;
2096     size_t paramSetLen = 0;
2097     mCodecSpecificDataSize = 0;
2098     while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) {
2099         getNalUnitType(*(tmp + 4), &type);
2100         if (type == kNalUnitTypeSeqParamSet) {
2101             if (gotPps) {
2102                 ALOGE("SPS must come before PPS");
2103                 return ERROR_MALFORMED;
2104             }
2105             if (!gotSps) {
2106                 gotSps = true;
2107             }
2108             nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
2109         } else if (type == kNalUnitTypePicParamSet) {
2110             if (!gotSps) {
2111                 ALOGE("SPS must come before PPS");
2112                 return ERROR_MALFORMED;
2113             }
2114             if (!gotPps) {
2115                 gotPps = true;
2116             }
2117             nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
2118         } else {
2119             ALOGE("Only SPS and PPS Nal units are expected");
2120             return ERROR_MALFORMED;
2121         }
2122 
2123         if (nextStartCode == NULL) {
2124             return ERROR_MALFORMED;
2125         }
2126 
2127         // Move on to find the next parameter set
2128         bytesLeft -= nextStartCode - tmp;
2129         tmp = nextStartCode;
2130         mCodecSpecificDataSize += (2 + paramSetLen);
2131     }
2132 
2133     {
2134         // Check on the number of seq parameter sets
2135         size_t nSeqParamSets = mSeqParamSets.size();
2136         if (nSeqParamSets == 0) {
2137             ALOGE("Cound not find sequence parameter set");
2138             return ERROR_MALFORMED;
2139         }
2140 
2141         if (nSeqParamSets > 0x1F) {
2142             ALOGE("Too many seq parameter sets (%zu) found", nSeqParamSets);
2143             return ERROR_MALFORMED;
2144         }
2145     }
2146 
2147     {
2148         // Check on the number of pic parameter sets
2149         size_t nPicParamSets = mPicParamSets.size();
2150         if (nPicParamSets == 0) {
2151             ALOGE("Cound not find picture parameter set");
2152             return ERROR_MALFORMED;
2153         }
2154         if (nPicParamSets > 0xFF) {
2155             ALOGE("Too many pic parameter sets (%zd) found", nPicParamSets);
2156             return ERROR_MALFORMED;
2157         }
2158     }
2159 // FIXME:
2160 // Add chromat_format_idc, bit depth values, etc for AVC/h264 high profile and above
2161 // and remove #if 0
2162 #if 0
2163     {
2164         // Check on the profiles
2165         // These profiles requires additional parameter set extensions
2166         if (mProfileIdc == 100 || mProfileIdc == 110 ||
2167             mProfileIdc == 122 || mProfileIdc == 144) {
2168             ALOGE("Sorry, no support for profile_idc: %d!", mProfileIdc);
2169             return BAD_VALUE;
2170         }
2171     }
2172 #endif
2173     return OK;
2174 }
2175 
makeAVCCodecSpecificData(const uint8_t * data,size_t size)2176 status_t MPEG4Writer::Track::makeAVCCodecSpecificData(
2177         const uint8_t *data, size_t size) {
2178 
2179     if (mCodecSpecificData != NULL) {
2180         ALOGE("Already have codec specific data");
2181         return ERROR_MALFORMED;
2182     }
2183 
2184     if (size < 4) {
2185         ALOGE("Codec specific data length too short: %zu", size);
2186         return ERROR_MALFORMED;
2187     }
2188 
2189     // Data is in the form of AVCCodecSpecificData
2190     if (memcmp("\x00\x00\x00\x01", data, 4)) {
2191         return copyAVCCodecSpecificData(data, size);
2192     }
2193 
2194     if (parseAVCCodecSpecificData(data, size) != OK) {
2195         return ERROR_MALFORMED;
2196     }
2197 
2198     // ISO 14496-15: AVC file format
2199     mCodecSpecificDataSize += 7;  // 7 more bytes in the header
2200     mCodecSpecificData = malloc(mCodecSpecificDataSize);
2201     if (mCodecSpecificData == NULL) {
2202         mCodecSpecificDataSize = 0;
2203         ALOGE("Failed allocating codec specific data");
2204         return NO_MEMORY;
2205     }
2206     uint8_t *header = (uint8_t *)mCodecSpecificData;
2207     header[0] = 1;                     // version
2208     header[1] = mProfileIdc;           // profile indication
2209     header[2] = mProfileCompatible;    // profile compatibility
2210     header[3] = mLevelIdc;
2211 
2212     // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne
2213     if (mOwner->useNalLengthFour()) {
2214         header[4] = 0xfc | 3;  // length size == 4 bytes
2215     } else {
2216         header[4] = 0xfc | 1;  // length size == 2 bytes
2217     }
2218 
2219     // 3-bit '111' followed by 5-bit numSequenceParameterSets
2220     int nSequenceParamSets = mSeqParamSets.size();
2221     header[5] = 0xe0 | nSequenceParamSets;
2222     header += 6;
2223     for (List<AVCParamSet>::iterator it = mSeqParamSets.begin();
2224          it != mSeqParamSets.end(); ++it) {
2225         // 16-bit sequence parameter set length
2226         uint16_t seqParamSetLength = it->mLength;
2227         header[0] = seqParamSetLength >> 8;
2228         header[1] = seqParamSetLength & 0xff;
2229 
2230         // SPS NAL unit (sequence parameter length bytes)
2231         memcpy(&header[2], it->mData, seqParamSetLength);
2232         header += (2 + seqParamSetLength);
2233     }
2234 
2235     // 8-bit nPictureParameterSets
2236     int nPictureParamSets = mPicParamSets.size();
2237     header[0] = nPictureParamSets;
2238     header += 1;
2239     for (List<AVCParamSet>::iterator it = mPicParamSets.begin();
2240          it != mPicParamSets.end(); ++it) {
2241         // 16-bit picture parameter set length
2242         uint16_t picParamSetLength = it->mLength;
2243         header[0] = picParamSetLength >> 8;
2244         header[1] = picParamSetLength & 0xff;
2245 
2246         // PPS Nal unit (picture parameter set length bytes)
2247         memcpy(&header[2], it->mData, picParamSetLength);
2248         header += (2 + picParamSetLength);
2249     }
2250 
2251     return OK;
2252 }
2253 
2254 
parseHEVCCodecSpecificData(const uint8_t * data,size_t size,HevcParameterSets & paramSets)2255 status_t MPEG4Writer::Track::parseHEVCCodecSpecificData(
2256         const uint8_t *data, size_t size, HevcParameterSets &paramSets) {
2257 
2258     ALOGV("parseHEVCCodecSpecificData");
2259     const uint8_t *tmp = data;
2260     const uint8_t *nextStartCode = data;
2261     size_t bytesLeft = size;
2262     while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) {
2263         nextStartCode = findNextNalStartCode(tmp + 4, bytesLeft - 4);
2264         status_t err = paramSets.addNalUnit(tmp + 4, (nextStartCode - tmp) - 4);
2265         if (err != OK) {
2266             return ERROR_MALFORMED;
2267         }
2268 
2269         // Move on to find the next parameter set
2270         bytesLeft -= nextStartCode - tmp;
2271         tmp = nextStartCode;
2272     }
2273 
2274     size_t csdSize = 23;
2275     const size_t numNalUnits = paramSets.getNumNalUnits();
2276     for (size_t i = 0; i < ARRAY_SIZE(kMandatoryHevcNalUnitTypes); ++i) {
2277         int type = kMandatoryHevcNalUnitTypes[i];
2278         size_t numParamSets = paramSets.getNumNalUnitsOfType(type);
2279         if (numParamSets == 0) {
2280             ALOGE("Cound not find NAL unit of type %d", type);
2281             return ERROR_MALFORMED;
2282         }
2283     }
2284     for (size_t i = 0; i < ARRAY_SIZE(kHevcNalUnitTypes); ++i) {
2285         int type = kHevcNalUnitTypes[i];
2286         size_t numParamSets = paramSets.getNumNalUnitsOfType(type);
2287         if (numParamSets > 0xffff) {
2288             ALOGE("Too many seq parameter sets (%zu) found", numParamSets);
2289             return ERROR_MALFORMED;
2290         }
2291         csdSize += 3;
2292         for (size_t j = 0; j < numNalUnits; ++j) {
2293             if (paramSets.getType(j) != type) {
2294                 continue;
2295             }
2296             csdSize += 2 + paramSets.getSize(j);
2297         }
2298     }
2299     mCodecSpecificDataSize = csdSize;
2300     return OK;
2301 }
2302 
makeHEVCCodecSpecificData(const uint8_t * data,size_t size)2303 status_t MPEG4Writer::Track::makeHEVCCodecSpecificData(
2304         const uint8_t *data, size_t size) {
2305 
2306     if (mCodecSpecificData != NULL) {
2307         ALOGE("Already have codec specific data");
2308         return ERROR_MALFORMED;
2309     }
2310 
2311     if (size < 4) {
2312         ALOGE("Codec specific data length too short: %zu", size);
2313         return ERROR_MALFORMED;
2314     }
2315 
2316     // Data is in the form of HEVCCodecSpecificData
2317     if (memcmp("\x00\x00\x00\x01", data, 4)) {
2318         return copyHEVCCodecSpecificData(data, size);
2319     }
2320 
2321     HevcParameterSets paramSets;
2322     if (parseHEVCCodecSpecificData(data, size, paramSets) != OK) {
2323         ALOGE("failed parsing codec specific data");
2324         return ERROR_MALFORMED;
2325     }
2326 
2327     mCodecSpecificData = malloc(mCodecSpecificDataSize);
2328     if (mCodecSpecificData == NULL) {
2329         mCodecSpecificDataSize = 0;
2330         ALOGE("Failed allocating codec specific data");
2331         return NO_MEMORY;
2332     }
2333     status_t err = paramSets.makeHvcc((uint8_t *)mCodecSpecificData,
2334             &mCodecSpecificDataSize, mOwner->useNalLengthFour() ? 4 : 2);
2335     if (err != OK) {
2336         ALOGE("failed constructing HVCC atom");
2337         return err;
2338     }
2339 
2340     return OK;
2341 }
2342 
2343 /*
2344  * Updates the drift time from the audio track so that
2345  * the video track can get the updated drift time information
2346  * from the file writer. The fluctuation of the drift time of the audio
2347  * encoding path is smoothed out with a simple filter by giving a larger
2348  * weight to more recently drift time. The filter coefficients, 0.5 and 0.5,
2349  * are heuristically determined.
2350  */
updateDriftTime(const sp<MetaData> & meta)2351 void MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) {
2352     int64_t driftTimeUs = 0;
2353     if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) {
2354         int64_t prevDriftTimeUs = mOwner->getDriftTimeUs();
2355         int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1;
2356         mOwner->setDriftTimeUs(timeUs);
2357     }
2358 }
2359 
threadEntry()2360 status_t MPEG4Writer::Track::threadEntry() {
2361     int32_t count = 0;
2362     const int64_t interleaveDurationUs = mOwner->interleaveDuration();
2363     const bool hasMultipleTracks = (mOwner->numTracks() > 1);
2364     int64_t chunkTimestampUs = 0;
2365     int32_t nChunks = 0;
2366     int32_t nActualFrames = 0;        // frames containing non-CSD data (non-0 length)
2367     int32_t nZeroLengthFrames = 0;
2368     int64_t lastTimestampUs = 0;      // Previous sample time stamp
2369     int64_t lastDurationUs = 0;       // Between the previous two samples
2370     int64_t currDurationTicks = 0;    // Timescale based ticks
2371     int64_t lastDurationTicks = 0;    // Timescale based ticks
2372     int32_t sampleCount = 1;          // Sample count in the current stts table entry
2373     uint32_t previousSampleSize = 0;  // Size of the previous sample
2374     int64_t previousPausedDurationUs = 0;
2375     int64_t timestampUs = 0;
2376     int64_t cttsOffsetTimeUs = 0;
2377     int64_t currCttsOffsetTimeTicks = 0;   // Timescale based ticks
2378     int64_t lastCttsOffsetTimeTicks = -1;  // Timescale based ticks
2379     int32_t cttsSampleCount = 0;           // Sample count in the current ctts table entry
2380     uint32_t lastSamplesPerChunk = 0;
2381 
2382     if (mIsAudio) {
2383         prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
2384     } else {
2385         prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0);
2386     }
2387 
2388     if (mOwner->isRealTimeRecording()) {
2389         androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
2390     }
2391 
2392     sp<MetaData> meta_data;
2393 
2394     status_t err = OK;
2395     MediaBuffer *buffer;
2396     const char *trackName = mIsAudio ? "Audio" : "Video";
2397     while (!mDone && (err = mSource->read(&buffer)) == OK) {
2398         if (buffer->range_length() == 0) {
2399             buffer->release();
2400             buffer = NULL;
2401             ++nZeroLengthFrames;
2402             continue;
2403         }
2404 
2405         // If the codec specific data has not been received yet, delay pause.
2406         // After the codec specific data is received, discard what we received
2407         // when the track is to be paused.
2408         if (mPaused && !mResumed) {
2409             buffer->release();
2410             buffer = NULL;
2411             continue;
2412         }
2413 
2414         ++count;
2415 
2416         int32_t isCodecConfig;
2417         if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
2418                 && isCodecConfig) {
2419             // if config format (at track addition) already had CSD, keep that
2420             // UNLESS we have not received any frames yet.
2421             // TODO: for now the entire CSD has to come in one frame for encoders, even though
2422             // they need to be spread out for decoders.
2423             if (mGotAllCodecSpecificData && nActualFrames > 0) {
2424                 ALOGI("ignoring additional CSD for video track after first frame");
2425             } else {
2426                 mMeta = mSource->getFormat(); // get output format after format change
2427 
2428                 if (mIsAvc) {
2429                     status_t err = makeAVCCodecSpecificData(
2430                             (const uint8_t *)buffer->data()
2431                                 + buffer->range_offset(),
2432                             buffer->range_length());
2433                     CHECK_EQ((status_t)OK, err);
2434                 } else if (mIsHevc) {
2435                     status_t err = makeHEVCCodecSpecificData(
2436                             (const uint8_t *)buffer->data()
2437                                 + buffer->range_offset(),
2438                             buffer->range_length());
2439                     CHECK_EQ((status_t)OK, err);
2440                 } else if (mIsMPEG4) {
2441                     copyCodecSpecificData((const uint8_t *)buffer->data() + buffer->range_offset(),
2442                             buffer->range_length());
2443                 }
2444             }
2445 
2446             buffer->release();
2447             buffer = NULL;
2448 
2449             mGotAllCodecSpecificData = true;
2450             continue;
2451         }
2452 
2453         ++nActualFrames;
2454 
2455         // Make a deep copy of the MediaBuffer and Metadata and release
2456         // the original as soon as we can
2457         MediaBuffer *copy = new MediaBuffer(buffer->range_length());
2458         memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(),
2459                 buffer->range_length());
2460         copy->set_range(0, buffer->range_length());
2461         meta_data = new MetaData(*buffer->meta_data().get());
2462         buffer->release();
2463         buffer = NULL;
2464 
2465         if (mIsAvc || mIsHevc) StripStartcode(copy);
2466 
2467         size_t sampleSize = copy->range_length();
2468         if (mIsAvc || mIsHevc) {
2469             if (mOwner->useNalLengthFour()) {
2470                 sampleSize += 4;
2471             } else {
2472                 sampleSize += 2;
2473             }
2474         }
2475 
2476         // Max file size or duration handling
2477         mMdatSizeBytes += sampleSize;
2478         updateTrackSizeEstimate();
2479 
2480         if (mOwner->exceedsFileSizeLimit()) {
2481             ALOGW("Recorded file size exceeds limit %" PRId64 "bytes",
2482                     mOwner->mMaxFileSizeLimitBytes);
2483             mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
2484             copy->release();
2485             mSource->stop();
2486             break;
2487         }
2488         if (mOwner->exceedsFileDurationLimit()) {
2489             ALOGW("Recorded file duration exceeds limit %" PRId64 "microseconds",
2490                     mOwner->mMaxFileDurationLimitUs);
2491             mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
2492             copy->release();
2493             mSource->stop();
2494             break;
2495         }
2496 
2497 
2498         int32_t isSync = false;
2499         meta_data->findInt32(kKeyIsSyncFrame, &isSync);
2500         CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
2501 
2502 ////////////////////////////////////////////////////////////////////////////////
2503         if (mStszTableEntries->count() == 0) {
2504             mFirstSampleTimeRealUs = systemTime() / 1000;
2505             mStartTimestampUs = timestampUs;
2506             mOwner->setStartTimestampUs(mStartTimestampUs);
2507             previousPausedDurationUs = mStartTimestampUs;
2508         }
2509 
2510         if (mResumed) {
2511             int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
2512             if (WARN_UNLESS(durExcludingEarlierPausesUs >= 0ll, "for %s track", trackName)) {
2513                 copy->release();
2514                 mSource->stop();
2515                 mIsMalformed = true;
2516                 break;
2517             }
2518 
2519             int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
2520             if (WARN_UNLESS(pausedDurationUs >= lastDurationUs, "for %s track", trackName)) {
2521                 copy->release();
2522                 mSource->stop();
2523                 mIsMalformed = true;
2524                 break;
2525             }
2526 
2527             previousPausedDurationUs += pausedDurationUs - lastDurationUs;
2528             mResumed = false;
2529         }
2530 
2531         timestampUs -= previousPausedDurationUs;
2532         if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
2533             copy->release();
2534             mSource->stop();
2535             mIsMalformed = true;
2536             break;
2537         }
2538 
2539         if (!mIsAudio) {
2540             /*
2541              * Composition time: timestampUs
2542              * Decoding time: decodingTimeUs
2543              * Composition time offset = composition time - decoding time
2544              */
2545             int64_t decodingTimeUs;
2546             CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs));
2547             decodingTimeUs -= previousPausedDurationUs;
2548 
2549             // ensure non-negative, monotonic decoding time
2550             if (mLastDecodingTimeUs < 0) {
2551                 decodingTimeUs = std::max((int64_t)0, decodingTimeUs);
2552             } else {
2553                 // increase decoding time by at least 1 tick
2554                 decodingTimeUs = std::max(
2555                         mLastDecodingTimeUs + divUp(1000000, mTimeScale), decodingTimeUs);
2556             }
2557 
2558             mLastDecodingTimeUs = decodingTimeUs;
2559             cttsOffsetTimeUs =
2560                     timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
2561             if (WARN_UNLESS(cttsOffsetTimeUs >= 0ll, "for %s track", trackName)) {
2562                 copy->release();
2563                 mSource->stop();
2564                 mIsMalformed = true;
2565                 break;
2566             }
2567 
2568             timestampUs = decodingTimeUs;
2569             ALOGV("decoding time: %" PRId64 " and ctts offset time: %" PRId64,
2570                 timestampUs, cttsOffsetTimeUs);
2571 
2572             // Update ctts box table if necessary
2573             currCttsOffsetTimeTicks =
2574                     (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL;
2575             if (WARN_UNLESS(currCttsOffsetTimeTicks <= 0x0FFFFFFFFLL, "for %s track", trackName)) {
2576                 copy->release();
2577                 mSource->stop();
2578                 mIsMalformed = true;
2579                 break;
2580             }
2581 
2582             if (mStszTableEntries->count() == 0) {
2583                 // Force the first ctts table entry to have one single entry
2584                 // so that we can do adjustment for the initial track start
2585                 // time offset easily in writeCttsBox().
2586                 lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
2587                 addOneCttsTableEntry(1, currCttsOffsetTimeTicks);
2588                 cttsSampleCount = 0;      // No sample in ctts box is pending
2589             } else {
2590                 if (currCttsOffsetTimeTicks != lastCttsOffsetTimeTicks) {
2591                     addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
2592                     lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
2593                     cttsSampleCount = 1;  // One sample in ctts box is pending
2594                 } else {
2595                     ++cttsSampleCount;
2596                 }
2597             }
2598 
2599             // Update ctts time offset range
2600             if (mStszTableEntries->count() == 0) {
2601                 mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2602                 mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2603             } else {
2604                 if (currCttsOffsetTimeTicks > mMaxCttsOffsetTimeUs) {
2605                     mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2606                 } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTimeUs) {
2607                     mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2608                 }
2609             }
2610 
2611         }
2612 
2613         if (mOwner->isRealTimeRecording()) {
2614             if (mIsAudio) {
2615                 updateDriftTime(meta_data);
2616             }
2617         }
2618 
2619         if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
2620             copy->release();
2621             mSource->stop();
2622             mIsMalformed = true;
2623             break;
2624         }
2625 
2626         ALOGV("%s media time stamp: %" PRId64 " and previous paused duration %" PRId64,
2627                 trackName, timestampUs, previousPausedDurationUs);
2628         if (timestampUs > mTrackDurationUs) {
2629             mTrackDurationUs = timestampUs;
2630         }
2631 
2632         // We need to use the time scale based ticks, rather than the
2633         // timestamp itself to determine whether we have to use a new
2634         // stts entry, since we may have rounding errors.
2635         // The calculation is intended to reduce the accumulated
2636         // rounding errors.
2637         currDurationTicks =
2638             ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
2639                 (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
2640         if (currDurationTicks < 0ll) {
2641             ALOGE("do not support out of order frames (timestamp: %lld < last: %lld for %s track",
2642                     (long long)timestampUs, (long long)lastTimestampUs, trackName);
2643             copy->release();
2644             mSource->stop();
2645             mIsMalformed = true;
2646             break;
2647         }
2648 
2649         // if the duration is different for this sample, see if it is close enough to the previous
2650         // duration that we can fudge it and use the same value, to avoid filling the stts table
2651         // with lots of near-identical entries.
2652         // "close enough" here means that the current duration needs to be adjusted by less
2653         // than 0.1 milliseconds
2654         if (lastDurationTicks && (currDurationTicks != lastDurationTicks)) {
2655             int64_t deltaUs = ((lastDurationTicks - currDurationTicks) * 1000000LL
2656                     + (mTimeScale / 2)) / mTimeScale;
2657             if (deltaUs > -100 && deltaUs < 100) {
2658                 // use previous ticks, and adjust timestamp as if it was actually that number
2659                 // of ticks
2660                 currDurationTicks = lastDurationTicks;
2661                 timestampUs += deltaUs;
2662             }
2663         }
2664 
2665         mStszTableEntries->add(htonl(sampleSize));
2666         if (mStszTableEntries->count() > 2) {
2667 
2668             // Force the first sample to have its own stts entry so that
2669             // we can adjust its value later to maintain the A/V sync.
2670             if (mStszTableEntries->count() == 3 || currDurationTicks != lastDurationTicks) {
2671                 addOneSttsTableEntry(sampleCount, lastDurationTicks);
2672                 sampleCount = 1;
2673             } else {
2674                 ++sampleCount;
2675             }
2676 
2677         }
2678         if (mSamplesHaveSameSize) {
2679             if (mStszTableEntries->count() >= 2 && previousSampleSize != sampleSize) {
2680                 mSamplesHaveSameSize = false;
2681             }
2682             previousSampleSize = sampleSize;
2683         }
2684         ALOGV("%s timestampUs/lastTimestampUs: %" PRId64 "/%" PRId64,
2685                 trackName, timestampUs, lastTimestampUs);
2686         lastDurationUs = timestampUs - lastTimestampUs;
2687         lastDurationTicks = currDurationTicks;
2688         lastTimestampUs = timestampUs;
2689 
2690         if (isSync != 0) {
2691             addOneStssTableEntry(mStszTableEntries->count());
2692         }
2693 
2694         if (mTrackingProgressStatus) {
2695             if (mPreviousTrackTimeUs <= 0) {
2696                 mPreviousTrackTimeUs = mStartTimestampUs;
2697             }
2698             trackProgressStatus(timestampUs);
2699         }
2700         if (!hasMultipleTracks) {
2701             off64_t offset = (mIsAvc || mIsHevc) ? mOwner->addMultipleLengthPrefixedSamples_l(copy)
2702                                  : mOwner->addSample_l(copy);
2703 
2704             uint32_t count = (mOwner->use32BitFileOffset()
2705                         ? mStcoTableEntries->count()
2706                         : mCo64TableEntries->count());
2707 
2708             if (count == 0) {
2709                 addChunkOffset(offset);
2710             }
2711             copy->release();
2712             copy = NULL;
2713             continue;
2714         }
2715 
2716         mChunkSamples.push_back(copy);
2717         if (interleaveDurationUs == 0) {
2718             addOneStscTableEntry(++nChunks, 1);
2719             bufferChunk(timestampUs);
2720         } else {
2721             if (chunkTimestampUs == 0) {
2722                 chunkTimestampUs = timestampUs;
2723             } else {
2724                 int64_t chunkDurationUs = timestampUs - chunkTimestampUs;
2725                 if (chunkDurationUs > interleaveDurationUs) {
2726                     if (chunkDurationUs > mMaxChunkDurationUs) {
2727                         mMaxChunkDurationUs = chunkDurationUs;
2728                     }
2729                     ++nChunks;
2730                     if (nChunks == 1 ||  // First chunk
2731                         lastSamplesPerChunk != mChunkSamples.size()) {
2732                         lastSamplesPerChunk = mChunkSamples.size();
2733                         addOneStscTableEntry(nChunks, lastSamplesPerChunk);
2734                     }
2735                     bufferChunk(timestampUs);
2736                     chunkTimestampUs = timestampUs;
2737                 }
2738             }
2739         }
2740 
2741     }
2742 
2743     if (isTrackMalFormed()) {
2744         err = ERROR_MALFORMED;
2745     }
2746 
2747     mOwner->trackProgressStatus(mTrackId, -1, err);
2748 
2749     // Last chunk
2750     if (!hasMultipleTracks) {
2751         addOneStscTableEntry(1, mStszTableEntries->count());
2752     } else if (!mChunkSamples.empty()) {
2753         addOneStscTableEntry(++nChunks, mChunkSamples.size());
2754         bufferChunk(timestampUs);
2755     }
2756 
2757     // We don't really know how long the last frame lasts, since
2758     // there is no frame time after it, just repeat the previous
2759     // frame's duration.
2760     if (mStszTableEntries->count() == 1) {
2761         lastDurationUs = 0;  // A single sample's duration
2762         lastDurationTicks = 0;
2763     } else {
2764         ++sampleCount;  // Count for the last sample
2765     }
2766 
2767     if (mStszTableEntries->count() <= 2) {
2768         addOneSttsTableEntry(1, lastDurationTicks);
2769         if (sampleCount - 1 > 0) {
2770             addOneSttsTableEntry(sampleCount - 1, lastDurationTicks);
2771         }
2772     } else {
2773         addOneSttsTableEntry(sampleCount, lastDurationTicks);
2774     }
2775 
2776     // The last ctts box may not have been written yet, and this
2777     // is to make sure that we write out the last ctts box.
2778     if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) {
2779         if (cttsSampleCount > 0) {
2780             addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
2781         }
2782     }
2783 
2784     mTrackDurationUs += lastDurationUs;
2785     mReachedEOS = true;
2786 
2787     sendTrackSummary(hasMultipleTracks);
2788 
2789     ALOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s",
2790             count, nZeroLengthFrames, mStszTableEntries->count(), trackName);
2791     if (mIsAudio) {
2792         ALOGI("Audio track drift time: %" PRId64 " us", mOwner->getDriftTimeUs());
2793     }
2794 
2795     if (err == ERROR_END_OF_STREAM) {
2796         return OK;
2797     }
2798     return err;
2799 }
2800 
isTrackMalFormed() const2801 bool MPEG4Writer::Track::isTrackMalFormed() const {
2802     if (mIsMalformed) {
2803         return true;
2804     }
2805 
2806     if (mStszTableEntries->count() == 0) {                      // no samples written
2807         ALOGE("The number of recorded samples is 0");
2808         return true;
2809     }
2810 
2811     if (!mIsAudio && mStssTableEntries->count() == 0) {  // no sync frames for video
2812         ALOGE("There are no sync frames for video track");
2813         return true;
2814     }
2815 
2816     if (OK != checkCodecSpecificData()) {         // no codec specific data
2817         return true;
2818     }
2819 
2820     return false;
2821 }
2822 
sendTrackSummary(bool hasMultipleTracks)2823 void MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) {
2824 
2825     // Send track summary only if test mode is enabled.
2826     if (!isTestModeEnabled()) {
2827         return;
2828     }
2829 
2830     int trackNum = (mTrackId << 28);
2831 
2832     mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2833                     trackNum | MEDIA_RECORDER_TRACK_INFO_TYPE,
2834                     mIsAudio? 0: 1);
2835 
2836     mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2837                     trackNum | MEDIA_RECORDER_TRACK_INFO_DURATION_MS,
2838                     mTrackDurationUs / 1000);
2839 
2840     mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2841                     trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES,
2842                     mStszTableEntries->count());
2843 
2844     {
2845         // The system delay time excluding the requested initial delay that
2846         // is used to eliminate the recording sound.
2847         int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL;
2848         if (startTimeOffsetUs < 0) {  // Start time offset was not set
2849             startTimeOffsetUs = kInitialDelayTimeUs;
2850         }
2851         int64_t initialDelayUs =
2852             mFirstSampleTimeRealUs - mStartTimeRealUs - startTimeOffsetUs;
2853 
2854         mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2855                     trackNum | MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS,
2856                     (initialDelayUs) / 1000);
2857     }
2858 
2859     mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2860                     trackNum | MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES,
2861                     mMdatSizeBytes / 1024);
2862 
2863     if (hasMultipleTracks) {
2864         mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2865                     trackNum | MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS,
2866                     mMaxChunkDurationUs / 1000);
2867 
2868         int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
2869         if (mStartTimestampUs != moovStartTimeUs) {
2870             int64_t startTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
2871             mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2872                     trackNum | MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS,
2873                     startTimeOffsetUs / 1000);
2874         }
2875     }
2876 }
2877 
trackProgressStatus(int64_t timeUs,status_t err)2878 void MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) {
2879     ALOGV("trackProgressStatus: %" PRId64 " us", timeUs);
2880 
2881     if (mTrackEveryTimeDurationUs > 0 &&
2882         timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) {
2883         ALOGV("Fire time tracking progress status at %" PRId64 " us", timeUs);
2884         mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err);
2885         mPreviousTrackTimeUs = timeUs;
2886     }
2887 }
2888 
trackProgressStatus(size_t trackId,int64_t timeUs,status_t err)2889 void MPEG4Writer::trackProgressStatus(
2890         size_t trackId, int64_t timeUs, status_t err) {
2891     Mutex::Autolock lock(mLock);
2892     int32_t trackNum = (trackId << 28);
2893 
2894     // Error notification
2895     // Do not consider ERROR_END_OF_STREAM an error
2896     if (err != OK && err != ERROR_END_OF_STREAM) {
2897         notify(MEDIA_RECORDER_TRACK_EVENT_ERROR,
2898                trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL,
2899                err);
2900         return;
2901     }
2902 
2903     if (timeUs == -1) {
2904         // Send completion notification
2905         notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2906                trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS,
2907                err);
2908     } else {
2909         // Send progress status
2910         notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2911                trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME,
2912                timeUs / 1000);
2913     }
2914 }
2915 
setDriftTimeUs(int64_t driftTimeUs)2916 void MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) {
2917     ALOGV("setDriftTimeUs: %" PRId64 " us", driftTimeUs);
2918     Mutex::Autolock autolock(mLock);
2919     mDriftTimeUs = driftTimeUs;
2920 }
2921 
getDriftTimeUs()2922 int64_t MPEG4Writer::getDriftTimeUs() {
2923     ALOGV("getDriftTimeUs: %" PRId64 " us", mDriftTimeUs);
2924     Mutex::Autolock autolock(mLock);
2925     return mDriftTimeUs;
2926 }
2927 
isRealTimeRecording() const2928 bool MPEG4Writer::isRealTimeRecording() const {
2929     return mIsRealTimeRecording;
2930 }
2931 
useNalLengthFour()2932 bool MPEG4Writer::useNalLengthFour() {
2933     return mUse4ByteNalLength;
2934 }
2935 
bufferChunk(int64_t timestampUs)2936 void MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
2937     ALOGV("bufferChunk");
2938 
2939     Chunk chunk(this, timestampUs, mChunkSamples);
2940     mOwner->bufferChunk(chunk);
2941     mChunkSamples.clear();
2942 }
2943 
getDurationUs() const2944 int64_t MPEG4Writer::Track::getDurationUs() const {
2945     return mTrackDurationUs;
2946 }
2947 
getEstimatedTrackSizeBytes() const2948 int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
2949     return mEstimatedTrackSizeBytes;
2950 }
2951 
checkCodecSpecificData() const2952 status_t MPEG4Writer::Track::checkCodecSpecificData() const {
2953     const char *mime;
2954     CHECK(mMeta->findCString(kKeyMIMEType, &mime));
2955     if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) ||
2956         !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
2957         !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime) ||
2958         !strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
2959         if (!mCodecSpecificData ||
2960             mCodecSpecificDataSize <= 0) {
2961             ALOGE("Missing codec specific data");
2962             return ERROR_MALFORMED;
2963         }
2964     } else {
2965         if (mCodecSpecificData ||
2966             mCodecSpecificDataSize > 0) {
2967             ALOGE("Unexepected codec specific data found");
2968             return ERROR_MALFORMED;
2969         }
2970     }
2971     return OK;
2972 }
2973 
writeTrackHeader(bool use32BitOffset)2974 void MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) {
2975 
2976     ALOGV("%s track time scale: %d",
2977         mIsAudio? "Audio": "Video", mTimeScale);
2978 
2979     uint32_t now = getMpeg4Time();
2980     mOwner->beginBox("trak");
2981         writeTkhdBox(now);
2982         mOwner->beginBox("mdia");
2983             writeMdhdBox(now);
2984             writeHdlrBox();
2985             mOwner->beginBox("minf");
2986                 if (mIsAudio) {
2987                     writeSmhdBox();
2988                 } else {
2989                     writeVmhdBox();
2990                 }
2991                 writeDinfBox();
2992                 writeStblBox(use32BitOffset);
2993             mOwner->endBox();  // minf
2994         mOwner->endBox();  // mdia
2995     mOwner->endBox();  // trak
2996 }
2997 
writeStblBox(bool use32BitOffset)2998 void MPEG4Writer::Track::writeStblBox(bool use32BitOffset) {
2999     mOwner->beginBox("stbl");
3000     mOwner->beginBox("stsd");
3001     mOwner->writeInt32(0);               // version=0, flags=0
3002     mOwner->writeInt32(1);               // entry count
3003     if (mIsAudio) {
3004         writeAudioFourCCBox();
3005     } else {
3006         writeVideoFourCCBox();
3007     }
3008     mOwner->endBox();  // stsd
3009     writeSttsBox();
3010     writeCttsBox();
3011     if (!mIsAudio) {
3012         writeStssBox();
3013     }
3014     writeStszBox();
3015     writeStscBox();
3016     writeStcoBox(use32BitOffset);
3017     mOwner->endBox();  // stbl
3018 }
3019 
writeVideoFourCCBox()3020 void MPEG4Writer::Track::writeVideoFourCCBox() {
3021     const char *mime;
3022     bool success = mMeta->findCString(kKeyMIMEType, &mime);
3023     CHECK(success);
3024     const char *fourcc = getFourCCForMime(mime);
3025     if (fourcc == NULL) {
3026         ALOGE("Unknown mime type '%s'.", mime);
3027         CHECK(!"should not be here, unknown mime type.");
3028     }
3029 
3030     mOwner->beginBox(fourcc);        // video format
3031     mOwner->writeInt32(0);           // reserved
3032     mOwner->writeInt16(0);           // reserved
3033     mOwner->writeInt16(1);           // data ref index
3034     mOwner->writeInt16(0);           // predefined
3035     mOwner->writeInt16(0);           // reserved
3036     mOwner->writeInt32(0);           // predefined
3037     mOwner->writeInt32(0);           // predefined
3038     mOwner->writeInt32(0);           // predefined
3039 
3040     int32_t width, height;
3041     success = mMeta->findInt32(kKeyWidth, &width);
3042     success = success && mMeta->findInt32(kKeyHeight, &height);
3043     CHECK(success);
3044 
3045     mOwner->writeInt16(width);
3046     mOwner->writeInt16(height);
3047     mOwner->writeInt32(0x480000);    // horiz resolution
3048     mOwner->writeInt32(0x480000);    // vert resolution
3049     mOwner->writeInt32(0);           // reserved
3050     mOwner->writeInt16(1);           // frame count
3051     mOwner->writeInt8(0);            // compressor string length
3052     mOwner->write("                               ", 31);
3053     mOwner->writeInt16(0x18);        // depth
3054     mOwner->writeInt16(-1);          // predefined
3055 
3056     if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
3057         writeMp4vEsdsBox();
3058     } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
3059         writeD263Box();
3060     } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
3061         writeAvccBox();
3062     } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
3063         writeHvccBox();
3064     }
3065 
3066     writePaspBox();
3067     writeColrBox();
3068     mOwner->endBox();  // mp4v, s263 or avc1
3069 }
3070 
writeColrBox()3071 void MPEG4Writer::Track::writeColrBox() {
3072     ColorAspects aspects;
3073     memset(&aspects, 0, sizeof(aspects));
3074     // TRICKY: using | instead of || because we want to execute all findInt32-s
3075     if (mMeta->findInt32(kKeyColorPrimaries, (int32_t*)&aspects.mPrimaries)
3076             | mMeta->findInt32(kKeyTransferFunction, (int32_t*)&aspects.mTransfer)
3077             | mMeta->findInt32(kKeyColorMatrix, (int32_t*)&aspects.mMatrixCoeffs)
3078             | mMeta->findInt32(kKeyColorRange, (int32_t*)&aspects.mRange)) {
3079         int32_t primaries, transfer, coeffs;
3080         bool fullRange;
3081         ColorUtils::convertCodecColorAspectsToIsoAspects(
3082                 aspects, &primaries, &transfer, &coeffs, &fullRange);
3083         mOwner->beginBox("colr");
3084         mOwner->writeFourcc("nclx");
3085         mOwner->writeInt16(primaries);
3086         mOwner->writeInt16(transfer);
3087         mOwner->writeInt16(coeffs);
3088         mOwner->writeInt8(fullRange ? 128 : 0);
3089         mOwner->endBox(); // colr
3090     }
3091 }
3092 
writeAudioFourCCBox()3093 void MPEG4Writer::Track::writeAudioFourCCBox() {
3094     const char *mime;
3095     bool success = mMeta->findCString(kKeyMIMEType, &mime);
3096     CHECK(success);
3097     const char *fourcc = getFourCCForMime(mime);
3098     if (fourcc == NULL) {
3099         ALOGE("Unknown mime type '%s'.", mime);
3100         CHECK(!"should not be here, unknown mime type.");
3101     }
3102 
3103     mOwner->beginBox(fourcc);        // audio format
3104     mOwner->writeInt32(0);           // reserved
3105     mOwner->writeInt16(0);           // reserved
3106     mOwner->writeInt16(0x1);         // data ref index
3107     mOwner->writeInt32(0);           // reserved
3108     mOwner->writeInt32(0);           // reserved
3109     int32_t nChannels;
3110     CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels));
3111     mOwner->writeInt16(nChannels);   // channel count
3112     mOwner->writeInt16(16);          // sample size
3113     mOwner->writeInt16(0);           // predefined
3114     mOwner->writeInt16(0);           // reserved
3115 
3116     int32_t samplerate;
3117     success = mMeta->findInt32(kKeySampleRate, &samplerate);
3118     CHECK(success);
3119     mOwner->writeInt32(samplerate << 16);
3120     if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
3121         writeMp4aEsdsBox();
3122     } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) ||
3123                !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
3124         writeDamrBox();
3125     }
3126     mOwner->endBox();
3127 }
3128 
writeMp4aEsdsBox()3129 void MPEG4Writer::Track::writeMp4aEsdsBox() {
3130     mOwner->beginBox("esds");
3131     CHECK(mCodecSpecificData);
3132     CHECK_GT(mCodecSpecificDataSize, 0);
3133 
3134     // Make sure all sizes encode to a single byte.
3135     CHECK_LT(mCodecSpecificDataSize + 23, 128);
3136 
3137     mOwner->writeInt32(0);     // version=0, flags=0
3138     mOwner->writeInt8(0x03);   // ES_DescrTag
3139     mOwner->writeInt8(23 + mCodecSpecificDataSize);
3140     mOwner->writeInt16(0x0000);// ES_ID
3141     mOwner->writeInt8(0x00);
3142 
3143     mOwner->writeInt8(0x04);   // DecoderConfigDescrTag
3144     mOwner->writeInt8(15 + mCodecSpecificDataSize);
3145     mOwner->writeInt8(0x40);   // objectTypeIndication ISO/IEC 14492-2
3146     mOwner->writeInt8(0x15);   // streamType AudioStream
3147 
3148     mOwner->writeInt16(0x03);  // XXX
3149     mOwner->writeInt8(0x00);   // buffer size 24-bit (0x300)
3150 
3151     int32_t avgBitrate = 0;
3152     (void)mMeta->findInt32(kKeyBitRate, &avgBitrate);
3153     int32_t maxBitrate = 0;
3154     (void)mMeta->findInt32(kKeyMaxBitRate, &maxBitrate);
3155     mOwner->writeInt32(maxBitrate);
3156     mOwner->writeInt32(avgBitrate);
3157 
3158     mOwner->writeInt8(0x05);   // DecoderSpecificInfoTag
3159     mOwner->writeInt8(mCodecSpecificDataSize);
3160     mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
3161 
3162     static const uint8_t kData2[] = {
3163         0x06,  // SLConfigDescriptorTag
3164         0x01,
3165         0x02
3166     };
3167     mOwner->write(kData2, sizeof(kData2));
3168 
3169     mOwner->endBox();  // esds
3170 }
3171 
writeMp4vEsdsBox()3172 void MPEG4Writer::Track::writeMp4vEsdsBox() {
3173     CHECK(mCodecSpecificData);
3174     CHECK_GT(mCodecSpecificDataSize, 0);
3175 
3176     // Make sure all sizes encode to a single byte.
3177     CHECK_LT(23 + mCodecSpecificDataSize, 128);
3178 
3179     mOwner->beginBox("esds");
3180 
3181     mOwner->writeInt32(0);    // version=0, flags=0
3182 
3183     mOwner->writeInt8(0x03);  // ES_DescrTag
3184     mOwner->writeInt8(23 + mCodecSpecificDataSize);
3185     mOwner->writeInt16(0x0000);  // ES_ID
3186     mOwner->writeInt8(0x1f);
3187 
3188     mOwner->writeInt8(0x04);  // DecoderConfigDescrTag
3189     mOwner->writeInt8(15 + mCodecSpecificDataSize);
3190     mOwner->writeInt8(0x20);  // objectTypeIndication ISO/IEC 14492-2
3191     mOwner->writeInt8(0x11);  // streamType VisualStream
3192 
3193     static const uint8_t kData[] = {
3194         0x01, 0x77, 0x00, // buffer size 96000 bytes
3195     };
3196     mOwner->write(kData, sizeof(kData));
3197 
3198     int32_t avgBitrate = 0;
3199     (void)mMeta->findInt32(kKeyBitRate, &avgBitrate);
3200     int32_t maxBitrate = 0;
3201     (void)mMeta->findInt32(kKeyMaxBitRate, &maxBitrate);
3202     mOwner->writeInt32(maxBitrate);
3203     mOwner->writeInt32(avgBitrate);
3204 
3205     mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
3206 
3207     mOwner->writeInt8(mCodecSpecificDataSize);
3208     mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
3209 
3210     static const uint8_t kData2[] = {
3211         0x06,  // SLConfigDescriptorTag
3212         0x01,
3213         0x02
3214     };
3215     mOwner->write(kData2, sizeof(kData2));
3216 
3217     mOwner->endBox();  // esds
3218 }
3219 
writeTkhdBox(uint32_t now)3220 void MPEG4Writer::Track::writeTkhdBox(uint32_t now) {
3221     mOwner->beginBox("tkhd");
3222     // Flags = 7 to indicate that the track is enabled, and
3223     // part of the presentation
3224     mOwner->writeInt32(0x07);          // version=0, flags=7
3225     mOwner->writeInt32(now);           // creation time
3226     mOwner->writeInt32(now);           // modification time
3227     mOwner->writeInt32(mTrackId);      // track id starts with 1
3228     mOwner->writeInt32(0);             // reserved
3229     int64_t trakDurationUs = getDurationUs();
3230     int32_t mvhdTimeScale = mOwner->getTimeScale();
3231     int32_t tkhdDuration =
3232         (trakDurationUs * mvhdTimeScale + 5E5) / 1E6;
3233     mOwner->writeInt32(tkhdDuration);  // in mvhd timescale
3234     mOwner->writeInt32(0);             // reserved
3235     mOwner->writeInt32(0);             // reserved
3236     mOwner->writeInt16(0);             // layer
3237     mOwner->writeInt16(0);             // alternate group
3238     mOwner->writeInt16(mIsAudio ? 0x100 : 0);  // volume
3239     mOwner->writeInt16(0);             // reserved
3240 
3241     mOwner->writeCompositionMatrix(mRotation);       // matrix
3242 
3243     if (mIsAudio) {
3244         mOwner->writeInt32(0);
3245         mOwner->writeInt32(0);
3246     } else {
3247         int32_t width, height;
3248         bool success = mMeta->findInt32(kKeyWidth, &width);
3249         success = success && mMeta->findInt32(kKeyHeight, &height);
3250         CHECK(success);
3251 
3252         mOwner->writeInt32(width << 16);   // 32-bit fixed-point value
3253         mOwner->writeInt32(height << 16);  // 32-bit fixed-point value
3254     }
3255     mOwner->endBox();  // tkhd
3256 }
3257 
writeVmhdBox()3258 void MPEG4Writer::Track::writeVmhdBox() {
3259     mOwner->beginBox("vmhd");
3260     mOwner->writeInt32(0x01);        // version=0, flags=1
3261     mOwner->writeInt16(0);           // graphics mode
3262     mOwner->writeInt16(0);           // opcolor
3263     mOwner->writeInt16(0);
3264     mOwner->writeInt16(0);
3265     mOwner->endBox();
3266 }
3267 
writeSmhdBox()3268 void MPEG4Writer::Track::writeSmhdBox() {
3269     mOwner->beginBox("smhd");
3270     mOwner->writeInt32(0);           // version=0, flags=0
3271     mOwner->writeInt16(0);           // balance
3272     mOwner->writeInt16(0);           // reserved
3273     mOwner->endBox();
3274 }
3275 
writeHdlrBox()3276 void MPEG4Writer::Track::writeHdlrBox() {
3277     mOwner->beginBox("hdlr");
3278     mOwner->writeInt32(0);             // version=0, flags=0
3279     mOwner->writeInt32(0);             // component type: should be mhlr
3280     mOwner->writeFourcc(mIsAudio ? "soun" : "vide");  // component subtype
3281     mOwner->writeInt32(0);             // reserved
3282     mOwner->writeInt32(0);             // reserved
3283     mOwner->writeInt32(0);             // reserved
3284     // Removing "r" for the name string just makes the string 4 byte aligned
3285     mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle");  // name
3286     mOwner->endBox();
3287 }
3288 
writeMdhdBox(uint32_t now)3289 void MPEG4Writer::Track::writeMdhdBox(uint32_t now) {
3290     int64_t trakDurationUs = getDurationUs();
3291     mOwner->beginBox("mdhd");
3292     mOwner->writeInt32(0);             // version=0, flags=0
3293     mOwner->writeInt32(now);           // creation time
3294     mOwner->writeInt32(now);           // modification time
3295     mOwner->writeInt32(mTimeScale);    // media timescale
3296     int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6;
3297     mOwner->writeInt32(mdhdDuration);  // use media timescale
3298     // Language follows the three letter standard ISO-639-2/T
3299     // 'e', 'n', 'g' for "English", for instance.
3300     // Each character is packed as the difference between its ASCII value and 0x60.
3301     // For "English", these are 00101, 01110, 00111.
3302     // XXX: Where is the padding bit located: 0x15C7?
3303     mOwner->writeInt16(0);             // language code
3304     mOwner->writeInt16(0);             // predefined
3305     mOwner->endBox();
3306 }
3307 
writeDamrBox()3308 void MPEG4Writer::Track::writeDamrBox() {
3309     // 3gpp2 Spec AMRSampleEntry fields
3310     mOwner->beginBox("damr");
3311     mOwner->writeCString("   ");  // vendor: 4 bytes
3312     mOwner->writeInt8(0);         // decoder version
3313     mOwner->writeInt16(0x83FF);   // mode set: all enabled
3314     mOwner->writeInt8(0);         // mode change period
3315     mOwner->writeInt8(1);         // frames per sample
3316     mOwner->endBox();
3317 }
3318 
writeUrlBox()3319 void MPEG4Writer::Track::writeUrlBox() {
3320     // The table index here refers to the sample description index
3321     // in the sample table entries.
3322     mOwner->beginBox("url ");
3323     mOwner->writeInt32(1);  // version=0, flags=1 (self-contained)
3324     mOwner->endBox();  // url
3325 }
3326 
writeDrefBox()3327 void MPEG4Writer::Track::writeDrefBox() {
3328     mOwner->beginBox("dref");
3329     mOwner->writeInt32(0);  // version=0, flags=0
3330     mOwner->writeInt32(1);  // entry count (either url or urn)
3331     writeUrlBox();
3332     mOwner->endBox();  // dref
3333 }
3334 
writeDinfBox()3335 void MPEG4Writer::Track::writeDinfBox() {
3336     mOwner->beginBox("dinf");
3337     writeDrefBox();
3338     mOwner->endBox();  // dinf
3339 }
3340 
writeAvccBox()3341 void MPEG4Writer::Track::writeAvccBox() {
3342     CHECK(mCodecSpecificData);
3343     CHECK_GE(mCodecSpecificDataSize, 5);
3344 
3345     // Patch avcc's lengthSize field to match the number
3346     // of bytes we use to indicate the size of a nal unit.
3347     uint8_t *ptr = (uint8_t *)mCodecSpecificData;
3348     ptr[4] = (ptr[4] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1);
3349     mOwner->beginBox("avcC");
3350     mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
3351     mOwner->endBox();  // avcC
3352 }
3353 
3354 
writeHvccBox()3355 void MPEG4Writer::Track::writeHvccBox() {
3356     CHECK(mCodecSpecificData);
3357     CHECK_GE(mCodecSpecificDataSize, 5);
3358 
3359     // Patch avcc's lengthSize field to match the number
3360     // of bytes we use to indicate the size of a nal unit.
3361     uint8_t *ptr = (uint8_t *)mCodecSpecificData;
3362     ptr[21] = (ptr[21] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1);
3363     mOwner->beginBox("hvcC");
3364     mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
3365     mOwner->endBox();  // hvcC
3366 }
3367 
writeD263Box()3368 void MPEG4Writer::Track::writeD263Box() {
3369     mOwner->beginBox("d263");
3370     mOwner->writeInt32(0);  // vendor
3371     mOwner->writeInt8(0);   // decoder version
3372     mOwner->writeInt8(10);  // level: 10
3373     mOwner->writeInt8(0);   // profile: 0
3374     mOwner->endBox();  // d263
3375 }
3376 
3377 // This is useful if the pixel is not square
writePaspBox()3378 void MPEG4Writer::Track::writePaspBox() {
3379     mOwner->beginBox("pasp");
3380     mOwner->writeInt32(1 << 16);  // hspacing
3381     mOwner->writeInt32(1 << 16);  // vspacing
3382     mOwner->endBox();  // pasp
3383 }
3384 
getStartTimeOffsetScaledTime() const3385 int32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const {
3386     int64_t trackStartTimeOffsetUs = 0;
3387     int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
3388     if (mStartTimestampUs != moovStartTimeUs) {
3389         CHECK_GT(mStartTimestampUs, moovStartTimeUs);
3390         trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
3391     }
3392     return (trackStartTimeOffsetUs *  mTimeScale + 500000LL) / 1000000LL;
3393 }
3394 
writeSttsBox()3395 void MPEG4Writer::Track::writeSttsBox() {
3396     mOwner->beginBox("stts");
3397     mOwner->writeInt32(0);  // version=0, flags=0
3398     uint32_t duration;
3399     CHECK(mSttsTableEntries->get(duration, 1));
3400     duration = htonl(duration);  // Back to host byte order
3401     mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1);
3402     mSttsTableEntries->write(mOwner);
3403     mOwner->endBox();  // stts
3404 }
3405 
writeCttsBox()3406 void MPEG4Writer::Track::writeCttsBox() {
3407     if (mIsAudio) {  // ctts is not for audio
3408         return;
3409     }
3410 
3411     // There is no B frame at all
3412     if (mMinCttsOffsetTimeUs == mMaxCttsOffsetTimeUs) {
3413         return;
3414     }
3415 
3416     // Do not write ctts box when there is no need to have it.
3417     if (mCttsTableEntries->count() == 0) {
3418         return;
3419     }
3420 
3421     ALOGV("ctts box has %d entries with range [%" PRId64 ", %" PRId64 "]",
3422             mCttsTableEntries->count(), mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs);
3423 
3424     mOwner->beginBox("ctts");
3425     mOwner->writeInt32(0);  // version=0, flags=0
3426     uint32_t delta = mMinCttsOffsetTimeUs - getStartTimeOffsetScaledTime();
3427     mCttsTableEntries->adjustEntries([delta](size_t /* ix */, uint32_t (&value)[2]) {
3428         // entries are <count, ctts> pairs; adjust only ctts
3429         uint32_t duration = htonl(value[1]); // back to host byte order
3430         value[1] = htonl(duration - delta);
3431     });
3432     mCttsTableEntries->write(mOwner);
3433     mOwner->endBox();  // ctts
3434 }
3435 
writeStssBox()3436 void MPEG4Writer::Track::writeStssBox() {
3437     mOwner->beginBox("stss");
3438     mOwner->writeInt32(0);  // version=0, flags=0
3439     mStssTableEntries->write(mOwner);
3440     mOwner->endBox();  // stss
3441 }
3442 
writeStszBox()3443 void MPEG4Writer::Track::writeStszBox() {
3444     mOwner->beginBox("stsz");
3445     mOwner->writeInt32(0);  // version=0, flags=0
3446     mOwner->writeInt32(0);
3447     mStszTableEntries->write(mOwner);
3448     mOwner->endBox();  // stsz
3449 }
3450 
writeStscBox()3451 void MPEG4Writer::Track::writeStscBox() {
3452     mOwner->beginBox("stsc");
3453     mOwner->writeInt32(0);  // version=0, flags=0
3454     mStscTableEntries->write(mOwner);
3455     mOwner->endBox();  // stsc
3456 }
3457 
writeStcoBox(bool use32BitOffset)3458 void MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) {
3459     mOwner->beginBox(use32BitOffset? "stco": "co64");
3460     mOwner->writeInt32(0);  // version=0, flags=0
3461     if (use32BitOffset) {
3462         mStcoTableEntries->write(mOwner);
3463     } else {
3464         mCo64TableEntries->write(mOwner);
3465     }
3466     mOwner->endBox();  // stco or co64
3467 }
3468 
writeUdtaBox()3469 void MPEG4Writer::writeUdtaBox() {
3470     beginBox("udta");
3471     writeGeoDataBox();
3472     endBox();
3473 }
3474 
writeHdlr()3475 void MPEG4Writer::writeHdlr() {
3476     beginBox("hdlr");
3477     writeInt32(0); // Version, Flags
3478     writeInt32(0); // Predefined
3479     writeFourcc("mdta");
3480     writeInt32(0); // Reserved[0]
3481     writeInt32(0); // Reserved[1]
3482     writeInt32(0); // Reserved[2]
3483     writeInt8(0);  // Name (empty)
3484     endBox();
3485 }
3486 
writeKeys()3487 void MPEG4Writer::writeKeys() {
3488     size_t count = mMetaKeys->countEntries();
3489 
3490     beginBox("keys");
3491     writeInt32(0);     // Version, Flags
3492     writeInt32(count); // Entry_count
3493     for (size_t i = 0; i < count; i++) {
3494         AMessage::Type type;
3495         const char *key = mMetaKeys->getEntryNameAt(i, &type);
3496         size_t n = strlen(key);
3497         writeInt32(n + 8);
3498         writeFourcc("mdta");
3499         write(key, n); // write without the \0
3500     }
3501     endBox();
3502 }
3503 
writeIlst()3504 void MPEG4Writer::writeIlst() {
3505     size_t count = mMetaKeys->countEntries();
3506 
3507     beginBox("ilst");
3508     for (size_t i = 0; i < count; i++) {
3509         beginBox(i + 1); // key id (1-based)
3510         beginBox("data");
3511         AMessage::Type type;
3512         const char *key = mMetaKeys->getEntryNameAt(i, &type);
3513         switch (type) {
3514             case AMessage::kTypeString:
3515             {
3516                 AString val;
3517                 CHECK(mMetaKeys->findString(key, &val));
3518                 writeInt32(1); // type = UTF8
3519                 writeInt32(0); // default country/language
3520                 write(val.c_str(), strlen(val.c_str())); // write without \0
3521                 break;
3522             }
3523 
3524             case AMessage::kTypeFloat:
3525             {
3526                 float val;
3527                 CHECK(mMetaKeys->findFloat(key, &val));
3528                 writeInt32(23); // type = float32
3529                 writeInt32(0);  // default country/language
3530                 writeInt32(*reinterpret_cast<int32_t *>(&val));
3531                 break;
3532             }
3533 
3534             case AMessage::kTypeInt32:
3535             {
3536                 int32_t val;
3537                 CHECK(mMetaKeys->findInt32(key, &val));
3538                 writeInt32(67); // type = signed int32
3539                 writeInt32(0);  // default country/language
3540                 writeInt32(val);
3541                 break;
3542             }
3543 
3544             default:
3545             {
3546                 ALOGW("Unsupported key type, writing 0 instead");
3547                 writeInt32(77); // type = unsigned int32
3548                 writeInt32(0);  // default country/language
3549                 writeInt32(0);
3550                 break;
3551             }
3552         }
3553         endBox(); // data
3554         endBox(); // key id
3555     }
3556     endBox(); // ilst
3557 }
3558 
writeMetaBox()3559 void MPEG4Writer::writeMetaBox() {
3560     size_t count = mMetaKeys->countEntries();
3561     if (count == 0) {
3562         return;
3563     }
3564 
3565     beginBox("meta");
3566     writeHdlr();
3567     writeKeys();
3568     writeIlst();
3569     endBox();
3570 }
3571 
3572 /*
3573  * Geodata is stored according to ISO-6709 standard.
3574  */
writeGeoDataBox()3575 void MPEG4Writer::writeGeoDataBox() {
3576     beginBox("\xA9xyz");
3577     /*
3578      * For historical reasons, any user data start
3579      * with "\0xA9", must be followed by its assoicated
3580      * language code.
3581      * 0x0012: text string length
3582      * 0x15c7: lang (locale) code: en
3583      */
3584     writeInt32(0x001215c7);
3585     writeLatitude(mLatitudex10000);
3586     writeLongitude(mLongitudex10000);
3587     writeInt8(0x2F);
3588     endBox();
3589 }
3590 
3591 }  // namespace android
3592