MPEG4Writer.cpp revision 19c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bb
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#include <utils/Log.h>
20
21#include <arpa/inet.h>
22
23#include <ctype.h>
24#include <pthread.h>
25
26#include <media/stagefright/MPEG4Writer.h>
27#include <media/stagefright/MediaBuffer.h>
28#include <media/stagefright/MetaData.h>
29#include <media/stagefright/MediaDebug.h>
30#include <media/stagefright/MediaDefs.h>
31#include <media/stagefright/MediaErrors.h>
32#include <media/stagefright/MediaSource.h>
33#include <media/stagefright/Utils.h>
34#include <media/mediarecorder.h>
35#include <cutils/properties.h>
36
37#include "include/ESDS.h"
38
39namespace android {
40
41class MPEG4Writer::Track {
42public:
43    Track(MPEG4Writer *owner, const sp<MediaSource> &source);
44    ~Track();
45
46    status_t start(MetaData *params);
47    void stop();
48    void pause();
49    bool reachedEOS();
50
51    int64_t getDurationUs() const;
52    int64_t getEstimatedTrackSizeBytes() const;
53    void writeTrackHeader(int32_t trackID, bool use32BitOffset = true);
54
55private:
56    MPEG4Writer *mOwner;
57    sp<MetaData> mMeta;
58    sp<MediaSource> mSource;
59    volatile bool mDone;
60    volatile bool mPaused;
61    volatile bool mResumed;
62    int64_t mMaxTimeStampUs;
63    int64_t mEstimatedTrackSizeBytes;
64
65    pthread_t mThread;
66
67    struct SampleInfo {
68        size_t size;
69        int64_t timestamp;
70    };
71    List<SampleInfo>    mSampleInfos;
72    bool                mSamplesHaveSameSize;
73
74    List<MediaBuffer *> mChunkSamples;
75    List<off_t>         mChunkOffsets;
76
77    struct StscTableEntry {
78
79        StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id)
80            : firstChunk(chunk),
81              samplesPerChunk(samples),
82              sampleDescriptionId(id) {}
83
84        uint32_t firstChunk;
85        uint32_t samplesPerChunk;
86        uint32_t sampleDescriptionId;
87    };
88    List<StscTableEntry> mStscTableEntries;
89
90    List<int32_t> mStssTableEntries;
91    List<int64_t> mChunkDurations;
92
93    struct SttsTableEntry {
94
95        SttsTableEntry(uint32_t count, uint32_t duration)
96            : sampleCount(count), sampleDuration(duration) {}
97
98        uint32_t sampleCount;
99        uint32_t sampleDuration;
100    };
101    List<SttsTableEntry> mSttsTableEntries;
102
103    void *mCodecSpecificData;
104    size_t mCodecSpecificDataSize;
105    bool mGotAllCodecSpecificData;
106    bool mTrackingProgressStatus;
107
108    bool mReachedEOS;
109    int64_t mStartTimestampUs;
110    int64_t mPreviousTrackTimeUs;
111    int64_t mTrackEveryTimeDurationUs;
112    int32_t mTrackEveryNumberOfFrames;
113
114    static void *ThreadWrapper(void *me);
115    void threadEntry();
116
117    status_t makeAVCCodecSpecificData(
118            const uint8_t *data, size_t size);
119    void writeOneChunk(bool isAvc);
120
121    // Track authoring progress status
122    void trackProgressStatus(int32_t nFrames, int64_t timeUs);
123    void initTrackingProgressStatus(MetaData *params);
124
125    // Utilities for collecting statistical data
126    void logStatisticalData(bool isAudio);
127    void findMinAvgMaxSampleDurationMs(
128            int32_t *min, int32_t *avg, int32_t *max);
129    void findMinMaxChunkDurations(int64_t *min, int64_t *max);
130
131    void getCodecSpecificDataFromInputFormatIfPossible();
132
133    Track(const Track &);
134    Track &operator=(const Track &);
135};
136
137#define USE_NALLEN_FOUR         1
138
139MPEG4Writer::MPEG4Writer(const char *filename)
140    : mFile(fopen(filename, "wb")),
141      mUse32BitOffset(true),
142      mPaused(false),
143      mStarted(false),
144      mOffset(0),
145      mMdatOffset(0),
146      mEstimatedMoovBoxSize(0),
147      mInterleaveDurationUs(500000) {
148    CHECK(mFile != NULL);
149}
150
151MPEG4Writer::MPEG4Writer(int fd)
152    : mFile(fdopen(fd, "wb")),
153      mUse32BitOffset(true),
154      mPaused(false),
155      mStarted(false),
156      mOffset(0),
157      mMdatOffset(0),
158      mEstimatedMoovBoxSize(0),
159      mInterleaveDurationUs(500000) {
160    CHECK(mFile != NULL);
161}
162
163MPEG4Writer::~MPEG4Writer() {
164    stop();
165
166    for (List<Track *>::iterator it = mTracks.begin();
167         it != mTracks.end(); ++it) {
168        delete *it;
169    }
170    mTracks.clear();
171}
172
173status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
174    Track *track = new Track(this, source);
175    mTracks.push_back(track);
176
177    return OK;
178}
179
180status_t MPEG4Writer::startTracks(MetaData *params) {
181    for (List<Track *>::iterator it = mTracks.begin();
182         it != mTracks.end(); ++it) {
183        status_t err = (*it)->start(params);
184
185        if (err != OK) {
186            for (List<Track *>::iterator it2 = mTracks.begin();
187                 it2 != it; ++it2) {
188                (*it2)->stop();
189            }
190
191            return err;
192        }
193    }
194    return OK;
195}
196
197int64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) {
198    // This implementation is highly experimental/heurisitic.
199    //
200    // Statistical analysis shows that metadata usually accounts
201    // for a small portion of the total file size, usually < 0.6%.
202    // Currently, lets set to 0.4% for now.
203
204    // The default MIN_MOOV_BOX_SIZE is set to 0.4% x 1MB,
205    // where 1MB is the common file size limit for MMS application.
206    // The default MAX _MOOV_BOX_SIZE value is based on about 4
207    // minute video recording with a bit rate about 3 Mbps, because
208    // statistics also show that most of the video captured are going
209    // to be less than 3 minutes.
210
211    // If the estimation is wrong, we will pay the price of wasting
212    // some reserved space. This should not happen so often statistically.
213    static const int32_t factor = mUse32BitOffset? 1: 2;
214    static const int64_t MIN_MOOV_BOX_SIZE = 4 * 1024;  // 4 KB
215    static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000);
216    int64_t size = MIN_MOOV_BOX_SIZE;
217
218    if (mMaxFileSizeLimitBytes != 0) {
219        size = mMaxFileSizeLimitBytes * 4 / 1000;
220    } else if (mMaxFileDurationLimitUs != 0) {
221        if (bitRate <= 0) {
222            // We could not estimate the file size since bitRate is not set.
223            size = MIN_MOOV_BOX_SIZE;
224        } else {
225            size = ((mMaxFileDurationLimitUs * bitRate * 4) / 1000 / 8000000);
226        }
227    }
228    if (size < MIN_MOOV_BOX_SIZE) {
229        size = MIN_MOOV_BOX_SIZE;
230    }
231
232    // Any long duration recording will be probably end up with
233    // non-streamable mp4 file.
234    if (size > MAX_MOOV_BOX_SIZE) {
235        size = MAX_MOOV_BOX_SIZE;
236    }
237
238    LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated"
239         " moov size %lld bytes",
240         mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size);
241    return factor * size;
242}
243
244status_t MPEG4Writer::start(MetaData *param) {
245    if (mFile == NULL) {
246        return UNKNOWN_ERROR;
247    }
248
249    int32_t use64BitOffset;
250    if (param &&
251        param->findInt32(kKey64BitFileOffset, &use64BitOffset) &&
252        use64BitOffset) {
253        mUse32BitOffset = false;
254    }
255
256    // System property can overwrite the file offset bits parameter
257    char value[PROPERTY_VALUE_MAX];
258    if (property_get("media.stagefright.record-64bits", value, NULL)
259        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
260        mUse32BitOffset = false;
261    }
262
263    mStartTimestampUs = -1;
264
265    if (mStarted) {
266        if (mPaused) {
267            mPaused = false;
268            return startTracks(param);
269        }
270        return OK;
271    }
272
273    mStreamableFile = true;
274    mWriteMoovBoxToMemory = false;
275    mMoovBoxBuffer = NULL;
276    mMoovBoxBufferOffset = 0;
277
278    beginBox("ftyp");
279      {
280        int32_t fileType;
281        if (param && param->findInt32(kKeyFileType, &fileType) &&
282            fileType != OUTPUT_FORMAT_MPEG_4) {
283            writeFourcc("3gp4");
284        } else {
285            writeFourcc("isom");
286        }
287      }
288      writeInt32(0);
289      writeFourcc("isom");
290      writeFourcc("3gp4");
291    endBox();
292
293    mFreeBoxOffset = mOffset;
294
295    if (mEstimatedMoovBoxSize == 0) {
296        int32_t bitRate = -1;
297        if (param) {
298            param->findInt32(kKeyBitRate, &bitRate);
299        }
300        mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate);
301    }
302    CHECK(mEstimatedMoovBoxSize >= 8);
303    fseeko(mFile, mFreeBoxOffset, SEEK_SET);
304    writeInt32(mEstimatedMoovBoxSize);
305    write("free", 4);
306
307    mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize;
308    mOffset = mMdatOffset;
309    fseeko(mFile, mMdatOffset, SEEK_SET);
310    if (mUse32BitOffset) {
311        write("????mdat", 8);
312    } else {
313        write("\x00\x00\x00\x01mdat????????", 16);
314    }
315    status_t err = startTracks(param);
316    if (err != OK) {
317        return err;
318    }
319    mStarted = true;
320    return OK;
321}
322
323void MPEG4Writer::pause() {
324    if (mFile == NULL) {
325        return;
326    }
327    mPaused = true;
328    for (List<Track *>::iterator it = mTracks.begin();
329         it != mTracks.end(); ++it) {
330        (*it)->pause();
331    }
332}
333
334void MPEG4Writer::stop() {
335    if (mFile == NULL) {
336        return;
337    }
338
339    int64_t max_duration = 0;
340    for (List<Track *>::iterator it = mTracks.begin();
341         it != mTracks.end(); ++it) {
342        (*it)->stop();
343
344        int64_t duration = (*it)->getDurationUs();
345        if (duration > max_duration) {
346            max_duration = duration;
347        }
348    }
349
350
351    // Fix up the size of the 'mdat' chunk.
352    if (mUse32BitOffset) {
353        fseeko(mFile, mMdatOffset, SEEK_SET);
354        int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset));
355        fwrite(&size, 1, 4, mFile);
356    } else {
357        fseeko(mFile, mMdatOffset + 8, SEEK_SET);
358        int64_t size = mOffset - mMdatOffset;
359        size = hton64(size);
360        fwrite(&size, 1, 8, mFile);
361    }
362    fseeko(mFile, mOffset, SEEK_SET);
363
364    time_t now = time(NULL);
365    const off_t moovOffset = mOffset;
366    mWriteMoovBoxToMemory = true;
367    mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
368    mMoovBoxBufferOffset = 0;
369    CHECK(mMoovBoxBuffer != NULL);
370    int32_t timeScale = 1000;
371    int32_t duration = max_duration / timeScale;
372
373    beginBox("moov");
374
375      beginBox("mvhd");
376        writeInt32(0);             // version=0, flags=0
377        writeInt32(now);           // creation time
378        writeInt32(now);           // modification time
379        writeInt32(timeScale);          // timescale
380        writeInt32(duration);
381        writeInt32(0x10000);       // rate: 1.0
382        writeInt16(0x100);         // volume
383        writeInt16(0);             // reserved
384        writeInt32(0);             // reserved
385        writeInt32(0);             // reserved
386        writeInt32(0x10000);       // matrix
387        writeInt32(0);
388        writeInt32(0);
389        writeInt32(0);
390        writeInt32(0x10000);
391        writeInt32(0);
392        writeInt32(0);
393        writeInt32(0);
394        writeInt32(0x40000000);
395        writeInt32(0);             // predefined
396        writeInt32(0);             // predefined
397        writeInt32(0);             // predefined
398        writeInt32(0);             // predefined
399        writeInt32(0);             // predefined
400        writeInt32(0);             // predefined
401        writeInt32(mTracks.size() + 1);  // nextTrackID
402      endBox();  // mvhd
403
404      int32_t id = 1;
405      for (List<Track *>::iterator it = mTracks.begin();
406           it != mTracks.end(); ++it, ++id) {
407          (*it)->writeTrackHeader(id, mUse32BitOffset);
408      }
409    endBox();  // moov
410
411    mWriteMoovBoxToMemory = false;
412    if (mStreamableFile) {
413        CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize);
414
415        // Moov box
416        fseeko(mFile, mFreeBoxOffset, SEEK_SET);
417        mOffset = mFreeBoxOffset;
418        write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, mFile);
419
420        // Free box
421        fseeko(mFile, mOffset, SEEK_SET);
422        writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset);
423        write("free", 4);
424
425        // Free temp memory
426        free(mMoovBoxBuffer);
427        mMoovBoxBuffer = NULL;
428        mMoovBoxBufferOffset = 0;
429    } else {
430        LOGI("The mp4 file will not be streamable.");
431    }
432
433    CHECK(mBoxes.empty());
434
435    fflush(mFile);
436    fclose(mFile);
437    mFile = NULL;
438    mStarted = false;
439}
440
441status_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) {
442    mInterleaveDurationUs = durationUs;
443    return OK;
444}
445
446void MPEG4Writer::lock() {
447    mLock.lock();
448}
449
450void MPEG4Writer::unlock() {
451    mLock.unlock();
452}
453
454off_t MPEG4Writer::addSample_l(MediaBuffer *buffer) {
455    off_t old_offset = mOffset;
456
457    fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
458           1, buffer->range_length(), mFile);
459
460    mOffset += buffer->range_length();
461
462    return old_offset;
463}
464
465static void StripStartcode(MediaBuffer *buffer) {
466    if (buffer->range_length() < 4) {
467        return;
468    }
469
470    const uint8_t *ptr =
471        (const uint8_t *)buffer->data() + buffer->range_offset();
472
473    if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
474        buffer->set_range(
475                buffer->range_offset() + 4, buffer->range_length() - 4);
476    }
477}
478
479off_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
480    off_t old_offset = mOffset;
481
482    size_t length = buffer->range_length();
483
484#if USE_NALLEN_FOUR
485    uint8_t x = length >> 24;
486    fwrite(&x, 1, 1, mFile);
487    x = (length >> 16) & 0xff;
488    fwrite(&x, 1, 1, mFile);
489    x = (length >> 8) & 0xff;
490    fwrite(&x, 1, 1, mFile);
491    x = length & 0xff;
492    fwrite(&x, 1, 1, mFile);
493#else
494    CHECK(length < 65536);
495
496    uint8_t x = length >> 8;
497    fwrite(&x, 1, 1, mFile);
498    x = length & 0xff;
499    fwrite(&x, 1, 1, mFile);
500#endif
501
502    fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
503           1, length, mFile);
504
505#if USE_NALLEN_FOUR
506    mOffset += length + 4;
507#else
508    mOffset += length + 2;
509#endif
510
511    return old_offset;
512}
513
514size_t MPEG4Writer::write(
515        const void *ptr, size_t size, size_t nmemb, FILE *stream) {
516
517    const size_t bytes = size * nmemb;
518    if (mWriteMoovBoxToMemory) {
519        off_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes;
520        if (moovBoxSize > mEstimatedMoovBoxSize) {
521            for (List<off_t>::iterator it = mBoxes.begin();
522                 it != mBoxes.end(); ++it) {
523                (*it) += mOffset;
524            }
525            fseeko(mFile, mOffset, SEEK_SET);
526            fwrite(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, stream);
527            fwrite(ptr, size, nmemb, stream);
528            mOffset += (bytes + mMoovBoxBufferOffset);
529            free(mMoovBoxBuffer);
530            mMoovBoxBuffer = NULL;
531            mMoovBoxBufferOffset = 0;
532            mWriteMoovBoxToMemory = false;
533            mStreamableFile = false;
534        } else {
535            memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes);
536            mMoovBoxBufferOffset += bytes;
537        }
538    } else {
539        fwrite(ptr, size, nmemb, stream);
540        mOffset += bytes;
541    }
542    return bytes;
543}
544
545void MPEG4Writer::beginBox(const char *fourcc) {
546    CHECK_EQ(strlen(fourcc), 4);
547
548    mBoxes.push_back(mWriteMoovBoxToMemory?
549            mMoovBoxBufferOffset: mOffset);
550
551    writeInt32(0);
552    writeFourcc(fourcc);
553}
554
555void MPEG4Writer::endBox() {
556    CHECK(!mBoxes.empty());
557
558    off_t offset = *--mBoxes.end();
559    mBoxes.erase(--mBoxes.end());
560
561    if (mWriteMoovBoxToMemory) {
562       int32_t x = htonl(mMoovBoxBufferOffset - offset);
563       memcpy(mMoovBoxBuffer + offset, &x, 4);
564    } else {
565        fseeko(mFile, offset, SEEK_SET);
566        writeInt32(mOffset - offset);
567        mOffset -= 4;
568        fseeko(mFile, mOffset, SEEK_SET);
569    }
570}
571
572void MPEG4Writer::writeInt8(int8_t x) {
573    write(&x, 1, 1, mFile);
574}
575
576void MPEG4Writer::writeInt16(int16_t x) {
577    x = htons(x);
578    write(&x, 1, 2, mFile);
579}
580
581void MPEG4Writer::writeInt32(int32_t x) {
582    x = htonl(x);
583    write(&x, 1, 4, mFile);
584}
585
586void MPEG4Writer::writeInt64(int64_t x) {
587    x = hton64(x);
588    write(&x, 1, 8, mFile);
589}
590
591void MPEG4Writer::writeCString(const char *s) {
592    size_t n = strlen(s);
593    write(s, 1, n + 1, mFile);
594}
595
596void MPEG4Writer::writeFourcc(const char *s) {
597    CHECK_EQ(strlen(s), 4);
598    write(s, 1, 4, mFile);
599}
600
601void MPEG4Writer::write(const void *data, size_t size) {
602    write(data, 1, size, mFile);
603}
604
605bool MPEG4Writer::exceedsFileSizeLimit() {
606    // No limit
607    if (mMaxFileSizeLimitBytes == 0) {
608        return false;
609    }
610
611    int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize);
612    for (List<Track *>::iterator it = mTracks.begin();
613         it != mTracks.end(); ++it) {
614        nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
615    }
616    return (nTotalBytesEstimate >= mMaxFileSizeLimitBytes);
617}
618
619bool MPEG4Writer::exceedsFileDurationLimit() {
620    // No limit
621    if (mMaxFileDurationLimitUs == 0) {
622        return false;
623    }
624
625    for (List<Track *>::iterator it = mTracks.begin();
626         it != mTracks.end(); ++it) {
627        if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) {
628            return true;
629        }
630    }
631    return false;
632}
633
634bool MPEG4Writer::reachedEOS() {
635    bool allDone = true;
636    for (List<Track *>::iterator it = mTracks.begin();
637         it != mTracks.end(); ++it) {
638        if (!(*it)->reachedEOS()) {
639            allDone = false;
640            break;
641        }
642    }
643
644    return allDone;
645}
646
647void MPEG4Writer::setStartTimestampUs(int64_t timeUs) {
648    LOGI("setStartTimestampUs: %lld", timeUs);
649    CHECK(timeUs >= 0);
650    Mutex::Autolock autoLock(mLock);
651    if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) {
652        mStartTimestampUs = timeUs;
653        LOGI("Earliest track starting time: %lld", mStartTimestampUs);
654    }
655}
656
657int64_t MPEG4Writer::getStartTimestampUs() {
658    LOGI("getStartTimestampUs: %lld", mStartTimestampUs);
659    Mutex::Autolock autoLock(mLock);
660    return mStartTimestampUs;
661}
662
663size_t MPEG4Writer::numTracks() {
664    Mutex::Autolock autolock(mLock);
665    return mTracks.size();
666}
667
668////////////////////////////////////////////////////////////////////////////////
669
670MPEG4Writer::Track::Track(
671        MPEG4Writer *owner, const sp<MediaSource> &source)
672    : mOwner(owner),
673      mMeta(source->getFormat()),
674      mSource(source),
675      mDone(false),
676      mPaused(false),
677      mResumed(false),
678      mMaxTimeStampUs(0),
679      mEstimatedTrackSizeBytes(0),
680      mSamplesHaveSameSize(true),
681      mCodecSpecificData(NULL),
682      mCodecSpecificDataSize(0),
683      mGotAllCodecSpecificData(false),
684      mReachedEOS(false) {
685    getCodecSpecificDataFromInputFormatIfPossible();
686}
687
688void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
689    const char *mime;
690    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
691
692    if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
693        uint32_t type;
694        const void *data;
695        size_t size;
696        if (mMeta->findData(kKeyAVCC, &type, &data, &size)) {
697            mCodecSpecificData = malloc(size);
698            mCodecSpecificDataSize = size;
699            memcpy(mCodecSpecificData, data, size);
700            mGotAllCodecSpecificData = true;
701        }
702    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
703            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
704        uint32_t type;
705        const void *data;
706        size_t size;
707        if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
708            ESDS esds(data, size);
709            if (esds.getCodecSpecificInfo(&data, &size) == OK) {
710                mCodecSpecificData = malloc(size);
711                mCodecSpecificDataSize = size;
712                memcpy(mCodecSpecificData, data, size);
713                mGotAllCodecSpecificData = true;
714            }
715        }
716    }
717}
718
719MPEG4Writer::Track::~Track() {
720    stop();
721
722    if (mCodecSpecificData != NULL) {
723        free(mCodecSpecificData);
724        mCodecSpecificData = NULL;
725    }
726}
727
728void MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) {
729    LOGV("initTrackingProgressStatus");
730    mPreviousTrackTimeUs = -1;
731    mTrackingProgressStatus = false;
732    mTrackEveryTimeDurationUs = 0;
733    mTrackEveryNumberOfFrames = 0;
734    {
735        int64_t timeUs;
736        if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) {
737            LOGV("Receive request to track progress status for every %lld us", timeUs);
738            mTrackEveryTimeDurationUs = timeUs;
739            mTrackingProgressStatus = true;
740        }
741    }
742    {
743        int32_t nFrames;
744        if (params && params->findInt32(kKeyTrackFrameStatus, &nFrames)) {
745            LOGV("Receive request to track progress status for every %d frames", nFrames);
746            mTrackEveryNumberOfFrames = nFrames;
747            mTrackingProgressStatus = true;
748        }
749    }
750}
751
752status_t MPEG4Writer::Track::start(MetaData *params) {
753    if (!mDone && mPaused) {
754        mPaused = false;
755        mResumed = true;
756        return OK;
757    }
758
759    int64_t startTimeUs;
760    if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) {
761        startTimeUs = 0;
762    }
763
764    initTrackingProgressStatus(params);
765
766    sp<MetaData> meta = new MetaData;
767    meta->setInt64(kKeyTime, startTimeUs);
768    status_t err = mSource->start(meta.get());
769    if (err != OK) {
770        mDone = mReachedEOS = true;
771        return err;
772    }
773
774    pthread_attr_t attr;
775    pthread_attr_init(&attr);
776    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
777
778    mDone = false;
779    mMaxTimeStampUs = 0;
780    mReachedEOS = false;
781    mEstimatedTrackSizeBytes = 0;
782
783    pthread_create(&mThread, &attr, ThreadWrapper, this);
784    pthread_attr_destroy(&attr);
785
786    return OK;
787}
788
789void MPEG4Writer::Track::pause() {
790    mPaused = true;
791}
792
793void MPEG4Writer::Track::stop() {
794    if (mDone) {
795        return;
796    }
797
798    mDone = true;
799
800    void *dummy;
801    pthread_join(mThread, &dummy);
802
803    mSource->stop();
804}
805
806bool MPEG4Writer::Track::reachedEOS() {
807    return mReachedEOS;
808}
809
810// static
811void *MPEG4Writer::Track::ThreadWrapper(void *me) {
812    Track *track = static_cast<Track *>(me);
813
814    track->threadEntry();
815
816    return NULL;
817}
818
819#include <ctype.h>
820static void hexdump(const void *_data, size_t size) {
821    const uint8_t *data = (const uint8_t *)_data;
822    size_t offset = 0;
823    while (offset < size) {
824        printf("0x%04x  ", offset);
825
826        size_t n = size - offset;
827        if (n > 16) {
828            n = 16;
829        }
830
831        for (size_t i = 0; i < 16; ++i) {
832            if (i == 8) {
833                printf(" ");
834            }
835
836            if (offset + i < size) {
837                printf("%02x ", data[offset + i]);
838            } else {
839                printf("   ");
840            }
841        }
842
843        printf(" ");
844
845        for (size_t i = 0; i < n; ++i) {
846            if (isprint(data[offset + i])) {
847                printf("%c", data[offset + i]);
848            } else {
849                printf(".");
850            }
851        }
852
853        printf("\n");
854
855        offset += 16;
856    }
857}
858
859
860status_t MPEG4Writer::Track::makeAVCCodecSpecificData(
861        const uint8_t *data, size_t size) {
862    // hexdump(data, size);
863
864    if (mCodecSpecificData != NULL) {
865        LOGE("Already have codec specific data");
866        return ERROR_MALFORMED;
867    }
868
869    if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) {
870        LOGE("Must start with a start code");
871        return ERROR_MALFORMED;
872    }
873
874    size_t picParamOffset = 4;
875    while (picParamOffset + 3 < size
876            && memcmp("\x00\x00\x00\x01", &data[picParamOffset], 4)) {
877        ++picParamOffset;
878    }
879
880    if (picParamOffset + 3 >= size) {
881        LOGE("Could not find start-code for pictureParameterSet");
882        return ERROR_MALFORMED;
883    }
884
885    size_t seqParamSetLength = picParamOffset - 4;
886    size_t picParamSetLength = size - picParamOffset - 4;
887
888    mCodecSpecificDataSize =
889        6 + 1 + seqParamSetLength + 2 + picParamSetLength + 2;
890
891    mCodecSpecificData = malloc(mCodecSpecificDataSize);
892    uint8_t *header = (uint8_t *)mCodecSpecificData;
893    header[0] = 1;
894    header[1] = 0x42;  // profile
895    header[2] = 0x80;
896    header[3] = 0x1e;  // level
897
898#if USE_NALLEN_FOUR
899    header[4] = 0xfc | 3;  // length size == 4 bytes
900#else
901    header[4] = 0xfc | 1;  // length size == 2 bytes
902#endif
903
904    header[5] = 0xe0 | 1;
905    header[6] = seqParamSetLength >> 8;
906    header[7] = seqParamSetLength & 0xff;
907    memcpy(&header[8], &data[4], seqParamSetLength);
908    header += 8 + seqParamSetLength;
909    header[0] = 1;
910    header[1] = picParamSetLength >> 8;
911    header[2] = picParamSetLength & 0xff;
912    memcpy(&header[3], &data[picParamOffset + 4], picParamSetLength);
913
914    return OK;
915}
916
917void MPEG4Writer::Track::threadEntry() {
918    sp<MetaData> meta = mSource->getFormat();
919    const char *mime;
920    meta->findCString(kKeyMIMEType, &mime);
921    bool is_mpeg4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
922                    !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
923    bool is_avc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
924    bool is_audio = !strncasecmp(mime, "audio/", 6);
925    int32_t count = 0;
926    const int64_t interleaveDurationUs = mOwner->interleaveDuration();
927    int64_t chunkTimestampUs = 0;
928    int32_t nChunks = 0;
929    int32_t nZeroLengthFrames = 0;
930    int64_t lastTimestamp = 0;  // Timestamp of the previous sample
931    int64_t lastDuration = 0;   // Time spacing between the previous two samples
932    int32_t sampleCount = 1;    // Sample count in the current stts table entry
933    uint32_t previousSampleSize = 0;  // Size of the previous sample
934    int64_t previousPausedDurationUs = 0;
935    sp<MetaData> meta_data;
936
937    status_t err = OK;
938    MediaBuffer *buffer;
939    while (!mDone && (err = mSource->read(&buffer)) == OK) {
940        if (buffer->range_length() == 0) {
941            buffer->release();
942            buffer = NULL;
943            ++nZeroLengthFrames;
944            continue;
945        }
946
947        // If the codec specific data has not been received yet, delay pause.
948        // After the codec specific data is received, discard what we received
949        // when the track is to be paused.
950        if (mPaused && !mResumed) {
951            buffer->release();
952            buffer = NULL;
953            continue;
954        }
955
956        ++count;
957
958        int32_t isCodecConfig;
959        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
960                && isCodecConfig) {
961            CHECK(!mGotAllCodecSpecificData);
962
963            if (is_avc) {
964                status_t err = makeAVCCodecSpecificData(
965                        (const uint8_t *)buffer->data()
966                            + buffer->range_offset(),
967                        buffer->range_length());
968                CHECK_EQ(OK, err);
969            } else if (is_mpeg4) {
970                mCodecSpecificDataSize = buffer->range_length();
971                mCodecSpecificData = malloc(mCodecSpecificDataSize);
972                memcpy(mCodecSpecificData,
973                        (const uint8_t *)buffer->data()
974                            + buffer->range_offset(),
975                       buffer->range_length());
976            }
977
978            buffer->release();
979            buffer = NULL;
980
981            mGotAllCodecSpecificData = true;
982            continue;
983        } else if (!mGotAllCodecSpecificData &&
984                count == 1 && is_mpeg4 && mCodecSpecificData == NULL) {
985            // The TI mpeg4 encoder does not properly set the
986            // codec-specific-data flag.
987
988            const uint8_t *data =
989                (const uint8_t *)buffer->data() + buffer->range_offset();
990
991            const size_t size = buffer->range_length();
992
993            size_t offset = 0;
994            while (offset + 3 < size) {
995                if (data[offset] == 0x00 && data[offset + 1] == 0x00
996                    && data[offset + 2] == 0x01 && data[offset + 3] == 0xb6) {
997                    break;
998                }
999
1000                ++offset;
1001            }
1002
1003            // CHECK(offset + 3 < size);
1004            if (offset + 3 >= size) {
1005                // XXX assume the entire first chunk of data is the codec specific
1006                // data.
1007                offset = size;
1008            }
1009
1010            mCodecSpecificDataSize = offset;
1011            mCodecSpecificData = malloc(offset);
1012            memcpy(mCodecSpecificData, data, offset);
1013
1014            buffer->set_range(buffer->range_offset() + offset, size - offset);
1015
1016            if (size == offset) {
1017                buffer->release();
1018                buffer = NULL;
1019
1020                continue;
1021            }
1022
1023            mGotAllCodecSpecificData = true;
1024        } else if (!mGotAllCodecSpecificData && is_avc && count < 3) {
1025            // The TI video encoder does not flag codec specific data
1026            // as such and also splits up SPS and PPS across two buffers.
1027
1028            const uint8_t *data =
1029                (const uint8_t *)buffer->data() + buffer->range_offset();
1030
1031            size_t size = buffer->range_length();
1032
1033            CHECK(count == 2 || mCodecSpecificData == NULL);
1034
1035            size_t offset = mCodecSpecificDataSize;
1036            mCodecSpecificDataSize += size + 4;
1037            mCodecSpecificData =
1038                realloc(mCodecSpecificData, mCodecSpecificDataSize);
1039
1040            memcpy((uint8_t *)mCodecSpecificData + offset,
1041                   "\x00\x00\x00\x01", 4);
1042
1043            memcpy((uint8_t *)mCodecSpecificData + offset + 4, data, size);
1044
1045            buffer->release();
1046            buffer = NULL;
1047
1048            if (count == 2) {
1049                void *tmp = mCodecSpecificData;
1050                size = mCodecSpecificDataSize;
1051                mCodecSpecificData = NULL;
1052                mCodecSpecificDataSize = 0;
1053
1054                status_t err = makeAVCCodecSpecificData(
1055                        (const uint8_t *)tmp, size);
1056                free(tmp);
1057                tmp = NULL;
1058                CHECK_EQ(OK, err);
1059
1060                mGotAllCodecSpecificData = true;
1061            }
1062
1063            continue;
1064        }
1065
1066        if (!mGotAllCodecSpecificData) {
1067            mGotAllCodecSpecificData = true;
1068        }
1069
1070        // Make a deep copy of the MediaBuffer and Metadata and release
1071        // the original as soon as we can
1072        MediaBuffer *copy = new MediaBuffer(buffer->range_length());
1073        memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(),
1074                buffer->range_length());
1075        copy->set_range(0, buffer->range_length());
1076        meta_data = new MetaData(*buffer->meta_data().get());
1077        buffer->release();
1078        buffer = NULL;
1079
1080        if (is_avc) StripStartcode(copy);
1081
1082        SampleInfo info;
1083        info.size = is_avc
1084#if USE_NALLEN_FOUR
1085                ? copy->range_length() + 4
1086#else
1087                ? copy->range_length() + 2
1088#endif
1089                : copy->range_length();
1090
1091        // Max file size or duration handling
1092        mEstimatedTrackSizeBytes += info.size;
1093        if (mOwner->exceedsFileSizeLimit()) {
1094            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
1095            break;
1096        }
1097        if (mOwner->exceedsFileDurationLimit()) {
1098            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
1099            break;
1100        }
1101
1102
1103        int32_t isSync = false;
1104        meta_data->findInt32(kKeyIsSyncFrame, &isSync);
1105
1106        int64_t timestampUs;
1107        CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
1108
1109////////////////////////////////////////////////////////////////////////////////
1110        if (mSampleInfos.empty()) {
1111            mStartTimestampUs = timestampUs;
1112            mOwner->setStartTimestampUs(mStartTimestampUs);
1113        }
1114
1115        if (mResumed) {
1116            previousPausedDurationUs += (timestampUs - mMaxTimeStampUs - 1000 * lastDuration);
1117            mResumed = false;
1118        }
1119
1120        timestampUs -= previousPausedDurationUs;
1121        LOGV("time stamp: %lld and previous paused duration %lld",
1122                timestampUs, previousPausedDurationUs);
1123        if (timestampUs > mMaxTimeStampUs) {
1124            mMaxTimeStampUs = timestampUs;
1125        }
1126
1127        // Our timestamp is in ms.
1128        info.timestamp = (timestampUs + 500) / 1000;
1129        mSampleInfos.push_back(info);
1130        if (mSampleInfos.size() > 2) {
1131            if (lastDuration != info.timestamp - lastTimestamp) {
1132                SttsTableEntry sttsEntry(sampleCount, lastDuration);
1133                mSttsTableEntries.push_back(sttsEntry);
1134                sampleCount = 1;
1135            } else {
1136                ++sampleCount;
1137            }
1138        }
1139        if (mSamplesHaveSameSize) {
1140            if (mSampleInfos.size() >= 2 && previousSampleSize != info.size) {
1141                mSamplesHaveSameSize = false;
1142            }
1143            previousSampleSize = info.size;
1144        }
1145        lastDuration = info.timestamp - lastTimestamp;
1146        lastTimestamp = info.timestamp;
1147
1148        if (isSync != 0) {
1149            mStssTableEntries.push_back(mSampleInfos.size());
1150        }
1151
1152        if (mTrackingProgressStatus) {
1153            if (mPreviousTrackTimeUs <= 0) {
1154                mPreviousTrackTimeUs = mStartTimestampUs;
1155            }
1156            trackProgressStatus(mSampleInfos.size(), timestampUs);
1157        }
1158        if (mOwner->numTracks() == 1) {
1159            off_t offset = is_avc? mOwner->addLengthPrefixedSample_l(copy)
1160                                 : mOwner->addSample_l(copy);
1161            if (mChunkOffsets.empty()) {
1162                mChunkOffsets.push_back(offset);
1163            }
1164            copy->release();
1165            copy = NULL;
1166            continue;
1167        }
1168
1169        mChunkSamples.push_back(copy);
1170        if (interleaveDurationUs == 0) {
1171            StscTableEntry stscEntry(++nChunks, 1, 1);
1172            mStscTableEntries.push_back(stscEntry);
1173            writeOneChunk(is_avc);
1174        } else {
1175            if (chunkTimestampUs == 0) {
1176                chunkTimestampUs = timestampUs;
1177            } else {
1178                if (timestampUs - chunkTimestampUs > interleaveDurationUs) {
1179                    ++nChunks;
1180                    mChunkDurations.push_back(timestampUs - chunkTimestampUs);
1181                    if (nChunks == 1 ||  // First chunk
1182                        (--(mStscTableEntries.end()))->samplesPerChunk !=
1183                         mChunkSamples.size()) {
1184                        StscTableEntry stscEntry(nChunks,
1185                                mChunkSamples.size(), 1);
1186                        mStscTableEntries.push_back(stscEntry);
1187                    }
1188                    writeOneChunk(is_avc);
1189                    chunkTimestampUs = timestampUs;
1190                }
1191            }
1192        }
1193
1194    }
1195
1196    if (mSampleInfos.empty()) {
1197        err = UNKNOWN_ERROR;
1198    }
1199    mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_COMPLETION_STATUS, err);
1200
1201    // Last chunk
1202    if (mOwner->numTracks() == 1) {
1203        StscTableEntry stscEntry(1, mSampleInfos.size(), 1);
1204        mStscTableEntries.push_back(stscEntry);
1205    } else if (!mChunkSamples.empty()) {
1206        ++nChunks;
1207        StscTableEntry stscEntry(nChunks, mChunkSamples.size(), 1);
1208        mStscTableEntries.push_back(stscEntry);
1209        writeOneChunk(is_avc);
1210    }
1211
1212    // We don't really know how long the last frame lasts, since
1213    // there is no frame time after it, just repeat the previous
1214    // frame's duration.
1215    if (mSampleInfos.size() == 1) {
1216        lastDuration = 0;  // A single sample's duration
1217    } else {
1218        ++sampleCount;  // Count for the last sample
1219    }
1220    SttsTableEntry sttsEntry(sampleCount, lastDuration);
1221    mSttsTableEntries.push_back(sttsEntry);
1222    mReachedEOS = true;
1223    LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames - %s",
1224            count, nZeroLengthFrames, mSampleInfos.size(), is_audio? "audio": "video");
1225
1226    logStatisticalData(is_audio);
1227}
1228
1229void MPEG4Writer::Track::trackProgressStatus(int32_t nFrames, int64_t timeUs) {
1230    LOGV("trackProgressStatus: %d frames and %lld us", nFrames, timeUs);
1231    if (mTrackEveryNumberOfFrames > 0 &&
1232        nFrames % mTrackEveryNumberOfFrames == 0) {
1233        LOGV("Fire frame tracking progress status at frame %d", nFrames);
1234        mOwner->notify(MEDIA_RECORDER_EVENT_INFO,
1235                       MEDIA_RECORDER_INFO_PROGRESS_FRAME_STATUS,
1236                       nFrames);
1237    }
1238
1239    if (mTrackEveryTimeDurationUs > 0 &&
1240        timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) {
1241        LOGV("Fire time tracking progress status at %lld us", timeUs);
1242        mOwner->notify(MEDIA_RECORDER_EVENT_INFO,
1243                       MEDIA_RECORDER_INFO_PROGRESS_TIME_STATUS,
1244                       timeUs / 1000);
1245        mPreviousTrackTimeUs = timeUs;
1246    }
1247}
1248
1249void MPEG4Writer::Track::findMinAvgMaxSampleDurationMs(
1250        int32_t *min, int32_t *avg, int32_t *max) {
1251    CHECK(!mSampleInfos.empty());
1252    int32_t avgSampleDurationMs = mMaxTimeStampUs / 1000/ mSampleInfos.size();
1253    int32_t minSampleDurationMs = 0x7FFFFFFF;
1254    int32_t maxSampleDurationMs = 0;
1255    for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
1256        it != mSttsTableEntries.end(); ++it) {
1257        int32_t sampleDurationMs = static_cast<int32_t>(it->sampleDuration);
1258        if (sampleDurationMs > maxSampleDurationMs) {
1259            maxSampleDurationMs = sampleDurationMs;
1260        } else if (sampleDurationMs < minSampleDurationMs) {
1261            minSampleDurationMs = sampleDurationMs;
1262        }
1263        LOGI("sample duration: %d ms", sampleDurationMs);
1264    }
1265    CHECK(minSampleDurationMs != 0);
1266    CHECK(avgSampleDurationMs != 0);
1267    CHECK(maxSampleDurationMs != 0);
1268    *min = minSampleDurationMs;
1269    *avg = avgSampleDurationMs;
1270    *max = maxSampleDurationMs;
1271}
1272
1273// Don't count the last duration
1274void MPEG4Writer::Track::findMinMaxChunkDurations(int64_t *min, int64_t *max) {
1275    int64_t duration = mOwner->interleaveDuration();
1276    int64_t minChunkDuration = duration;
1277    int64_t maxChunkDuration = duration;
1278    if (mChunkDurations.size() > 1) {
1279        for (List<int64_t>::iterator it = mChunkDurations.begin();
1280            it != --mChunkDurations.end(); ++it) {
1281            if (minChunkDuration > (*it)) {
1282                minChunkDuration = (*it);
1283            } else if (maxChunkDuration < (*it)) {
1284                maxChunkDuration = (*it);
1285            }
1286        }
1287    }
1288    *min = minChunkDuration;
1289    *max = maxChunkDuration;
1290}
1291
1292void MPEG4Writer::Track::logStatisticalData(bool isAudio) {
1293    if (mMaxTimeStampUs <= 0 || mSampleInfos.empty()) {
1294        LOGI("nothing is recorded");
1295        return;
1296    }
1297
1298    bool collectStats = false;
1299    char value[PROPERTY_VALUE_MAX];
1300    if (property_get("media.stagefright.record-stats", value, NULL)
1301        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
1302        collectStats = true;
1303    }
1304
1305    if (collectStats) {
1306        LOGI("%s track - duration %lld us, total %d frames",
1307                isAudio? "audio": "video", mMaxTimeStampUs,
1308                mSampleInfos.size());
1309        int32_t min, avg, max;
1310        findMinAvgMaxSampleDurationMs(&min, &avg, &max);
1311        LOGI("min/avg/max sample duration (ms): %d/%d/%d", min, avg, max);
1312        if (!isAudio) {
1313            float avgFps = 1000.0 / avg;
1314            float minFps = 1000.0 / max;
1315            float maxFps = 1000.0 / min;
1316            LOGI("min/avg/max frame rate (fps): %.2f/%.2f/%.2f",
1317                minFps, avgFps, maxFps);
1318        }
1319
1320        int64_t totalBytes = 0;
1321        for (List<SampleInfo>::iterator it = mSampleInfos.begin();
1322            it != mSampleInfos.end(); ++it) {
1323            totalBytes += it->size;
1324        }
1325        float bitRate = (totalBytes * 8000000.0) / mMaxTimeStampUs;
1326        LOGI("avg bit rate (bps): %.2f", bitRate);
1327
1328        int64_t duration = mOwner->interleaveDuration();
1329        if (duration != 0) {  // If interleaving is enabled
1330            int64_t minChunk, maxChunk;
1331            findMinMaxChunkDurations(&minChunk, &maxChunk);
1332            LOGI("min/avg/max chunk duration (ms): %lld/%lld/%lld",
1333                minChunk, duration, maxChunk);
1334        }
1335    }
1336}
1337
1338void MPEG4Writer::Track::writeOneChunk(bool isAvc) {
1339    mOwner->lock();
1340    for (List<MediaBuffer *>::iterator it = mChunkSamples.begin();
1341         it != mChunkSamples.end(); ++it) {
1342        off_t offset = isAvc? mOwner->addLengthPrefixedSample_l(*it)
1343                            : mOwner->addSample_l(*it);
1344        if (it == mChunkSamples.begin()) {
1345            mChunkOffsets.push_back(offset);
1346        }
1347    }
1348    mOwner->unlock();
1349    while (!mChunkSamples.empty()) {
1350        List<MediaBuffer *>::iterator it = mChunkSamples.begin();
1351        (*it)->release();
1352        (*it) = NULL;
1353        mChunkSamples.erase(it);
1354    }
1355    mChunkSamples.clear();
1356}
1357
1358int64_t MPEG4Writer::Track::getDurationUs() const {
1359    return mMaxTimeStampUs;
1360}
1361
1362int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
1363    return mEstimatedTrackSizeBytes;
1364}
1365
1366void MPEG4Writer::Track::writeTrackHeader(
1367        int32_t trackID, bool use32BitOffset) {
1368    const char *mime;
1369    bool success = mMeta->findCString(kKeyMIMEType, &mime);
1370    CHECK(success);
1371
1372    bool is_audio = !strncasecmp(mime, "audio/", 6);
1373    int32_t timeScale = 1000;
1374    int32_t duration = getDurationUs() / timeScale;
1375
1376    time_t now = time(NULL);
1377
1378    mOwner->beginBox("trak");
1379
1380      mOwner->beginBox("tkhd");
1381        // Flags = 7 to indicate that the track is enabled, and
1382        // part of the presentation
1383        mOwner->writeInt32(0x07);          // version=0, flags=7
1384        mOwner->writeInt32(now);           // creation time
1385        mOwner->writeInt32(now);           // modification time
1386        mOwner->writeInt32(trackID);
1387        mOwner->writeInt32(0);             // reserved
1388        mOwner->writeInt32(duration);
1389        mOwner->writeInt32(0);             // reserved
1390        mOwner->writeInt32(0);             // reserved
1391        mOwner->writeInt16(0);             // layer
1392        mOwner->writeInt16(0);             // alternate group
1393        mOwner->writeInt16(is_audio ? 0x100 : 0);  // volume
1394        mOwner->writeInt16(0);             // reserved
1395
1396        mOwner->writeInt32(0x10000);       // matrix
1397        mOwner->writeInt32(0);
1398        mOwner->writeInt32(0);
1399        mOwner->writeInt32(0);
1400        mOwner->writeInt32(0x10000);
1401        mOwner->writeInt32(0);
1402        mOwner->writeInt32(0);
1403        mOwner->writeInt32(0);
1404        mOwner->writeInt32(0x40000000);
1405
1406        if (is_audio) {
1407            mOwner->writeInt32(0);
1408            mOwner->writeInt32(0);
1409        } else {
1410            int32_t width, height;
1411            bool success = mMeta->findInt32(kKeyWidth, &width);
1412            success = success && mMeta->findInt32(kKeyHeight, &height);
1413            CHECK(success);
1414
1415            mOwner->writeInt32(width << 16);   // 32-bit fixed-point value
1416            mOwner->writeInt32(height << 16);  // 32-bit fixed-point value
1417        }
1418      mOwner->endBox();  // tkhd
1419
1420      int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
1421      if (mStartTimestampUs != moovStartTimeUs) {
1422        mOwner->beginBox("edts");
1423          mOwner->beginBox("elst");
1424            mOwner->writeInt32(0);           // version=0, flags=0: 32-bit time
1425            mOwner->writeInt32(2);           // never ends with an empty list
1426            int64_t durationMs =
1427                (mStartTimestampUs - moovStartTimeUs) / 1000;
1428            mOwner->writeInt32(durationMs);  // edit duration
1429            mOwner->writeInt32(-1);          // empty edit box to signal starting time offset
1430            mOwner->writeInt32(1 << 16);     // x1 rate
1431            mOwner->writeInt32(duration);
1432            mOwner->writeInt32(0);
1433            mOwner->writeInt32(1 << 16);
1434          mOwner->endBox();
1435        mOwner->endBox();
1436      }
1437
1438      mOwner->beginBox("mdia");
1439
1440        mOwner->beginBox("mdhd");
1441          mOwner->writeInt32(0);             // version=0, flags=0
1442          mOwner->writeInt32(now);           // creation time
1443          mOwner->writeInt32(now);           // modification time
1444          mOwner->writeInt32(timeScale);     // timescale
1445          mOwner->writeInt32(duration);      // duration
1446          // Language follows the three letter standard ISO-639-2/T
1447          // 'e', 'n', 'g' for "English", for instance.
1448          // Each character is packed as the difference between its ASCII value and 0x60.
1449          // For "English", these are 00101, 01110, 00111.
1450          // XXX: Where is the padding bit located: 0x15C7?
1451          mOwner->writeInt16(0);             // language code
1452          mOwner->writeInt16(0);             // predefined
1453        mOwner->endBox();
1454
1455        mOwner->beginBox("hdlr");
1456          mOwner->writeInt32(0);             // version=0, flags=0
1457          mOwner->writeInt32(0);             // component type: should be mhlr
1458          mOwner->writeFourcc(is_audio ? "soun" : "vide");  // component subtype
1459          mOwner->writeInt32(0);             // reserved
1460          mOwner->writeInt32(0);             // reserved
1461          mOwner->writeInt32(0);             // reserved
1462          // Removing "r" for the name string just makes the string 4 byte aligned
1463          mOwner->writeCString(is_audio ? "SoundHandle": "VideoHandle");  // name
1464        mOwner->endBox();
1465
1466        mOwner->beginBox("minf");
1467          if (is_audio) {
1468              mOwner->beginBox("smhd");
1469              mOwner->writeInt32(0);           // version=0, flags=0
1470              mOwner->writeInt16(0);           // balance
1471              mOwner->writeInt16(0);           // reserved
1472              mOwner->endBox();
1473          } else {
1474              mOwner->beginBox("vmhd");
1475              mOwner->writeInt32(0x01);        // version=0, flags=1
1476              mOwner->writeInt16(0);           // graphics mode
1477              mOwner->writeInt16(0);           // opcolor
1478              mOwner->writeInt16(0);
1479              mOwner->writeInt16(0);
1480              mOwner->endBox();
1481          }
1482
1483          mOwner->beginBox("dinf");
1484            mOwner->beginBox("dref");
1485              mOwner->writeInt32(0);  // version=0, flags=0
1486              mOwner->writeInt32(1);  // entry count (either url or urn)
1487              // The table index here refers to the sample description index
1488              // in the sample table entries.
1489              mOwner->beginBox("url ");
1490                mOwner->writeInt32(1);  // version=0, flags=1 (self-contained)
1491              mOwner->endBox();  // url
1492            mOwner->endBox();  // dref
1493          mOwner->endBox();  // dinf
1494
1495        mOwner->beginBox("stbl");
1496
1497          mOwner->beginBox("stsd");
1498            mOwner->writeInt32(0);               // version=0, flags=0
1499            mOwner->writeInt32(1);               // entry count
1500            if (is_audio) {
1501                const char *fourcc = NULL;
1502                if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
1503                    fourcc = "samr";
1504                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
1505                    fourcc = "sawb";
1506                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
1507                    fourcc = "mp4a";
1508                } else {
1509                    LOGE("Unknown mime type '%s'.", mime);
1510                    CHECK(!"should not be here, unknown mime type.");
1511                }
1512
1513                mOwner->beginBox(fourcc);          // audio format
1514                  mOwner->writeInt32(0);           // reserved
1515                  mOwner->writeInt16(0);           // reserved
1516                  mOwner->writeInt16(0x1);         // data ref index
1517                  mOwner->writeInt32(0);           // reserved
1518                  mOwner->writeInt32(0);           // reserved
1519                  int32_t nChannels;
1520                  CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels));
1521                  mOwner->writeInt16(nChannels);   // channel count
1522                  mOwner->writeInt16(16);          // sample size
1523                  mOwner->writeInt16(0);           // predefined
1524                  mOwner->writeInt16(0);           // reserved
1525
1526                  int32_t samplerate;
1527                  bool success = mMeta->findInt32(kKeySampleRate, &samplerate);
1528                  CHECK(success);
1529
1530                  mOwner->writeInt32(samplerate << 16);
1531                  if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
1532                    mOwner->beginBox("esds");
1533
1534                        mOwner->writeInt32(0);     // version=0, flags=0
1535                        mOwner->writeInt8(0x03);   // ES_DescrTag
1536                        mOwner->writeInt8(23 + mCodecSpecificDataSize);
1537                        mOwner->writeInt16(0x0000);// ES_ID
1538                        mOwner->writeInt8(0x00);
1539
1540                        mOwner->writeInt8(0x04);   // DecoderConfigDescrTag
1541                        mOwner->writeInt8(15 + mCodecSpecificDataSize);
1542                        mOwner->writeInt8(0x40);   // objectTypeIndication ISO/IEC 14492-2
1543                        mOwner->writeInt8(0x15);   // streamType AudioStream
1544
1545                        mOwner->writeInt16(0x03);  // XXX
1546                        mOwner->writeInt8(0x00);   // buffer size 24-bit
1547                        mOwner->writeInt32(96000); // max bit rate
1548                        mOwner->writeInt32(96000); // avg bit rate
1549
1550                        mOwner->writeInt8(0x05);   // DecoderSpecificInfoTag
1551                        mOwner->writeInt8(mCodecSpecificDataSize);
1552                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
1553
1554                        static const uint8_t kData2[] = {
1555                            0x06,  // SLConfigDescriptorTag
1556                            0x01,
1557                            0x02
1558                        };
1559                        mOwner->write(kData2, sizeof(kData2));
1560
1561                    mOwner->endBox();  // esds
1562                  }
1563                mOwner->endBox();
1564            } else {
1565                if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
1566                    mOwner->beginBox("mp4v");
1567                } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
1568                    mOwner->beginBox("s263");
1569                } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
1570                    mOwner->beginBox("avc1");
1571                } else {
1572                    LOGE("Unknown mime type '%s'.", mime);
1573                    CHECK(!"should not be here, unknown mime type.");
1574                }
1575
1576                  mOwner->writeInt32(0);           // reserved
1577                  mOwner->writeInt16(0);           // reserved
1578                  mOwner->writeInt16(1);           // data ref index
1579                  mOwner->writeInt16(0);           // predefined
1580                  mOwner->writeInt16(0);           // reserved
1581                  mOwner->writeInt32(0);           // predefined
1582                  mOwner->writeInt32(0);           // predefined
1583                  mOwner->writeInt32(0);           // predefined
1584
1585                  int32_t width, height;
1586                  bool success = mMeta->findInt32(kKeyWidth, &width);
1587                  success = success && mMeta->findInt32(kKeyHeight, &height);
1588                  CHECK(success);
1589
1590                  mOwner->writeInt16(width);
1591                  mOwner->writeInt16(height);
1592                  mOwner->writeInt32(0x480000);    // horiz resolution
1593                  mOwner->writeInt32(0x480000);    // vert resolution
1594                  mOwner->writeInt32(0);           // reserved
1595                  mOwner->writeInt16(1);           // frame count
1596                  mOwner->write("                                ", 32);
1597                  mOwner->writeInt16(0x18);        // depth
1598                  mOwner->writeInt16(-1);          // predefined
1599
1600                  CHECK(23 + mCodecSpecificDataSize < 128);
1601
1602                  if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
1603                      mOwner->beginBox("esds");
1604
1605                        mOwner->writeInt32(0);           // version=0, flags=0
1606
1607                        mOwner->writeInt8(0x03);  // ES_DescrTag
1608                        mOwner->writeInt8(23 + mCodecSpecificDataSize);
1609                        mOwner->writeInt16(0x0000);  // ES_ID
1610                        mOwner->writeInt8(0x1f);
1611
1612                        mOwner->writeInt8(0x04);  // DecoderConfigDescrTag
1613                        mOwner->writeInt8(15 + mCodecSpecificDataSize);
1614                        mOwner->writeInt8(0x20);  // objectTypeIndication ISO/IEC 14492-2
1615                        mOwner->writeInt8(0x11);  // streamType VisualStream
1616
1617                        static const uint8_t kData[] = {
1618                            0x01, 0x77, 0x00,
1619                            0x00, 0x03, 0xe8, 0x00,
1620                            0x00, 0x03, 0xe8, 0x00
1621                        };
1622                        mOwner->write(kData, sizeof(kData));
1623
1624                        mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
1625
1626                        mOwner->writeInt8(mCodecSpecificDataSize);
1627                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
1628
1629                        static const uint8_t kData2[] = {
1630                            0x06,  // SLConfigDescriptorTag
1631                            0x01,
1632                            0x02
1633                        };
1634                        mOwner->write(kData2, sizeof(kData2));
1635
1636                      mOwner->endBox();  // esds
1637                  } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
1638                      mOwner->beginBox("d263");
1639
1640                          mOwner->writeInt32(0);  // vendor
1641                          mOwner->writeInt8(0);   // decoder version
1642                          mOwner->writeInt8(10);  // level: 10
1643                          mOwner->writeInt8(0);   // profile: 0
1644
1645                      mOwner->endBox();  // d263
1646                  } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
1647                      mOwner->beginBox("avcC");
1648                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
1649                      mOwner->endBox();  // avcC
1650                  }
1651
1652                  mOwner->beginBox("pasp");
1653                    // This is useful if the pixel is not square
1654                    mOwner->writeInt32(1 << 16);  // hspacing
1655                    mOwner->writeInt32(1 << 16);  // vspacing
1656                  mOwner->endBox();  // pasp
1657                mOwner->endBox();  // mp4v, s263 or avc1
1658            }
1659          mOwner->endBox();  // stsd
1660
1661          mOwner->beginBox("stts");
1662            mOwner->writeInt32(0);  // version=0, flags=0
1663            mOwner->writeInt32(mSttsTableEntries.size());
1664            for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
1665                 it != mSttsTableEntries.end(); ++it) {
1666                mOwner->writeInt32(it->sampleCount);
1667                mOwner->writeInt32(it->sampleDuration);
1668            }
1669          mOwner->endBox();  // stts
1670
1671          if (!is_audio) {
1672            mOwner->beginBox("stss");
1673              mOwner->writeInt32(0);  // version=0, flags=0
1674              mOwner->writeInt32(mStssTableEntries.size());  // number of sync frames
1675              for (List<int32_t>::iterator it = mStssTableEntries.begin();
1676                   it != mStssTableEntries.end(); ++it) {
1677                  mOwner->writeInt32(*it);
1678              }
1679            mOwner->endBox();  // stss
1680          }
1681
1682          mOwner->beginBox("stsz");
1683            mOwner->writeInt32(0);  // version=0, flags=0
1684            if (mSamplesHaveSameSize) {
1685                List<SampleInfo>::iterator it = mSampleInfos.begin();
1686                mOwner->writeInt32(it->size);  // default sample size
1687            } else {
1688                mOwner->writeInt32(0);
1689            }
1690            mOwner->writeInt32(mSampleInfos.size());
1691            if (!mSamplesHaveSameSize) {
1692                for (List<SampleInfo>::iterator it = mSampleInfos.begin();
1693                     it != mSampleInfos.end(); ++it) {
1694                    mOwner->writeInt32((*it).size);
1695                }
1696            }
1697          mOwner->endBox();  // stsz
1698
1699          mOwner->beginBox("stsc");
1700            mOwner->writeInt32(0);  // version=0, flags=0
1701            mOwner->writeInt32(mStscTableEntries.size());
1702            for (List<StscTableEntry>::iterator it = mStscTableEntries.begin();
1703                 it != mStscTableEntries.end(); ++it) {
1704                mOwner->writeInt32(it->firstChunk);
1705                mOwner->writeInt32(it->samplesPerChunk);
1706                mOwner->writeInt32(it->sampleDescriptionId);
1707            }
1708          mOwner->endBox();  // stsc
1709          mOwner->beginBox(use32BitOffset? "stco": "co64");
1710            mOwner->writeInt32(0);  // version=0, flags=0
1711            mOwner->writeInt32(mChunkOffsets.size());
1712            for (List<off_t>::iterator it = mChunkOffsets.begin();
1713                 it != mChunkOffsets.end(); ++it) {
1714                if (use32BitOffset) {
1715                    mOwner->writeInt32(static_cast<int32_t>(*it));
1716                } else {
1717                    mOwner->writeInt64((*it));
1718                }
1719            }
1720          mOwner->endBox();  // co64
1721
1722        mOwner->endBox();  // stbl
1723       mOwner->endBox();  // minf
1724      mOwner->endBox();  // mdia
1725    mOwner->endBox();  // trak
1726}
1727
1728}  // namespace android
1729