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