MPEG4Writer.cpp revision 065d1aff96818df54456053f1574aec8a234d0de
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 = -1;
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 || mStartTimestampUs > timeUs) {
565        mStartTimestampUs = timeUs;
566        LOGI("Earliest track starting time: %lld", mStartTimestampUs);
567    }
568}
569
570int64_t MPEG4Writer::getStartTimestampUs() {
571    LOGI("getStartTimestampUs: %lld", mStartTimestampUs);
572    Mutex::Autolock autoLock(mLock);
573    return mStartTimestampUs;
574}
575
576size_t MPEG4Writer::numTracks() {
577    Mutex::Autolock autolock(mLock);
578    return mTracks.size();
579}
580
581////////////////////////////////////////////////////////////////////////////////
582
583MPEG4Writer::Track::Track(
584        MPEG4Writer *owner, const sp<MediaSource> &source)
585    : mOwner(owner),
586      mMeta(source->getFormat()),
587      mSource(source),
588      mDone(false),
589      mPaused(false),
590      mResumed(false),
591      mMaxTimeStampUs(0),
592      mEstimatedTrackSizeBytes(0),
593      mSamplesHaveSameSize(true),
594      mCodecSpecificData(NULL),
595      mCodecSpecificDataSize(0),
596      mGotAllCodecSpecificData(false),
597      mReachedEOS(false) {
598}
599
600MPEG4Writer::Track::~Track() {
601    stop();
602
603    if (mCodecSpecificData != NULL) {
604        free(mCodecSpecificData);
605        mCodecSpecificData = NULL;
606    }
607}
608
609status_t MPEG4Writer::Track::start(int64_t startTimeUs) {
610    if (!mDone && mPaused) {
611        mPaused = false;
612        mResumed = true;
613        return OK;
614    }
615
616    sp<MetaData> meta = new MetaData;
617    meta->setInt64(kKeyTime, startTimeUs);
618    status_t err = mSource->start(meta.get());
619    if (err != OK) {
620        mDone = mReachedEOS = true;
621        return err;
622    }
623
624    pthread_attr_t attr;
625    pthread_attr_init(&attr);
626    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
627
628    mDone = false;
629    mMaxTimeStampUs = 0;
630    mReachedEOS = false;
631    mEstimatedTrackSizeBytes = 0;
632
633    pthread_create(&mThread, &attr, ThreadWrapper, this);
634    pthread_attr_destroy(&attr);
635
636    return OK;
637}
638
639void MPEG4Writer::Track::pause() {
640    mPaused = true;
641}
642
643void MPEG4Writer::Track::stop() {
644    if (mDone) {
645        return;
646    }
647
648    mDone = true;
649
650    void *dummy;
651    pthread_join(mThread, &dummy);
652
653    mSource->stop();
654}
655
656bool MPEG4Writer::Track::reachedEOS() {
657    return mReachedEOS;
658}
659
660// static
661void *MPEG4Writer::Track::ThreadWrapper(void *me) {
662    Track *track = static_cast<Track *>(me);
663
664    track->threadEntry();
665
666    return NULL;
667}
668
669#include <ctype.h>
670static void hexdump(const void *_data, size_t size) {
671    const uint8_t *data = (const uint8_t *)_data;
672    size_t offset = 0;
673    while (offset < size) {
674        printf("0x%04x  ", offset);
675
676        size_t n = size - offset;
677        if (n > 16) {
678            n = 16;
679        }
680
681        for (size_t i = 0; i < 16; ++i) {
682            if (i == 8) {
683                printf(" ");
684            }
685
686            if (offset + i < size) {
687                printf("%02x ", data[offset + i]);
688            } else {
689                printf("   ");
690            }
691        }
692
693        printf(" ");
694
695        for (size_t i = 0; i < n; ++i) {
696            if (isprint(data[offset + i])) {
697                printf("%c", data[offset + i]);
698            } else {
699                printf(".");
700            }
701        }
702
703        printf("\n");
704
705        offset += 16;
706    }
707}
708
709
710status_t MPEG4Writer::Track::makeAVCCodecSpecificData(
711        const uint8_t *data, size_t size) {
712    // hexdump(data, size);
713
714    if (mCodecSpecificData != NULL) {
715        LOGE("Already have codec specific data");
716        return ERROR_MALFORMED;
717    }
718
719    if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) {
720        LOGE("Must start with a start code");
721        return ERROR_MALFORMED;
722    }
723
724    size_t picParamOffset = 4;
725    while (picParamOffset + 3 < size
726            && memcmp("\x00\x00\x00\x01", &data[picParamOffset], 4)) {
727        ++picParamOffset;
728    }
729
730    if (picParamOffset + 3 >= size) {
731        LOGE("Could not find start-code for pictureParameterSet");
732        return ERROR_MALFORMED;
733    }
734
735    size_t seqParamSetLength = picParamOffset - 4;
736    size_t picParamSetLength = size - picParamOffset - 4;
737
738    mCodecSpecificDataSize =
739        6 + 1 + seqParamSetLength + 2 + picParamSetLength + 2;
740
741    mCodecSpecificData = malloc(mCodecSpecificDataSize);
742    uint8_t *header = (uint8_t *)mCodecSpecificData;
743    header[0] = 1;
744    header[1] = 0x42;  // profile
745    header[2] = 0x80;
746    header[3] = 0x1e;  // level
747
748#if USE_NALLEN_FOUR
749    header[4] = 0xfc | 3;  // length size == 4 bytes
750#else
751    header[4] = 0xfc | 1;  // length size == 2 bytes
752#endif
753
754    header[5] = 0xe0 | 1;
755    header[6] = seqParamSetLength >> 8;
756    header[7] = seqParamSetLength & 0xff;
757    memcpy(&header[8], &data[4], seqParamSetLength);
758    header += 8 + seqParamSetLength;
759    header[0] = 1;
760    header[1] = picParamSetLength >> 8;
761    header[2] = picParamSetLength & 0xff;
762    memcpy(&header[3], &data[picParamOffset + 4], picParamSetLength);
763
764    return OK;
765}
766
767void MPEG4Writer::Track::threadEntry() {
768    sp<MetaData> meta = mSource->getFormat();
769    const char *mime;
770    meta->findCString(kKeyMIMEType, &mime);
771    bool is_mpeg4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
772                    !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
773    bool is_avc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
774    bool is_audio = !strncasecmp(mime, "audio/", 6);
775    int32_t count = 0;
776    const int64_t interleaveDurationUs = mOwner->interleaveDuration();
777    int64_t chunkTimestampUs = 0;
778    int32_t nChunks = 0;
779    int32_t nZeroLengthFrames = 0;
780    int64_t lastTimestamp = 0;  // Timestamp of the previous sample
781    int64_t lastDuration = 0;   // Time spacing between the previous two samples
782    int32_t sampleCount = 1;    // Sample count in the current stts table entry
783    uint32_t previousSampleSize = 0;  // Size of the previous sample
784    int64_t previousPausedDurationUs = 0;
785    sp<MetaData> meta_data;
786
787    MediaBuffer *buffer;
788    while (!mDone && mSource->read(&buffer) == OK) {
789        if (buffer->range_length() == 0) {
790            buffer->release();
791            buffer = NULL;
792            ++nZeroLengthFrames;
793            continue;
794        }
795
796        // If the codec specific data has not been received yet, delay pause.
797        // After the codec specific data is received, discard what we received
798        // when the track is to be paused.
799        if (mPaused && !mResumed) {
800            buffer->release();
801            buffer = NULL;
802            continue;
803        }
804
805        ++count;
806
807        int32_t isCodecConfig;
808        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
809                && isCodecConfig) {
810            CHECK(!mGotAllCodecSpecificData);
811
812            if (is_avc) {
813                status_t err = makeAVCCodecSpecificData(
814                        (const uint8_t *)buffer->data()
815                            + buffer->range_offset(),
816                        buffer->range_length());
817                CHECK_EQ(OK, err);
818            } else if (is_mpeg4) {
819                mCodecSpecificDataSize = buffer->range_length();
820                mCodecSpecificData = malloc(mCodecSpecificDataSize);
821                memcpy(mCodecSpecificData,
822                        (const uint8_t *)buffer->data()
823                            + buffer->range_offset(),
824                       buffer->range_length());
825            }
826
827            buffer->release();
828            buffer = NULL;
829
830            mGotAllCodecSpecificData = true;
831            continue;
832        } else if (!mGotAllCodecSpecificData &&
833                count == 1 && is_mpeg4 && mCodecSpecificData == NULL) {
834            // The TI mpeg4 encoder does not properly set the
835            // codec-specific-data flag.
836
837            const uint8_t *data =
838                (const uint8_t *)buffer->data() + buffer->range_offset();
839
840            const size_t size = buffer->range_length();
841
842            size_t offset = 0;
843            while (offset + 3 < size) {
844                if (data[offset] == 0x00 && data[offset + 1] == 0x00
845                    && data[offset + 2] == 0x01 && data[offset + 3] == 0xb6) {
846                    break;
847                }
848
849                ++offset;
850            }
851
852            // CHECK(offset + 3 < size);
853            if (offset + 3 >= size) {
854                // XXX assume the entire first chunk of data is the codec specific
855                // data.
856                offset = size;
857            }
858
859            mCodecSpecificDataSize = offset;
860            mCodecSpecificData = malloc(offset);
861            memcpy(mCodecSpecificData, data, offset);
862
863            buffer->set_range(buffer->range_offset() + offset, size - offset);
864
865            if (size == offset) {
866                buffer->release();
867                buffer = NULL;
868
869                continue;
870            }
871
872            mGotAllCodecSpecificData = true;
873        } else if (!mGotAllCodecSpecificData && is_avc && count < 3) {
874            // The TI video encoder does not flag codec specific data
875            // as such and also splits up SPS and PPS across two buffers.
876
877            const uint8_t *data =
878                (const uint8_t *)buffer->data() + buffer->range_offset();
879
880            size_t size = buffer->range_length();
881
882            CHECK(count == 2 || mCodecSpecificData == NULL);
883
884            size_t offset = mCodecSpecificDataSize;
885            mCodecSpecificDataSize += size + 4;
886            mCodecSpecificData =
887                realloc(mCodecSpecificData, mCodecSpecificDataSize);
888
889            memcpy((uint8_t *)mCodecSpecificData + offset,
890                   "\x00\x00\x00\x01", 4);
891
892            memcpy((uint8_t *)mCodecSpecificData + offset + 4, data, size);
893
894            buffer->release();
895            buffer = NULL;
896
897            if (count == 2) {
898                void *tmp = mCodecSpecificData;
899                size = mCodecSpecificDataSize;
900                mCodecSpecificData = NULL;
901                mCodecSpecificDataSize = 0;
902
903                status_t err = makeAVCCodecSpecificData(
904                        (const uint8_t *)tmp, size);
905                free(tmp);
906                tmp = NULL;
907                CHECK_EQ(OK, err);
908
909                mGotAllCodecSpecificData = true;
910            }
911
912            continue;
913        }
914
915        if (!mGotAllCodecSpecificData) {
916            mGotAllCodecSpecificData = true;
917        }
918
919        // Make a deep copy of the MediaBuffer and Metadata and release
920        // the original as soon as we can
921        MediaBuffer *copy = new MediaBuffer(buffer->range_length());
922        memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(),
923                buffer->range_length());
924        copy->set_range(0, buffer->range_length());
925        meta_data = new MetaData(*buffer->meta_data().get());
926        buffer->release();
927        buffer = NULL;
928
929        if (is_avc) StripStartcode(copy);
930
931        SampleInfo info;
932        info.size = is_avc
933#if USE_NALLEN_FOUR
934                ? copy->range_length() + 4
935#else
936                ? copy->range_length() + 2
937#endif
938                : copy->range_length();
939
940        // Max file size or duration handling
941        mEstimatedTrackSizeBytes += info.size;
942        if (mOwner->exceedsFileSizeLimit()) {
943            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
944            break;
945        }
946        if (mOwner->exceedsFileDurationLimit()) {
947            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
948            break;
949        }
950
951
952        int32_t isSync = false;
953        meta_data->findInt32(kKeyIsSyncFrame, &isSync);
954
955        int64_t timestampUs;
956        CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
957
958////////////////////////////////////////////////////////////////////////////////
959        if (mSampleInfos.empty()) {
960            mStartTimestampUs = timestampUs;
961            mOwner->setStartTimestampUs(mStartTimestampUs);
962        }
963
964        if (mResumed) {
965            previousPausedDurationUs += (timestampUs - mMaxTimeStampUs - 1000 * lastDuration);
966            mResumed = false;
967        }
968
969        timestampUs -= previousPausedDurationUs;
970        LOGV("time stamp: %lld and previous paused duration %lld",
971                timestampUs, previousPausedDurationUs);
972        if (timestampUs > mMaxTimeStampUs) {
973            mMaxTimeStampUs = timestampUs;
974        }
975
976        // Our timestamp is in ms.
977        info.timestamp = (timestampUs + 500) / 1000;
978        mSampleInfos.push_back(info);
979        if (mSampleInfos.size() > 2) {
980            if (lastDuration != info.timestamp - lastTimestamp) {
981                SttsTableEntry sttsEntry(sampleCount, lastDuration);
982                mSttsTableEntries.push_back(sttsEntry);
983                sampleCount = 1;
984            } else {
985                ++sampleCount;
986            }
987        }
988        if (mSamplesHaveSameSize) {
989            if (mSampleInfos.size() >= 2 && previousSampleSize != info.size) {
990                mSamplesHaveSameSize = false;
991            }
992            previousSampleSize = info.size;
993        }
994        lastDuration = info.timestamp - lastTimestamp;
995        lastTimestamp = info.timestamp;
996
997        if (isSync != 0) {
998            mStssTableEntries.push_back(mSampleInfos.size());
999        }
1000
1001        if (mOwner->numTracks() == 1) {
1002            off_t offset = is_avc? mOwner->addLengthPrefixedSample_l(copy)
1003                                 : mOwner->addSample_l(copy);
1004            if (mChunkOffsets.empty()) {
1005                mChunkOffsets.push_back(offset);
1006            }
1007            copy->release();
1008            copy = NULL;
1009            continue;
1010        }
1011
1012        mChunkSamples.push_back(copy);
1013        if (interleaveDurationUs == 0) {
1014            StscTableEntry stscEntry(++nChunks, 1, 1);
1015            mStscTableEntries.push_back(stscEntry);
1016            writeOneChunk(is_avc);
1017        } else {
1018            if (chunkTimestampUs == 0) {
1019                chunkTimestampUs = timestampUs;
1020            } else {
1021                if (timestampUs - chunkTimestampUs > interleaveDurationUs) {
1022                    ++nChunks;
1023                    mChunkDurations.push_back(timestampUs - chunkTimestampUs);
1024                    if (nChunks == 1 ||  // First chunk
1025                        (--(mStscTableEntries.end()))->samplesPerChunk !=
1026                         mChunkSamples.size()) {
1027                        StscTableEntry stscEntry(nChunks,
1028                                mChunkSamples.size(), 1);
1029                        mStscTableEntries.push_back(stscEntry);
1030                    }
1031                    writeOneChunk(is_avc);
1032                    chunkTimestampUs = timestampUs;
1033                }
1034            }
1035        }
1036
1037    }
1038
1039    if (mSampleInfos.empty()) {
1040        mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_STOP_PREMATURELY, 0);
1041    }
1042
1043    // Last chunk
1044    if (mOwner->numTracks() == 1) {
1045        StscTableEntry stscEntry(1, mSampleInfos.size(), 1);
1046        mStscTableEntries.push_back(stscEntry);
1047    } else if (!mChunkSamples.empty()) {
1048        ++nChunks;
1049        StscTableEntry stscEntry(nChunks, mChunkSamples.size(), 1);
1050        mStscTableEntries.push_back(stscEntry);
1051        writeOneChunk(is_avc);
1052    }
1053
1054    // We don't really know how long the last frame lasts, since
1055    // there is no frame time after it, just repeat the previous
1056    // frame's duration.
1057    if (mSampleInfos.size() == 1) {
1058        lastDuration = 0;  // A single sample's duration
1059    } else {
1060        ++sampleCount;  // Count for the last sample
1061    }
1062    SttsTableEntry sttsEntry(sampleCount, lastDuration);
1063    mSttsTableEntries.push_back(sttsEntry);
1064    mReachedEOS = true;
1065    LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames - %s",
1066            count, nZeroLengthFrames, mSampleInfos.size(), is_audio? "audio": "video");
1067
1068    logStatisticalData(is_audio);
1069}
1070
1071void MPEG4Writer::Track::findMinMaxFrameRates(float *minFps, float *maxFps) {
1072    int32_t minSampleDuration = 0x7FFFFFFF;
1073    int32_t maxSampleDuration = 0;
1074    for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
1075        it != mSttsTableEntries.end(); ++it) {
1076        int32_t sampleDuration = static_cast<int32_t>(it->sampleDuration);
1077        if (sampleDuration > maxSampleDuration) {
1078            maxSampleDuration = sampleDuration;
1079        } else if (sampleDuration < minSampleDuration) {
1080            minSampleDuration = sampleDuration;
1081        }
1082    }
1083    CHECK(minSampleDuration != 0 && maxSampleDuration != 0);
1084    *minFps = 1000.0 / maxSampleDuration;
1085    *maxFps = 1000.0 / minSampleDuration;
1086}
1087
1088// Don't count the last duration
1089void MPEG4Writer::Track::findMinMaxChunkDurations(int64_t *min, int64_t *max) {
1090    int64_t duration = mOwner->interleaveDuration();
1091    int64_t minChunkDuration = duration;
1092    int64_t maxChunkDuration = duration;
1093    if (mChunkDurations.size() > 1) {
1094        for (List<int64_t>::iterator it = mChunkDurations.begin();
1095            it != --mChunkDurations.end(); ++it) {
1096            if (minChunkDuration > (*it)) {
1097                minChunkDuration = (*it);
1098            } else if (maxChunkDuration < (*it)) {
1099                maxChunkDuration = (*it);
1100            }
1101        }
1102    }
1103    *min = minChunkDuration;
1104    *max = maxChunkDuration;
1105}
1106
1107void MPEG4Writer::Track::logStatisticalData(bool isAudio) {
1108    if (mMaxTimeStampUs <= 0 || mSampleInfos.empty()) {
1109        LOGI("nothing is recorded");
1110        return;
1111    }
1112
1113    bool collectStats = false;
1114    char value[PROPERTY_VALUE_MAX];
1115    if (property_get("media.stagefright.record-stats", value, NULL)
1116        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
1117        collectStats = true;
1118    }
1119
1120    if (collectStats) {
1121        if (isAudio) {
1122            LOGI("audio track - duration %lld us", mMaxTimeStampUs);
1123        } else {
1124            float fps = (mSampleInfos.size() * 1000000.0) / mMaxTimeStampUs;
1125            float minFps;
1126            float maxFps;
1127            findMinMaxFrameRates(&minFps, &maxFps);
1128            LOGI("video track - duration %lld us", mMaxTimeStampUs);
1129            LOGI("min/avg/max frame rate (fps): %.2f/%.2f/%.2f",
1130                minFps, fps, maxFps);
1131        }
1132
1133        int64_t totalBytes = 0;
1134        for (List<SampleInfo>::iterator it = mSampleInfos.begin();
1135            it != mSampleInfos.end(); ++it) {
1136            totalBytes += it->size;
1137        }
1138        float bitRate = (totalBytes * 8000000.0) / mMaxTimeStampUs;
1139        LOGI("avg bit rate (bps): %.2f", bitRate);
1140
1141        int64_t duration = mOwner->interleaveDuration();
1142        if (duration != 0) {  // If interleaving is enabled
1143            int64_t minChunk, maxChunk;
1144            findMinMaxChunkDurations(&minChunk, &maxChunk);
1145            LOGI("min/avg/max chunk duration (ms): %lld/%lld/%lld",
1146                minChunk, duration, maxChunk);
1147        }
1148    }
1149}
1150
1151void MPEG4Writer::Track::writeOneChunk(bool isAvc) {
1152    mOwner->lock();
1153    for (List<MediaBuffer *>::iterator it = mChunkSamples.begin();
1154         it != mChunkSamples.end(); ++it) {
1155        off_t offset = isAvc? mOwner->addLengthPrefixedSample_l(*it)
1156                            : mOwner->addSample_l(*it);
1157        if (it == mChunkSamples.begin()) {
1158            mChunkOffsets.push_back(offset);
1159        }
1160    }
1161    mOwner->unlock();
1162    while (!mChunkSamples.empty()) {
1163        List<MediaBuffer *>::iterator it = mChunkSamples.begin();
1164        (*it)->release();
1165        (*it) = NULL;
1166        mChunkSamples.erase(it);
1167    }
1168    mChunkSamples.clear();
1169}
1170
1171int64_t MPEG4Writer::Track::getDurationUs() const {
1172    return mMaxTimeStampUs;
1173}
1174
1175int64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
1176    return mEstimatedTrackSizeBytes;
1177}
1178
1179void MPEG4Writer::Track::writeTrackHeader(
1180        int32_t trackID, bool use32BitOffset) {
1181    const char *mime;
1182    bool success = mMeta->findCString(kKeyMIMEType, &mime);
1183    CHECK(success);
1184
1185    bool is_audio = !strncasecmp(mime, "audio/", 6);
1186    int32_t timeScale = 1000;
1187    int32_t duration = getDurationUs() / timeScale;
1188
1189    time_t now = time(NULL);
1190
1191    mOwner->beginBox("trak");
1192
1193      mOwner->beginBox("tkhd");
1194        // Flags = 7 to indicate that the track is enabled, and
1195        // part of the presentation
1196        mOwner->writeInt32(0x07);          // version=0, flags=7
1197        mOwner->writeInt32(now);           // creation time
1198        mOwner->writeInt32(now);           // modification time
1199        mOwner->writeInt32(trackID);
1200        mOwner->writeInt32(0);             // reserved
1201        mOwner->writeInt32(duration);
1202        mOwner->writeInt32(0);             // reserved
1203        mOwner->writeInt32(0);             // reserved
1204        mOwner->writeInt16(0);             // layer
1205        mOwner->writeInt16(0);             // alternate group
1206        mOwner->writeInt16(is_audio ? 0x100 : 0);  // volume
1207        mOwner->writeInt16(0);             // reserved
1208
1209        mOwner->writeInt32(0x10000);       // matrix
1210        mOwner->writeInt32(0);
1211        mOwner->writeInt32(0);
1212        mOwner->writeInt32(0);
1213        mOwner->writeInt32(0x10000);
1214        mOwner->writeInt32(0);
1215        mOwner->writeInt32(0);
1216        mOwner->writeInt32(0);
1217        mOwner->writeInt32(0x40000000);
1218
1219        if (is_audio) {
1220            mOwner->writeInt32(0);
1221            mOwner->writeInt32(0);
1222        } else {
1223            int32_t width, height;
1224            bool success = mMeta->findInt32(kKeyWidth, &width);
1225            success = success && mMeta->findInt32(kKeyHeight, &height);
1226            CHECK(success);
1227
1228            mOwner->writeInt32(width << 16);   // 32-bit fixed-point value
1229            mOwner->writeInt32(height << 16);  // 32-bit fixed-point value
1230        }
1231      mOwner->endBox();  // tkhd
1232
1233      int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
1234      if (mStartTimestampUs != moovStartTimeUs) {
1235        mOwner->beginBox("edts");
1236          mOwner->beginBox("elst");
1237            mOwner->writeInt32(0);           // version=0, flags=0: 32-bit time
1238            mOwner->writeInt32(2);           // never ends with an empty list
1239            int64_t durationMs =
1240                (mStartTimestampUs - moovStartTimeUs) / 1000;
1241            mOwner->writeInt32(durationMs);  // edit duration
1242            mOwner->writeInt32(-1);          // empty edit box to signal starting time offset
1243            mOwner->writeInt32(1 << 16);     // x1 rate
1244            mOwner->writeInt32(duration);
1245            mOwner->writeInt32(0);
1246            mOwner->writeInt32(1 << 16);
1247          mOwner->endBox();
1248        mOwner->endBox();
1249      }
1250
1251      mOwner->beginBox("mdia");
1252
1253        mOwner->beginBox("mdhd");
1254          mOwner->writeInt32(0);             // version=0, flags=0
1255          mOwner->writeInt32(now);           // creation time
1256          mOwner->writeInt32(now);           // modification time
1257          mOwner->writeInt32(timeScale);     // timescale
1258          mOwner->writeInt32(duration);      // duration
1259          // Language follows the three letter standard ISO-639-2/T
1260          // 'e', 'n', 'g' for "English", for instance.
1261          // Each character is packed as the difference between its ASCII value and 0x60.
1262          // For "English", these are 00101, 01110, 00111.
1263          // XXX: Where is the padding bit located: 0x15C7?
1264          mOwner->writeInt16(0);             // language code
1265          mOwner->writeInt16(0);             // predefined
1266        mOwner->endBox();
1267
1268        mOwner->beginBox("hdlr");
1269          mOwner->writeInt32(0);             // version=0, flags=0
1270          mOwner->writeInt32(0);             // component type: should be mhlr
1271          mOwner->writeFourcc(is_audio ? "soun" : "vide");  // component subtype
1272          mOwner->writeInt32(0);             // reserved
1273          mOwner->writeInt32(0);             // reserved
1274          mOwner->writeInt32(0);             // reserved
1275          // Removing "r" for the name string just makes the string 4 byte aligned
1276          mOwner->writeCString(is_audio ? "SoundHandle": "VideoHandle");  // name
1277        mOwner->endBox();
1278
1279        mOwner->beginBox("minf");
1280          if (is_audio) {
1281              mOwner->beginBox("smhd");
1282              mOwner->writeInt32(0);           // version=0, flags=0
1283              mOwner->writeInt16(0);           // balance
1284              mOwner->writeInt16(0);           // reserved
1285              mOwner->endBox();
1286          } else {
1287              mOwner->beginBox("vmhd");
1288              mOwner->writeInt32(0x01);        // version=0, flags=1
1289              mOwner->writeInt16(0);           // graphics mode
1290              mOwner->writeInt16(0);           // opcolor
1291              mOwner->writeInt16(0);
1292              mOwner->writeInt16(0);
1293              mOwner->endBox();
1294          }
1295
1296          mOwner->beginBox("dinf");
1297            mOwner->beginBox("dref");
1298              mOwner->writeInt32(0);  // version=0, flags=0
1299              mOwner->writeInt32(1);  // entry count (either url or urn)
1300              // The table index here refers to the sample description index
1301              // in the sample table entries.
1302              mOwner->beginBox("url ");
1303                mOwner->writeInt32(1);  // version=0, flags=1 (self-contained)
1304              mOwner->endBox();  // url
1305            mOwner->endBox();  // dref
1306          mOwner->endBox();  // dinf
1307
1308        mOwner->beginBox("stbl");
1309
1310          mOwner->beginBox("stsd");
1311            mOwner->writeInt32(0);               // version=0, flags=0
1312            mOwner->writeInt32(1);               // entry count
1313            if (is_audio) {
1314                const char *fourcc = NULL;
1315                if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
1316                    fourcc = "samr";
1317                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
1318                    fourcc = "sawb";
1319                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
1320                    fourcc = "mp4a";
1321                } else {
1322                    LOGE("Unknown mime type '%s'.", mime);
1323                    CHECK(!"should not be here, unknown mime type.");
1324                }
1325
1326                mOwner->beginBox(fourcc);          // audio format
1327                  mOwner->writeInt32(0);           // reserved
1328                  mOwner->writeInt16(0);           // reserved
1329                  mOwner->writeInt16(0x1);         // data ref index
1330                  mOwner->writeInt32(0);           // reserved
1331                  mOwner->writeInt32(0);           // reserved
1332                  int32_t nChannels;
1333                  CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels));
1334                  mOwner->writeInt16(nChannels);   // channel count
1335                  mOwner->writeInt16(16);          // sample size
1336                  mOwner->writeInt16(0);           // predefined
1337                  mOwner->writeInt16(0);           // reserved
1338
1339                  int32_t samplerate;
1340                  bool success = mMeta->findInt32(kKeySampleRate, &samplerate);
1341                  CHECK(success);
1342
1343                  mOwner->writeInt32(samplerate << 16);
1344                  if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
1345                    mOwner->beginBox("esds");
1346
1347                        mOwner->writeInt32(0);     // version=0, flags=0
1348                        mOwner->writeInt8(0x03);   // ES_DescrTag
1349                        mOwner->writeInt8(23 + mCodecSpecificDataSize);
1350                        mOwner->writeInt16(0x0000);// ES_ID
1351                        mOwner->writeInt8(0x00);
1352
1353                        mOwner->writeInt8(0x04);   // DecoderConfigDescrTag
1354                        mOwner->writeInt8(15 + mCodecSpecificDataSize);
1355                        mOwner->writeInt8(0x40);   // objectTypeIndication ISO/IEC 14492-2
1356                        mOwner->writeInt8(0x15);   // streamType AudioStream
1357
1358                        mOwner->writeInt16(0x03);  // XXX
1359                        mOwner->writeInt8(0x00);   // buffer size 24-bit
1360                        mOwner->writeInt32(96000); // max bit rate
1361                        mOwner->writeInt32(96000); // avg bit rate
1362
1363                        mOwner->writeInt8(0x05);   // DecoderSpecificInfoTag
1364                        mOwner->writeInt8(mCodecSpecificDataSize);
1365                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
1366
1367                        static const uint8_t kData2[] = {
1368                            0x06,  // SLConfigDescriptorTag
1369                            0x01,
1370                            0x02
1371                        };
1372                        mOwner->write(kData2, sizeof(kData2));
1373
1374                    mOwner->endBox();  // esds
1375                  }
1376                mOwner->endBox();
1377            } else {
1378                if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
1379                    mOwner->beginBox("mp4v");
1380                } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
1381                    mOwner->beginBox("s263");
1382                } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
1383                    mOwner->beginBox("avc1");
1384                } else {
1385                    LOGE("Unknown mime type '%s'.", mime);
1386                    CHECK(!"should not be here, unknown mime type.");
1387                }
1388
1389                  mOwner->writeInt32(0);           // reserved
1390                  mOwner->writeInt16(0);           // reserved
1391                  mOwner->writeInt16(1);           // data ref index
1392                  mOwner->writeInt16(0);           // predefined
1393                  mOwner->writeInt16(0);           // reserved
1394                  mOwner->writeInt32(0);           // predefined
1395                  mOwner->writeInt32(0);           // predefined
1396                  mOwner->writeInt32(0);           // predefined
1397
1398                  int32_t width, height;
1399                  bool success = mMeta->findInt32(kKeyWidth, &width);
1400                  success = success && mMeta->findInt32(kKeyHeight, &height);
1401                  CHECK(success);
1402
1403                  mOwner->writeInt16(width);
1404                  mOwner->writeInt16(height);
1405                  mOwner->writeInt32(0x480000);    // horiz resolution
1406                  mOwner->writeInt32(0x480000);    // vert resolution
1407                  mOwner->writeInt32(0);           // reserved
1408                  mOwner->writeInt16(1);           // frame count
1409                  mOwner->write("                                ", 32);
1410                  mOwner->writeInt16(0x18);        // depth
1411                  mOwner->writeInt16(-1);          // predefined
1412
1413                  CHECK(23 + mCodecSpecificDataSize < 128);
1414
1415                  if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
1416                      mOwner->beginBox("esds");
1417
1418                        mOwner->writeInt32(0);           // version=0, flags=0
1419
1420                        mOwner->writeInt8(0x03);  // ES_DescrTag
1421                        mOwner->writeInt8(23 + mCodecSpecificDataSize);
1422                        mOwner->writeInt16(0x0000);  // ES_ID
1423                        mOwner->writeInt8(0x1f);
1424
1425                        mOwner->writeInt8(0x04);  // DecoderConfigDescrTag
1426                        mOwner->writeInt8(15 + mCodecSpecificDataSize);
1427                        mOwner->writeInt8(0x20);  // objectTypeIndication ISO/IEC 14492-2
1428                        mOwner->writeInt8(0x11);  // streamType VisualStream
1429
1430                        static const uint8_t kData[] = {
1431                            0x01, 0x77, 0x00,
1432                            0x00, 0x03, 0xe8, 0x00,
1433                            0x00, 0x03, 0xe8, 0x00
1434                        };
1435                        mOwner->write(kData, sizeof(kData));
1436
1437                        mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
1438
1439                        mOwner->writeInt8(mCodecSpecificDataSize);
1440                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
1441
1442                        static const uint8_t kData2[] = {
1443                            0x06,  // SLConfigDescriptorTag
1444                            0x01,
1445                            0x02
1446                        };
1447                        mOwner->write(kData2, sizeof(kData2));
1448
1449                      mOwner->endBox();  // esds
1450                  } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
1451                      mOwner->beginBox("d263");
1452
1453                          mOwner->writeInt32(0);  // vendor
1454                          mOwner->writeInt8(0);   // decoder version
1455                          mOwner->writeInt8(10);  // level: 10
1456                          mOwner->writeInt8(0);   // profile: 0
1457
1458                      mOwner->endBox();  // d263
1459                  } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
1460                      mOwner->beginBox("avcC");
1461                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
1462                      mOwner->endBox();  // avcC
1463                  }
1464
1465                  mOwner->beginBox("pasp");
1466                    // This is useful if the pixel is not square
1467                    mOwner->writeInt32(1 << 16);  // hspacing
1468                    mOwner->writeInt32(1 << 16);  // vspacing
1469                  mOwner->endBox();  // pasp
1470                mOwner->endBox();  // mp4v, s263 or avc1
1471            }
1472          mOwner->endBox();  // stsd
1473
1474          mOwner->beginBox("stts");
1475            mOwner->writeInt32(0);  // version=0, flags=0
1476            mOwner->writeInt32(mSttsTableEntries.size());
1477            for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
1478                 it != mSttsTableEntries.end(); ++it) {
1479                mOwner->writeInt32(it->sampleCount);
1480                mOwner->writeInt32(it->sampleDuration);
1481            }
1482          mOwner->endBox();  // stts
1483
1484          if (!is_audio) {
1485            mOwner->beginBox("stss");
1486              mOwner->writeInt32(0);  // version=0, flags=0
1487              mOwner->writeInt32(mStssTableEntries.size());  // number of sync frames
1488              for (List<int32_t>::iterator it = mStssTableEntries.begin();
1489                   it != mStssTableEntries.end(); ++it) {
1490                  mOwner->writeInt32(*it);
1491              }
1492            mOwner->endBox();  // stss
1493          }
1494
1495          mOwner->beginBox("stsz");
1496            mOwner->writeInt32(0);  // version=0, flags=0
1497            if (mSamplesHaveSameSize) {
1498                List<SampleInfo>::iterator it = mSampleInfos.begin();
1499                mOwner->writeInt32(it->size);  // default sample size
1500            } else {
1501                mOwner->writeInt32(0);
1502            }
1503            mOwner->writeInt32(mSampleInfos.size());
1504            if (!mSamplesHaveSameSize) {
1505                for (List<SampleInfo>::iterator it = mSampleInfos.begin();
1506                     it != mSampleInfos.end(); ++it) {
1507                    mOwner->writeInt32((*it).size);
1508                }
1509            }
1510          mOwner->endBox();  // stsz
1511
1512          mOwner->beginBox("stsc");
1513            mOwner->writeInt32(0);  // version=0, flags=0
1514            mOwner->writeInt32(mStscTableEntries.size());
1515            for (List<StscTableEntry>::iterator it = mStscTableEntries.begin();
1516                 it != mStscTableEntries.end(); ++it) {
1517                mOwner->writeInt32(it->firstChunk);
1518                mOwner->writeInt32(it->samplesPerChunk);
1519                mOwner->writeInt32(it->sampleDescriptionId);
1520            }
1521          mOwner->endBox();  // stsc
1522          mOwner->beginBox(use32BitOffset? "stco": "co64");
1523            mOwner->writeInt32(0);  // version=0, flags=0
1524            mOwner->writeInt32(mChunkOffsets.size());
1525            for (List<off_t>::iterator it = mChunkOffsets.begin();
1526                 it != mChunkOffsets.end(); ++it) {
1527                if (use32BitOffset) {
1528                    mOwner->writeInt32(static_cast<int32_t>(*it));
1529                } else {
1530                    mOwner->writeInt64((*it));
1531                }
1532            }
1533          mOwner->endBox();  // co64
1534
1535        mOwner->endBox();  // stbl
1536       mOwner->endBox();  // minf
1537      mOwner->endBox();  // mdia
1538    mOwner->endBox();  // trak
1539}
1540
1541}  // namespace android
1542