MPEG4Writer.cpp revision d707fcb3e29707ca4a5935c294ef0b38eb5aba5f
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
17050b28a593350047845a45a14cc5026221ac1620James Dong//#define LOG_NDEBUG 0
18050b28a593350047845a45a14cc5026221ac1620James Dong#define LOG_TAG "MPEG4Writer"
19050b28a593350047845a45a14cc5026221ac1620James Dong#include <utils/Log.h>
20050b28a593350047845a45a14cc5026221ac1620James Dong
2120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <arpa/inet.h>
2220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <ctype.h>
2420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <pthread.h>
2520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MPEG4Writer.h>
2720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaBuffer.h>
2820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MetaData.h>
290c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber#include <media/stagefright/MediaDebug.h>
3018291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber#include <media/stagefright/MediaDefs.h>
3103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#include <media/stagefright/MediaErrors.h>
3220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaSource.h>
3320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/Utils.h>
34d599cd4573b5a2d5914c5040e0565ef866749b77James Dong#include <media/mediarecorder.h>
35365a963142093a1cd8efdcea76b5f65096a5b115James Dong#include <cutils/properties.h>
3620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
3719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber#include "include/ESDS.h"
3819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
3920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubernamespace android {
4020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypeSeqParamSet = 0x07;
423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypePicParamSet = 0x08;
433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
4420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberclass MPEG4Writer::Track {
4520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberpublic:
4625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    Track(MPEG4Writer *owner, const sp<MediaSource> &source);
478f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
4820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    ~Track();
4920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
5093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    status_t start(MetaData *params);
5137187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t stop();
5237187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t pause();
5325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool reachedEOS();
5420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
553b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber    int64_t getDurationUs() const;
56d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    int64_t getEstimatedTrackSizeBytes() const;
571acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    void writeTrackHeader(int32_t trackID, bool use32BitOffset = true);
581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    void bufferChunk(int64_t timestampUs);
591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool isAvc() const { return mIsAvc; }
601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool isAudio() const { return mIsAudio; }
611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool isMPEG4() const { return mIsMPEG4; }
621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    void addChunkOffset(off_t offset) { mChunkOffsets.push_back(offset); }
63dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    status_t dump(int fd, const Vector<String16>& args) const;
6420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberprivate:
6620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    MPEG4Writer *mOwner;
6720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    sp<MetaData> mMeta;
68693d271e62a3726689ff68f4505ba49228eb94b2Andreas Huber    sp<MediaSource> mSource;
6920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    volatile bool mDone;
70a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    volatile bool mPaused;
71a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    volatile bool mResumed;
721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool mIsAvc;
731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool mIsAudio;
741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool mIsMPEG4;
75c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    int64_t mTrackDurationUs;
76e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
77e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    // For realtime applications, we need to adjust the media clock
78e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    // for video track based on the audio media clock
79e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    bool mIsRealTimeRecording;
80e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    int64_t mMaxTimeStampUs;
81d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    int64_t mEstimatedTrackSizeBytes;
821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    int64_t mMaxWriteTimeUs;
838f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int32_t mTimeScale;
8420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
8520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_t mThread;
8620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
87ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    // mNumSamples is used to track how many samples in mSampleSizes List.
88ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    // This is to reduce the cost associated with mSampleSizes.size() call,
89ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    // since it is O(n). Ideally, the fix should be in List class.
90ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    size_t              mNumSamples;
918644c14618d30d9e57a69df40ed939986ebf02c4James Dong    List<size_t>        mSampleSizes;
92be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    bool                mSamplesHaveSameSize;
93be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
9413aec890216948b0c364f8f92792129d0335f506James Dong    List<MediaBuffer *> mChunkSamples;
9513aec890216948b0c364f8f92792129d0335f506James Dong    List<off_t>         mChunkOffsets;
9613aec890216948b0c364f8f92792129d0335f506James Dong
9713aec890216948b0c364f8f92792129d0335f506James Dong    struct StscTableEntry {
9813aec890216948b0c364f8f92792129d0335f506James Dong
9913aec890216948b0c364f8f92792129d0335f506James Dong        StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id)
10013aec890216948b0c364f8f92792129d0335f506James Dong            : firstChunk(chunk),
10113aec890216948b0c364f8f92792129d0335f506James Dong              samplesPerChunk(samples),
10213aec890216948b0c364f8f92792129d0335f506James Dong              sampleDescriptionId(id) {}
10313aec890216948b0c364f8f92792129d0335f506James Dong
10413aec890216948b0c364f8f92792129d0335f506James Dong        uint32_t firstChunk;
10513aec890216948b0c364f8f92792129d0335f506James Dong        uint32_t samplesPerChunk;
10613aec890216948b0c364f8f92792129d0335f506James Dong        uint32_t sampleDescriptionId;
10713aec890216948b0c364f8f92792129d0335f506James Dong    };
10813aec890216948b0c364f8f92792129d0335f506James Dong    List<StscTableEntry> mStscTableEntries;
10920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
110050b28a593350047845a45a14cc5026221ac1620James Dong    List<int32_t> mStssTableEntries;
111365a963142093a1cd8efdcea76b5f65096a5b115James Dong    List<int64_t> mChunkDurations;
112050b28a593350047845a45a14cc5026221ac1620James Dong
113be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    struct SttsTableEntry {
114be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
1158f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        SttsTableEntry(uint32_t count, uint32_t durationUs)
1168f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            : sampleCount(count), sampleDurationUs(durationUs) {}
117be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
118be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        uint32_t sampleCount;
1198f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        uint32_t sampleDurationUs;
120be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    };
121be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    List<SttsTableEntry> mSttsTableEntries;
122be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
1233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Sequence parameter set or picture parameter set
1243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    struct AVCParamSet {
1253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        AVCParamSet(uint16_t length, const uint8_t *data)
1263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            : mLength(length), mData(data) {}
1273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
1283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t mLength;
1293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *mData;
1303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    };
1313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    List<AVCParamSet> mSeqParamSets;
1323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    List<AVCParamSet> mPicParamSets;
1333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mProfileIdc;
1343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mProfileCompatible;
1353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mLevelIdc;
1363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
13720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    void *mCodecSpecificData;
13820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    size_t mCodecSpecificDataSize;
139548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber    bool mGotAllCodecSpecificData;
14093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    bool mTrackingProgressStatus;
14120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
14225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool mReachedEOS;
1433c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    int64_t mStartTimestampUs;
14493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t mPreviousTrackTimeUs;
14593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t mTrackEveryTimeDurationUs;
14625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
14720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    static void *ThreadWrapper(void *me);
14837187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t threadEntry();
14920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *parseParamSet(
1513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length, int type, size_t *paramSetLen);
1523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    status_t makeAVCCodecSpecificData(
15403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber            const uint8_t *data, size_t size);
1553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    status_t copyAVCCodecSpecificData(
1563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            const uint8_t *data, size_t size);
1573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    status_t parseAVCCodecSpecificData(
1583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            const uint8_t *data, size_t size);
159215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong
160215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    // Track authoring progress status
161faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    void trackProgressStatus(int64_t timeUs, status_t err = OK);
16293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    void initTrackingProgressStatus(MetaData *params);
16303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
164215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    // Utilities for collecting statistical data
165215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    void logStatisticalData(bool isAudio);
166215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    void findMinAvgMaxSampleDurationMs(
167215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong            int32_t *min, int32_t *avg, int32_t *max);
168215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    void findMinMaxChunkDurations(int64_t *min, int64_t *max);
169215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong
17019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    void getCodecSpecificDataFromInputFormatIfPossible();
17119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
172c059860c73678a202bfa33062723e8f82fb779d9James Dong    // Determine the track time scale
173c059860c73678a202bfa33062723e8f82fb779d9James Dong    // If it is an audio track, try to use the sampling rate as
174c059860c73678a202bfa33062723e8f82fb779d9James Dong    // the time scale; however, if user chooses the overwrite
175c059860c73678a202bfa33062723e8f82fb779d9James Dong    // value, the user-supplied time scale will be used.
176c059860c73678a202bfa33062723e8f82fb779d9James Dong    void setTimeScale();
177c059860c73678a202bfa33062723e8f82fb779d9James Dong
178690f546b0ee548dbfe997df36418e5302ec2d786James Dong    // Simple validation on the codec specific data
179690f546b0ee548dbfe997df36418e5302ec2d786James Dong    status_t checkCodecSpecificData() const;
180690f546b0ee548dbfe997df36418e5302ec2d786James Dong
18120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track(const Track &);
18220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track &operator=(const Track &);
18320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber};
18420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
18503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#define USE_NALLEN_FOUR         1
18603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
18720111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::MPEG4Writer(const char *filename)
18820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    : mFile(fopen(filename, "wb")),
1891acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong      mUse32BitOffset(true),
190a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
191a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mStarted(false),
19220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mOffset(0),
19313aec890216948b0c364f8f92792129d0335f506James Dong      mMdatOffset(0),
1947837c17063a4c50bc856ba59418516fdab731de7James Dong      mEstimatedMoovBoxSize(0),
195f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong      mInterleaveDurationUs(1000000) {
1960c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(mFile != NULL);
19720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
19820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
19930ab66297501757d745b9ae10da61adcd891f497Andreas HuberMPEG4Writer::MPEG4Writer(int fd)
20030ab66297501757d745b9ae10da61adcd891f497Andreas Huber    : mFile(fdopen(fd, "wb")),
2011acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong      mUse32BitOffset(true),
202a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
203a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mStarted(false),
20430ab66297501757d745b9ae10da61adcd891f497Andreas Huber      mOffset(0),
20513aec890216948b0c364f8f92792129d0335f506James Dong      mMdatOffset(0),
2067837c17063a4c50bc856ba59418516fdab731de7James Dong      mEstimatedMoovBoxSize(0),
207f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong      mInterleaveDurationUs(1000000) {
20830ab66297501757d745b9ae10da61adcd891f497Andreas Huber    CHECK(mFile != NULL);
20930ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
21030ab66297501757d745b9ae10da61adcd891f497Andreas Huber
21120111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() {
21220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    stop();
21320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
21420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    for (List<Track *>::iterator it = mTracks.begin();
21520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber         it != mTracks.end(); ++it) {
21620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        delete *it;
21720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
21820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mTracks.clear();
21920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
22020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
221dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::dump(
222dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        int fd, const Vector<String16>& args) {
223dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    const size_t SIZE = 256;
224dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    char buffer[SIZE];
225dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    String8 result;
226dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "   MPEG4Writer %p\n", this);
227dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
228dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "     mStarted: %s\n", mStarted? "true": "false");
229dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
230dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    ::write(fd, result.string(), result.size());
231dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    for (List<Track *>::iterator it = mTracks.begin();
232dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong         it != mTracks.end(); ++it) {
233dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        (*it)->dump(fd, args);
234dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    }
235dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    return OK;
236dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong}
237dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong
238dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::Track::dump(
239dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        int fd, const Vector<String16>& args) const {
240dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    const size_t SIZE = 256;
241dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    char buffer[SIZE];
242dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    String8 result;
243dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "     %s track\n", mIsAudio? "Audio": "Video");
244dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
245dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "       reached EOS: %s\n",
246dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong            mReachedEOS? "true": "false");
247dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
248dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    ::write(fd, result.string(), result.size());
249dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    return OK;
250dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong}
251dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong
2522dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
25325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    Track *track = new Track(this, source);
25420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mTracks.push_back(track);
2552dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
2562dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    return OK;
25720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
25820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
25993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::startTracks(MetaData *params) {
260a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    for (List<Track *>::iterator it = mTracks.begin();
261a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong         it != mTracks.end(); ++it) {
26293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        status_t err = (*it)->start(params);
263a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
264a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (err != OK) {
265a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            for (List<Track *>::iterator it2 = mTracks.begin();
266a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong                 it2 != it; ++it2) {
267a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong                (*it2)->stop();
268a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            }
269a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
270a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            return err;
271a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
272a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
273a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    return OK;
274a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
275a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
2762dec2b5be2056c6d9428897dc672185872d30d17James Dongint64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) {
2772dec2b5be2056c6d9428897dc672185872d30d17James Dong    // This implementation is highly experimental/heurisitic.
2782dec2b5be2056c6d9428897dc672185872d30d17James Dong    //
2792dec2b5be2056c6d9428897dc672185872d30d17James Dong    // Statistical analysis shows that metadata usually accounts
2802dec2b5be2056c6d9428897dc672185872d30d17James Dong    // for a small portion of the total file size, usually < 0.6%.
2812dec2b5be2056c6d9428897dc672185872d30d17James Dong    // Currently, lets set to 0.4% for now.
2822dec2b5be2056c6d9428897dc672185872d30d17James Dong
2832dec2b5be2056c6d9428897dc672185872d30d17James Dong    // The default MIN_MOOV_BOX_SIZE is set to 0.4% x 1MB,
2842dec2b5be2056c6d9428897dc672185872d30d17James Dong    // where 1MB is the common file size limit for MMS application.
2852dec2b5be2056c6d9428897dc672185872d30d17James Dong    // The default MAX _MOOV_BOX_SIZE value is based on about 4
2862dec2b5be2056c6d9428897dc672185872d30d17James Dong    // minute video recording with a bit rate about 3 Mbps, because
2872dec2b5be2056c6d9428897dc672185872d30d17James Dong    // statistics also show that most of the video captured are going
2882dec2b5be2056c6d9428897dc672185872d30d17James Dong    // to be less than 3 minutes.
2892dec2b5be2056c6d9428897dc672185872d30d17James Dong
2902dec2b5be2056c6d9428897dc672185872d30d17James Dong    // If the estimation is wrong, we will pay the price of wasting
2912dec2b5be2056c6d9428897dc672185872d30d17James Dong    // some reserved space. This should not happen so often statistically.
2922dec2b5be2056c6d9428897dc672185872d30d17James Dong    static const int32_t factor = mUse32BitOffset? 1: 2;
2932dec2b5be2056c6d9428897dc672185872d30d17James Dong    static const int64_t MIN_MOOV_BOX_SIZE = 4 * 1024;  // 4 KB
2942dec2b5be2056c6d9428897dc672185872d30d17James Dong    static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000);
2952dec2b5be2056c6d9428897dc672185872d30d17James Dong    int64_t size = MIN_MOOV_BOX_SIZE;
2962dec2b5be2056c6d9428897dc672185872d30d17James Dong
2972dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (mMaxFileSizeLimitBytes != 0) {
2982dec2b5be2056c6d9428897dc672185872d30d17James Dong        size = mMaxFileSizeLimitBytes * 4 / 1000;
2992dec2b5be2056c6d9428897dc672185872d30d17James Dong    } else if (mMaxFileDurationLimitUs != 0) {
3002dec2b5be2056c6d9428897dc672185872d30d17James Dong        if (bitRate <= 0) {
3012dec2b5be2056c6d9428897dc672185872d30d17James Dong            // We could not estimate the file size since bitRate is not set.
3022dec2b5be2056c6d9428897dc672185872d30d17James Dong            size = MIN_MOOV_BOX_SIZE;
3032dec2b5be2056c6d9428897dc672185872d30d17James Dong        } else {
3042dec2b5be2056c6d9428897dc672185872d30d17James Dong            size = ((mMaxFileDurationLimitUs * bitRate * 4) / 1000 / 8000000);
3052dec2b5be2056c6d9428897dc672185872d30d17James Dong        }
3062dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
3072dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (size < MIN_MOOV_BOX_SIZE) {
3082dec2b5be2056c6d9428897dc672185872d30d17James Dong        size = MIN_MOOV_BOX_SIZE;
3092dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
3102dec2b5be2056c6d9428897dc672185872d30d17James Dong
3112dec2b5be2056c6d9428897dc672185872d30d17James Dong    // Any long duration recording will be probably end up with
3122dec2b5be2056c6d9428897dc672185872d30d17James Dong    // non-streamable mp4 file.
3132dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (size > MAX_MOOV_BOX_SIZE) {
3142dec2b5be2056c6d9428897dc672185872d30d17James Dong        size = MAX_MOOV_BOX_SIZE;
3152dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
3162dec2b5be2056c6d9428897dc672185872d30d17James Dong
3172dec2b5be2056c6d9428897dc672185872d30d17James Dong    LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated"
3182dec2b5be2056c6d9428897dc672185872d30d17James Dong         " moov size %lld bytes",
3192dec2b5be2056c6d9428897dc672185872d30d17James Dong         mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size);
3202dec2b5be2056c6d9428897dc672185872d30d17James Dong    return factor * size;
3212dec2b5be2056c6d9428897dc672185872d30d17James Dong}
3222dec2b5be2056c6d9428897dc672185872d30d17James Dong
3232dec2b5be2056c6d9428897dc672185872d30d17James Dongstatus_t MPEG4Writer::start(MetaData *param) {
32420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mFile == NULL) {
32525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        return UNKNOWN_ERROR;
32620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
32720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
3282dec2b5be2056c6d9428897dc672185872d30d17James Dong    int32_t use64BitOffset;
3292dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (param &&
3302dec2b5be2056c6d9428897dc672185872d30d17James Dong        param->findInt32(kKey64BitFileOffset, &use64BitOffset) &&
3312dec2b5be2056c6d9428897dc672185872d30d17James Dong        use64BitOffset) {
3322dec2b5be2056c6d9428897dc672185872d30d17James Dong        mUse32BitOffset = false;
3332dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
3342dec2b5be2056c6d9428897dc672185872d30d17James Dong
3352dec2b5be2056c6d9428897dc672185872d30d17James Dong    // System property can overwrite the file offset bits parameter
3362dec2b5be2056c6d9428897dc672185872d30d17James Dong    char value[PROPERTY_VALUE_MAX];
3372dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (property_get("media.stagefright.record-64bits", value, NULL)
3382dec2b5be2056c6d9428897dc672185872d30d17James Dong        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
3392dec2b5be2056c6d9428897dc672185872d30d17James Dong        mUse32BitOffset = false;
3402dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
3412dec2b5be2056c6d9428897dc672185872d30d17James Dong
342065d1aff96818df54456053f1574aec8a234d0deJames Dong    mStartTimestampUs = -1;
34393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
344a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (mStarted) {
345a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mPaused) {
346a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            mPaused = false;
34793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            return startTracks(param);
348a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
349a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return OK;
350a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
351a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
3528f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    if (!param ||
3538f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        !param->findInt32(kKeyTimeScale, &mTimeScale)) {
3548f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        mTimeScale = 1000;
3558f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    }
3568f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    CHECK(mTimeScale > 0);
3578f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    LOGV("movie time scale: %d", mTimeScale);
3588f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
3597837c17063a4c50bc856ba59418516fdab731de7James Dong    mStreamableFile = true;
3607837c17063a4c50bc856ba59418516fdab731de7James Dong    mWriteMoovBoxToMemory = false;
3617837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBuffer = NULL;
3627837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBufferOffset = 0;
3637837c17063a4c50bc856ba59418516fdab731de7James Dong
36420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    beginBox("ftyp");
36593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong      {
36693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        int32_t fileType;
36793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        if (param && param->findInt32(kKeyFileType, &fileType) &&
36893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            fileType != OUTPUT_FORMAT_MPEG_4) {
36993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            writeFourcc("3gp4");
37093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        } else {
37193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            writeFourcc("isom");
37293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        }
37393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong      }
37420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      writeInt32(0);
37520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      writeFourcc("isom");
37693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong      writeFourcc("3gp4");
37720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    endBox();
37820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
3797837c17063a4c50bc856ba59418516fdab731de7James Dong    mFreeBoxOffset = mOffset;
38020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
3817837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mEstimatedMoovBoxSize == 0) {
3822dec2b5be2056c6d9428897dc672185872d30d17James Dong        int32_t bitRate = -1;
3832dec2b5be2056c6d9428897dc672185872d30d17James Dong        if (param) {
3842dec2b5be2056c6d9428897dc672185872d30d17James Dong            param->findInt32(kKeyBitRate, &bitRate);
3852dec2b5be2056c6d9428897dc672185872d30d17James Dong        }
3862dec2b5be2056c6d9428897dc672185872d30d17James Dong        mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate);
3877837c17063a4c50bc856ba59418516fdab731de7James Dong    }
3887837c17063a4c50bc856ba59418516fdab731de7James Dong    CHECK(mEstimatedMoovBoxSize >= 8);
3897837c17063a4c50bc856ba59418516fdab731de7James Dong    fseeko(mFile, mFreeBoxOffset, SEEK_SET);
3907837c17063a4c50bc856ba59418516fdab731de7James Dong    writeInt32(mEstimatedMoovBoxSize);
3917837c17063a4c50bc856ba59418516fdab731de7James Dong    write("free", 4);
3927837c17063a4c50bc856ba59418516fdab731de7James Dong
3937837c17063a4c50bc856ba59418516fdab731de7James Dong    mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize;
3947837c17063a4c50bc856ba59418516fdab731de7James Dong    mOffset = mMdatOffset;
3957837c17063a4c50bc856ba59418516fdab731de7James Dong    fseeko(mFile, mMdatOffset, SEEK_SET);
3961acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    if (mUse32BitOffset) {
3971acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        write("????mdat", 8);
3981acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    } else {
3991acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        write("\x00\x00\x00\x01mdat????????", 16);
4001acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    }
4011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
4021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    status_t err = startWriterThread();
4031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (err != OK) {
4041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        return err;
4051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
4061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
4071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    err = startTracks(param);
408a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (err != OK) {
409a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return err;
41020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
4111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
412a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mStarted = true;
41325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return OK;
41420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
41520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
41637187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::pause() {
417a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (mFile == NULL) {
41837187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
419a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
420a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mPaused = true;
42137187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = OK;
422a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    for (List<Track *>::iterator it = mTracks.begin();
423a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong         it != mTracks.end(); ++it) {
42437187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = (*it)->pause();
42537187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (status != OK) {
42637187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
42737187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
428a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
42937187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
430a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
431a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
4321c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::stopWriterThread() {
4331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("stopWriterThread");
4341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
4351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    {
4361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        Mutex::Autolock autolock(mLock);
4371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
4381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mDone = true;
4391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mChunkReadyCondition.signal();
4401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
4411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
4421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    void *dummy;
4431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_join(mThread, &dummy);
4441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
4451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
44637187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::stop() {
44720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mFile == NULL) {
44837187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
44920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
45020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
45137187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = OK;
4528f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t maxDurationUs = 0;
45320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    for (List<Track *>::iterator it = mTracks.begin();
45420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber         it != mTracks.end(); ++it) {
45537187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = (*it)->stop();
45637187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (err == OK && status != OK) {
45737187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
45837187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
45920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
4608f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        int64_t durationUs = (*it)->getDurationUs();
4618f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        if (durationUs > maxDurationUs) {
4628f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            maxDurationUs = durationUs;
46320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
46420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
46520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
4661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    stopWriterThread();
4677837c17063a4c50bc856ba59418516fdab731de7James Dong
46837187916a486504acaf83bea30147eb5fbf46ae5James Dong    // Do not write out movie header on error.
46937187916a486504acaf83bea30147eb5fbf46ae5James Dong    if (err != OK) {
47037187916a486504acaf83bea30147eb5fbf46ae5James Dong        fflush(mFile);
47137187916a486504acaf83bea30147eb5fbf46ae5James Dong        fclose(mFile);
47237187916a486504acaf83bea30147eb5fbf46ae5James Dong        mFile = NULL;
47337187916a486504acaf83bea30147eb5fbf46ae5James Dong        mStarted = false;
47437187916a486504acaf83bea30147eb5fbf46ae5James Dong        return err;
47537187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
47637187916a486504acaf83bea30147eb5fbf46ae5James Dong
47720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    // Fix up the size of the 'mdat' chunk.
4781acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    if (mUse32BitOffset) {
4791acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        fseeko(mFile, mMdatOffset, SEEK_SET);
4801acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset));
4811acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        fwrite(&size, 1, 4, mFile);
4821acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    } else {
4831acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        fseeko(mFile, mMdatOffset + 8, SEEK_SET);
4841acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        int64_t size = mOffset - mMdatOffset;
4851acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        size = hton64(size);
4861acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        fwrite(&size, 1, 8, mFile);
4871acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    }
4887837c17063a4c50bc856ba59418516fdab731de7James Dong    fseeko(mFile, mOffset, SEEK_SET);
48920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
49020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    time_t now = time(NULL);
4917837c17063a4c50bc856ba59418516fdab731de7James Dong    const off_t moovOffset = mOffset;
4927837c17063a4c50bc856ba59418516fdab731de7James Dong    mWriteMoovBoxToMemory = true;
4937837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
4947837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBufferOffset = 0;
4957837c17063a4c50bc856ba59418516fdab731de7James Dong    CHECK(mMoovBoxBuffer != NULL);
496c059860c73678a202bfa33062723e8f82fb779d9James Dong    int32_t duration = (maxDurationUs * mTimeScale + 5E5) / 1E6;
49720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
49820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    beginBox("moov");
49920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
50020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      beginBox("mvhd");
50120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);             // version=0, flags=0
50220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(now);           // creation time
50320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(now);           // modification time
5048f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        writeInt32(mTimeScale);    // mvhd timescale
5051acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        writeInt32(duration);
5061acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        writeInt32(0x10000);       // rate: 1.0
50720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt16(0x100);         // volume
50820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt16(0);             // reserved
50920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);             // reserved
51020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);             // reserved
51120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0x10000);       // matrix
51220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);
51320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);
51420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);
51520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0x10000);
51620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);
51720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);
51820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);
51920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0x40000000);
52020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);             // predefined
52120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);             // predefined
52220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);             // predefined
52320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);             // predefined
52420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);             // predefined
52520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(0);             // predefined
52620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        writeInt32(mTracks.size() + 1);  // nextTrackID
52720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      endBox();  // mvhd
52820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
52920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      int32_t id = 1;
53020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      for (List<Track *>::iterator it = mTracks.begin();
53120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber           it != mTracks.end(); ++it, ++id) {
5321acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong          (*it)->writeTrackHeader(id, mUse32BitOffset);
53320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      }
53420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    endBox();  // moov
53520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
5367837c17063a4c50bc856ba59418516fdab731de7James Dong    mWriteMoovBoxToMemory = false;
5377837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mStreamableFile) {
5387837c17063a4c50bc856ba59418516fdab731de7James Dong        CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize);
5397837c17063a4c50bc856ba59418516fdab731de7James Dong
5407837c17063a4c50bc856ba59418516fdab731de7James Dong        // Moov box
5417837c17063a4c50bc856ba59418516fdab731de7James Dong        fseeko(mFile, mFreeBoxOffset, SEEK_SET);
5427837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset = mFreeBoxOffset;
5437837c17063a4c50bc856ba59418516fdab731de7James Dong        write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, mFile);
5447837c17063a4c50bc856ba59418516fdab731de7James Dong
5457837c17063a4c50bc856ba59418516fdab731de7James Dong        // Free box
5462dec2b5be2056c6d9428897dc672185872d30d17James Dong        fseeko(mFile, mOffset, SEEK_SET);
5477837c17063a4c50bc856ba59418516fdab731de7James Dong        writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset);
5487837c17063a4c50bc856ba59418516fdab731de7James Dong        write("free", 4);
5497837c17063a4c50bc856ba59418516fdab731de7James Dong
5507837c17063a4c50bc856ba59418516fdab731de7James Dong        // Free temp memory
5517837c17063a4c50bc856ba59418516fdab731de7James Dong        free(mMoovBoxBuffer);
5527837c17063a4c50bc856ba59418516fdab731de7James Dong        mMoovBoxBuffer = NULL;
5537837c17063a4c50bc856ba59418516fdab731de7James Dong        mMoovBoxBufferOffset = 0;
5542dec2b5be2056c6d9428897dc672185872d30d17James Dong    } else {
5552dec2b5be2056c6d9428897dc672185872d30d17James Dong        LOGI("The mp4 file will not be streamable.");
5567837c17063a4c50bc856ba59418516fdab731de7James Dong    }
5577837c17063a4c50bc856ba59418516fdab731de7James Dong
5580c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(mBoxes.empty());
55920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
5607837c17063a4c50bc856ba59418516fdab731de7James Dong    fflush(mFile);
56120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    fclose(mFile);
56220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mFile = NULL;
563a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mStarted = false;
56437187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
56520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
56620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
56713aec890216948b0c364f8f92792129d0335f506James Dongstatus_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) {
56813aec890216948b0c364f8f92792129d0335f506James Dong    mInterleaveDurationUs = durationUs;
56913aec890216948b0c364f8f92792129d0335f506James Dong    return OK;
57013aec890216948b0c364f8f92792129d0335f506James Dong}
57113aec890216948b0c364f8f92792129d0335f506James Dong
57213aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::lock() {
57313aec890216948b0c364f8f92792129d0335f506James Dong    mLock.lock();
57413aec890216948b0c364f8f92792129d0335f506James Dong}
57513aec890216948b0c364f8f92792129d0335f506James Dong
57613aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::unlock() {
57713aec890216948b0c364f8f92792129d0335f506James Dong    mLock.unlock();
57813aec890216948b0c364f8f92792129d0335f506James Dong}
57920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
58013aec890216948b0c364f8f92792129d0335f506James Dongoff_t MPEG4Writer::addSample_l(MediaBuffer *buffer) {
58120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    off_t old_offset = mOffset;
58220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
58320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
58420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber           1, buffer->range_length(), mFile);
58520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
58620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mOffset += buffer->range_length();
58720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
58820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    return old_offset;
58920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
59020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
59103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) {
59203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (buffer->range_length() < 4) {
59303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return;
59403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
59503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
59603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    const uint8_t *ptr =
59703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        (const uint8_t *)buffer->data() + buffer->range_offset();
59803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
59903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
60003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        buffer->set_range(
60103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                buffer->range_offset() + 4, buffer->range_length() - 4);
60203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
60303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber}
60403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
60513aec890216948b0c364f8f92792129d0335f506James Dongoff_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
60630ab66297501757d745b9ae10da61adcd891f497Andreas Huber    off_t old_offset = mOffset;
60730ab66297501757d745b9ae10da61adcd891f497Andreas Huber
60830ab66297501757d745b9ae10da61adcd891f497Andreas Huber    size_t length = buffer->range_length();
60903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
61003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR
61103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    uint8_t x = length >> 24;
61203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    fwrite(&x, 1, 1, mFile);
61303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    x = (length >> 16) & 0xff;
61403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    fwrite(&x, 1, 1, mFile);
61503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    x = (length >> 8) & 0xff;
61603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    fwrite(&x, 1, 1, mFile);
61703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    x = length & 0xff;
61803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    fwrite(&x, 1, 1, mFile);
61903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else
62030ab66297501757d745b9ae10da61adcd891f497Andreas Huber    CHECK(length < 65536);
62130ab66297501757d745b9ae10da61adcd891f497Andreas Huber
62230ab66297501757d745b9ae10da61adcd891f497Andreas Huber    uint8_t x = length >> 8;
62330ab66297501757d745b9ae10da61adcd891f497Andreas Huber    fwrite(&x, 1, 1, mFile);
62430ab66297501757d745b9ae10da61adcd891f497Andreas Huber    x = length & 0xff;
62530ab66297501757d745b9ae10da61adcd891f497Andreas Huber    fwrite(&x, 1, 1, mFile);
62603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif
62730ab66297501757d745b9ae10da61adcd891f497Andreas Huber
62830ab66297501757d745b9ae10da61adcd891f497Andreas Huber    fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
62930ab66297501757d745b9ae10da61adcd891f497Andreas Huber           1, length, mFile);
63030ab66297501757d745b9ae10da61adcd891f497Andreas Huber
63103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR
63203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    mOffset += length + 4;
63303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else
63430ab66297501757d745b9ae10da61adcd891f497Andreas Huber    mOffset += length + 2;
63503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif
63630ab66297501757d745b9ae10da61adcd891f497Andreas Huber
63730ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return old_offset;
63830ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
63930ab66297501757d745b9ae10da61adcd891f497Andreas Huber
6407837c17063a4c50bc856ba59418516fdab731de7James Dongsize_t MPEG4Writer::write(
6417837c17063a4c50bc856ba59418516fdab731de7James Dong        const void *ptr, size_t size, size_t nmemb, FILE *stream) {
6427837c17063a4c50bc856ba59418516fdab731de7James Dong
6437837c17063a4c50bc856ba59418516fdab731de7James Dong    const size_t bytes = size * nmemb;
6447837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mWriteMoovBoxToMemory) {
6451acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        off_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes;
6461acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        if (moovBoxSize > mEstimatedMoovBoxSize) {
6477837c17063a4c50bc856ba59418516fdab731de7James Dong            for (List<off_t>::iterator it = mBoxes.begin();
6487837c17063a4c50bc856ba59418516fdab731de7James Dong                 it != mBoxes.end(); ++it) {
6497837c17063a4c50bc856ba59418516fdab731de7James Dong                (*it) += mOffset;
6507837c17063a4c50bc856ba59418516fdab731de7James Dong            }
6517837c17063a4c50bc856ba59418516fdab731de7James Dong            fseeko(mFile, mOffset, SEEK_SET);
6527837c17063a4c50bc856ba59418516fdab731de7James Dong            fwrite(mMoovBoxBuffer, 1, mMoovBoxBufferOffset, stream);
6537837c17063a4c50bc856ba59418516fdab731de7James Dong            fwrite(ptr, size, nmemb, stream);
6547837c17063a4c50bc856ba59418516fdab731de7James Dong            mOffset += (bytes + mMoovBoxBufferOffset);
6557837c17063a4c50bc856ba59418516fdab731de7James Dong            free(mMoovBoxBuffer);
6567837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBuffer = NULL;
6577837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBufferOffset = 0;
6587837c17063a4c50bc856ba59418516fdab731de7James Dong            mWriteMoovBoxToMemory = false;
6597837c17063a4c50bc856ba59418516fdab731de7James Dong            mStreamableFile = false;
6607837c17063a4c50bc856ba59418516fdab731de7James Dong        } else {
6617837c17063a4c50bc856ba59418516fdab731de7James Dong            memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes);
6627837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBufferOffset += bytes;
6637837c17063a4c50bc856ba59418516fdab731de7James Dong        }
6647837c17063a4c50bc856ba59418516fdab731de7James Dong    } else {
6657837c17063a4c50bc856ba59418516fdab731de7James Dong        fwrite(ptr, size, nmemb, stream);
6667837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset += bytes;
6677837c17063a4c50bc856ba59418516fdab731de7James Dong    }
6687837c17063a4c50bc856ba59418516fdab731de7James Dong    return bytes;
6697837c17063a4c50bc856ba59418516fdab731de7James Dong}
6707837c17063a4c50bc856ba59418516fdab731de7James Dong
67120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) {
6720c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK_EQ(strlen(fourcc), 4);
67320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6747837c17063a4c50bc856ba59418516fdab731de7James Dong    mBoxes.push_back(mWriteMoovBoxToMemory?
6757837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBufferOffset: mOffset);
67620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
67720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    writeInt32(0);
67820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    writeFourcc(fourcc);
67920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
68020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
68120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() {
6820c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(!mBoxes.empty());
68320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
68420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    off_t offset = *--mBoxes.end();
68520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mBoxes.erase(--mBoxes.end());
68620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6877837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mWriteMoovBoxToMemory) {
6887837c17063a4c50bc856ba59418516fdab731de7James Dong       int32_t x = htonl(mMoovBoxBufferOffset - offset);
6897837c17063a4c50bc856ba59418516fdab731de7James Dong       memcpy(mMoovBoxBuffer + offset, &x, 4);
6907837c17063a4c50bc856ba59418516fdab731de7James Dong    } else {
6917837c17063a4c50bc856ba59418516fdab731de7James Dong        fseeko(mFile, offset, SEEK_SET);
6927837c17063a4c50bc856ba59418516fdab731de7James Dong        writeInt32(mOffset - offset);
6937837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset -= 4;
6947837c17063a4c50bc856ba59418516fdab731de7James Dong        fseeko(mFile, mOffset, SEEK_SET);
6957837c17063a4c50bc856ba59418516fdab731de7James Dong    }
69620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
69720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
69820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) {
6997837c17063a4c50bc856ba59418516fdab731de7James Dong    write(&x, 1, 1, mFile);
70020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
70120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
70220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) {
70320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = htons(x);
7047837c17063a4c50bc856ba59418516fdab731de7James Dong    write(&x, 1, 2, mFile);
70520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
70620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
70720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) {
70820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = htonl(x);
7097837c17063a4c50bc856ba59418516fdab731de7James Dong    write(&x, 1, 4, mFile);
71020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
71120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
71220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) {
71320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = hton64(x);
7147837c17063a4c50bc856ba59418516fdab731de7James Dong    write(&x, 1, 8, mFile);
71520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
71620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
71720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) {
71820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    size_t n = strlen(s);
7197837c17063a4c50bc856ba59418516fdab731de7James Dong    write(s, 1, n + 1, mFile);
72020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
72120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
72220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) {
7230c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK_EQ(strlen(s), 4);
7247837c17063a4c50bc856ba59418516fdab731de7James Dong    write(s, 1, 4, mFile);
72520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
72620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
72720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) {
7287837c17063a4c50bc856ba59418516fdab731de7James Dong    write(data, 1, size, mFile);
72920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
73020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
731d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileSizeLimit() {
732d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    // No limit
733d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    if (mMaxFileSizeLimitBytes == 0) {
734d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        return false;
735d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
736d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
737956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize);
738d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    for (List<Track *>::iterator it = mTracks.begin();
739d599cd4573b5a2d5914c5040e0565ef866749b77James Dong         it != mTracks.end(); ++it) {
740d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
741d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
742d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    return (nTotalBytesEstimate >= mMaxFileSizeLimitBytes);
743d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
744d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
745d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileDurationLimit() {
746d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    // No limit
747d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    if (mMaxFileDurationLimitUs == 0) {
748d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        return false;
749d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
750d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
751d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    for (List<Track *>::iterator it = mTracks.begin();
752d599cd4573b5a2d5914c5040e0565ef866749b77James Dong         it != mTracks.end(); ++it) {
753d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) {
754d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            return true;
755d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
756d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
757d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    return false;
758d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
759d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
76025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() {
76125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool allDone = true;
76225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    for (List<Track *>::iterator it = mTracks.begin();
76325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber         it != mTracks.end(); ++it) {
76425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        if (!(*it)->reachedEOS()) {
76525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber            allDone = false;
76625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber            break;
76725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        }
76825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    }
76925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
77025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return allDone;
77125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber}
77225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
773f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongvoid MPEG4Writer::setStartTimestampUs(int64_t timeUs) {
774f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    LOGI("setStartTimestampUs: %lld", timeUs);
775f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    CHECK(timeUs >= 0);
7763c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    Mutex::Autolock autoLock(mLock);
777065d1aff96818df54456053f1574aec8a234d0deJames Dong    if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) {
778f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong        mStartTimestampUs = timeUs;
779f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong        LOGI("Earliest track starting time: %lld", mStartTimestampUs);
7803c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    }
7813c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong}
7823c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong
783f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongint64_t MPEG4Writer::getStartTimestampUs() {
7843c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    Mutex::Autolock autoLock(mLock);
7853c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    return mStartTimestampUs;
7863c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong}
7873c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong
78858ae9c530247668f8af36e30d228c716c226b3d4James Dongsize_t MPEG4Writer::numTracks() {
78958ae9c530247668f8af36e30d228c716c226b3d4James Dong    Mutex::Autolock autolock(mLock);
79058ae9c530247668f8af36e30d228c716c226b3d4James Dong    return mTracks.size();
79158ae9c530247668f8af36e30d228c716c226b3d4James Dong}
79258ae9c530247668f8af36e30d228c716c226b3d4James Dong
79320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber////////////////////////////////////////////////////////////////////////////////
79420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
79520111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track(
79625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        MPEG4Writer *owner, const sp<MediaSource> &source)
79720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    : mOwner(owner),
79825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber      mMeta(source->getFormat()),
79920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mSource(source),
80020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mDone(false),
801a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
802a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mResumed(false),
803c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong      mTrackDurationUs(0),
804956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      mEstimatedTrackSizeBytes(0),
805be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong      mSamplesHaveSameSize(true),
80620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mCodecSpecificData(NULL),
80725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber      mCodecSpecificDataSize(0),
808548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber      mGotAllCodecSpecificData(false),
80925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber      mReachedEOS(false) {
81019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    getCodecSpecificDataFromInputFormatIfPossible();
8118f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
8121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    const char *mime;
8131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mMeta->findCString(kKeyMIMEType, &mime);
8141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
8151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsAudio = !strncasecmp(mime, "audio/", 6);
8161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
8171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong               !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
8181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
819c059860c73678a202bfa33062723e8f82fb779d9James Dong    setTimeScale();
820c059860c73678a202bfa33062723e8f82fb779d9James Dong}
821c059860c73678a202bfa33062723e8f82fb779d9James Dong
822c059860c73678a202bfa33062723e8f82fb779d9James Dongvoid MPEG4Writer::Track::setTimeScale() {
823c059860c73678a202bfa33062723e8f82fb779d9James Dong    LOGV("setTimeScale");
824c059860c73678a202bfa33062723e8f82fb779d9James Dong    // Default time scale
825c059860c73678a202bfa33062723e8f82fb779d9James Dong    mTimeScale = 90000;
826c059860c73678a202bfa33062723e8f82fb779d9James Dong
827c059860c73678a202bfa33062723e8f82fb779d9James Dong    if (mIsAudio) {
828c059860c73678a202bfa33062723e8f82fb779d9James Dong        // Use the sampling rate as the default time scale for audio track.
829c059860c73678a202bfa33062723e8f82fb779d9James Dong        int32_t sampleRate;
830c059860c73678a202bfa33062723e8f82fb779d9James Dong        bool success = mMeta->findInt32(kKeySampleRate, &sampleRate);
831c059860c73678a202bfa33062723e8f82fb779d9James Dong        CHECK(success);
832c059860c73678a202bfa33062723e8f82fb779d9James Dong        mTimeScale = sampleRate;
833c059860c73678a202bfa33062723e8f82fb779d9James Dong    }
834c059860c73678a202bfa33062723e8f82fb779d9James Dong
835c059860c73678a202bfa33062723e8f82fb779d9James Dong    // If someone would like to overwrite the timescale, use user-supplied value.
836c059860c73678a202bfa33062723e8f82fb779d9James Dong    int32_t timeScale;
837c059860c73678a202bfa33062723e8f82fb779d9James Dong    if (mMeta->findInt32(kKeyTimeScale, &timeScale)) {
838c059860c73678a202bfa33062723e8f82fb779d9James Dong        mTimeScale = timeScale;
839c059860c73678a202bfa33062723e8f82fb779d9James Dong    }
840c059860c73678a202bfa33062723e8f82fb779d9James Dong
8418f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    CHECK(mTimeScale > 0);
84219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber}
84319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
84419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Hubervoid MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
84519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    const char *mime;
84619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
84719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
84819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
84919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        uint32_t type;
85019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        const void *data;
85119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        size_t size;
85219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        if (mMeta->findData(kKeyAVCC, &type, &data, &size)) {
85319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mCodecSpecificData = malloc(size);
85419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mCodecSpecificDataSize = size;
85519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            memcpy(mCodecSpecificData, data, size);
85619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mGotAllCodecSpecificData = true;
85719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        }
85819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
85919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
86019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        uint32_t type;
86119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        const void *data;
86219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        size_t size;
86319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
86419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            ESDS esds(data, size);
86519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            if (esds.getCodecSpecificInfo(&data, &size) == OK) {
86619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mCodecSpecificData = malloc(size);
86719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mCodecSpecificDataSize = size;
86819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                memcpy(mCodecSpecificData, data, size);
86919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mGotAllCodecSpecificData = true;
87019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            }
87119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        }
87219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    }
87320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
87420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
87520111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() {
87620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    stop();
87720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
87820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mCodecSpecificData != NULL) {
87920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        free(mCodecSpecificData);
88020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mCodecSpecificData = NULL;
88120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
88220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
88320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
88493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongvoid MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) {
88593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    LOGV("initTrackingProgressStatus");
88693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mPreviousTrackTimeUs = -1;
88793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mTrackingProgressStatus = false;
88893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mTrackEveryTimeDurationUs = 0;
88993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    {
89093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        int64_t timeUs;
89193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) {
89293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            LOGV("Receive request to track progress status for every %lld us", timeUs);
89393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            mTrackEveryTimeDurationUs = timeUs;
89493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            mTrackingProgressStatus = true;
89593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        }
89693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    }
89793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong}
89893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
8991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong// static
9001c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid *MPEG4Writer::ThreadWrapper(void *me) {
9011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("ThreadWrapper: %p", me);
9021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    MPEG4Writer *writer = static_cast<MPEG4Writer *>(me);
9031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    writer->threadFunc();
9041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    return NULL;
9051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
9061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
9071c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::bufferChunk(const Chunk& chunk) {
9081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("bufferChunk: %p", chunk.mTrack);
9091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Mutex::Autolock autolock(mLock);
9101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    CHECK_EQ(mDone, false);
9111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
9121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
9131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
9141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
9151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (chunk.mTrack == it->mTrack) {  // Found owner
9161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            it->mChunks.push_back(chunk);
9171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            mChunkReadyCondition.signal();
9181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            return;
9191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
9201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
9211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
9221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    CHECK("Received a chunk for a unknown track" == 0);
9231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
9241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
9251c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::writeFirstChunk(ChunkInfo* info) {
9261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("writeFirstChunk: %p", info->mTrack);
9271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
9281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    List<Chunk>::iterator chunkIt = info->mChunks.begin();
9291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<MediaBuffer *>::iterator it = chunkIt->mSamples.begin();
9301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != chunkIt->mSamples.end(); ++it) {
9311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
9321c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        off_t offset = info->mTrack->isAvc()
9331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                            ? addLengthPrefixedSample_l(*it)
9341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                            : addSample_l(*it);
9351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (it == chunkIt->mSamples.begin()) {
9361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            info->mTrack->addChunkOffset(offset);
9371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
9381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
9391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
9401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    // Done with the current chunk.
9411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    // Release all the samples in this chunk.
9421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    while (!chunkIt->mSamples.empty()) {
9431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        List<MediaBuffer *>::iterator it = chunkIt->mSamples.begin();
9441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        (*it)->release();
9451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        (*it) = NULL;
9461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        chunkIt->mSamples.erase(it);
9471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
9481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    chunkIt->mSamples.clear();
9491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    info->mChunks.erase(chunkIt);
9501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
9511c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
9521c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::writeChunks() {
9531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("writeChunks");
9541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    size_t outstandingChunks = 0;
9551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    while (!mChunkInfos.empty()) {
9561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        List<ChunkInfo>::iterator it = mChunkInfos.begin();
9571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        while (!it->mChunks.empty()) {
9581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            CHECK_EQ(OK, writeOneChunk());
9591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            ++outstandingChunks;
9601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
9611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        it->mTrack = NULL;
9621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mChunkInfos.erase(it);
9631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
9641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mChunkInfos.clear();
9651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGD("%d chunks are written in the last batch", outstandingChunks);
9661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
9671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
9681c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::writeOneChunk() {
9691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("writeOneChunk");
9701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
9711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    // Find the smallest timestamp, and write that chunk out
9721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    // XXX: What if some track is just too slow?
9731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL;
9741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Track *track = NULL;
9751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
9761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
9771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (!it->mChunks.empty()) {
9781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            List<Chunk>::iterator chunkIt = it->mChunks.begin();
9791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            if (chunkIt->mTimeStampUs < minTimestampUs) {
9801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                minTimestampUs = chunkIt->mTimeStampUs;
9811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                track = it->mTrack;
9821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            }
9831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
9841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
9851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
9861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (track == NULL) {
9871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        LOGV("Nothing to be written after all");
9881c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        return OK;
9891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
9901c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
9911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (mIsFirstChunk) {
9921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mIsFirstChunk = false;
9931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
9941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
9951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
9961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (it->mTrack == track) {
9971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            writeFirstChunk(&(*it));
9981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
9991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
10001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    return OK;
10011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
10021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
10031c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::threadFunc() {
10041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("threadFunc");
10051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
10061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    while (!mDone) {
10071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        {
10081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            Mutex::Autolock autolock(mLock);
10091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            mChunkReadyCondition.wait(mLock);
10101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            CHECK_EQ(writeOneChunk(), OK);
10111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
10121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
10131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
10141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    {
10151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        // Write ALL samples
10161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        Mutex::Autolock autolock(mLock);
10171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        writeChunks();
10181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
10191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
10201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
10211c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::startWriterThread() {
10221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("startWriterThread");
10231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
10241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mDone = false;
10251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsFirstChunk = true;
1026e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    mDriftTimeUs = 0;
10271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<Track *>::iterator it = mTracks.begin();
10281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mTracks.end(); ++it) {
10291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        ChunkInfo info;
10301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        info.mTrack = *it;
10311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mChunkInfos.push_back(info);
10321c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
10331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
10341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_t attr;
10351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_init(&attr);
10361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
10371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_create(&mThread, &attr, ThreadWrapper, this);
10381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_destroy(&attr);
10391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    return OK;
10401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
10411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
104293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::Track::start(MetaData *params) {
1043a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (!mDone && mPaused) {
1044a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        mPaused = false;
1045a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        mResumed = true;
1046a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return OK;
1047a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
104825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
104993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t startTimeUs;
105019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) {
105119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        startTimeUs = 0;
105219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    }
105319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
1054e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    mIsRealTimeRecording = true;
1055e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    {
1056e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        int32_t isNotRealTime;
1057e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) {
1058e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            mIsRealTimeRecording = (isNotRealTime == 0);
1059e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        }
1060e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    }
1061e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
106293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    initTrackingProgressStatus(params);
106393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
1064f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    sp<MetaData> meta = new MetaData;
1065f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    meta->setInt64(kKeyTime, startTimeUs);
1066f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    status_t err = mSource->start(meta.get());
106725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    if (err != OK) {
106825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        mDone = mReachedEOS = true;
106925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        return err;
107025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    }
107120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
107220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_t attr;
107320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_init(&attr);
107420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
107520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
107620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mDone = false;
1077c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    mTrackDurationUs = 0;
107825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    mReachedEOS = false;
1079956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    mEstimatedTrackSizeBytes = 0;
108020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
108125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    pthread_create(&mThread, &attr, ThreadWrapper, this);
108220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_destroy(&attr);
108325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
108425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return OK;
108520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
108620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
108737187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::pause() {
1088a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mPaused = true;
108937187916a486504acaf83bea30147eb5fbf46ae5James Dong    return OK;
1090a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
1091a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
109237187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::stop() {
109320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mDone) {
109437187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
109520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
109620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
109720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mDone = true;
109820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
109920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    void *dummy;
110020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_join(mThread, &dummy);
110120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
110237187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = (status_t) dummy;
110337187916a486504acaf83bea30147eb5fbf46ae5James Dong
110437187916a486504acaf83bea30147eb5fbf46ae5James Dong    {
110537187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = mSource->stop();
110637187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (err == OK && status != OK && status != ERROR_END_OF_STREAM) {
110737187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
110837187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
110937187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
111037187916a486504acaf83bea30147eb5fbf46ae5James Dong
111137187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
111220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
111320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
111425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() {
111525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return mReachedEOS;
111625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber}
111725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
111820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static
111920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) {
112020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track *track = static_cast<Track *>(me);
112120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
112237187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = track->threadEntry();
112337187916a486504acaf83bea30147eb5fbf46ae5James Dong    return (void *) err;
112420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
112520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1126548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber#include <ctype.h>
1127548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huberstatic void hexdump(const void *_data, size_t size) {
1128548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber    const uint8_t *data = (const uint8_t *)_data;
1129548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber    size_t offset = 0;
1130548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber    while (offset < size) {
1131548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber        printf("0x%04x  ", offset);
1132548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
1133548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber        size_t n = size - offset;
1134548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber        if (n > 16) {
1135548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            n = 16;
1136548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber        }
1137548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
1138548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber        for (size_t i = 0; i < 16; ++i) {
1139548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            if (i == 8) {
1140548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber                printf(" ");
1141548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            }
1142548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
1143548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            if (offset + i < size) {
1144548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber                printf("%02x ", data[offset + i]);
1145548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            } else {
1146548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber                printf("   ");
1147548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            }
1148548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber        }
1149548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
1150548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber        printf(" ");
1151548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
1152548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber        for (size_t i = 0; i < n; ++i) {
1153548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            if (isprint(data[offset + i])) {
1154548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber                printf("%c", data[offset + i]);
1155548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            } else {
1156548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber                printf(".");
1157548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            }
1158548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber        }
1159548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
1160548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber        printf("\n");
1161548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
1162548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber        offset += 16;
1163548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber    }
1164548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber}
1165548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
11663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic void getNalUnitType(uint8_t byte, uint8_t* type) {
11673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("getNalUnitType: %d", byte);
11683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
11693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // nal_unit_type: 5-bit unsigned integer
11703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    *type = (byte & 0x1F);
11713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
11723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
11733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t *findNextStartCode(
11743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length) {
11753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
11763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("findNextStartCode: %p %d", data, length);
11773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
11783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t bytesLeft = length;
11793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    while (bytesLeft > 4  &&
11803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) {
11813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        --bytesLeft;
11823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
11833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (bytesLeft <= 4) {
11843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        bytesLeft = 0; // Last parameter set
11853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
11863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return &data[length - bytesLeft];
11873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
11883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
11893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongconst uint8_t *MPEG4Writer::Track::parseParamSet(
11903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length, int type, size_t *paramSetLen) {
11913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
11923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("parseParamSet");
11933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    CHECK(type == kNalUnitTypeSeqParamSet ||
11943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong          type == kNalUnitTypePicParamSet);
11953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
11963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *nextStartCode = findNextStartCode(data, length);
11973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    *paramSetLen = nextStartCode - data;
11983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (*paramSetLen == 0) {
11993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        LOGE("Param set is malformed, since its length is 0");
12003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return NULL;
12013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
12023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
12033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    AVCParamSet paramSet(*paramSetLen, data);
12043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (type == kNalUnitTypeSeqParamSet) {
12053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (*paramSetLen < 4) {
12063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Seq parameter set malformed");
12073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return NULL;
12083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
12093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (mSeqParamSets.empty()) {
12103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileIdc = data[1];
12113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileCompatible = data[2];
12123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mLevelIdc = data[3];
12133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else {
12143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (mProfileIdc != data[1] ||
12153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                mProfileCompatible != data[2] ||
12163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                mLevelIdc != data[3]) {
12173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                LOGE("Inconsistent profile/level found in seq parameter sets");
12183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return NULL;
12193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
12203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
12213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mSeqParamSets.push_back(paramSet);
12223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    } else {
12233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mPicParamSets.push_back(paramSet);
12243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
12253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return nextStartCode;
12263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
12273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
12283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::copyAVCCodecSpecificData(
12293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t size) {
12303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("copyAVCCodecSpecificData");
12313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
12323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 2 bytes for each of the parameter set length field
12333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // plus the 7 bytes for the header
12343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (size < 4 + 7) {
12353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        LOGE("Codec specific data length too short: %d", size);
12363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return ERROR_MALFORMED;
12373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
12383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
12393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize = size;
12403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificData = malloc(size);
12413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    memcpy(mCodecSpecificData, data, size);
12423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return OK;
12433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
12443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
12453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::parseAVCCodecSpecificData(
12463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t size) {
12473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
12483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("parseAVCCodecSpecificData");
12493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Data starts with a start code.
12503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // SPS and PPS are separated with start codes.
12513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Also, SPS must come before PPS
12523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t type = kNalUnitTypeSeqParamSet;
12533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    bool gotSps = false;
12543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    bool gotPps = false;
12553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *tmp = data;
12563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *nextStartCode = data;
12573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t bytesLeft = size;
12583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t paramSetLen = 0;
12593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize = 0;
12603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) {
12613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        getNalUnitType(*(tmp + 4), &type);
12623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (type == kNalUnitTypeSeqParamSet) {
12633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (gotPps) {
12643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                LOGE("SPS must come before PPS");
12653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return ERROR_MALFORMED;
12663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
12673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotSps) {
12683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                gotSps = true;
12693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
12703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
12713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else if (type == kNalUnitTypePicParamSet) {
12723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotSps) {
12733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                LOGE("SPS must come before PPS");
12743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return ERROR_MALFORMED;
12753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
12763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotPps) {
12773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                gotPps = true;
12783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
12793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
12803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else {
12813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Only SPS and PPS Nal units are expected");
12823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
12833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
12843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
12853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nextStartCode == NULL) {
12863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
12873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
12883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
12893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Move on to find the next parameter set
12903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        bytesLeft -= nextStartCode - tmp;
12913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        tmp = nextStartCode;
12923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mCodecSpecificDataSize += (2 + paramSetLen);
12933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
12943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
12953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
12963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the number of seq parameter sets
12973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        size_t nSeqParamSets = mSeqParamSets.size();
12983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nSeqParamSets == 0) {
12993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Cound not find sequence parameter set");
13003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
13013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
13023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
13033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nSeqParamSets > 0x1F) {
13043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Too many seq parameter sets (%d) found", nSeqParamSets);
13053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
13063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
13073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
13083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
13093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
13103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the number of pic parameter sets
13113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        size_t nPicParamSets = mPicParamSets.size();
13123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nPicParamSets == 0) {
13133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Cound not find picture parameter set");
13143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
13153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
13163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nPicParamSets > 0xFF) {
13173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Too many pic parameter sets (%d) found", nPicParamSets);
13183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
13193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
13203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
13213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
13223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
13233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the profiles
13243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // These profiles requires additional parameter set extensions
13253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (mProfileIdc == 100 || mProfileIdc == 110 ||
13263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileIdc == 122 || mProfileIdc == 144) {
13273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Sorry, no support for profile_idc: %d!", mProfileIdc);
13283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return BAD_VALUE;
13293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
13303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
13313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
13323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return OK;
13333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
1334548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
133503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData(
133603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        const uint8_t *data, size_t size) {
1337548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber    // hexdump(data, size);
1338548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
133903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (mCodecSpecificData != NULL) {
1340548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber        LOGE("Already have codec specific data");
134103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
134203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
134303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
13443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (size < 4) {
13453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        LOGE("Codec specific data length too short: %d", size);
134603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
134703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
134803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
13493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Data is in the form of AVCCodecSpecificData
13503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (memcmp("\x00\x00\x00\x01", data, 4)) {
13513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return copyAVCCodecSpecificData(data, size);
135203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
135303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
13543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (parseAVCCodecSpecificData(data, size) != OK) {
135503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
135603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
135703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
13583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // ISO 14496-15: AVC file format
13593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize += 7;  // 7 more bytes in the header
136003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    mCodecSpecificData = malloc(mCodecSpecificDataSize);
136103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    uint8_t *header = (uint8_t *)mCodecSpecificData;
13623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[0] = 1;                     // version
13633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[1] = mProfileIdc;           // profile indication
13643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[2] = mProfileCompatible;    // profile compatibility
13653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[3] = mLevelIdc;
136603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
13673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne
136803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR
136903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    header[4] = 0xfc | 3;  // length size == 4 bytes
137003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else
137103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    header[4] = 0xfc | 1;  // length size == 2 bytes
137203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif
137303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
13743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 3-bit '111' followed by 5-bit numSequenceParameterSets
13753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    int nSequenceParamSets = mSeqParamSets.size();
13763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[5] = 0xe0 | nSequenceParamSets;
13773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header += 6;
13783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    for (List<AVCParamSet>::iterator it = mSeqParamSets.begin();
13793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong         it != mSeqParamSets.end(); ++it) {
13803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // 16-bit sequence parameter set length
13813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t seqParamSetLength = it->mLength;
13823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[0] = seqParamSetLength >> 8;
13833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[1] = seqParamSetLength & 0xff;
13843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
13853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // SPS NAL unit (sequence parameter length bytes)
13863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        memcpy(&header[2], it->mData, seqParamSetLength);
13873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header += (2 + seqParamSetLength);
13883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
13893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
13903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 8-bit nPictureParameterSets
13913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    int nPictureParamSets = mPicParamSets.size();
13923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[0] = nPictureParamSets;
13933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header += 1;
13943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    for (List<AVCParamSet>::iterator it = mPicParamSets.begin();
13953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong         it != mPicParamSets.end(); ++it) {
13963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // 16-bit picture parameter set length
13973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t picParamSetLength = it->mLength;
13983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[0] = picParamSetLength >> 8;
13993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[1] = picParamSetLength & 0xff;
14003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // PPS Nal unit (picture parameter set length bytes)
14023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        memcpy(&header[2], it->mData, picParamSetLength);
14033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header += (2 + picParamSetLength);
14043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
140503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
140603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    return OK;
140703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber}
140803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
14098644c14618d30d9e57a69df40ed939986ebf02c4James Dongstatic bool collectStatisticalData() {
14108644c14618d30d9e57a69df40ed939986ebf02c4James Dong    char value[PROPERTY_VALUE_MAX];
14118644c14618d30d9e57a69df40ed939986ebf02c4James Dong    if (property_get("media.stagefright.record-stats", value, NULL)
14128644c14618d30d9e57a69df40ed939986ebf02c4James Dong        && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
14138644c14618d30d9e57a69df40ed939986ebf02c4James Dong        return true;
14148644c14618d30d9e57a69df40ed939986ebf02c4James Dong    }
14158644c14618d30d9e57a69df40ed939986ebf02c4James Dong    return false;
14168644c14618d30d9e57a69df40ed939986ebf02c4James Dong}
14178644c14618d30d9e57a69df40ed939986ebf02c4James Dong
141837187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::threadEntry() {
141930ab66297501757d745b9ae10da61adcd891f497Andreas Huber    int32_t count = 0;
142013aec890216948b0c364f8f92792129d0335f506James Dong    const int64_t interleaveDurationUs = mOwner->interleaveDuration();
142113aec890216948b0c364f8f92792129d0335f506James Dong    int64_t chunkTimestampUs = 0;
142213aec890216948b0c364f8f92792129d0335f506James Dong    int32_t nChunks = 0;
142313aec890216948b0c364f8f92792129d0335f506James Dong    int32_t nZeroLengthFrames = 0;
14248f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t lastTimestampUs = 0;  // Previous sample time stamp in ms
14258f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t lastDurationUs = 0;   // Between the previous two samples in ms
1426c059860c73678a202bfa33062723e8f82fb779d9James Dong    int64_t currDurationTicks = 0;  // Timescale based ticks
1427c059860c73678a202bfa33062723e8f82fb779d9James Dong    int64_t lastDurationTicks = 0;  // Timescale based ticks
14288f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int32_t sampleCount = 1;      // Sample count in the current stts table entry
1429be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    uint32_t previousSampleSize = 0;  // Size of the previous sample
1430a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    int64_t previousPausedDurationUs = 0;
14311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    int64_t timestampUs;
1432e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
1433d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong    sp<MetaData> meta_data;
14348644c14618d30d9e57a69df40ed939986ebf02c4James Dong    bool collectStats = collectStatisticalData();
143520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1436ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    mNumSamples = 0;
14371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mMaxWriteTimeUs = 0;
143893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    status_t err = OK;
143920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    MediaBuffer *buffer;
144093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    while (!mDone && (err = mSource->read(&buffer)) == OK) {
144120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        if (buffer->range_length() == 0) {
144220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            buffer->release();
144320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            buffer = NULL;
144413aec890216948b0c364f8f92792129d0335f506James Dong            ++nZeroLengthFrames;
144520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            continue;
144620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
144720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1448a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // If the codec specific data has not been received yet, delay pause.
1449a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // After the codec specific data is received, discard what we received
1450a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // when the track is to be paused.
1451a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mPaused && !mResumed) {
1452a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            buffer->release();
1453a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            buffer = NULL;
1454a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            continue;
1455a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
1456a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
145730ab66297501757d745b9ae10da61adcd891f497Andreas Huber        ++count;
145830ab66297501757d745b9ae10da61adcd891f497Andreas Huber
145903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        int32_t isCodecConfig;
146003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
146103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                && isCodecConfig) {
1462548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            CHECK(!mGotAllCodecSpecificData);
1463548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
14641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            if (mIsAvc) {
146503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                status_t err = makeAVCCodecSpecificData(
146603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        (const uint8_t *)buffer->data()
146703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                            + buffer->range_offset(),
146803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        buffer->range_length());
1469be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                CHECK_EQ(OK, err);
14701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            } else if (mIsMPEG4) {
147103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                mCodecSpecificDataSize = buffer->range_length();
147203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                mCodecSpecificData = malloc(mCodecSpecificDataSize);
147303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                memcpy(mCodecSpecificData,
147403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        (const uint8_t *)buffer->data()
147503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                            + buffer->range_offset(),
147603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                       buffer->range_length());
147730ab66297501757d745b9ae10da61adcd891f497Andreas Huber            }
147830ab66297501757d745b9ae10da61adcd891f497Andreas Huber
147930ab66297501757d745b9ae10da61adcd891f497Andreas Huber            buffer->release();
148030ab66297501757d745b9ae10da61adcd891f497Andreas Huber            buffer = NULL;
148130ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1482548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            mGotAllCodecSpecificData = true;
148330ab66297501757d745b9ae10da61adcd891f497Andreas Huber            continue;
1484a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
1485a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
1486d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        // Make a deep copy of the MediaBuffer and Metadata and release
1487d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        // the original as soon as we can
1488d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        MediaBuffer *copy = new MediaBuffer(buffer->range_length());
1489d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(),
1490d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong                buffer->range_length());
1491d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        copy->set_range(0, buffer->range_length());
1492d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        meta_data = new MetaData(*buffer->meta_data().get());
1493d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        buffer->release();
1494d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        buffer = NULL;
1495d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
14961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (mIsAvc) StripStartcode(copy);
1497e136c3bb38e88315bf8797a464ebf2c788296b22James Dong
14988644c14618d30d9e57a69df40ed939986ebf02c4James Dong        size_t sampleSize;
14991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        sampleSize = mIsAvc
150003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#if USE_NALLEN_FOUR
1501d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong                ? copy->range_length() + 4
150203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#else
1503d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong                ? copy->range_length() + 2
150403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#endif
1505d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong                : copy->range_length();
1506050b28a593350047845a45a14cc5026221ac1620James Dong
1507d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        // Max file size or duration handling
15088644c14618d30d9e57a69df40ed939986ebf02c4James Dong        mEstimatedTrackSizeBytes += sampleSize;
1509d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if (mOwner->exceedsFileSizeLimit()) {
1510d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
1511d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            break;
1512d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
1513d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if (mOwner->exceedsFileDurationLimit()) {
1514d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
1515d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            break;
1516d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
1517d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
1518050b28a593350047845a45a14cc5026221ac1620James Dong
1519d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        int32_t isSync = false;
1520d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        meta_data->findInt32(kKeyIsSyncFrame, &isSync);
1521d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
1522d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
1523d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
1524d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong////////////////////////////////////////////////////////////////////////////////
15258644c14618d30d9e57a69df40ed939986ebf02c4James Dong        if (mSampleSizes.empty()) {
1526f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong            mStartTimestampUs = timestampUs;
1527f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong            mOwner->setStartTimestampUs(mStartTimestampUs);
15283c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong        }
152948c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber
1530a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mResumed) {
1531c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong            previousPausedDurationUs += (timestampUs - mTrackDurationUs - lastDurationUs);
1532a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            mResumed = false;
1533a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
1534a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
1535a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        timestampUs -= previousPausedDurationUs;
1536e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        if (mIsRealTimeRecording && !mIsAudio) {
1537e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            // The minor adjustment on the timestamp is heuristic/experimental
1538e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            // We are adjusting the timestamp to reduce the fluctuation of the duration
1539e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            // of neighboring samples. This in turn helps reduce the track header size,
1540e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            // especially, the number of entries in the "stts" box.
1541e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            if (mNumSamples > 1) {
1542d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong                int64_t currDriftTimeUs = mOwner->getDriftTimeUs();
1543d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong                int64_t durationUs = timestampUs + currDriftTimeUs - lastTimestampUs;
1544e259531ce59ab1f31de5a23124b22536f6a5a767James Dong                int64_t diffUs = (durationUs > lastDurationUs)
1545e259531ce59ab1f31de5a23124b22536f6a5a767James Dong                            ? durationUs - lastDurationUs
1546e259531ce59ab1f31de5a23124b22536f6a5a767James Dong                            : lastDurationUs - durationUs;
1547e259531ce59ab1f31de5a23124b22536f6a5a767James Dong                if (diffUs <= 5000) {  // XXX: Magic number 5ms
1548e259531ce59ab1f31de5a23124b22536f6a5a767James Dong                    timestampUs = lastTimestampUs + lastDurationUs;
1549e259531ce59ab1f31de5a23124b22536f6a5a767James Dong                } else {
1550d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong                    timestampUs += currDriftTimeUs;
1551e259531ce59ab1f31de5a23124b22536f6a5a767James Dong                }
1552e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            }
1553e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        }
1554e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        CHECK(timestampUs >= 0);
1555e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        if (mNumSamples > 1) {
1556e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            if (timestampUs <= lastTimestampUs) {
15574f86a980fee1880dca61b828599fa6d76755a485James Dong                LOGW("Frame arrives too late!");
15584f86a980fee1880dca61b828599fa6d76755a485James Dong                // Don't drop the late frame, since dropping a frame may cause
15594f86a980fee1880dca61b828599fa6d76755a485James Dong                // problems later during playback
15604f86a980fee1880dca61b828599fa6d76755a485James Dong
15614f86a980fee1880dca61b828599fa6d76755a485James Dong                // The idea here is to avoid having two or more samples with the
15624f86a980fee1880dca61b828599fa6d76755a485James Dong                // same timestamp in the output file.
15634f86a980fee1880dca61b828599fa6d76755a485James Dong                if (mTimeScale >= 1000000LL) {
156440e9940fadf22daa64c1e766fa8a855c7b149c17James Dong                    timestampUs = lastTimestampUs + 1;
15654f86a980fee1880dca61b828599fa6d76755a485James Dong                } else {
156640e9940fadf22daa64c1e766fa8a855c7b149c17James Dong                    timestampUs = lastTimestampUs + (1000000LL + (mTimeScale >> 1)) / mTimeScale;
15674f86a980fee1880dca61b828599fa6d76755a485James Dong                }
1568e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            }
1569e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        }
1570e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
1571a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        LOGV("time stamp: %lld and previous paused duration %lld",
1572a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong                timestampUs, previousPausedDurationUs);
1573c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong        if (timestampUs > mTrackDurationUs) {
1574c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong            mTrackDurationUs = timestampUs;
15753b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber        }
15763b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber
15778644c14618d30d9e57a69df40ed939986ebf02c4James Dong        mSampleSizes.push_back(sampleSize);
1578ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong        ++mNumSamples;
1579ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong        if (mNumSamples > 2) {
1580c059860c73678a202bfa33062723e8f82fb779d9James Dong            // We need to use the time scale based ticks, rather than the
1581c059860c73678a202bfa33062723e8f82fb779d9James Dong            // timestamp itself to determine whether we have to use a new
1582c059860c73678a202bfa33062723e8f82fb779d9James Dong            // stts entry, since we may have rounding errors.
1583c059860c73678a202bfa33062723e8f82fb779d9James Dong            // The calculation is intended to reduce the accumulated
1584c059860c73678a202bfa33062723e8f82fb779d9James Dong            // rounding errors.
1585c059860c73678a202bfa33062723e8f82fb779d9James Dong            currDurationTicks =
1586c059860c73678a202bfa33062723e8f82fb779d9James Dong                     ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
1587c059860c73678a202bfa33062723e8f82fb779d9James Dong                     (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
1588c059860c73678a202bfa33062723e8f82fb779d9James Dong
1589c059860c73678a202bfa33062723e8f82fb779d9James Dong            if (currDurationTicks != lastDurationTicks) {
15908f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong                SttsTableEntry sttsEntry(sampleCount, lastDurationUs);
1591be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                mSttsTableEntries.push_back(sttsEntry);
1592be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                sampleCount = 1;
1593be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            } else {
1594be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                ++sampleCount;
1595be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            }
1596be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        }
1597be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        if (mSamplesHaveSameSize) {
1598ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong            if (mNumSamples >= 2 && previousSampleSize != sampleSize) {
1599be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                mSamplesHaveSameSize = false;
1600be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            }
16018644c14618d30d9e57a69df40ed939986ebf02c4James Dong            previousSampleSize = sampleSize;
1602be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        }
16038644c14618d30d9e57a69df40ed939986ebf02c4James Dong        lastDurationUs = timestampUs - lastTimestampUs;
1604c059860c73678a202bfa33062723e8f82fb779d9James Dong        lastDurationTicks = currDurationTicks;
16058644c14618d30d9e57a69df40ed939986ebf02c4James Dong        lastTimestampUs = timestampUs;
1606e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        if (mIsRealTimeRecording && mIsAudio) {
1607d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong            int64_t driftTimeUs = 0;
1608d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong            if (meta_data->findInt64(kKeyDriftTime, &driftTimeUs)) {
1609d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong                mOwner->setDriftTimeUs(driftTimeUs);
1610e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            }
1611e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        }
161220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1613d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        if (isSync != 0) {
1614ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong            mStssTableEntries.push_back(mNumSamples);
1615d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        }
1616d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
161793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        if (mTrackingProgressStatus) {
161893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            if (mPreviousTrackTimeUs <= 0) {
161993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong                mPreviousTrackTimeUs = mStartTimestampUs;
162093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            }
1621faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong            trackProgressStatus(timestampUs);
162293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        }
162358ae9c530247668f8af36e30d228c716c226b3d4James Dong        if (mOwner->numTracks() == 1) {
16241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            off_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy)
162558ae9c530247668f8af36e30d228c716c226b3d4James Dong                                 : mOwner->addSample_l(copy);
162658ae9c530247668f8af36e30d228c716c226b3d4James Dong            if (mChunkOffsets.empty()) {
162758ae9c530247668f8af36e30d228c716c226b3d4James Dong                mChunkOffsets.push_back(offset);
162858ae9c530247668f8af36e30d228c716c226b3d4James Dong            }
162958ae9c530247668f8af36e30d228c716c226b3d4James Dong            copy->release();
163058ae9c530247668f8af36e30d228c716c226b3d4James Dong            copy = NULL;
163158ae9c530247668f8af36e30d228c716c226b3d4James Dong            continue;
163258ae9c530247668f8af36e30d228c716c226b3d4James Dong        }
163313aec890216948b0c364f8f92792129d0335f506James Dong
163413aec890216948b0c364f8f92792129d0335f506James Dong        mChunkSamples.push_back(copy);
163513aec890216948b0c364f8f92792129d0335f506James Dong        if (interleaveDurationUs == 0) {
163613aec890216948b0c364f8f92792129d0335f506James Dong            StscTableEntry stscEntry(++nChunks, 1, 1);
163713aec890216948b0c364f8f92792129d0335f506James Dong            mStscTableEntries.push_back(stscEntry);
16381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            bufferChunk(timestampUs);
163913aec890216948b0c364f8f92792129d0335f506James Dong        } else {
164013aec890216948b0c364f8f92792129d0335f506James Dong            if (chunkTimestampUs == 0) {
164113aec890216948b0c364f8f92792129d0335f506James Dong                chunkTimestampUs = timestampUs;
164213aec890216948b0c364f8f92792129d0335f506James Dong            } else {
164313aec890216948b0c364f8f92792129d0335f506James Dong                if (timestampUs - chunkTimestampUs > interleaveDurationUs) {
164413aec890216948b0c364f8f92792129d0335f506James Dong                    ++nChunks;
16458644c14618d30d9e57a69df40ed939986ebf02c4James Dong                    if (collectStats) {
16468644c14618d30d9e57a69df40ed939986ebf02c4James Dong                        mChunkDurations.push_back(timestampUs - chunkTimestampUs);
16478644c14618d30d9e57a69df40ed939986ebf02c4James Dong                    }
164813aec890216948b0c364f8f92792129d0335f506James Dong                    if (nChunks == 1 ||  // First chunk
164913aec890216948b0c364f8f92792129d0335f506James Dong                        (--(mStscTableEntries.end()))->samplesPerChunk !=
165013aec890216948b0c364f8f92792129d0335f506James Dong                         mChunkSamples.size()) {
165113aec890216948b0c364f8f92792129d0335f506James Dong                        StscTableEntry stscEntry(nChunks,
165213aec890216948b0c364f8f92792129d0335f506James Dong                                mChunkSamples.size(), 1);
165313aec890216948b0c364f8f92792129d0335f506James Dong                        mStscTableEntries.push_back(stscEntry);
165413aec890216948b0c364f8f92792129d0335f506James Dong                    }
16551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                    bufferChunk(timestampUs);
165613aec890216948b0c364f8f92792129d0335f506James Dong                    chunkTimestampUs = timestampUs;
165713aec890216948b0c364f8f92792129d0335f506James Dong                }
165813aec890216948b0c364f8f92792129d0335f506James Dong            }
165913aec890216948b0c364f8f92792129d0335f506James Dong        }
166013aec890216948b0c364f8f92792129d0335f506James Dong
166120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
166225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
16638644c14618d30d9e57a69df40ed939986ebf02c4James Dong    if (mSampleSizes.empty()) {
166437187916a486504acaf83bea30147eb5fbf46ae5James Dong        err = ERROR_MALFORMED;
1665690f546b0ee548dbfe997df36418e5302ec2d786James Dong    } else if (OK != checkCodecSpecificData()) {
1666690f546b0ee548dbfe997df36418e5302ec2d786James Dong        err = ERROR_MALFORMED;
1667f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong    }
1668faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    mOwner->trackProgressStatus(this, -1, err);
1669be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
167013aec890216948b0c364f8f92792129d0335f506James Dong    // Last chunk
167158ae9c530247668f8af36e30d228c716c226b3d4James Dong    if (mOwner->numTracks() == 1) {
1672ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong        StscTableEntry stscEntry(1, mNumSamples, 1);
167358ae9c530247668f8af36e30d228c716c226b3d4James Dong        mStscTableEntries.push_back(stscEntry);
167458ae9c530247668f8af36e30d228c716c226b3d4James Dong    } else if (!mChunkSamples.empty()) {
167513aec890216948b0c364f8f92792129d0335f506James Dong        ++nChunks;
167613aec890216948b0c364f8f92792129d0335f506James Dong        StscTableEntry stscEntry(nChunks, mChunkSamples.size(), 1);
167713aec890216948b0c364f8f92792129d0335f506James Dong        mStscTableEntries.push_back(stscEntry);
16781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        bufferChunk(timestampUs);
167913aec890216948b0c364f8f92792129d0335f506James Dong    }
168013aec890216948b0c364f8f92792129d0335f506James Dong
1681be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // We don't really know how long the last frame lasts, since
1682be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // there is no frame time after it, just repeat the previous
1683be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // frame's duration.
1684ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    if (mNumSamples == 1) {
16858f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        lastDurationUs = 0;  // A single sample's duration
1686be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    } else {
1687be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        ++sampleCount;  // Count for the last sample
1688be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    }
16898f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    SttsTableEntry sttsEntry(sampleCount, lastDurationUs);
1690be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    mSttsTableEntries.push_back(sttsEntry);
1691c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    mTrackDurationUs += lastDurationUs;
169225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    mReachedEOS = true;
16931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. Max write time: %lld us - %s",
16941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            count, nZeroLengthFrames, mNumSamples, mMaxWriteTimeUs, mIsAudio? "audio": "video");
1695365a963142093a1cd8efdcea76b5f65096a5b115James Dong
16961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    logStatisticalData(mIsAudio);
169737187916a486504acaf83bea30147eb5fbf46ae5James Dong    if (err == ERROR_END_OF_STREAM) {
169837187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
169937187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
170037187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
1701365a963142093a1cd8efdcea76b5f65096a5b115James Dong}
1702365a963142093a1cd8efdcea76b5f65096a5b115James Dong
1703faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) {
1704faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    LOGV("trackProgressStatus: %lld us", timeUs);
1705215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    if (mTrackEveryTimeDurationUs > 0 &&
1706215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong        timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) {
170793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        LOGV("Fire time tracking progress status at %lld us", timeUs);
1708faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        mOwner->trackProgressStatus(this, timeUs - mPreviousTrackTimeUs, err);
170993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        mPreviousTrackTimeUs = timeUs;
171093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    }
171193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong}
171293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
1713faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::trackProgressStatus(
1714faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        const MPEG4Writer::Track* track, int64_t timeUs, status_t err) {
1715faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    Mutex::Autolock lock(mLock);
1716faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    int32_t nTracks = mTracks.size();
1717faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    CHECK(nTracks >= 1);
1718faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    CHECK(nTracks < 64);  // Arbitrary number
1719faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
1720faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    int32_t trackNum = 0;
1721faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong#if 0
1722faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    // In the worst case, we can put the trackNum
1723faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    // along with MEDIA_RECORDER_INFO_COMPLETION_STATUS
1724faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    // to report the progress.
1725faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    for (List<Track *>::iterator it = mTracks.begin();
1726faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong         it != mTracks.end(); ++it, ++trackNum) {
1727faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        if (track == (*it)) {
1728faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong            break;
1729faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        }
1730faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    }
1731faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong#endif
1732faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    CHECK(trackNum < nTracks);
1733faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    trackNum <<= 16;
1734faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
1735faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    // Error notification
1736faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    // Do not consider ERROR_END_OF_STREAM an error
1737faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    if (err != OK && err != ERROR_END_OF_STREAM) {
1738faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        notify(MEDIA_RECORDER_EVENT_ERROR,
1739faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               trackNum | MEDIA_RECORDER_ERROR_UNKNOWN,
1740faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               err);
1741faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        return;
1742faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    }
1743faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
1744faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    if (timeUs == -1) {
1745faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        // Send completion notification
1746faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        notify(MEDIA_RECORDER_EVENT_INFO,
1747faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               trackNum | MEDIA_RECORDER_INFO_COMPLETION_STATUS,
1748faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               err);
1749faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        return;
1750faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    } else {
1751faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        // Send progress status
1752faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        notify(MEDIA_RECORDER_EVENT_INFO,
1753faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               trackNum | MEDIA_RECORDER_INFO_PROGRESS_TIME_STATUS,
1754faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               timeUs / 1000);
1755faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    }
1756faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong}
1757faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
1758215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dongvoid MPEG4Writer::Track::findMinAvgMaxSampleDurationMs(
1759215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong        int32_t *min, int32_t *avg, int32_t *max) {
17608644c14618d30d9e57a69df40ed939986ebf02c4James Dong    CHECK(!mSampleSizes.empty());
1761c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    int32_t avgSampleDurationMs = mTrackDurationUs / 1000 / mNumSamples;
1762215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    int32_t minSampleDurationMs = 0x7FFFFFFF;
1763215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    int32_t maxSampleDurationMs = 0;
1764365a963142093a1cd8efdcea76b5f65096a5b115James Dong    for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
1765365a963142093a1cd8efdcea76b5f65096a5b115James Dong        it != mSttsTableEntries.end(); ++it) {
17668f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        int32_t sampleDurationMs =
17678f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            (static_cast<int32_t>(it->sampleDurationUs) + 500) / 1000;
1768215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong        if (sampleDurationMs > maxSampleDurationMs) {
1769215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong            maxSampleDurationMs = sampleDurationMs;
1770215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong        } else if (sampleDurationMs < minSampleDurationMs) {
1771215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong            minSampleDurationMs = sampleDurationMs;
1772365a963142093a1cd8efdcea76b5f65096a5b115James Dong        }
1773215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong        LOGI("sample duration: %d ms", sampleDurationMs);
1774365a963142093a1cd8efdcea76b5f65096a5b115James Dong    }
1775215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    CHECK(minSampleDurationMs != 0);
1776215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    CHECK(avgSampleDurationMs != 0);
1777215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    CHECK(maxSampleDurationMs != 0);
1778215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    *min = minSampleDurationMs;
1779215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    *avg = avgSampleDurationMs;
1780215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    *max = maxSampleDurationMs;
1781365a963142093a1cd8efdcea76b5f65096a5b115James Dong}
1782365a963142093a1cd8efdcea76b5f65096a5b115James Dong
1783365a963142093a1cd8efdcea76b5f65096a5b115James Dong// Don't count the last duration
1784365a963142093a1cd8efdcea76b5f65096a5b115James Dongvoid MPEG4Writer::Track::findMinMaxChunkDurations(int64_t *min, int64_t *max) {
1785365a963142093a1cd8efdcea76b5f65096a5b115James Dong    int64_t duration = mOwner->interleaveDuration();
1786365a963142093a1cd8efdcea76b5f65096a5b115James Dong    int64_t minChunkDuration = duration;
1787365a963142093a1cd8efdcea76b5f65096a5b115James Dong    int64_t maxChunkDuration = duration;
1788365a963142093a1cd8efdcea76b5f65096a5b115James Dong    if (mChunkDurations.size() > 1) {
1789365a963142093a1cd8efdcea76b5f65096a5b115James Dong        for (List<int64_t>::iterator it = mChunkDurations.begin();
1790365a963142093a1cd8efdcea76b5f65096a5b115James Dong            it != --mChunkDurations.end(); ++it) {
1791365a963142093a1cd8efdcea76b5f65096a5b115James Dong            if (minChunkDuration > (*it)) {
1792365a963142093a1cd8efdcea76b5f65096a5b115James Dong                minChunkDuration = (*it);
1793365a963142093a1cd8efdcea76b5f65096a5b115James Dong            } else if (maxChunkDuration < (*it)) {
1794365a963142093a1cd8efdcea76b5f65096a5b115James Dong                maxChunkDuration = (*it);
1795365a963142093a1cd8efdcea76b5f65096a5b115James Dong            }
1796365a963142093a1cd8efdcea76b5f65096a5b115James Dong        }
1797365a963142093a1cd8efdcea76b5f65096a5b115James Dong    }
1798365a963142093a1cd8efdcea76b5f65096a5b115James Dong    *min = minChunkDuration;
1799365a963142093a1cd8efdcea76b5f65096a5b115James Dong    *max = maxChunkDuration;
1800365a963142093a1cd8efdcea76b5f65096a5b115James Dong}
1801365a963142093a1cd8efdcea76b5f65096a5b115James Dong
1802365a963142093a1cd8efdcea76b5f65096a5b115James Dongvoid MPEG4Writer::Track::logStatisticalData(bool isAudio) {
1803c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    if (mTrackDurationUs <= 0 || mSampleSizes.empty()) {
1804365a963142093a1cd8efdcea76b5f65096a5b115James Dong        LOGI("nothing is recorded");
1805365a963142093a1cd8efdcea76b5f65096a5b115James Dong        return;
1806365a963142093a1cd8efdcea76b5f65096a5b115James Dong    }
1807365a963142093a1cd8efdcea76b5f65096a5b115James Dong
18088644c14618d30d9e57a69df40ed939986ebf02c4James Dong    bool collectStats = collectStatisticalData();
1809365a963142093a1cd8efdcea76b5f65096a5b115James Dong
1810365a963142093a1cd8efdcea76b5f65096a5b115James Dong    if (collectStats) {
1811215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong        LOGI("%s track - duration %lld us, total %d frames",
1812c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong                isAudio? "audio": "video", mTrackDurationUs,
1813ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong                mNumSamples);
1814215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong        int32_t min, avg, max;
1815215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong        findMinAvgMaxSampleDurationMs(&min, &avg, &max);
1816215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong        LOGI("min/avg/max sample duration (ms): %d/%d/%d", min, avg, max);
1817215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong        if (!isAudio) {
1818215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong            float avgFps = 1000.0 / avg;
1819215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong            float minFps = 1000.0 / max;
1820215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong            float maxFps = 1000.0 / min;
1821365a963142093a1cd8efdcea76b5f65096a5b115James Dong            LOGI("min/avg/max frame rate (fps): %.2f/%.2f/%.2f",
1822215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong                minFps, avgFps, maxFps);
1823365a963142093a1cd8efdcea76b5f65096a5b115James Dong        }
1824365a963142093a1cd8efdcea76b5f65096a5b115James Dong
1825365a963142093a1cd8efdcea76b5f65096a5b115James Dong        int64_t totalBytes = 0;
18268644c14618d30d9e57a69df40ed939986ebf02c4James Dong        for (List<size_t>::iterator it = mSampleSizes.begin();
18278644c14618d30d9e57a69df40ed939986ebf02c4James Dong            it != mSampleSizes.end(); ++it) {
18288644c14618d30d9e57a69df40ed939986ebf02c4James Dong            totalBytes += (*it);
1829365a963142093a1cd8efdcea76b5f65096a5b115James Dong        }
1830c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong        float bitRate = (totalBytes * 8000000.0) / mTrackDurationUs;
1831365a963142093a1cd8efdcea76b5f65096a5b115James Dong        LOGI("avg bit rate (bps): %.2f", bitRate);
1832365a963142093a1cd8efdcea76b5f65096a5b115James Dong
1833365a963142093a1cd8efdcea76b5f65096a5b115James Dong        int64_t duration = mOwner->interleaveDuration();
1834365a963142093a1cd8efdcea76b5f65096a5b115James Dong        if (duration != 0) {  // If interleaving is enabled
1835365a963142093a1cd8efdcea76b5f65096a5b115James Dong            int64_t minChunk, maxChunk;
1836365a963142093a1cd8efdcea76b5f65096a5b115James Dong            findMinMaxChunkDurations(&minChunk, &maxChunk);
1837365a963142093a1cd8efdcea76b5f65096a5b115James Dong            LOGI("min/avg/max chunk duration (ms): %lld/%lld/%lld",
1838365a963142093a1cd8efdcea76b5f65096a5b115James Dong                minChunk, duration, maxChunk);
1839365a963142093a1cd8efdcea76b5f65096a5b115James Dong        }
1840365a963142093a1cd8efdcea76b5f65096a5b115James Dong    }
184113aec890216948b0c364f8f92792129d0335f506James Dong}
184213aec890216948b0c364f8f92792129d0335f506James Dong
1843d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dongvoid MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) {
1844d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong    LOGV("setDriftTimeUs: %lld us", driftTimeUs);
1845e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    Mutex::Autolock autolock(mLock);
1846d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong    mDriftTimeUs = driftTimeUs;
1847e259531ce59ab1f31de5a23124b22536f6a5a767James Dong}
1848e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
1849e259531ce59ab1f31de5a23124b22536f6a5a767James Dongint64_t MPEG4Writer::getDriftTimeUs() {
1850e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    LOGV("getDriftTimeUs: %lld us", mDriftTimeUs);
1851e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    Mutex::Autolock autolock(mLock);
1852e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    return mDriftTimeUs;
1853e259531ce59ab1f31de5a23124b22536f6a5a767James Dong}
1854e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
18551c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
18561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("bufferChunk");
18571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
18581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    int64_t startTimeUs = systemTime() / 1000;
18591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Chunk chunk(this, timestampUs, mChunkSamples);
18601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mOwner->bufferChunk(chunk);
186113aec890216948b0c364f8f92792129d0335f506James Dong    mChunkSamples.clear();
18621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    int64_t endTimeUs = systemTime() / 1000;
18631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (mMaxWriteTimeUs < endTimeUs - startTimeUs) {
18641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mMaxWriteTimeUs = endTimeUs - startTimeUs;
18651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
186620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
186720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
18683b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const {
1869c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    return mTrackDurationUs;
187020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
187120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1872d599cd4573b5a2d5914c5040e0565ef866749b77James Dongint64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
1873d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    return mEstimatedTrackSizeBytes;
1874d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
1875d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
1876690f546b0ee548dbfe997df36418e5302ec2d786James Dongstatus_t MPEG4Writer::Track::checkCodecSpecificData() const {
1877690f546b0ee548dbfe997df36418e5302ec2d786James Dong    const char *mime;
1878690f546b0ee548dbfe997df36418e5302ec2d786James Dong    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
1879690f546b0ee548dbfe997df36418e5302ec2d786James Dong    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) ||
1880690f546b0ee548dbfe997df36418e5302ec2d786James Dong        !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
1881690f546b0ee548dbfe997df36418e5302ec2d786James Dong        !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
1882690f546b0ee548dbfe997df36418e5302ec2d786James Dong        if (!mCodecSpecificData ||
1883690f546b0ee548dbfe997df36418e5302ec2d786James Dong            mCodecSpecificDataSize <= 0) {
1884690f546b0ee548dbfe997df36418e5302ec2d786James Dong            // Missing codec specific data
1885690f546b0ee548dbfe997df36418e5302ec2d786James Dong            return ERROR_MALFORMED;
1886690f546b0ee548dbfe997df36418e5302ec2d786James Dong        }
1887690f546b0ee548dbfe997df36418e5302ec2d786James Dong    } else {
1888690f546b0ee548dbfe997df36418e5302ec2d786James Dong        if (mCodecSpecificData ||
1889690f546b0ee548dbfe997df36418e5302ec2d786James Dong            mCodecSpecificDataSize > 0) {
1890690f546b0ee548dbfe997df36418e5302ec2d786James Dong            // Unexepected codec specific data found
1891690f546b0ee548dbfe997df36418e5302ec2d786James Dong            return ERROR_MALFORMED;
1892690f546b0ee548dbfe997df36418e5302ec2d786James Dong        }
1893690f546b0ee548dbfe997df36418e5302ec2d786James Dong    }
1894690f546b0ee548dbfe997df36418e5302ec2d786James Dong    return OK;
1895690f546b0ee548dbfe997df36418e5302ec2d786James Dong}
1896690f546b0ee548dbfe997df36418e5302ec2d786James Dong
18971acfe8649f8169caf2ff098c2dc2de880d9a3760James Dongvoid MPEG4Writer::Track::writeTrackHeader(
18981acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        int32_t trackID, bool use32BitOffset) {
189920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    const char *mime;
190020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    bool success = mMeta->findCString(kKeyMIMEType, &mime);
19010c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(success);
190220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
19038f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    LOGV("%s track time scale: %d",
19041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mIsAudio? "Audio": "Video", mTimeScale);
19058f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
190620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    time_t now = time(NULL);
19078f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int32_t mvhdTimeScale = mOwner->getTimeScale();
19088f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t trakDurationUs = getDurationUs();
190920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
191020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mOwner->beginBox("trak");
191120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
191220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mOwner->beginBox("tkhd");
19131acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        // Flags = 7 to indicate that the track is enabled, and
19141acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        // part of the presentation
19151acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        mOwner->writeInt32(0x07);          // version=0, flags=7
191620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(now);           // creation time
191720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(now);           // modification time
191820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(trackID);
191920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0);             // reserved
19208f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        int32_t tkhdDuration =
19218f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            (trakDurationUs * mvhdTimeScale + 5E5) / 1E6;
19228f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        mOwner->writeInt32(tkhdDuration);  // in mvhd timescale
192320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0);             // reserved
192420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0);             // reserved
192520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt16(0);             // layer
192620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt16(0);             // alternate group
19271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mOwner->writeInt16(mIsAudio ? 0x100 : 0);  // volume
192820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt16(0);             // reserved
192920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
193020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0x10000);       // matrix
193120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0);
193220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0);
193320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0);
193420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0x10000);
193520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0);
193620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0);
193720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0);
193820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->writeInt32(0x40000000);
193920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
19401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (mIsAudio) {
194120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(0);
194220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(0);
194320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        } else {
194420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            int32_t width, height;
194520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            bool success = mMeta->findInt32(kKeyWidth, &width);
194620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            success = success && mMeta->findInt32(kKeyHeight, &height);
19470c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber            CHECK(success);
194820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1949050b28a593350047845a45a14cc5026221ac1620James Dong            mOwner->writeInt32(width << 16);   // 32-bit fixed-point value
1950050b28a593350047845a45a14cc5026221ac1620James Dong            mOwner->writeInt32(height << 16);  // 32-bit fixed-point value
195120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
195220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mOwner->endBox();  // tkhd
195320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1954f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong      int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
1955f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong      if (mStartTimestampUs != moovStartTimeUs) {
19563c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong        mOwner->beginBox("edts");
19573c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong          mOwner->beginBox("elst");
19581acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong            mOwner->writeInt32(0);           // version=0, flags=0: 32-bit time
19591acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong            mOwner->writeInt32(2);           // never ends with an empty list
19608f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
19618f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            // First elst entry: specify the starting time offset
19628f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            int64_t offsetUs = mStartTimestampUs - moovStartTimeUs;
19638f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            int32_t seg = (offsetUs * mvhdTimeScale + 5E5) / 1E6;
19648f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            mOwner->writeInt32(seg);         // in mvhd timecale
19658f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            mOwner->writeInt32(-1);          // starting time offset
19668f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            mOwner->writeInt32(1 << 16);     // rate = 1.0
19678f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
19688f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            // Second elst entry: specify the track duration
19698f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            seg = (trakDurationUs * mvhdTimeScale + 5E5) / 1E6;
19708f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            mOwner->writeInt32(seg);         // in mvhd timescale
19711acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong            mOwner->writeInt32(0);
19721acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong            mOwner->writeInt32(1 << 16);
19733c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong          mOwner->endBox();
19743c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong        mOwner->endBox();
19753c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong      }
19763c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong
197720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mOwner->beginBox("mdia");
197820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
197920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->beginBox("mdhd");
198020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeInt32(0);             // version=0, flags=0
198120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeInt32(now);           // creation time
198220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeInt32(now);           // modification time
19838f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong          mOwner->writeInt32(mTimeScale);    // media timescale
19848f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong          int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6;
19858f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong          mOwner->writeInt32(mdhdDuration);  // use media timescale
19861acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong          // Language follows the three letter standard ISO-639-2/T
19871acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong          // 'e', 'n', 'g' for "English", for instance.
19881acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong          // Each character is packed as the difference between its ASCII value and 0x60.
19891acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong          // For "English", these are 00101, 01110, 00111.
19901acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong          // XXX: Where is the padding bit located: 0x15C7?
19911acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong          mOwner->writeInt16(0);             // language code
199220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeInt16(0);             // predefined
199320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->endBox();
199420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
199520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->beginBox("hdlr");
199620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeInt32(0);             // version=0, flags=0
1997050b28a593350047845a45a14cc5026221ac1620James Dong          mOwner->writeInt32(0);             // component type: should be mhlr
19981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong          mOwner->writeFourcc(mIsAudio ? "soun" : "vide");  // component subtype
199920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeInt32(0);             // reserved
200020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeInt32(0);             // reserved
200120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->writeInt32(0);             // reserved
20021acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong          // Removing "r" for the name string just makes the string 4 byte aligned
20031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong          mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle");  // name
200420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->endBox();
200520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
200620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->beginBox("minf");
20071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong          if (mIsAudio) {
200820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->beginBox("smhd");
200920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->writeInt32(0);           // version=0, flags=0
201020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->writeInt16(0);           // balance
201120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->writeInt16(0);           // reserved
201220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->endBox();
201320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          } else {
201420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->beginBox("vmhd");
20151acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong              mOwner->writeInt32(0x01);        // version=0, flags=1
201620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->writeInt16(0);           // graphics mode
201720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->writeInt16(0);           // opcolor
201820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->writeInt16(0);
201920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->writeInt16(0);
202020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber              mOwner->endBox();
202120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          }
2022050b28a593350047845a45a14cc5026221ac1620James Dong
2023050b28a593350047845a45a14cc5026221ac1620James Dong          mOwner->beginBox("dinf");
2024050b28a593350047845a45a14cc5026221ac1620James Dong            mOwner->beginBox("dref");
2025050b28a593350047845a45a14cc5026221ac1620James Dong              mOwner->writeInt32(0);  // version=0, flags=0
20261acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong              mOwner->writeInt32(1);  // entry count (either url or urn)
20271acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong              // The table index here refers to the sample description index
20281acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong              // in the sample table entries.
2029050b28a593350047845a45a14cc5026221ac1620James Dong              mOwner->beginBox("url ");
20301acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong                mOwner->writeInt32(1);  // version=0, flags=1 (self-contained)
2031050b28a593350047845a45a14cc5026221ac1620James Dong              mOwner->endBox();  // url
2032050b28a593350047845a45a14cc5026221ac1620James Dong            mOwner->endBox();  // dref
2033050b28a593350047845a45a14cc5026221ac1620James Dong          mOwner->endBox();  // dinf
2034050b28a593350047845a45a14cc5026221ac1620James Dong
203520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->beginBox("stbl");
203620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
203720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->beginBox("stsd");
203820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(0);               // version=0, flags=0
203920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(1);               // entry count
20401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            if (mIsAudio) {
204125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                const char *fourcc = NULL;
204218291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber                if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
204325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                    fourcc = "samr";
204418291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
204525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                    fourcc = "sawb";
2046050b28a593350047845a45a14cc5026221ac1620James Dong                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2047050b28a593350047845a45a14cc5026221ac1620James Dong                    fourcc = "mp4a";
204825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                } else {
204925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                    LOGE("Unknown mime type '%s'.", mime);
205025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                    CHECK(!"should not be here, unknown mime type.");
205125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                }
205225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
205325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                mOwner->beginBox(fourcc);          // audio format
205420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0);           // reserved
205520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(0);           // reserved
2056050b28a593350047845a45a14cc5026221ac1620James Dong                  mOwner->writeInt16(0x1);         // data ref index
205720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0);           // reserved
205820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0);           // reserved
2059050b28a593350047845a45a14cc5026221ac1620James Dong                  int32_t nChannels;
2060050b28a593350047845a45a14cc5026221ac1620James Dong                  CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels));
2061050b28a593350047845a45a14cc5026221ac1620James Dong                  mOwner->writeInt16(nChannels);   // channel count
206220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(16);          // sample size
206320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(0);           // predefined
206420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(0);           // reserved
206520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
206620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  int32_t samplerate;
206720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  bool success = mMeta->findInt32(kKeySampleRate, &samplerate);
20680c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber                  CHECK(success);
206920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(samplerate << 16);
2070050b28a593350047845a45a14cc5026221ac1620James Dong                  if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2071050b28a593350047845a45a14cc5026221ac1620James Dong                    mOwner->beginBox("esds");
207251dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong                        CHECK(mCodecSpecificData);
207351dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong                        CHECK(mCodecSpecificDataSize > 0);
2074050b28a593350047845a45a14cc5026221ac1620James Dong
2075050b28a593350047845a45a14cc5026221ac1620James Dong                        mOwner->writeInt32(0);     // version=0, flags=0
2076050b28a593350047845a45a14cc5026221ac1620James Dong                        mOwner->writeInt8(0x03);   // ES_DescrTag
2077050b28a593350047845a45a14cc5026221ac1620James Dong                        mOwner->writeInt8(23 + mCodecSpecificDataSize);
2078050b28a593350047845a45a14cc5026221ac1620James Dong                        mOwner->writeInt16(0x0000);// ES_ID
2079050b28a593350047845a45a14cc5026221ac1620James Dong                        mOwner->writeInt8(0x00);
2080050b28a593350047845a45a14cc5026221ac1620James Dong
2081050b28a593350047845a45a14cc5026221ac1620James Dong                        mOwner->writeInt8(0x04);   // DecoderConfigDescrTag
2082050b28a593350047845a45a14cc5026221ac1620James Dong                        mOwner->writeInt8(15 + mCodecSpecificDataSize);
2083050b28a593350047845a45a14cc5026221ac1620James Dong                        mOwner->writeInt8(0x40);   // objectTypeIndication ISO/IEC 14492-2
2084050b28a593350047845a45a14cc5026221ac1620James Dong                        mOwner->writeInt8(0x15);   // streamType AudioStream
2085050b28a593350047845a45a14cc5026221ac1620James Dong
2086050b28a593350047845a45a14cc5026221ac1620James Dong                        mOwner->writeInt16(0x03);  // XXX
2087050b28a593350047845a45a14cc5026221ac1620James Dong                        mOwner->writeInt8(0x00);   // buffer size 24-bit
2088050b28a593350047845a45a14cc5026221ac1620James Dong                        mOwner->writeInt32(96000); // max bit rate
2089050b28a593350047845a45a14cc5026221ac1620James Dong                        mOwner->writeInt32(96000); // avg bit rate
2090050b28a593350047845a45a14cc5026221ac1620James Dong
2091050b28a593350047845a45a14cc5026221ac1620James Dong                        mOwner->writeInt8(0x05);   // DecoderSpecificInfoTag
2092050b28a593350047845a45a14cc5026221ac1620James Dong                        mOwner->writeInt8(mCodecSpecificDataSize);
2093050b28a593350047845a45a14cc5026221ac1620James Dong                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2094050b28a593350047845a45a14cc5026221ac1620James Dong
2095050b28a593350047845a45a14cc5026221ac1620James Dong                        static const uint8_t kData2[] = {
2096050b28a593350047845a45a14cc5026221ac1620James Dong                            0x06,  // SLConfigDescriptorTag
2097050b28a593350047845a45a14cc5026221ac1620James Dong                            0x01,
2098050b28a593350047845a45a14cc5026221ac1620James Dong                            0x02
2099050b28a593350047845a45a14cc5026221ac1620James Dong                        };
2100050b28a593350047845a45a14cc5026221ac1620James Dong                        mOwner->write(kData2, sizeof(kData2));
2101050b28a593350047845a45a14cc5026221ac1620James Dong
2102050b28a593350047845a45a14cc5026221ac1620James Dong                    mOwner->endBox();  // esds
21035aff464f67322cd13dc8ed165806971cfff2e4d5James Dong                  } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) ||
21045aff464f67322cd13dc8ed165806971cfff2e4d5James Dong                             !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
21055aff464f67322cd13dc8ed165806971cfff2e4d5James Dong                    // 3gpp2 Spec AMRSampleEntry fields
21065aff464f67322cd13dc8ed165806971cfff2e4d5James Dong                    mOwner->beginBox("damr");
21075aff464f67322cd13dc8ed165806971cfff2e4d5James Dong                      mOwner->writeCString("   ");  // vendor: 4 bytes
21085aff464f67322cd13dc8ed165806971cfff2e4d5James Dong                      mOwner->writeInt8(0);         // decoder version
21095aff464f67322cd13dc8ed165806971cfff2e4d5James Dong                      mOwner->writeInt16(0x83FF);   // mode set: all enabled
21105aff464f67322cd13dc8ed165806971cfff2e4d5James Dong                      mOwner->writeInt8(0);         // mode change period
21115aff464f67322cd13dc8ed165806971cfff2e4d5James Dong                      mOwner->writeInt8(1);         // frames per sample
21125aff464f67322cd13dc8ed165806971cfff2e4d5James Dong                    mOwner->endBox();
2113050b28a593350047845a45a14cc5026221ac1620James Dong                  }
211420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                mOwner->endBox();
211520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            } else {
211618291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber                if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
211720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                    mOwner->beginBox("mp4v");
211818291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber                } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
211920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                    mOwner->beginBox("s263");
212030ab66297501757d745b9ae10da61adcd891f497Andreas Huber                } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
212130ab66297501757d745b9ae10da61adcd891f497Andreas Huber                    mOwner->beginBox("avc1");
212220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                } else {
212325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber                    LOGE("Unknown mime type '%s'.", mime);
21240c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber                    CHECK(!"should not be here, unknown mime type.");
212520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                }
212620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
212720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0);           // reserved
212820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(0);           // reserved
21291acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong                  mOwner->writeInt16(1);           // data ref index
213020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(0);           // predefined
213120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(0);           // reserved
213220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0);           // predefined
213320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0);           // predefined
213420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0);           // predefined
213520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
213620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  int32_t width, height;
213720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  bool success = mMeta->findInt32(kKeyWidth, &width);
213820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  success = success && mMeta->findInt32(kKeyHeight, &height);
21390c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber                  CHECK(success);
214020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
214120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(width);
214220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(height);
214320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0x480000);    // horiz resolution
214420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0x480000);    // vert resolution
214520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt32(0);           // reserved
214620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(1);           // frame count
214720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->write("                                ", 32);
214820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(0x18);        // depth
214920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  mOwner->writeInt16(-1);          // predefined
215020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
21510c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber                  CHECK(23 + mCodecSpecificDataSize < 128);
215220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
215318291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber                  if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2154a37923e9a57d489e7bed2129369219039fa5f12cJames Dong                      CHECK(mCodecSpecificData);
2155a37923e9a57d489e7bed2129369219039fa5f12cJames Dong                      CHECK(mCodecSpecificDataSize > 0);
215620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                      mOwner->beginBox("esds");
215720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
215820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt32(0);           // version=0, flags=0
215920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
216020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt8(0x03);  // ES_DescrTag
216120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt8(23 + mCodecSpecificDataSize);
216220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt16(0x0000);  // ES_ID
216320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt8(0x1f);
216420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
216520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt8(0x04);  // DecoderConfigDescrTag
216620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt8(15 + mCodecSpecificDataSize);
216720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt8(0x20);  // objectTypeIndication ISO/IEC 14492-2
216820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt8(0x11);  // streamType VisualStream
216920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
217020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        static const uint8_t kData[] = {
217120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                            0x01, 0x77, 0x00,
217220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                            0x00, 0x03, 0xe8, 0x00,
217320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                            0x00, 0x03, 0xe8, 0x00
217420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        };
217520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->write(kData, sizeof(kData));
2176050b28a593350047845a45a14cc5026221ac1620James Dong
217720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
217820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
217920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->writeInt8(mCodecSpecificDataSize);
218020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
218120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
218220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        static const uint8_t kData2[] = {
218320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                            0x06,  // SLConfigDescriptorTag
218420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                            0x01,
218520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                            0x02
218620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        };
218720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                        mOwner->write(kData2, sizeof(kData2));
218820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
218920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                      mOwner->endBox();  // esds
219018291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber                  } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
219120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                      mOwner->beginBox("d263");
219220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
219320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                          mOwner->writeInt32(0);  // vendor
219420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                          mOwner->writeInt8(0);   // decoder version
219520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                          mOwner->writeInt8(10);  // level: 10
219620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                          mOwner->writeInt8(0);   // profile: 0
219720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
219820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                      mOwner->endBox();  // d263
219930ab66297501757d745b9ae10da61adcd891f497Andreas Huber                  } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
220051dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong                      CHECK(mCodecSpecificData);
220151dfe6d646ddcc5fc252aa4c19c9936d32af8ad7James Dong                      CHECK(mCodecSpecificDataSize > 0);
220230ab66297501757d745b9ae10da61adcd891f497Andreas Huber                      mOwner->beginBox("avcC");
220330ab66297501757d745b9ae10da61adcd891f497Andreas Huber                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
220430ab66297501757d745b9ae10da61adcd891f497Andreas Huber                      mOwner->endBox();  // avcC
220520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber                  }
220630ab66297501757d745b9ae10da61adcd891f497Andreas Huber
22071acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong                  mOwner->beginBox("pasp");
22081acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong                    // This is useful if the pixel is not square
22091acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong                    mOwner->writeInt32(1 << 16);  // hspacing
22101acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong                    mOwner->writeInt32(1 << 16);  // vspacing
22111acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong                  mOwner->endBox();  // pasp
221230ab66297501757d745b9ae10da61adcd891f497Andreas Huber                mOwner->endBox();  // mp4v, s263 or avc1
221320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            }
221420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->endBox();  // stsd
221520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
221620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->beginBox("stts");
221720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(0);  // version=0, flags=0
2218be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            mOwner->writeInt32(mSttsTableEntries.size());
2219c059860c73678a202bfa33062723e8f82fb779d9James Dong            int64_t prevTimestampUs = 0;
2220be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
2221be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                 it != mSttsTableEntries.end(); ++it) {
2222be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                mOwner->writeInt32(it->sampleCount);
2223c059860c73678a202bfa33062723e8f82fb779d9James Dong
2224c059860c73678a202bfa33062723e8f82fb779d9James Dong                // Make sure that we are calculating the sample duration the exactly
2225c059860c73678a202bfa33062723e8f82fb779d9James Dong                // same way as we made decision on how to create stts entries.
2226c059860c73678a202bfa33062723e8f82fb779d9James Dong                int64_t currTimestampUs = prevTimestampUs + it->sampleDurationUs;
2227c059860c73678a202bfa33062723e8f82fb779d9James Dong                int32_t dur = ((currTimestampUs * mTimeScale + 500000LL) / 1000000LL -
2228c059860c73678a202bfa33062723e8f82fb779d9James Dong                               (prevTimestampUs * mTimeScale + 500000LL) / 1000000LL);
2229c059860c73678a202bfa33062723e8f82fb779d9James Dong                prevTimestampUs += (it->sampleCount * it->sampleDurationUs);
2230c059860c73678a202bfa33062723e8f82fb779d9James Dong
22318f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong                mOwner->writeInt32(dur);
223220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            }
223320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->endBox();  // stts
223420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
22351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong          if (!mIsAudio) {
2236050b28a593350047845a45a14cc5026221ac1620James Dong            mOwner->beginBox("stss");
2237050b28a593350047845a45a14cc5026221ac1620James Dong              mOwner->writeInt32(0);  // version=0, flags=0
2238050b28a593350047845a45a14cc5026221ac1620James Dong              mOwner->writeInt32(mStssTableEntries.size());  // number of sync frames
2239050b28a593350047845a45a14cc5026221ac1620James Dong              for (List<int32_t>::iterator it = mStssTableEntries.begin();
2240050b28a593350047845a45a14cc5026221ac1620James Dong                   it != mStssTableEntries.end(); ++it) {
2241050b28a593350047845a45a14cc5026221ac1620James Dong                  mOwner->writeInt32(*it);
2242050b28a593350047845a45a14cc5026221ac1620James Dong              }
2243050b28a593350047845a45a14cc5026221ac1620James Dong            mOwner->endBox();  // stss
2244050b28a593350047845a45a14cc5026221ac1620James Dong          }
2245050b28a593350047845a45a14cc5026221ac1620James Dong
224620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->beginBox("stsz");
224720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(0);  // version=0, flags=0
2248be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            if (mSamplesHaveSameSize) {
22498644c14618d30d9e57a69df40ed939986ebf02c4James Dong                List<size_t>::iterator it = mSampleSizes.begin();
22508644c14618d30d9e57a69df40ed939986ebf02c4James Dong                mOwner->writeInt32(*it);  // default sample size
2251be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            } else {
2252be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                mOwner->writeInt32(0);
2253be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            }
2254ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong            mOwner->writeInt32(mNumSamples);
2255be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            if (!mSamplesHaveSameSize) {
22568644c14618d30d9e57a69df40ed939986ebf02c4James Dong                for (List<size_t>::iterator it = mSampleSizes.begin();
22578644c14618d30d9e57a69df40ed939986ebf02c4James Dong                     it != mSampleSizes.end(); ++it) {
22588644c14618d30d9e57a69df40ed939986ebf02c4James Dong                    mOwner->writeInt32(*it);
2259be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                }
226020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            }
226120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->endBox();  // stsz
226220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
226320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->beginBox("stsc");
226420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(0);  // version=0, flags=0
226513aec890216948b0c364f8f92792129d0335f506James Dong            mOwner->writeInt32(mStscTableEntries.size());
226613aec890216948b0c364f8f92792129d0335f506James Dong            for (List<StscTableEntry>::iterator it = mStscTableEntries.begin();
226713aec890216948b0c364f8f92792129d0335f506James Dong                 it != mStscTableEntries.end(); ++it) {
226813aec890216948b0c364f8f92792129d0335f506James Dong                mOwner->writeInt32(it->firstChunk);
226913aec890216948b0c364f8f92792129d0335f506James Dong                mOwner->writeInt32(it->samplesPerChunk);
227013aec890216948b0c364f8f92792129d0335f506James Dong                mOwner->writeInt32(it->sampleDescriptionId);
227120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            }
227220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber          mOwner->endBox();  // stsc
22731acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong          mOwner->beginBox(use32BitOffset? "stco": "co64");
227420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            mOwner->writeInt32(0);  // version=0, flags=0
227513aec890216948b0c364f8f92792129d0335f506James Dong            mOwner->writeInt32(mChunkOffsets.size());
227613aec890216948b0c364f8f92792129d0335f506James Dong            for (List<off_t>::iterator it = mChunkOffsets.begin();
227713aec890216948b0c364f8f92792129d0335f506James Dong                 it != mChunkOffsets.end(); ++it) {
22781acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong                if (use32BitOffset) {
22791acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong                    mOwner->writeInt32(static_cast<int32_t>(*it));
22801acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong                } else {
22811acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong                    mOwner->writeInt64((*it));
22821acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong                }
228320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            }
22848f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong          mOwner->endBox();  // stco or co64
228520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
228620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mOwner->endBox();  // stbl
22871acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong       mOwner->endBox();  // minf
228820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mOwner->endBox();  // mdia
228920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mOwner->endBox();  // trak
229020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
229120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
229220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}  // namespace android
2293