MPEG4Writer.cpp revision 03b268eac37ca2589bfff0bf58daf79d29cc14f4
120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber/*
220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Copyright (C) 2009 The Android Open Source Project
320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber *
420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * you may not use this file except in compliance with the License.
620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * You may obtain a copy of the License at
720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber *
820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber *
1020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Unless required by applicable law or agreed to in writing, software
1120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
1220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * See the License for the specific language governing permissions and
1420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * limitations under the License.
1520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber */
1620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <arpa/inet.h>
1820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <ctype.h>
2020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <pthread.h>
2120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MPEG4Writer.h>
2320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaBuffer.h>
2420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MetaData.h>
250c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber#include <media/stagefright/MediaDebug.h>
2618291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber#include <media/stagefright/MediaDefs.h>
2703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#include <media/stagefright/MediaErrors.h>
2820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaSource.h>
2920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/Utils.h>
3020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
3120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubernamespace android {
3220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
3320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberclass MPEG4Writer::Track {
3420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberpublic:
3525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    Track(MPEG4Writer *owner, const sp<MediaSource> &source);
3620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    ~Track();
3720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
3825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    status_t start();
3920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    void stop();
4025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool reachedEOS();
4120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
423b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber    int64_t getDurationUs() const;
4320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    void writeTrackHeader(int32_t trackID);
4420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
4520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberprivate:
4620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    MPEG4Writer *mOwner;
4720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    sp<MetaData> mMeta;
48693d271e62a3726689ff68f4505ba49228eb94b2Andreas Huber    sp<MediaSource> mSource;
4920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    volatile bool mDone;
503b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber    int64_t mMaxTimeStampUs;
5120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
5220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_t mThread;
5320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
5420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    struct SampleInfo {
5520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        size_t size;
5620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        off_t offset;
5720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        int64_t timestamp;
5820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    };
5920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    List<SampleInfo> mSampleInfos;
6020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    void *mCodecSpecificData;
6220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    size_t mCodecSpecificDataSize;
6320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool mReachedEOS;
6525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
6620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    static void *ThreadWrapper(void *me);
6720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    void threadEntry();
6820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    status_t makeAVCCodecSpecificData(
7003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            const uint8_t *data, size_t size);
7103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
7220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track(const Track &);
7320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track &operator=(const Track &);
7420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber};
7520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
7603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#define USE_NALLEN_FOUR         1
7703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
7820111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::MPEG4Writer(const char *filename)
7920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    : mFile(fopen(filename, "wb")),
8020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mOffset(0),
8120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mMdatOffset(0) {
820c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(mFile != NULL);
8320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
8420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
8530ab66297501757d745b9ae10da61adcd891f497Andreas HuberMPEG4Writer::MPEG4Writer(int fd)
8630ab66297501757d745b9ae10da61adcd891f497Andreas Huber    : mFile(fdopen(fd, "wb")),
8730ab66297501757d745b9ae10da61adcd891f497Andreas Huber      mOffset(0),
8830ab66297501757d745b9ae10da61adcd891f497Andreas Huber      mMdatOffset(0) {
8930ab66297501757d745b9ae10da61adcd891f497Andreas Huber    CHECK(mFile != NULL);
9030ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
9130ab66297501757d745b9ae10da61adcd891f497Andreas Huber
9220111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() {
9320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    stop();
9420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
9520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    for (List<Track *>::iterator it = mTracks.begin();
9620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber         it != mTracks.end(); ++it) {
9720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        delete *it;
9820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
9920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mTracks.clear();
10020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
10120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1022dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
10325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    Track *track = new Track(this, source);
10420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mTracks.push_back(track);
1052dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
1062dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    return OK;
10720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
10820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
10925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberstatus_t MPEG4Writer::start() {
11020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mFile == NULL) {
11125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        return UNKNOWN_ERROR;
11220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
11320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
11420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    beginBox("ftyp");
11520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      writeFourcc("isom");
11620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      writeInt32(0);
11720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      writeFourcc("isom");
11820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    endBox();
11920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
12020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mMdatOffset = mOffset;
12120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    write("\x00\x00\x00\x01mdat????????", 16);
12220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
12320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    for (List<Track *>::iterator it = mTracks.begin();
12420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber         it != mTracks.end(); ++it) {
12525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        status_t err = (*it)->start();
12625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
12725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        if (err != OK) {
12825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber            for (List<Track *>::iterator it2 = mTracks.begin();
12925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                 it2 != it; ++it2) {
13025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                (*it2)->stop();
13125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber            }
13225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
13325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber            return err;
13425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        }
13520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
13625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
13725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return OK;
13820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
13920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
14020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::stop() {
14120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mFile == NULL) {
14220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        return;
14320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
14420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
14520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    int64_t max_duration = 0;
14620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    for (List<Track *>::iterator it = mTracks.begin();
14720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber         it != mTracks.end(); ++it) {
14820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        (*it)->stop();
14920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1503b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber        int64_t duration = (*it)->getDurationUs();
15120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        if (duration > max_duration) {
15220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            max_duration = duration;
15320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
15420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
15520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
15620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    // Fix up the size of the 'mdat' chunk.
15720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    fseek(mFile, mMdatOffset + 8, SEEK_SET);
15820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    int64_t size = mOffset - mMdatOffset;
15920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    size = hton64(size);
16020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    fwrite(&size, 1, 8, mFile);
16120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    fseek(mFile, mOffset, SEEK_SET);
16220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
16320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    time_t now = time(NULL);
16420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
16520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    beginBox("moov");
16620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
16720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      beginBox("mvhd");
16820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);             // version=0, flags=0
16920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(now);           // creation time
17020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(now);           // modification time
17120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(1000);          // timescale
1723b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber        writeInt32(max_duration / 1000);
17320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0x10000);       // rate
17420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt16(0x100);         // volume
17520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt16(0);             // reserved
17620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);             // reserved
17720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);             // reserved
17820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0x10000);       // matrix
17920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);
18020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);
18120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);
18220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0x10000);
18320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);
18420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);
18520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);
18620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0x40000000);
18720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);             // predefined
18820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);             // predefined
18920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);             // predefined
19020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);             // predefined
19120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);             // predefined
19220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);             // predefined
19320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(mTracks.size() + 1);  // nextTrackID
19420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      endBox();  // mvhd
19520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
19620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      int32_t id = 1;
19720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      for (List<Track *>::iterator it = mTracks.begin();
19820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber           it != mTracks.end(); ++it, ++id) {
19920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          (*it)->writeTrackHeader(id);
20020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      }
20120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    endBox();  // moov
20220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2030c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(mBoxes.empty());
20420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
20520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    fclose(mFile);
20620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mFile = NULL;
20720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
20820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
20920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberoff_t MPEG4Writer::addSample(MediaBuffer *buffer) {
21020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Mutex::Autolock autoLock(mLock);
21120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
21220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    off_t old_offset = mOffset;
21320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
21420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
21520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber           1, buffer->range_length(), mFile);
21620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
21720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mOffset += buffer->range_length();
21820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
21920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    return old_offset;
22020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
22120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
22203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) {
22303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (buffer->range_length() < 4) {
22403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return;
22503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
22603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
22703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    const uint8_t *ptr =
22803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        (const uint8_t *)buffer->data() + buffer->range_offset();
22903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
23003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
23103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        buffer->set_range(
23203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                buffer->range_offset() + 4, buffer->range_length() - 4);
23303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
23403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber}
23503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
23630ab66297501757d745b9ae10da61adcd891f497Andreas Huberoff_t MPEG4Writer::addLengthPrefixedSample(MediaBuffer *buffer) {
23730ab66297501757d745b9ae10da61adcd891f497Andreas Huber    Mutex::Autolock autoLock(mLock);
23830ab66297501757d745b9ae10da61adcd891f497Andreas Huber
23903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    StripStartcode(buffer);
24003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
24130ab66297501757d745b9ae10da61adcd891f497Andreas Huber    off_t old_offset = mOffset;
24230ab66297501757d745b9ae10da61adcd891f497Andreas Huber
24330ab66297501757d745b9ae10da61adcd891f497Andreas Huber    size_t length = buffer->range_length();
24403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
24503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR
24603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    uint8_t x = length >> 24;
24703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    fwrite(&x, 1, 1, mFile);
24803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    x = (length >> 16) & 0xff;
24903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    fwrite(&x, 1, 1, mFile);
25003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    x = (length >> 8) & 0xff;
25103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    fwrite(&x, 1, 1, mFile);
25203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    x = length & 0xff;
25303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    fwrite(&x, 1, 1, mFile);
25403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else
25530ab66297501757d745b9ae10da61adcd891f497Andreas Huber    CHECK(length < 65536);
25630ab66297501757d745b9ae10da61adcd891f497Andreas Huber
25730ab66297501757d745b9ae10da61adcd891f497Andreas Huber    uint8_t x = length >> 8;
25830ab66297501757d745b9ae10da61adcd891f497Andreas Huber    fwrite(&x, 1, 1, mFile);
25930ab66297501757d745b9ae10da61adcd891f497Andreas Huber    x = length & 0xff;
26030ab66297501757d745b9ae10da61adcd891f497Andreas Huber    fwrite(&x, 1, 1, mFile);
26103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif
26230ab66297501757d745b9ae10da61adcd891f497Andreas Huber
26330ab66297501757d745b9ae10da61adcd891f497Andreas Huber    fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
26430ab66297501757d745b9ae10da61adcd891f497Andreas Huber           1, length, mFile);
26530ab66297501757d745b9ae10da61adcd891f497Andreas Huber
26603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR
26703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    mOffset += length + 4;
26803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else
26930ab66297501757d745b9ae10da61adcd891f497Andreas Huber    mOffset += length + 2;
27003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif
27130ab66297501757d745b9ae10da61adcd891f497Andreas Huber
27230ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return old_offset;
27330ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
27430ab66297501757d745b9ae10da61adcd891f497Andreas Huber
27520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) {
2760c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK_EQ(strlen(fourcc), 4);
27720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
27820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mBoxes.push_back(mOffset);
27920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
28020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    writeInt32(0);
28120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    writeFourcc(fourcc);
28220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
28320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
28420111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() {
2850c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(!mBoxes.empty());
28620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
28720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    off_t offset = *--mBoxes.end();
28820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mBoxes.erase(--mBoxes.end());
28920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
29020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    fseek(mFile, offset, SEEK_SET);
29120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    writeInt32(mOffset - offset);
29220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mOffset -= 4;
29320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    fseek(mFile, mOffset, SEEK_SET);
29420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
29520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
29620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) {
29720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    fwrite(&x, 1, 1, mFile);
29820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    ++mOffset;
29920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
30020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
30120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) {
30220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = htons(x);
30320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    fwrite(&x, 1, 2, mFile);
30420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mOffset += 2;
30520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
30620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
30720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) {
30820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = htonl(x);
30920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    fwrite(&x, 1, 4, mFile);
31020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mOffset += 4;
31120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
31220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
31320111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) {
31420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = hton64(x);
31520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    fwrite(&x, 1, 8, mFile);
31620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mOffset += 8;
31720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
31820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
31920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) {
32020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    size_t n = strlen(s);
32120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
32220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    fwrite(s, 1, n + 1, mFile);
32320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mOffset += n + 1;
32420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
32520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
32620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) {
3270c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK_EQ(strlen(s), 4);
32820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    fwrite(s, 1, 4, mFile);
32920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mOffset += 4;
33020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
33120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
33220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) {
33320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    fwrite(data, 1, size, mFile);
33420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mOffset += size;
33520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
33620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
33725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() {
33825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool allDone = true;
33925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    for (List<Track *>::iterator it = mTracks.begin();
34025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber         it != mTracks.end(); ++it) {
34125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        if (!(*it)->reachedEOS()) {
34225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber            allDone = false;
34325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber            break;
34425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        }
34525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    }
34625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
34725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return allDone;
34825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber}
34925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
35020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber////////////////////////////////////////////////////////////////////////////////
35120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
35220111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track(
35325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        MPEG4Writer *owner, const sp<MediaSource> &source)
35420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    : mOwner(owner),
35525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber      mMeta(source->getFormat()),
35620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mSource(source),
35720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mDone(false),
3583b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber      mMaxTimeStampUs(0),
35920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mCodecSpecificData(NULL),
36025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber      mCodecSpecificDataSize(0),
36125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber      mReachedEOS(false) {
36220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
36320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
36420111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() {
36520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    stop();
36620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
36720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mCodecSpecificData != NULL) {
36820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        free(mCodecSpecificData);
36920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mCodecSpecificData = NULL;
37020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
37120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
37220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
37325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberstatus_t MPEG4Writer::Track::start() {
37425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    status_t err = mSource->start();
37525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
37625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    if (err != OK) {
37725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        mDone = mReachedEOS = true;
37825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        return err;
37925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    }
38020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
38120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_t attr;
38220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_init(&attr);
38320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
38420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
38520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mDone = false;
3863b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber    mMaxTimeStampUs = 0;
38725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    mReachedEOS = false;
38820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
38925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    pthread_create(&mThread, &attr, ThreadWrapper, this);
39020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_destroy(&attr);
39125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
39225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return OK;
39320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
39420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
39520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::Track::stop() {
39620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mDone) {
39720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        return;
39820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
39920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
40020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mDone = true;
40120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
40220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    void *dummy;
40320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_join(mThread, &dummy);
40420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
40520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mSource->stop();
40620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
40720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
40825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() {
40925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return mReachedEOS;
41025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber}
41125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
41220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static
41320111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) {
41420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track *track = static_cast<Track *>(me);
41520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
41620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    track->threadEntry();
41720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
41820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    return NULL;
41920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
42020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
42103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData(
42203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        const uint8_t *data, size_t size) {
42303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (mCodecSpecificData != NULL) {
42403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
42503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
42603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
42703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) {
42803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        // Must start with a start-code.
42903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
43003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
43103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
43203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    size_t picParamOffset = 4;
43303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    while (picParamOffset + 3 < size
43403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            && memcmp("\x00\x00\x00\x01", &data[picParamOffset], 4)) {
43503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        ++picParamOffset;
43603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
43703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
43803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (picParamOffset + 3 >= size) {
43903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        // Could not find start-code for pictureParameterSet.
44003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
44103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
44203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
44303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    size_t seqParamSetLength = picParamOffset - 4;
44403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    size_t picParamSetLength = size - picParamOffset - 4;
44503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
44603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    mCodecSpecificDataSize =
44703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        6 + 1 + seqParamSetLength + 2 + picParamSetLength + 2;
44803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
44903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    mCodecSpecificData = malloc(mCodecSpecificDataSize);
45003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    uint8_t *header = (uint8_t *)mCodecSpecificData;
45103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    header[0] = 1;
45203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    header[1] = 0x42;  // profile
45303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    header[2] = 0x80;
45403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    header[3] = 0x1e;  // level
45503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
45603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR
45703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    header[4] = 0xfc | 3;  // length size == 4 bytes
45803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else
45903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    header[4] = 0xfc | 1;  // length size == 2 bytes
46003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif
46103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
46203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    header[5] = 0xe0 | 1;
46303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    header[6] = seqParamSetLength >> 8;
46403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    header[7] = seqParamSetLength & 0xff;
46503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    memcpy(&header[8], &data[4], seqParamSetLength);
46603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    header += 8 + seqParamSetLength;
46703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    header[0] = 1;
46803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    header[1] = picParamSetLength >> 8;
46903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    header[2] = picParamSetLength & 0xff;
47003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    memcpy(&header[3], &data[picParamOffset + 4], picParamSetLength);
47103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
47203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    return OK;
47303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber}
47403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
47520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::Track::threadEntry() {
47620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    sp<MetaData> meta = mSource->getFormat();
47720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    const char *mime;
47820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    meta->findCString(kKeyMIMEType, &mime);
47930ab66297501757d745b9ae10da61adcd891f497Andreas Huber    bool is_mpeg4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4);
48030ab66297501757d745b9ae10da61adcd891f497Andreas Huber    bool is_avc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
48130ab66297501757d745b9ae10da61adcd891f497Andreas Huber    int32_t count = 0;
48220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
48320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    MediaBuffer *buffer;
48420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    while (!mDone && mSource->read(&buffer) == OK) {
48520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        if (buffer->range_length() == 0) {
48620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            buffer->release();
48720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            buffer = NULL;
48820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
48920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            continue;
49020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
49120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
49230ab66297501757d745b9ae10da61adcd891f497Andreas Huber        ++count;
49330ab66297501757d745b9ae10da61adcd891f497Andreas Huber
49403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        int32_t isCodecConfig;
49503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
49603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                && isCodecConfig) {
49703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            if (is_avc) {
49803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                status_t err = makeAVCCodecSpecificData(
49903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        (const uint8_t *)buffer->data()
50003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                            + buffer->range_offset(),
50103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        buffer->range_length());
50203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
50303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                if (err != OK) {
50403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                    LOGE("failed to parse avc codec specific data.");
50530ab66297501757d745b9ae10da61adcd891f497Andreas Huber                    break;
50630ab66297501757d745b9ae10da61adcd891f497Andreas Huber                }
50703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            } else if (is_mpeg4) {
50803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                if (mCodecSpecificData != NULL) {
50930ab66297501757d745b9ae10da61adcd891f497Andreas Huber                    break;
51030ab66297501757d745b9ae10da61adcd891f497Andreas Huber                }
51103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
51203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                mCodecSpecificDataSize = buffer->range_length();
51303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                mCodecSpecificData = malloc(mCodecSpecificDataSize);
51403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                memcpy(mCodecSpecificData,
51503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        (const uint8_t *)buffer->data()
51603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                            + buffer->range_offset(),
51703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                       buffer->range_length());
51830ab66297501757d745b9ae10da61adcd891f497Andreas Huber            }
51930ab66297501757d745b9ae10da61adcd891f497Andreas Huber
52030ab66297501757d745b9ae10da61adcd891f497Andreas Huber            buffer->release();
52130ab66297501757d745b9ae10da61adcd891f497Andreas Huber            buffer = NULL;
52230ab66297501757d745b9ae10da61adcd891f497Andreas Huber
52330ab66297501757d745b9ae10da61adcd891f497Andreas Huber            continue;
52403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        } else if (count == 1 && is_mpeg4 && mCodecSpecificData == NULL) {
52503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            // The TI mpeg4 encoder does not properly set the
52603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            // codec-specific-data flag.
52730ab66297501757d745b9ae10da61adcd891f497Andreas Huber
52820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            const uint8_t *data =
52920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                (const uint8_t *)buffer->data() + buffer->range_offset();
53020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
53120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            const size_t size = buffer->range_length();
53220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
53320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            size_t offset = 0;
53420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            while (offset + 3 < size) {
53520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                if (data[offset] == 0x00 && data[offset + 1] == 0x00
53620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                    && data[offset + 2] == 0x01 && data[offset + 3] == 0xb6) {
53720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                    break;
53820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                }
53920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
54020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                ++offset;
54120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            }
54220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
5430c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber            // CHECK(offset + 3 < size);
544bf37f3364804f521cc61845b1f1ce16fe133814bAndreas Huber            if (offset + 3 >= size) {
545bf37f3364804f521cc61845b1f1ce16fe133814bAndreas Huber                // XXX assume the entire first chunk of data is the codec specific
546bf37f3364804f521cc61845b1f1ce16fe133814bAndreas Huber                // data.
547bf37f3364804f521cc61845b1f1ce16fe133814bAndreas Huber                offset = size;
548bf37f3364804f521cc61845b1f1ce16fe133814bAndreas Huber            }
54920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
55020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mCodecSpecificDataSize = offset;
55120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mCodecSpecificData = malloc(offset);
55220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            memcpy(mCodecSpecificData, data, offset);
55320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
55420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            buffer->set_range(buffer->range_offset() + offset, size - offset);
55503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
55603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            if (size == offset) {
55703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                buffer->release();
55803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                buffer = NULL;
55903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
56003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                continue;
56103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            }
56203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        } else if (is_avc && count < 3) {
56303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            // The TI video encoder does not flag codec specific data
56403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            // as such and also splits up SPS and PPS across two buffers.
56503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
56603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            const uint8_t *data =
56703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                (const uint8_t *)buffer->data() + buffer->range_offset();
56803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
56903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            size_t size = buffer->range_length();
57003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
57103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            CHECK(count == 2 || mCodecSpecificData == NULL);
57203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
57303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            size_t offset = mCodecSpecificDataSize;
57403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            mCodecSpecificDataSize += size + 4;
57503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            mCodecSpecificData =
57603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                realloc(mCodecSpecificData, mCodecSpecificDataSize);
57703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
57803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            memcpy((uint8_t *)mCodecSpecificData + offset,
57903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                   "\x00\x00\x00\x01", 4);
58003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
58103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            memcpy((uint8_t *)mCodecSpecificData + offset + 4, data, size);
58203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
58303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            buffer->release();
58403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            buffer = NULL;
58503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
58603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            if (count == 2) {
58703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                void *tmp = mCodecSpecificData;
58803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                size = mCodecSpecificDataSize;
58903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                mCodecSpecificData = NULL;
59003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                mCodecSpecificDataSize = 0;
59103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
59203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                status_t err = makeAVCCodecSpecificData(
59303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        (const uint8_t *)tmp, size);
59403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
59503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                free(tmp);
59603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                tmp = NULL;
59703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
59803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                if (err != OK) {
59903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                    LOGE("failed to parse avc codec specific data.");
60003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                    break;
60103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                }
60203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            }
60303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
60403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            continue;
60520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
60620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
60730ab66297501757d745b9ae10da61adcd891f497Andreas Huber        off_t offset = is_avc ? mOwner->addLengthPrefixedSample(buffer)
60830ab66297501757d745b9ae10da61adcd891f497Andreas Huber                              : mOwner->addSample(buffer);
60920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
61020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        SampleInfo info;
61103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        info.size = is_avc
61203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR
61303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            ? buffer->range_length() + 4
61403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else
61503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            ? buffer->range_length() + 2
61603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif
61703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            : buffer->range_length();
61803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
61920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        info.offset = offset;
62020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
62148c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber        int64_t timestampUs;
62248c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber        CHECK(buffer->meta_data()->findInt64(kKeyTime, &timestampUs));
62348c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber
6243b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber        if (timestampUs > mMaxTimeStampUs) {
6253b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber            mMaxTimeStampUs = timestampUs;
6263b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber        }
6273b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber
62848c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber        // Our timestamp is in ms.
62948c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber        info.timestamp = (timestampUs + 500) / 1000;
63020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
63120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mSampleInfos.push_back(info);
63220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
63320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        buffer->release();
63420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        buffer = NULL;
63520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
63625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
63725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    mReachedEOS = true;
63820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
63920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6403b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const {
6413b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber    return mMaxTimeStampUs;
64220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
64320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
64420111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::Track::writeTrackHeader(int32_t trackID) {
64520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    const char *mime;
64620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    bool success = mMeta->findCString(kKeyMIMEType, &mime);
6470c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(success);
64820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
64920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    bool is_audio = !strncasecmp(mime, "audio/", 6);
65020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
65120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    time_t now = time(NULL);
65220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
65320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mOwner->beginBox("trak");
65420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
65520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mOwner->beginBox("tkhd");
65620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0);             // version=0, flags=0
65720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(now);           // creation time
65820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(now);           // modification time
65920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(trackID);
66020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0);             // reserved
6613b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber        mOwner->writeInt32(getDurationUs() / 1000);
66220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0);             // reserved
66320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0);             // reserved
66420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt16(0);             // layer
66520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt16(0);             // alternate group
66620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt16(is_audio ? 0x100 : 0);  // volume
66720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt16(0);             // reserved
66820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
66920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0x10000);       // matrix
67020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0);
67120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0);
67220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0);
67320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0x10000);
67420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0);
67520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0);
67620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0);
67720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0x40000000);
67820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
67920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        if (is_audio) {
68020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(0);
68120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(0);
68220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        } else {
68320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            int32_t width, height;
68420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            bool success = mMeta->findInt32(kKeyWidth, &width);
68520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            success = success && mMeta->findInt32(kKeyHeight, &height);
6860c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber            CHECK(success);
68720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
68820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(width);
68920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(height);
69020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
69120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mOwner->endBox();  // tkhd
69220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
69320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mOwner->beginBox("mdia");
69420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
69520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->beginBox("mdhd");
69620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeInt32(0);             // version=0, flags=0
69720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeInt32(now);           // creation time
69820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeInt32(now);           // modification time
69920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeInt32(1000);          // timescale
7003b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber          mOwner->writeInt32(getDurationUs() / 1000);
70120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeInt16(0);             // language code XXX
70220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeInt16(0);             // predefined
70320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->endBox();
70420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
70520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->beginBox("hdlr");
70620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeInt32(0);             // version=0, flags=0
70720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeInt32(0);             // predefined
70820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeFourcc(is_audio ? "soun" : "vide");
70920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeInt32(0);             // reserved
71020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeInt32(0);             // reserved
71120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeInt32(0);             // reserved
71220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeCString("");          // name
71320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->endBox();
71420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
71520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->beginBox("minf");
71620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
71720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->beginBox("dinf");
71820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->beginBox("dref");
71920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->writeInt32(0);  // version=0, flags=0
72020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->writeInt32(1);
72120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->beginBox("url ");
72220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                mOwner->writeInt32(1);  // version=0, flags=1
72320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->endBox();  // url
72420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->endBox();  // dref
72520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->endBox();  // dinf
72620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
72720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          if (is_audio) {
72820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->beginBox("smhd");
72920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->writeInt32(0);           // version=0, flags=0
73020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->writeInt16(0);           // balance
73120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->writeInt16(0);           // reserved
73220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->endBox();
73320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          } else {
73420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->beginBox("vmhd");
73520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->writeInt32(0x00000001);  // version=0, flags=1
73620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->writeInt16(0);           // graphics mode
73720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->writeInt16(0);           // opcolor
73820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->writeInt16(0);
73920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->writeInt16(0);
74020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->endBox();
74120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          }
74220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->endBox();  // minf
74320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
74420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->beginBox("stbl");
74520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
74620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->beginBox("stsd");
74720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(0);               // version=0, flags=0
74820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(1);               // entry count
74920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            if (is_audio) {
75025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                const char *fourcc = NULL;
75118291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber                if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
75225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                    fourcc = "samr";
75318291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
75425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                    fourcc = "sawb";
75525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                } else {
75625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                    LOGE("Unknown mime type '%s'.", mime);
75725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                    CHECK(!"should not be here, unknown mime type.");
75825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                }
75925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
76025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                mOwner->beginBox(fourcc);          // audio format
76120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0);           // reserved
76220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(0);           // reserved
76320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(0);           // data ref index
76420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0);           // reserved
76520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0);           // reserved
76620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(2);           // channel count
76720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(16);          // sample size
76820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(0);           // predefined
76920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(0);           // reserved
77020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
77120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  int32_t samplerate;
77220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  bool success = mMeta->findInt32(kKeySampleRate, &samplerate);
7730c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber                  CHECK(success);
77420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
77520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(samplerate << 16);
77620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                mOwner->endBox();
77720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            } else {
77818291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber                if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
77920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                    mOwner->beginBox("mp4v");
78018291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber                } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
78120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                    mOwner->beginBox("s263");
78230ab66297501757d745b9ae10da61adcd891f497Andreas Huber                } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
78330ab66297501757d745b9ae10da61adcd891f497Andreas Huber                    mOwner->beginBox("avc1");
78420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                } else {
78525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                    LOGE("Unknown mime type '%s'.", mime);
7860c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber                    CHECK(!"should not be here, unknown mime type.");
78720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                }
78820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
78920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0);           // reserved
79020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(0);           // reserved
79120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(0);           // data ref index
79220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(0);           // predefined
79320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(0);           // reserved
79420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0);           // predefined
79520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0);           // predefined
79620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0);           // predefined
79720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
79820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  int32_t width, height;
79920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  bool success = mMeta->findInt32(kKeyWidth, &width);
80020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  success = success && mMeta->findInt32(kKeyHeight, &height);
8010c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber                  CHECK(success);
80220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
80320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(width);
80420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(height);
80520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0x480000);    // horiz resolution
80620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0x480000);    // vert resolution
80720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0);           // reserved
80820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(1);           // frame count
80920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->write("                                ", 32);
81020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(0x18);        // depth
81120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(-1);          // predefined
81220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
8130c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber                  CHECK(23 + mCodecSpecificDataSize < 128);
81420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
81518291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber                  if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
81620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                      mOwner->beginBox("esds");
81720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
81820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt32(0);           // version=0, flags=0
81920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
82020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt8(0x03);  // ES_DescrTag
82120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt8(23 + mCodecSpecificDataSize);
82220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt16(0x0000);  // ES_ID
82320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt8(0x1f);
82420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
82520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt8(0x04);  // DecoderConfigDescrTag
82620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt8(15 + mCodecSpecificDataSize);
82720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt8(0x20);  // objectTypeIndication ISO/IEC 14492-2
82820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt8(0x11);  // streamType VisualStream
82920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
83020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        static const uint8_t kData[] = {
83120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                            0x01, 0x77, 0x00,
83220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                            0x00, 0x03, 0xe8, 0x00,
83320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                            0x00, 0x03, 0xe8, 0x00
83420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        };
83520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->write(kData, sizeof(kData));
83620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
83720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
83820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
83920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt8(mCodecSpecificDataSize);
84020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
84120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
84220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        static const uint8_t kData2[] = {
84320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                            0x06,  // SLConfigDescriptorTag
84420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                            0x01,
84520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                            0x02
84620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        };
84720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->write(kData2, sizeof(kData2));
84820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
84920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                      mOwner->endBox();  // esds
85018291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber                  } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
85120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                      mOwner->beginBox("d263");
85220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
85320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                          mOwner->writeInt32(0);  // vendor
85420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                          mOwner->writeInt8(0);   // decoder version
85520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                          mOwner->writeInt8(10);  // level: 10
85620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                          mOwner->writeInt8(0);   // profile: 0
85720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
85820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                      mOwner->endBox();  // d263
85930ab66297501757d745b9ae10da61adcd891f497Andreas Huber                  } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
86030ab66297501757d745b9ae10da61adcd891f497Andreas Huber                      mOwner->beginBox("avcC");
86130ab66297501757d745b9ae10da61adcd891f497Andreas Huber                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
86230ab66297501757d745b9ae10da61adcd891f497Andreas Huber                      mOwner->endBox();  // avcC
86320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  }
86430ab66297501757d745b9ae10da61adcd891f497Andreas Huber
86530ab66297501757d745b9ae10da61adcd891f497Andreas Huber                mOwner->endBox();  // mp4v, s263 or avc1
86620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            }
86720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->endBox();  // stsd
86820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
86920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->beginBox("stts");
87020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(0);  // version=0, flags=0
87103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            mOwner->writeInt32(mSampleInfos.size());
87220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
87320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            List<SampleInfo>::iterator it = mSampleInfos.begin();
87420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            int64_t last = (*it).timestamp;
87503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            int64_t lastDuration = 1;
87603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
87720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            ++it;
87820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            while (it != mSampleInfos.end()) {
87920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                mOwner->writeInt32(1);
88003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                lastDuration = (*it).timestamp - last;
88103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                mOwner->writeInt32(lastDuration);
88220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
88320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                last = (*it).timestamp;
88420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
88520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                ++it;
88620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            }
88703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
88803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            // We don't really know how long the last frame lasts, since
88903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            // there is no frame time after it, just repeat the previous
89003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            // frame's duration.
89103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            mOwner->writeInt32(1);
89203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            mOwner->writeInt32(lastDuration);
89303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
89420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->endBox();  // stts
89520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
89620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->beginBox("stsz");
89720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(0);  // version=0, flags=0
89820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(0);  // default sample size
89920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(mSampleInfos.size());
90020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            for (List<SampleInfo>::iterator it = mSampleInfos.begin();
90120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                 it != mSampleInfos.end(); ++it) {
90220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                mOwner->writeInt32((*it).size);
90320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            }
90420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->endBox();  // stsz
90520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
90620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->beginBox("stsc");
90720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(0);  // version=0, flags=0
90820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(mSampleInfos.size());
90920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            int32_t n = 1;
91020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            for (List<SampleInfo>::iterator it = mSampleInfos.begin();
91120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                 it != mSampleInfos.end(); ++it, ++n) {
91220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                mOwner->writeInt32(n);
91320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                mOwner->writeInt32(1);
91420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                mOwner->writeInt32(1);
91520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            }
91620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->endBox();  // stsc
91720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
91820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->beginBox("co64");
91920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(0);  // version=0, flags=0
92020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(mSampleInfos.size());
92120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            for (List<SampleInfo>::iterator it = mSampleInfos.begin();
92220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                 it != mSampleInfos.end(); ++it, ++n) {
92320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                mOwner->writeInt64((*it).offset);
92420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            }
92520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->endBox();  // co64
92620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
92720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->endBox();  // stbl
92820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mOwner->endBox();  // mdia
92920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mOwner->endBox();  // trak
93020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
93120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
93220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}  // namespace android
933