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