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