MPEG4Writer.cpp revision b21c564ce47041f9dd3ab65e36fed57c4937a42d
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 <pthread.h>
24a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong#include <sys/prctl.h>
25a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong#include <sys/resource.h>
2620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MPEG4Writer.h>
2820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaBuffer.h>
2920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MetaData.h>
300c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber#include <media/stagefright/MediaDebug.h>
3118291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber#include <media/stagefright/MediaDefs.h>
3203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#include <media/stagefright/MediaErrors.h>
3320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaSource.h>
3420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/Utils.h>
35d599cd4573b5a2d5914c5040e0565ef866749b77James Dong#include <media/mediarecorder.h>
36674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <sys/types.h>
37674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <sys/stat.h>
38674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <fcntl.h>
39674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <unistd.h>
4020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
4119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber#include "include/ESDS.h"
4219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
4320111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubernamespace android {
4420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
451f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongstatic const int64_t kMax32BitFileSize = 0x007fffffffLL;
463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypeSeqParamSet = 0x07;
473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypePicParamSet = 0x08;
485b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong
495b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong// Using longer adjustment period to suppress fluctuations in
505b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong// the audio encoding paths
515b6a01e65aa4129a9226667536d1bc1dad5980d8James Dongstatic const int64_t kVideoMediaTimeAdjustPeriodTimeUs = 600000000LL;  // 10 minutes
523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
5320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberclass MPEG4Writer::Track {
5420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberpublic:
55bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId);
568f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
5720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    ~Track();
5820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
5993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    status_t start(MetaData *params);
6037187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t stop();
6137187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t pause();
6225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool reachedEOS();
6320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
643b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber    int64_t getDurationUs() const;
65d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    int64_t getEstimatedTrackSizeBytes() const;
66b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeTrackHeader(bool use32BitOffset = true);
671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    void bufferChunk(int64_t timestampUs);
681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool isAvc() const { return mIsAvc; }
691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool isAudio() const { return mIsAudio; }
701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool isMPEG4() const { return mIsMPEG4; }
71c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    void addChunkOffset(off64_t offset);
72dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    status_t dump(int fd, const Vector<String16>& args) const;
7320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
7420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberprivate:
7520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    MPEG4Writer *mOwner;
7620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    sp<MetaData> mMeta;
77693d271e62a3726689ff68f4505ba49228eb94b2Andreas Huber    sp<MediaSource> mSource;
7820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    volatile bool mDone;
79a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    volatile bool mPaused;
80a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    volatile bool mResumed;
81eaae38445a340c4857c1c5569475879a728e63b7James Dong    volatile bool mStarted;
821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool mIsAvc;
831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool mIsAudio;
841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool mIsMPEG4;
85bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    int32_t mTrackId;
86c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    int64_t mTrackDurationUs;
87e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
88e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    // For realtime applications, we need to adjust the media clock
89e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    // for video track based on the audio media clock
90e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    bool mIsRealTimeRecording;
91e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    int64_t mMaxTimeStampUs;
92d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    int64_t mEstimatedTrackSizeBytes;
931f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    int64_t mMdatSizeBytes;
948f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int32_t mTimeScale;
9520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
9620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_t mThread;
9720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
98ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    // mNumSamples is used to track how many samples in mSampleSizes List.
99ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    // This is to reduce the cost associated with mSampleSizes.size() call,
100ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    // since it is O(n). Ideally, the fix should be in List class.
101ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    size_t              mNumSamples;
1028644c14618d30d9e57a69df40ed939986ebf02c4James Dong    List<size_t>        mSampleSizes;
103be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    bool                mSamplesHaveSameSize;
104be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
10513aec890216948b0c364f8f92792129d0335f506James Dong    List<MediaBuffer *> mChunkSamples;
1061f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1071f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    size_t              mNumStcoTableEntries;
108c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    List<off64_t>         mChunkOffsets;
10913aec890216948b0c364f8f92792129d0335f506James Dong
1101f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    size_t              mNumStscTableEntries;
11113aec890216948b0c364f8f92792129d0335f506James Dong    struct StscTableEntry {
11213aec890216948b0c364f8f92792129d0335f506James Dong
11313aec890216948b0c364f8f92792129d0335f506James Dong        StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id)
11413aec890216948b0c364f8f92792129d0335f506James Dong            : firstChunk(chunk),
11513aec890216948b0c364f8f92792129d0335f506James Dong              samplesPerChunk(samples),
11613aec890216948b0c364f8f92792129d0335f506James Dong              sampleDescriptionId(id) {}
11713aec890216948b0c364f8f92792129d0335f506James Dong
11813aec890216948b0c364f8f92792129d0335f506James Dong        uint32_t firstChunk;
11913aec890216948b0c364f8f92792129d0335f506James Dong        uint32_t samplesPerChunk;
12013aec890216948b0c364f8f92792129d0335f506James Dong        uint32_t sampleDescriptionId;
12113aec890216948b0c364f8f92792129d0335f506James Dong    };
12213aec890216948b0c364f8f92792129d0335f506James Dong    List<StscTableEntry> mStscTableEntries;
12320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1241f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    size_t        mNumStssTableEntries;
125050b28a593350047845a45a14cc5026221ac1620James Dong    List<int32_t> mStssTableEntries;
126050b28a593350047845a45a14cc5026221ac1620James Dong
1271f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    size_t        mNumSttsTableEntries;
128be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    struct SttsTableEntry {
129be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
1308f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        SttsTableEntry(uint32_t count, uint32_t durationUs)
1318f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            : sampleCount(count), sampleDurationUs(durationUs) {}
132be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
133be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        uint32_t sampleCount;
1348f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        uint32_t sampleDurationUs;
135be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    };
136be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    List<SttsTableEntry> mSttsTableEntries;
137be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
1383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Sequence parameter set or picture parameter set
1393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    struct AVCParamSet {
1403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        AVCParamSet(uint16_t length, const uint8_t *data)
1413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            : mLength(length), mData(data) {}
1423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
1433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t mLength;
1443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *mData;
1453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    };
1463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    List<AVCParamSet> mSeqParamSets;
1473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    List<AVCParamSet> mPicParamSets;
1483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mProfileIdc;
1493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mProfileCompatible;
1503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mLevelIdc;
1513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    void *mCodecSpecificData;
15320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    size_t mCodecSpecificDataSize;
154548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber    bool mGotAllCodecSpecificData;
15593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    bool mTrackingProgressStatus;
15620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
15725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool mReachedEOS;
1583c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    int64_t mStartTimestampUs;
15993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t mPreviousTrackTimeUs;
16093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t mTrackEveryTimeDurationUs;
16125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
162872a481558350634a3fd5cb67939de288af00ecbJames Dong    // Has the media time adjustment for video started?
163872a481558350634a3fd5cb67939de288af00ecbJames Dong    bool    mIsMediaTimeAdjustmentOn;
164872a481558350634a3fd5cb67939de288af00ecbJames Dong    // The time stamp when previous media time adjustment period starts
165872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t mPrevMediaTimeAdjustTimestampUs;
166872a481558350634a3fd5cb67939de288af00ecbJames Dong    // Number of vidoe frames whose time stamp may be adjusted
167872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t mMediaTimeAdjustNumFrames;
168872a481558350634a3fd5cb67939de288af00ecbJames Dong    // The sample number when previous meida time adjustmnet period starts
169872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t mPrevMediaTimeAdjustSample;
170872a481558350634a3fd5cb67939de288af00ecbJames Dong    // The total accumulated drift time within a period of
171872a481558350634a3fd5cb67939de288af00ecbJames Dong    // kVideoMediaTimeAdjustPeriodTimeUs.
172872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t mTotalDriftTimeToAdjustUs;
173872a481558350634a3fd5cb67939de288af00ecbJames Dong    // The total accumalated drift time since the start of the recording
174872a481558350634a3fd5cb67939de288af00ecbJames Dong    // excluding the current time adjustment period
175872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t mPrevTotalAccumDriftTimeUs;
176872a481558350634a3fd5cb67939de288af00ecbJames Dong
177872a481558350634a3fd5cb67939de288af00ecbJames Dong    // Update the audio track's drift information.
178872a481558350634a3fd5cb67939de288af00ecbJames Dong    void updateDriftTime(const sp<MetaData>& meta);
179872a481558350634a3fd5cb67939de288af00ecbJames Dong
180872a481558350634a3fd5cb67939de288af00ecbJames Dong    // Adjust the time stamp of the video track according to
181872a481558350634a3fd5cb67939de288af00ecbJames Dong    // the drift time information from the audio track.
182872a481558350634a3fd5cb67939de288af00ecbJames Dong    void adjustMediaTime(int64_t *timestampUs);
183872a481558350634a3fd5cb67939de288af00ecbJames Dong
18420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    static void *ThreadWrapper(void *me);
18537187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t threadEntry();
18620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *parseParamSet(
1883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length, int type, size_t *paramSetLen);
1893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
190b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    status_t makeAVCCodecSpecificData(const uint8_t *data, size_t size);
191b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    status_t copyAVCCodecSpecificData(const uint8_t *data, size_t size);
192b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    status_t parseAVCCodecSpecificData(const uint8_t *data, size_t size);
193215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong
194215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    // Track authoring progress status
195faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    void trackProgressStatus(int64_t timeUs, status_t err = OK);
19693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    void initTrackingProgressStatus(MetaData *params);
19703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
19819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    void getCodecSpecificDataFromInputFormatIfPossible();
19919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
200c059860c73678a202bfa33062723e8f82fb779d9James Dong    // Determine the track time scale
201c059860c73678a202bfa33062723e8f82fb779d9James Dong    // If it is an audio track, try to use the sampling rate as
202c059860c73678a202bfa33062723e8f82fb779d9James Dong    // the time scale; however, if user chooses the overwrite
203c059860c73678a202bfa33062723e8f82fb779d9James Dong    // value, the user-supplied time scale will be used.
204c059860c73678a202bfa33062723e8f82fb779d9James Dong    void setTimeScale();
205c059860c73678a202bfa33062723e8f82fb779d9James Dong
206690f546b0ee548dbfe997df36418e5302ec2d786James Dong    // Simple validation on the codec specific data
207690f546b0ee548dbfe997df36418e5302ec2d786James Dong    status_t checkCodecSpecificData() const;
20813f6284305e4b27395a23db7882d670bdb1bcae1James Dong    int32_t mRotation;
209690f546b0ee548dbfe997df36418e5302ec2d786James Dong
2101f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void updateTrackSizeEstimate();
2111f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void addOneStscTableEntry(size_t chunkId, size_t sampleId);
2121f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void addOneStssTableEntry(size_t sampleId);
2131f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void addOneSttsTableEntry(size_t sampleCount, int64_t durationUs);
2141f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
215b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Write the boxes
216b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStcoBox(bool use32BitOffset);
217b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStscBox();
218b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStszBox();
219b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStssBox();
220b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeSttsBox();
221b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeD263Box();
222b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writePaspBox();
223b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeAvccBox();
224b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeUrlBox();
225b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeDrefBox();
226b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeDinfBox();
227b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeDamrBox();
228b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeMdhdBox(time_t now);
229b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeSmhdBox();
230b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeVmhdBox();
231b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeHdlrBox();
232b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeTkhdBox(time_t now);
233b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeMp4aEsdsBox();
234b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeMp4vEsdsBox();
235b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeAudioFourCCBox();
236b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeVideoFourCCBox();
237b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStblBox(bool use32BitOffset);
238b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
23920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track(const Track &);
24020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track &operator=(const Track &);
24120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber};
24220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
24320111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::MPEG4Writer(const char *filename)
244674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    : mFd(-1),
245674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong      mInitCheck(NO_INIT),
246b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong      mUse4ByteNalLength(true),
2471acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong      mUse32BitOffset(true),
248a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong      mIsFileSizeLimitExplicitlyRequested(false),
249a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
250a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mStarted(false),
25120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mOffset(0),
25213aec890216948b0c364f8f92792129d0335f506James Dong      mMdatOffset(0),
2537837c17063a4c50bc856ba59418516fdab731de7James Dong      mEstimatedMoovBoxSize(0),
254f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong      mInterleaveDurationUs(1000000) {
255674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong
25603f6f4e7e2ce09357cbc05bb546cd8a6e54b5baeJames Dong    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR);
257674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mFd >= 0) {
258674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        mInitCheck = OK;
259674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    }
26020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
26120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
26230ab66297501757d745b9ae10da61adcd891f497Andreas HuberMPEG4Writer::MPEG4Writer(int fd)
263674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    : mFd(dup(fd)),
264674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong      mInitCheck(mFd < 0? NO_INIT: OK),
265b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong      mUse4ByteNalLength(true),
2661acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong      mUse32BitOffset(true),
267a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong      mIsFileSizeLimitExplicitlyRequested(false),
268a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
269a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mStarted(false),
27030ab66297501757d745b9ae10da61adcd891f497Andreas Huber      mOffset(0),
27113aec890216948b0c364f8f92792129d0335f506James Dong      mMdatOffset(0),
2727837c17063a4c50bc856ba59418516fdab731de7James Dong      mEstimatedMoovBoxSize(0),
273f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong      mInterleaveDurationUs(1000000) {
27430ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
27530ab66297501757d745b9ae10da61adcd891f497Andreas Huber
27620111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() {
27720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    stop();
27820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2791f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    while (!mTracks.empty()) {
2801f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        List<Track *>::iterator it = mTracks.begin();
28120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        delete *it;
2821f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        (*it) = NULL;
2831f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        mTracks.erase(it);
28420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
28520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mTracks.clear();
28620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
28720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
288dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::dump(
289dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        int fd, const Vector<String16>& args) {
290dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    const size_t SIZE = 256;
291dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    char buffer[SIZE];
292dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    String8 result;
293dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "   MPEG4Writer %p\n", this);
294dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
295dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "     mStarted: %s\n", mStarted? "true": "false");
296dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
297dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    ::write(fd, result.string(), result.size());
298dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    for (List<Track *>::iterator it = mTracks.begin();
299dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong         it != mTracks.end(); ++it) {
300dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        (*it)->dump(fd, args);
301dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    }
302dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    return OK;
303dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong}
304dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong
305dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::Track::dump(
306dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        int fd, const Vector<String16>& args) const {
307dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    const size_t SIZE = 256;
308dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    char buffer[SIZE];
309dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    String8 result;
310dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "     %s track\n", mIsAudio? "Audio": "Video");
311dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
312dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "       reached EOS: %s\n",
313dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong            mReachedEOS? "true": "false");
314dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
315dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    ::write(fd, result.string(), result.size());
316dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    return OK;
317dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong}
318dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong
3192dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
320bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    Mutex::Autolock l(mLock);
321bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    if (mStarted) {
322bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        LOGE("Attempt to add source AFTER recording is started");
323bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        return UNKNOWN_ERROR;
324bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    }
325bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    Track *track = new Track(this, source, mTracks.size());
32620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mTracks.push_back(track);
3272dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
3282dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    return OK;
32920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
33020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
33193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::startTracks(MetaData *params) {
332a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    for (List<Track *>::iterator it = mTracks.begin();
333a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong         it != mTracks.end(); ++it) {
33493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        status_t err = (*it)->start(params);
335a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
336a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (err != OK) {
337a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            for (List<Track *>::iterator it2 = mTracks.begin();
338a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong                 it2 != it; ++it2) {
339a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong                (*it2)->stop();
340a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            }
341a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
342a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            return err;
343a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
344a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
345a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    return OK;
346a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
347a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
3482dec2b5be2056c6d9428897dc672185872d30d17James Dongint64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) {
3492dec2b5be2056c6d9428897dc672185872d30d17James Dong    // This implementation is highly experimental/heurisitic.
3502dec2b5be2056c6d9428897dc672185872d30d17James Dong    //
3512dec2b5be2056c6d9428897dc672185872d30d17James Dong    // Statistical analysis shows that metadata usually accounts
3522dec2b5be2056c6d9428897dc672185872d30d17James Dong    // for a small portion of the total file size, usually < 0.6%.
3532dec2b5be2056c6d9428897dc672185872d30d17James Dong
35478a1a286f736888ae7af8860b2c424af0d978848James Dong    // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2,
3552dec2b5be2056c6d9428897dc672185872d30d17James Dong    // where 1MB is the common file size limit for MMS application.
35678a1a286f736888ae7af8860b2c424af0d978848James Dong    // The default MAX _MOOV_BOX_SIZE value is based on about 3
3572dec2b5be2056c6d9428897dc672185872d30d17James Dong    // minute video recording with a bit rate about 3 Mbps, because
3582dec2b5be2056c6d9428897dc672185872d30d17James Dong    // statistics also show that most of the video captured are going
3592dec2b5be2056c6d9428897dc672185872d30d17James Dong    // to be less than 3 minutes.
3602dec2b5be2056c6d9428897dc672185872d30d17James Dong
3612dec2b5be2056c6d9428897dc672185872d30d17James Dong    // If the estimation is wrong, we will pay the price of wasting
3622dec2b5be2056c6d9428897dc672185872d30d17James Dong    // some reserved space. This should not happen so often statistically.
3632dec2b5be2056c6d9428897dc672185872d30d17James Dong    static const int32_t factor = mUse32BitOffset? 1: 2;
36478a1a286f736888ae7af8860b2c424af0d978848James Dong    static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024;  // 3 KB
3652dec2b5be2056c6d9428897dc672185872d30d17James Dong    static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000);
3662dec2b5be2056c6d9428897dc672185872d30d17James Dong    int64_t size = MIN_MOOV_BOX_SIZE;
3672dec2b5be2056c6d9428897dc672185872d30d17James Dong
36878a1a286f736888ae7af8860b2c424af0d978848James Dong    // Max file size limit is set
369a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
37078a1a286f736888ae7af8860b2c424af0d978848James Dong        size = mMaxFileSizeLimitBytes * 6 / 1000;
37178a1a286f736888ae7af8860b2c424af0d978848James Dong    }
37278a1a286f736888ae7af8860b2c424af0d978848James Dong
37378a1a286f736888ae7af8860b2c424af0d978848James Dong    // Max file duration limit is set
37478a1a286f736888ae7af8860b2c424af0d978848James Dong    if (mMaxFileDurationLimitUs != 0) {
37578a1a286f736888ae7af8860b2c424af0d978848James Dong        if (bitRate > 0) {
37678a1a286f736888ae7af8860b2c424af0d978848James Dong            int64_t size2 =
37778a1a286f736888ae7af8860b2c424af0d978848James Dong                ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000);
37878a1a286f736888ae7af8860b2c424af0d978848James Dong            if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
37978a1a286f736888ae7af8860b2c424af0d978848James Dong                // When both file size and duration limits are set,
38078a1a286f736888ae7af8860b2c424af0d978848James Dong                // we use the smaller limit of the two.
38178a1a286f736888ae7af8860b2c424af0d978848James Dong                if (size > size2) {
38278a1a286f736888ae7af8860b2c424af0d978848James Dong                    size = size2;
38378a1a286f736888ae7af8860b2c424af0d978848James Dong                }
38478a1a286f736888ae7af8860b2c424af0d978848James Dong            } else {
38578a1a286f736888ae7af8860b2c424af0d978848James Dong                // Only max file duration limit is set
38678a1a286f736888ae7af8860b2c424af0d978848James Dong                size = size2;
38778a1a286f736888ae7af8860b2c424af0d978848James Dong            }
3882dec2b5be2056c6d9428897dc672185872d30d17James Dong        }
3892dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
39078a1a286f736888ae7af8860b2c424af0d978848James Dong
3912dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (size < MIN_MOOV_BOX_SIZE) {
3922dec2b5be2056c6d9428897dc672185872d30d17James Dong        size = MIN_MOOV_BOX_SIZE;
3932dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
3942dec2b5be2056c6d9428897dc672185872d30d17James Dong
3952dec2b5be2056c6d9428897dc672185872d30d17James Dong    // Any long duration recording will be probably end up with
3962dec2b5be2056c6d9428897dc672185872d30d17James Dong    // non-streamable mp4 file.
3972dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (size > MAX_MOOV_BOX_SIZE) {
3982dec2b5be2056c6d9428897dc672185872d30d17James Dong        size = MAX_MOOV_BOX_SIZE;
3992dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
4002dec2b5be2056c6d9428897dc672185872d30d17James Dong
401a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated"
4022dec2b5be2056c6d9428897dc672185872d30d17James Dong         " moov size %lld bytes",
4032dec2b5be2056c6d9428897dc672185872d30d17James Dong         mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size);
4042dec2b5be2056c6d9428897dc672185872d30d17James Dong    return factor * size;
4052dec2b5be2056c6d9428897dc672185872d30d17James Dong}
4062dec2b5be2056c6d9428897dc672185872d30d17James Dong
4072dec2b5be2056c6d9428897dc672185872d30d17James Dongstatus_t MPEG4Writer::start(MetaData *param) {
408674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mInitCheck != OK) {
40925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        return UNKNOWN_ERROR;
41020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
41120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
412a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    /*
413a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * Check mMaxFileSizeLimitBytes at the beginning
414a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * since mMaxFileSizeLimitBytes may be implicitly
415a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * changed later for 32-bit file offset even if
416a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * user does not ask to set it explicitly.
417a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     */
418a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    if (mMaxFileSizeLimitBytes != 0) {
419a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong        mIsFileSizeLimitExplicitlyRequested = true;
420a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    }
421a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong
4222dec2b5be2056c6d9428897dc672185872d30d17James Dong    int32_t use64BitOffset;
4232dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (param &&
4242dec2b5be2056c6d9428897dc672185872d30d17James Dong        param->findInt32(kKey64BitFileOffset, &use64BitOffset) &&
4252dec2b5be2056c6d9428897dc672185872d30d17James Dong        use64BitOffset) {
4262dec2b5be2056c6d9428897dc672185872d30d17James Dong        mUse32BitOffset = false;
4272dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
4282dec2b5be2056c6d9428897dc672185872d30d17James Dong
4291f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    if (mUse32BitOffset) {
4301f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        // Implicit 32 bit file size limit
4311f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        if (mMaxFileSizeLimitBytes == 0) {
4321f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            mMaxFileSizeLimitBytes = kMax32BitFileSize;
4331f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        }
4341f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
4351f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        // If file size is set to be larger than the 32 bit file
4361f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        // size limit, treat it as an error.
4371f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        if (mMaxFileSizeLimitBytes > kMax32BitFileSize) {
438872a481558350634a3fd5cb67939de288af00ecbJames Dong            LOGW("32-bit file size limit (%lld bytes) too big. "
439d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong                 "It is changed to %lld bytes",
440d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong                mMaxFileSizeLimitBytes, kMax32BitFileSize);
441d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong            mMaxFileSizeLimitBytes = kMax32BitFileSize;
4421f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        }
4431f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    }
4441f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
445b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    int32_t use2ByteNalLength;
446b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    if (param &&
447b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) &&
448b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        use2ByteNalLength) {
449b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        mUse4ByteNalLength = false;
4502dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
4512dec2b5be2056c6d9428897dc672185872d30d17James Dong
452065d1aff96818df54456053f1574aec8a234d0deJames Dong    mStartTimestampUs = -1;
45393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
454a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (mStarted) {
455a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mPaused) {
456a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            mPaused = false;
45793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            return startTracks(param);
458a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
459a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return OK;
460a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
461a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
4628f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    if (!param ||
4638f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        !param->findInt32(kKeyTimeScale, &mTimeScale)) {
4648f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        mTimeScale = 1000;
4658f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    }
4668f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    CHECK(mTimeScale > 0);
4678f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    LOGV("movie time scale: %d", mTimeScale);
4688f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
4697837c17063a4c50bc856ba59418516fdab731de7James Dong    mStreamableFile = true;
4707837c17063a4c50bc856ba59418516fdab731de7James Dong    mWriteMoovBoxToMemory = false;
4717837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBuffer = NULL;
4727837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBufferOffset = 0;
4737837c17063a4c50bc856ba59418516fdab731de7James Dong
474b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeFtypBox(param);
47520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
4767837c17063a4c50bc856ba59418516fdab731de7James Dong    mFreeBoxOffset = mOffset;
47720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
4787837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mEstimatedMoovBoxSize == 0) {
4792dec2b5be2056c6d9428897dc672185872d30d17James Dong        int32_t bitRate = -1;
4802dec2b5be2056c6d9428897dc672185872d30d17James Dong        if (param) {
4812dec2b5be2056c6d9428897dc672185872d30d17James Dong            param->findInt32(kKeyBitRate, &bitRate);
4822dec2b5be2056c6d9428897dc672185872d30d17James Dong        }
4832dec2b5be2056c6d9428897dc672185872d30d17James Dong        mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate);
4847837c17063a4c50bc856ba59418516fdab731de7James Dong    }
4857837c17063a4c50bc856ba59418516fdab731de7James Dong    CHECK(mEstimatedMoovBoxSize >= 8);
486c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    lseek64(mFd, mFreeBoxOffset, SEEK_SET);
4877837c17063a4c50bc856ba59418516fdab731de7James Dong    writeInt32(mEstimatedMoovBoxSize);
4887837c17063a4c50bc856ba59418516fdab731de7James Dong    write("free", 4);
4897837c17063a4c50bc856ba59418516fdab731de7James Dong
4907837c17063a4c50bc856ba59418516fdab731de7James Dong    mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize;
4917837c17063a4c50bc856ba59418516fdab731de7James Dong    mOffset = mMdatOffset;
492c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    lseek64(mFd, mMdatOffset, SEEK_SET);
4931acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    if (mUse32BitOffset) {
4941acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        write("????mdat", 8);
4951acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    } else {
4961acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        write("\x00\x00\x00\x01mdat????????", 16);
4971acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    }
4981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
4991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    status_t err = startWriterThread();
5001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (err != OK) {
5011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        return err;
5021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
5031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
5041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    err = startTracks(param);
505a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (err != OK) {
506a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return err;
50720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
5081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
509a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mStarted = true;
51025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return OK;
51120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
51220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
5131f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongbool MPEG4Writer::use32BitFileOffset() const {
5141f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    return mUse32BitOffset;
5151f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
5161f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
51737187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::pause() {
518674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mInitCheck != OK) {
51937187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
520a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
521a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mPaused = true;
52237187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = OK;
523a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    for (List<Track *>::iterator it = mTracks.begin();
524a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong         it != mTracks.end(); ++it) {
52537187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = (*it)->pause();
52637187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (status != OK) {
52737187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
52837187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
529a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
53037187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
531a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
532a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
5331c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::stopWriterThread() {
534cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong    LOGD("Stopping writer thread");
5351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
5361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    {
5371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        Mutex::Autolock autolock(mLock);
5381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
5391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mDone = true;
5401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mChunkReadyCondition.signal();
5411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
5421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
5431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    void *dummy;
5441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_join(mThread, &dummy);
545cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong    LOGD("Writer thread stopped");
5461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
5471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
54813f6284305e4b27395a23db7882d670bdb1bcae1James Dong/*
54913f6284305e4b27395a23db7882d670bdb1bcae1James Dong * MP4 file standard defines a composition matrix:
55013f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | a  b  u |
55113f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | c  d  v |
55213f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | x  y  w |
55313f6284305e4b27395a23db7882d670bdb1bcae1James Dong *
55413f6284305e4b27395a23db7882d670bdb1bcae1James Dong * the element in the matrix is stored in the following
55513f6284305e4b27395a23db7882d670bdb1bcae1James Dong * order: {a, b, u, c, d, v, x, y, w},
55613f6284305e4b27395a23db7882d670bdb1bcae1James Dong * where a, b, c, d, x, and y is in 16.16 format, while
55713f6284305e4b27395a23db7882d670bdb1bcae1James Dong * u, v and w is in 2.30 format.
55813f6284305e4b27395a23db7882d670bdb1bcae1James Dong */
55913f6284305e4b27395a23db7882d670bdb1bcae1James Dongvoid MPEG4Writer::writeCompositionMatrix(int degrees) {
56013f6284305e4b27395a23db7882d670bdb1bcae1James Dong    LOGV("writeCompositionMatrix");
56113f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t a = 0x00010000;
56213f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t b = 0;
56313f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t c = 0;
56413f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t d = 0x00010000;
56513f6284305e4b27395a23db7882d670bdb1bcae1James Dong    switch (degrees) {
56613f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 0:
56713f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
56813f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 90:
56913f6284305e4b27395a23db7882d670bdb1bcae1James Dong            a = 0;
57013f6284305e4b27395a23db7882d670bdb1bcae1James Dong            b = 0x00010000;
57113f6284305e4b27395a23db7882d670bdb1bcae1James Dong            c = 0xFFFF0000;
57213f6284305e4b27395a23db7882d670bdb1bcae1James Dong            d = 0;
57313f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
57413f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 180:
57513f6284305e4b27395a23db7882d670bdb1bcae1James Dong            a = 0xFFFF0000;
57613f6284305e4b27395a23db7882d670bdb1bcae1James Dong            d = 0xFFFF0000;
57713f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
57813f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 270:
57913f6284305e4b27395a23db7882d670bdb1bcae1James Dong            a = 0;
58013f6284305e4b27395a23db7882d670bdb1bcae1James Dong            b = 0xFFFF0000;
58113f6284305e4b27395a23db7882d670bdb1bcae1James Dong            c = 0x00010000;
58213f6284305e4b27395a23db7882d670bdb1bcae1James Dong            d = 0;
58313f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
58413f6284305e4b27395a23db7882d670bdb1bcae1James Dong        default:
58513f6284305e4b27395a23db7882d670bdb1bcae1James Dong            CHECK(!"Should never reach this unknown rotation");
58613f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
58713f6284305e4b27395a23db7882d670bdb1bcae1James Dong    }
58813f6284305e4b27395a23db7882d670bdb1bcae1James Dong
58913f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(a);           // a
59013f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(b);           // b
59113f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // u
59213f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(c);           // c
59313f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(d);           // d
59413f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // v
59513f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // x
59613f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // y
59713f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0x40000000);  // w
59813f6284305e4b27395a23db7882d670bdb1bcae1James Dong}
59913f6284305e4b27395a23db7882d670bdb1bcae1James Dong
60013f6284305e4b27395a23db7882d670bdb1bcae1James Dong
60137187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::stop() {
602674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mInitCheck != OK) {
60337187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
60420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
60520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
60637187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = OK;
6078f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t maxDurationUs = 0;
60865b3d76025c71d755b0fb3b6ead90255f25417edJames Dong    int64_t minDurationUs = 0x7fffffffffffffffLL;
60920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    for (List<Track *>::iterator it = mTracks.begin();
61020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber         it != mTracks.end(); ++it) {
61137187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = (*it)->stop();
61237187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (err == OK && status != OK) {
61337187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
61437187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
61520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6168f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        int64_t durationUs = (*it)->getDurationUs();
6178f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        if (durationUs > maxDurationUs) {
6188f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            maxDurationUs = durationUs;
61920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
62065b3d76025c71d755b0fb3b6ead90255f25417edJames Dong        if (durationUs < minDurationUs) {
62165b3d76025c71d755b0fb3b6ead90255f25417edJames Dong            minDurationUs = durationUs;
62265b3d76025c71d755b0fb3b6ead90255f25417edJames Dong        }
62365b3d76025c71d755b0fb3b6ead90255f25417edJames Dong    }
62465b3d76025c71d755b0fb3b6ead90255f25417edJames Dong
62565b3d76025c71d755b0fb3b6ead90255f25417edJames Dong    if (mTracks.size() > 1) {
62665b3d76025c71d755b0fb3b6ead90255f25417edJames Dong        LOGD("Duration from tracks range is [%lld, %lld] us",
62765b3d76025c71d755b0fb3b6ead90255f25417edJames Dong            minDurationUs, maxDurationUs);
62820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
62920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    stopWriterThread();
6317837c17063a4c50bc856ba59418516fdab731de7James Dong
63237187916a486504acaf83bea30147eb5fbf46ae5James Dong    // Do not write out movie header on error.
63337187916a486504acaf83bea30147eb5fbf46ae5James Dong    if (err != OK) {
634674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        close(mFd);
635674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        mFd = -1;
636674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        mInitCheck = NO_INIT;
63737187916a486504acaf83bea30147eb5fbf46ae5James Dong        mStarted = false;
63837187916a486504acaf83bea30147eb5fbf46ae5James Dong        return err;
63937187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
64037187916a486504acaf83bea30147eb5fbf46ae5James Dong
64120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    // Fix up the size of the 'mdat' chunk.
6421acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    if (mUse32BitOffset) {
643c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mMdatOffset, SEEK_SET);
6441acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset));
645c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &size, 4);
6461acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    } else {
647c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mMdatOffset + 8, SEEK_SET);
6481acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        int64_t size = mOffset - mMdatOffset;
6491acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        size = hton64(size);
650c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &size, 8);
6511acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    }
652c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    lseek64(mFd, mOffset, SEEK_SET);
65320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
654c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    const off64_t moovOffset = mOffset;
6557837c17063a4c50bc856ba59418516fdab731de7James Dong    mWriteMoovBoxToMemory = true;
6567837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
6577837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBufferOffset = 0;
6587837c17063a4c50bc856ba59418516fdab731de7James Dong    CHECK(mMoovBoxBuffer != NULL);
659b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeMoovBox(maxDurationUs);
66020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6617837c17063a4c50bc856ba59418516fdab731de7James Dong    mWriteMoovBoxToMemory = false;
6627837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mStreamableFile) {
6637837c17063a4c50bc856ba59418516fdab731de7James Dong        CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize);
6647837c17063a4c50bc856ba59418516fdab731de7James Dong
6657837c17063a4c50bc856ba59418516fdab731de7James Dong        // Moov box
666c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mFreeBoxOffset, SEEK_SET);
6677837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset = mFreeBoxOffset;
668674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset);
6697837c17063a4c50bc856ba59418516fdab731de7James Dong
6707837c17063a4c50bc856ba59418516fdab731de7James Dong        // Free box
671c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mOffset, SEEK_SET);
6727837c17063a4c50bc856ba59418516fdab731de7James Dong        writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset);
6737837c17063a4c50bc856ba59418516fdab731de7James Dong        write("free", 4);
6747837c17063a4c50bc856ba59418516fdab731de7James Dong
6757837c17063a4c50bc856ba59418516fdab731de7James Dong        // Free temp memory
6767837c17063a4c50bc856ba59418516fdab731de7James Dong        free(mMoovBoxBuffer);
6777837c17063a4c50bc856ba59418516fdab731de7James Dong        mMoovBoxBuffer = NULL;
6787837c17063a4c50bc856ba59418516fdab731de7James Dong        mMoovBoxBufferOffset = 0;
6792dec2b5be2056c6d9428897dc672185872d30d17James Dong    } else {
6802dec2b5be2056c6d9428897dc672185872d30d17James Dong        LOGI("The mp4 file will not be streamable.");
6817837c17063a4c50bc856ba59418516fdab731de7James Dong    }
6827837c17063a4c50bc856ba59418516fdab731de7James Dong
6830c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(mBoxes.empty());
68420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
685674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    close(mFd);
686674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    mFd = -1;
687674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    mInitCheck = NO_INIT;
688a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mStarted = false;
68937187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
69020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
69120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
692b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::writeMvhdBox(int64_t durationUs) {
693b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    time_t now = time(NULL);
694b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    beginBox("mvhd");
695b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // version=0, flags=0
696b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(now);           // creation time
697b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(now);           // modification time
698b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(mTimeScale);    // mvhd timescale
699b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t duration = (durationUs * mTimeScale + 5E5) / 1E6;
700b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(duration);
701b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0x10000);       // rate: 1.0
702b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt16(0x100);         // volume
703b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt16(0);             // reserved
704b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // reserved
705b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // reserved
706b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeCompositionMatrix(0); // matrix
707b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
708b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
709b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
710b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
711b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
712b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
713b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(mTracks.size() + 1);  // nextTrackID
714b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    endBox();  // mvhd
715b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
716b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
717b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::writeMoovBox(int64_t durationUs) {
718b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    beginBox("moov");
719b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeMvhdBox(durationUs);
720b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t id = 1;
721b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<Track *>::iterator it = mTracks.begin();
722b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mTracks.end(); ++it, ++id) {
723b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        (*it)->writeTrackHeader(mUse32BitOffset);
724b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
725b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    endBox();  // moov
726b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
727b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
728b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::writeFtypBox(MetaData *param) {
729b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    beginBox("ftyp");
730b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
731b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t fileType;
732b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (param && param->findInt32(kKeyFileType, &fileType) &&
733b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fileType != OUTPUT_FORMAT_MPEG_4) {
734b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeFourcc("3gp4");
735b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
736b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeFourcc("isom");
737b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
738b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
739b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);
740b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeFourcc("isom");
741b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeFourcc("3gp4");
742b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    endBox();
743b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
744b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
74513aec890216948b0c364f8f92792129d0335f506James Dongstatus_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) {
74613aec890216948b0c364f8f92792129d0335f506James Dong    mInterleaveDurationUs = durationUs;
74713aec890216948b0c364f8f92792129d0335f506James Dong    return OK;
74813aec890216948b0c364f8f92792129d0335f506James Dong}
74913aec890216948b0c364f8f92792129d0335f506James Dong
75013aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::lock() {
75113aec890216948b0c364f8f92792129d0335f506James Dong    mLock.lock();
75213aec890216948b0c364f8f92792129d0335f506James Dong}
75313aec890216948b0c364f8f92792129d0335f506James Dong
75413aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::unlock() {
75513aec890216948b0c364f8f92792129d0335f506James Dong    mLock.unlock();
75613aec890216948b0c364f8f92792129d0335f506James Dong}
75720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
758c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addSample_l(MediaBuffer *buffer) {
759c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t old_offset = mOffset;
76020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
761c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    ::write(mFd,
762c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong          (const uint8_t *)buffer->data() + buffer->range_offset(),
763c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong          buffer->range_length());
76420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
76520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mOffset += buffer->range_length();
76620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
76720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    return old_offset;
76820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
76920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
77003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) {
77103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (buffer->range_length() < 4) {
77203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return;
77303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
77403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
77503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    const uint8_t *ptr =
77603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        (const uint8_t *)buffer->data() + buffer->range_offset();
77703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
77803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
77903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        buffer->set_range(
78003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                buffer->range_offset() + 4, buffer->range_length() - 4);
78103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
78203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber}
78303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
784c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
785c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t old_offset = mOffset;
78630ab66297501757d745b9ae10da61adcd891f497Andreas Huber
78730ab66297501757d745b9ae10da61adcd891f497Andreas Huber    size_t length = buffer->range_length();
78803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
789b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    if (mUse4ByteNalLength) {
790b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        uint8_t x = length >> 24;
791c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
792b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = (length >> 16) & 0xff;
793c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
794b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = (length >> 8) & 0xff;
795c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
796b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = length & 0xff;
797c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
798c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong
799c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd,
800c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong              (const uint8_t *)buffer->data() + buffer->range_offset(),
801c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong              length);
802b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong
803b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        mOffset += length + 4;
804b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    } else {
805b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        CHECK(length < 65536);
80630ab66297501757d745b9ae10da61adcd891f497Andreas Huber
807b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        uint8_t x = length >> 8;
808c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
809b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = length & 0xff;
810c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
811c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length);
812b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        mOffset += length + 2;
813b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    }
81430ab66297501757d745b9ae10da61adcd891f497Andreas Huber
81530ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return old_offset;
81630ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
81730ab66297501757d745b9ae10da61adcd891f497Andreas Huber
8187837c17063a4c50bc856ba59418516fdab731de7James Dongsize_t MPEG4Writer::write(
819674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        const void *ptr, size_t size, size_t nmemb) {
8207837c17063a4c50bc856ba59418516fdab731de7James Dong
8217837c17063a4c50bc856ba59418516fdab731de7James Dong    const size_t bytes = size * nmemb;
8227837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mWriteMoovBoxToMemory) {
823674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        // This happens only when we write the moov box at the end of
824674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        // recording, not for each output video/audio frame we receive.
825c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        off64_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes;
8261acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        if (moovBoxSize > mEstimatedMoovBoxSize) {
827c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong            for (List<off64_t>::iterator it = mBoxes.begin();
8287837c17063a4c50bc856ba59418516fdab731de7James Dong                 it != mBoxes.end(); ++it) {
8297837c17063a4c50bc856ba59418516fdab731de7James Dong                (*it) += mOffset;
8307837c17063a4c50bc856ba59418516fdab731de7James Dong            }
831674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong            lseek64(mFd, mOffset, SEEK_SET);
832674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong            ::write(mFd, mMoovBoxBuffer, mMoovBoxBufferOffset);
833674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong            ::write(mFd, ptr, size * nmemb);
8347837c17063a4c50bc856ba59418516fdab731de7James Dong            mOffset += (bytes + mMoovBoxBufferOffset);
8357837c17063a4c50bc856ba59418516fdab731de7James Dong            free(mMoovBoxBuffer);
8367837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBuffer = NULL;
8377837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBufferOffset = 0;
8387837c17063a4c50bc856ba59418516fdab731de7James Dong            mWriteMoovBoxToMemory = false;
8397837c17063a4c50bc856ba59418516fdab731de7James Dong            mStreamableFile = false;
8407837c17063a4c50bc856ba59418516fdab731de7James Dong        } else {
8417837c17063a4c50bc856ba59418516fdab731de7James Dong            memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes);
8427837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBufferOffset += bytes;
8437837c17063a4c50bc856ba59418516fdab731de7James Dong        }
8447837c17063a4c50bc856ba59418516fdab731de7James Dong    } else {
845674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        ::write(mFd, ptr, size * nmemb);
8467837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset += bytes;
8477837c17063a4c50bc856ba59418516fdab731de7James Dong    }
8487837c17063a4c50bc856ba59418516fdab731de7James Dong    return bytes;
8497837c17063a4c50bc856ba59418516fdab731de7James Dong}
8507837c17063a4c50bc856ba59418516fdab731de7James Dong
85120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) {
8520c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK_EQ(strlen(fourcc), 4);
85320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
8547837c17063a4c50bc856ba59418516fdab731de7James Dong    mBoxes.push_back(mWriteMoovBoxToMemory?
8557837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBufferOffset: mOffset);
85620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
85720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    writeInt32(0);
85820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    writeFourcc(fourcc);
85920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
86020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
86120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() {
8620c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(!mBoxes.empty());
86320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
864c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t offset = *--mBoxes.end();
86520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mBoxes.erase(--mBoxes.end());
86620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
8677837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mWriteMoovBoxToMemory) {
8687837c17063a4c50bc856ba59418516fdab731de7James Dong       int32_t x = htonl(mMoovBoxBufferOffset - offset);
8697837c17063a4c50bc856ba59418516fdab731de7James Dong       memcpy(mMoovBoxBuffer + offset, &x, 4);
8707837c17063a4c50bc856ba59418516fdab731de7James Dong    } else {
871c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, offset, SEEK_SET);
8727837c17063a4c50bc856ba59418516fdab731de7James Dong        writeInt32(mOffset - offset);
8737837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset -= 4;
874c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mOffset, SEEK_SET);
8757837c17063a4c50bc856ba59418516fdab731de7James Dong    }
87620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
87720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
87820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) {
879674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 1);
88020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
88120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
88220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) {
88320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = htons(x);
884674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 2);
88520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
88620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
88720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) {
88820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = htonl(x);
889674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 4);
89020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
89120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
89220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) {
89320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = hton64(x);
894674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 8);
89520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
89620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
89720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) {
89820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    size_t n = strlen(s);
899674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(s, 1, n + 1);
90020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
90120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
90220111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) {
9030c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK_EQ(strlen(s), 4);
904674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(s, 1, 4);
90520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
90620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
90720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) {
908674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(data, 1, size);
90920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
91020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
91178a1a286f736888ae7af8860b2c424af0d978848James Dongbool MPEG4Writer::isFileStreamable() const {
91278a1a286f736888ae7af8860b2c424af0d978848James Dong    return mStreamableFile;
91378a1a286f736888ae7af8860b2c424af0d978848James Dong}
91478a1a286f736888ae7af8860b2c424af0d978848James Dong
915d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileSizeLimit() {
916d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    // No limit
917d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    if (mMaxFileSizeLimitBytes == 0) {
918d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        return false;
919d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
920d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
921956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize);
922d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    for (List<Track *>::iterator it = mTracks.begin();
923d599cd4573b5a2d5914c5040e0565ef866749b77James Dong         it != mTracks.end(); ++it) {
924d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
925d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
9261f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
927acd234bba9f048971d66890009eeff9a8db94be3James Dong    // Be conservative in the estimate: do not exceed 95% of
928acd234bba9f048971d66890009eeff9a8db94be3James Dong    // the target file limit. For small target file size limit, though,
929acd234bba9f048971d66890009eeff9a8db94be3James Dong    // this will not help.
930acd234bba9f048971d66890009eeff9a8db94be3James Dong    return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100);
931d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
932d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
933d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileDurationLimit() {
934d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    // No limit
935d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    if (mMaxFileDurationLimitUs == 0) {
936d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        return false;
937d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
938d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
939d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    for (List<Track *>::iterator it = mTracks.begin();
940d599cd4573b5a2d5914c5040e0565ef866749b77James Dong         it != mTracks.end(); ++it) {
941d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) {
942d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            return true;
943d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
944d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
945d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    return false;
946d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
947d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
94825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() {
94925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool allDone = true;
95025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    for (List<Track *>::iterator it = mTracks.begin();
95125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber         it != mTracks.end(); ++it) {
95225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        if (!(*it)->reachedEOS()) {
95325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber            allDone = false;
95425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber            break;
95525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        }
95625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    }
95725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
95825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return allDone;
95925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber}
96025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
961f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongvoid MPEG4Writer::setStartTimestampUs(int64_t timeUs) {
962f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    LOGI("setStartTimestampUs: %lld", timeUs);
963f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    CHECK(timeUs >= 0);
9643c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    Mutex::Autolock autoLock(mLock);
965065d1aff96818df54456053f1574aec8a234d0deJames Dong    if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) {
966f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong        mStartTimestampUs = timeUs;
967f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong        LOGI("Earliest track starting time: %lld", mStartTimestampUs);
9683c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    }
9693c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong}
9703c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong
971f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongint64_t MPEG4Writer::getStartTimestampUs() {
9723c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    Mutex::Autolock autoLock(mLock);
9733c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    return mStartTimestampUs;
9743c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong}
9753c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong
97658ae9c530247668f8af36e30d228c716c226b3d4James Dongsize_t MPEG4Writer::numTracks() {
97758ae9c530247668f8af36e30d228c716c226b3d4James Dong    Mutex::Autolock autolock(mLock);
97858ae9c530247668f8af36e30d228c716c226b3d4James Dong    return mTracks.size();
97958ae9c530247668f8af36e30d228c716c226b3d4James Dong}
98058ae9c530247668f8af36e30d228c716c226b3d4James Dong
98120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber////////////////////////////////////////////////////////////////////////////////
98220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
98320111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track(
984bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId)
98520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    : mOwner(owner),
98625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber      mMeta(source->getFormat()),
98720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mSource(source),
98820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mDone(false),
989a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
990a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mResumed(false),
991eaae38445a340c4857c1c5569475879a728e63b7James Dong      mStarted(false),
992bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong      mTrackId(trackId),
993c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong      mTrackDurationUs(0),
994956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      mEstimatedTrackSizeBytes(0),
995be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong      mSamplesHaveSameSize(true),
99620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mCodecSpecificData(NULL),
99725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber      mCodecSpecificDataSize(0),
998548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber      mGotAllCodecSpecificData(false),
99913f6284305e4b27395a23db7882d670bdb1bcae1James Dong      mReachedEOS(false),
100013f6284305e4b27395a23db7882d670bdb1bcae1James Dong      mRotation(0) {
100119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    getCodecSpecificDataFromInputFormatIfPossible();
10028f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
10031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    const char *mime;
10041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mMeta->findCString(kKeyMIMEType, &mime);
10051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
10061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsAudio = !strncasecmp(mime, "audio/", 6);
10071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
10081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong               !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
10091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1010c059860c73678a202bfa33062723e8f82fb779d9James Dong    setTimeScale();
1011c059860c73678a202bfa33062723e8f82fb779d9James Dong}
1012c059860c73678a202bfa33062723e8f82fb779d9James Dong
10131f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::updateTrackSizeEstimate() {
10141f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
10151f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    int64_t stcoBoxSizeBytes = mOwner->use32BitFileOffset()
10161f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                                ? mNumStcoTableEntries * 4
10171f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                                : mNumStcoTableEntries * 8;
10181f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
10191f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mNumSamples * 4);
10201f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
102178a1a286f736888ae7af8860b2c424af0d978848James Dong    mEstimatedTrackSizeBytes = mMdatSizeBytes;  // media data size
102278a1a286f736888ae7af8860b2c424af0d978848James Dong    if (!mOwner->isFileStreamable()) {
102378a1a286f736888ae7af8860b2c424af0d978848James Dong        // Reserved free space is not large enough to hold
102478a1a286f736888ae7af8860b2c424af0d978848James Dong        // all meta data and thus wasted.
102578a1a286f736888ae7af8860b2c424af0d978848James Dong        mEstimatedTrackSizeBytes += mNumStscTableEntries * 12 +  // stsc box size
102678a1a286f736888ae7af8860b2c424af0d978848James Dong                                    mNumStssTableEntries * 4 +   // stss box size
102778a1a286f736888ae7af8860b2c424af0d978848James Dong                                    mNumSttsTableEntries * 8 +   // stts box size
102878a1a286f736888ae7af8860b2c424af0d978848James Dong                                    stcoBoxSizeBytes +           // stco box size
102978a1a286f736888ae7af8860b2c424af0d978848James Dong                                    stszBoxSizeBytes;            // stsz box size
103078a1a286f736888ae7af8860b2c424af0d978848James Dong    }
10311f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
10321f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
10331f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStscTableEntry(
10341f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        size_t chunkId, size_t sampleId) {
10351f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
10361f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        StscTableEntry stscEntry(chunkId, sampleId, 1);
10371f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        mStscTableEntries.push_back(stscEntry);
10381f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        ++mNumStscTableEntries;
10391f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
10401f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
10411f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) {
10421f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mStssTableEntries.push_back(sampleId);
10431f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    ++mNumStssTableEntries;
10441f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
10451f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
10461f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneSttsTableEntry(
10471f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        size_t sampleCount, int64_t durationUs) {
10481f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
10491f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    SttsTableEntry sttsEntry(sampleCount, durationUs);
10501f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mSttsTableEntries.push_back(sttsEntry);
10511f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    ++mNumSttsTableEntries;
10521f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
10531f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1054c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongvoid MPEG4Writer::Track::addChunkOffset(off64_t offset) {
10551f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    ++mNumStcoTableEntries;
10561f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mChunkOffsets.push_back(offset);
10571f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
10581f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1059c059860c73678a202bfa33062723e8f82fb779d9James Dongvoid MPEG4Writer::Track::setTimeScale() {
1060c059860c73678a202bfa33062723e8f82fb779d9James Dong    LOGV("setTimeScale");
1061c059860c73678a202bfa33062723e8f82fb779d9James Dong    // Default time scale
1062c059860c73678a202bfa33062723e8f82fb779d9James Dong    mTimeScale = 90000;
1063c059860c73678a202bfa33062723e8f82fb779d9James Dong
1064c059860c73678a202bfa33062723e8f82fb779d9James Dong    if (mIsAudio) {
1065c059860c73678a202bfa33062723e8f82fb779d9James Dong        // Use the sampling rate as the default time scale for audio track.
1066c059860c73678a202bfa33062723e8f82fb779d9James Dong        int32_t sampleRate;
1067c059860c73678a202bfa33062723e8f82fb779d9James Dong        bool success = mMeta->findInt32(kKeySampleRate, &sampleRate);
1068c059860c73678a202bfa33062723e8f82fb779d9James Dong        CHECK(success);
1069c059860c73678a202bfa33062723e8f82fb779d9James Dong        mTimeScale = sampleRate;
1070c059860c73678a202bfa33062723e8f82fb779d9James Dong    }
1071c059860c73678a202bfa33062723e8f82fb779d9James Dong
1072c059860c73678a202bfa33062723e8f82fb779d9James Dong    // If someone would like to overwrite the timescale, use user-supplied value.
1073c059860c73678a202bfa33062723e8f82fb779d9James Dong    int32_t timeScale;
1074c059860c73678a202bfa33062723e8f82fb779d9James Dong    if (mMeta->findInt32(kKeyTimeScale, &timeScale)) {
1075c059860c73678a202bfa33062723e8f82fb779d9James Dong        mTimeScale = timeScale;
1076c059860c73678a202bfa33062723e8f82fb779d9James Dong    }
1077c059860c73678a202bfa33062723e8f82fb779d9James Dong
10788f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    CHECK(mTimeScale > 0);
107919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber}
108019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
108119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Hubervoid MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
108219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    const char *mime;
108319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
108419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
108519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
108619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        uint32_t type;
108719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        const void *data;
108819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        size_t size;
108919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        if (mMeta->findData(kKeyAVCC, &type, &data, &size)) {
109019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mCodecSpecificData = malloc(size);
109119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mCodecSpecificDataSize = size;
109219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            memcpy(mCodecSpecificData, data, size);
109319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mGotAllCodecSpecificData = true;
109419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        }
109519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
109619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
109719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        uint32_t type;
109819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        const void *data;
109919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        size_t size;
110019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
110119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            ESDS esds(data, size);
110219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            if (esds.getCodecSpecificInfo(&data, &size) == OK) {
110319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mCodecSpecificData = malloc(size);
110419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mCodecSpecificDataSize = size;
110519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                memcpy(mCodecSpecificData, data, size);
110619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mGotAllCodecSpecificData = true;
110719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            }
110819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        }
110919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    }
111020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
111120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
111220111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() {
111320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    stop();
111420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
111520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mCodecSpecificData != NULL) {
111620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        free(mCodecSpecificData);
111720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mCodecSpecificData = NULL;
111820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
111920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
112020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
112193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongvoid MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) {
112293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    LOGV("initTrackingProgressStatus");
112393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mPreviousTrackTimeUs = -1;
112493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mTrackingProgressStatus = false;
112593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mTrackEveryTimeDurationUs = 0;
112693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    {
112793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        int64_t timeUs;
112893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) {
112993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            LOGV("Receive request to track progress status for every %lld us", timeUs);
113093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            mTrackEveryTimeDurationUs = timeUs;
113193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            mTrackingProgressStatus = true;
113293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        }
113393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    }
113493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong}
113593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
11361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong// static
11371c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid *MPEG4Writer::ThreadWrapper(void *me) {
11381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("ThreadWrapper: %p", me);
11391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    MPEG4Writer *writer = static_cast<MPEG4Writer *>(me);
11401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    writer->threadFunc();
11411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    return NULL;
11421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
11431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
11441c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::bufferChunk(const Chunk& chunk) {
11451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("bufferChunk: %p", chunk.mTrack);
11461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Mutex::Autolock autolock(mLock);
11471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    CHECK_EQ(mDone, false);
11481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
11491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
11501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
11511c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
11521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (chunk.mTrack == it->mTrack) {  // Found owner
11531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            it->mChunks.push_back(chunk);
11541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            mChunkReadyCondition.signal();
11551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            return;
11561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
11571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
11581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
11591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    CHECK("Received a chunk for a unknown track" == 0);
11601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
11611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1162fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeChunkToFile(Chunk* chunk) {
1163fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    LOGV("writeChunkToFile: %lld from %s track",
1164fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        chunk.mTimestampUs, chunk.mTrack->isAudio()? "audio": "video");
1165fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1166fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    int32_t isFirstSample = true;
1167fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    while (!chunk->mSamples.empty()) {
1168fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        List<MediaBuffer *>::iterator it = chunk->mSamples.begin();
1169fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1170fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        off64_t offset = chunk->mTrack->isAvc()
1171fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong                                ? addLengthPrefixedSample_l(*it)
1172fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong                                : addSample_l(*it);
1173fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1174fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        if (isFirstSample) {
1175fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            chunk->mTrack->addChunkOffset(offset);
1176fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            isFirstSample = false;
11771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
11781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
11791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        (*it)->release();
11801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        (*it) = NULL;
1181fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        chunk->mSamples.erase(it);
11821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1183fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    chunk->mSamples.clear();
11841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
11851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1186fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeAllChunks() {
1187fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    LOGV("writeAllChunks");
11881c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    size_t outstandingChunks = 0;
11891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    while (!mChunkInfos.empty()) {
11901c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        List<ChunkInfo>::iterator it = mChunkInfos.begin();
11911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        while (!it->mChunks.empty()) {
1192fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            Chunk chunk;
1193fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            if (findChunkToWrite(&chunk)) {
1194fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong                writeChunkToFile(&chunk);
1195fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong                ++outstandingChunks;
1196fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            }
11971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
11981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        it->mTrack = NULL;
11991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mChunkInfos.erase(it);
12001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
12011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mChunkInfos.clear();
12021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGD("%d chunks are written in the last batch", outstandingChunks);
12031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
12041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1205fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongbool MPEG4Writer::findChunkToWrite(Chunk *chunk) {
1206fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    LOGV("findChunkToWrite");
12071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
12081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    // Find the smallest timestamp, and write that chunk out
12091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    // XXX: What if some track is just too slow?
12101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL;
12111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Track *track = NULL;
12121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
12131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
12141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (!it->mChunks.empty()) {
12151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            List<Chunk>::iterator chunkIt = it->mChunks.begin();
12161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            if (chunkIt->mTimeStampUs < minTimestampUs) {
12171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                minTimestampUs = chunkIt->mTimeStampUs;
12181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                track = it->mTrack;
12191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            }
12201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
12211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
12221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
12231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (track == NULL) {
12241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        LOGV("Nothing to be written after all");
1225fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        return false;
12261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
12271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
12281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (mIsFirstChunk) {
12291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mIsFirstChunk = false;
12301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1231fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
12321c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
12331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
12341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (it->mTrack == track) {
1235fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            *chunk = *(it->mChunks.begin());
1236fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            it->mChunks.erase(it->mChunks.begin());
1237fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            CHECK_EQ(chunk->mTrack, track);
1238fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            return true;
12391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
12401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1241fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1242fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    return false;
12431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
12441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
12451c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::threadFunc() {
12461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("threadFunc");
12471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1248a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0);
1249fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1250fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    Mutex::Autolock autoLock(mLock);
12511c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    while (!mDone) {
1252fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        Chunk chunk;
1253fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        bool chunkFound = false;
1254fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1255fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) {
12561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            mChunkReadyCondition.wait(mLock);
12571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
12581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1259fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        // Actual write without holding the lock in order to
1260fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        // reduce the blocking time for media track threads.
1261fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        if (chunkFound) {
1262fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            mLock.unlock();
1263fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            writeChunkToFile(&chunk);
1264fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            mLock.lock();
1265fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        }
12661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1267fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1268fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    writeAllChunks();
12691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
12701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
12711c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::startWriterThread() {
12721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("startWriterThread");
12731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
12741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mDone = false;
12751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsFirstChunk = true;
1276e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    mDriftTimeUs = 0;
12771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<Track *>::iterator it = mTracks.begin();
12781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mTracks.end(); ++it) {
12791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        ChunkInfo info;
12801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        info.mTrack = *it;
12811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mChunkInfos.push_back(info);
12821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
12831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
12841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_t attr;
12851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_init(&attr);
12861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
12871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_create(&mThread, &attr, ThreadWrapper, this);
12881c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_destroy(&attr);
12891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    return OK;
12901c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
12911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
12921f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
129393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::Track::start(MetaData *params) {
1294a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (!mDone && mPaused) {
1295a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        mPaused = false;
1296a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        mResumed = true;
1297a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return OK;
1298a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
129925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
130093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t startTimeUs;
130119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) {
130219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        startTimeUs = 0;
130319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    }
130419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
130513f6284305e4b27395a23db7882d670bdb1bcae1James Dong    int32_t rotationDegrees;
130613f6284305e4b27395a23db7882d670bdb1bcae1James Dong    if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) {
130713f6284305e4b27395a23db7882d670bdb1bcae1James Dong        mRotation = rotationDegrees;
130813f6284305e4b27395a23db7882d670bdb1bcae1James Dong    }
130913f6284305e4b27395a23db7882d670bdb1bcae1James Dong
13105b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong    mIsRealTimeRecording = true;
1311e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    {
1312e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        int32_t isNotRealTime;
1313e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) {
1314e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            mIsRealTimeRecording = (isNotRealTime == 0);
1315e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        }
1316e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    }
1317e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
131893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    initTrackingProgressStatus(params);
131993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
1320f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    sp<MetaData> meta = new MetaData;
1321a472613aec322e25891abf5c77bf3f7e3c244920James Dong    if (mIsRealTimeRecording && mOwner->numTracks() > 1) {
1322a472613aec322e25891abf5c77bf3f7e3c244920James Dong        /*
1323a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * This extra delay of accepting incoming audio/video signals
1324a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * helps to align a/v start time at the beginning of a recording
1325a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * session, and it also helps eliminate the "recording" sound for
1326a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * camcorder applications.
1327a472613aec322e25891abf5c77bf3f7e3c244920James Dong         *
1328a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * Ideally, this platform-specific value should be defined
1329a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * in media_profiles.xml file
1330a472613aec322e25891abf5c77bf3f7e3c244920James Dong         */
1331a472613aec322e25891abf5c77bf3f7e3c244920James Dong        startTimeUs += 700000;
1332a472613aec322e25891abf5c77bf3f7e3c244920James Dong    }
1333a472613aec322e25891abf5c77bf3f7e3c244920James Dong
1334f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    meta->setInt64(kKeyTime, startTimeUs);
1335a472613aec322e25891abf5c77bf3f7e3c244920James Dong
1336f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    status_t err = mSource->start(meta.get());
133725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    if (err != OK) {
133825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        mDone = mReachedEOS = true;
133925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        return err;
134025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    }
134120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
134220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_t attr;
134320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_init(&attr);
134420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
134520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
134620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mDone = false;
1347eaae38445a340c4857c1c5569475879a728e63b7James Dong    mStarted = true;
1348c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    mTrackDurationUs = 0;
134925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    mReachedEOS = false;
1350956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    mEstimatedTrackSizeBytes = 0;
13511f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mNumStcoTableEntries = 0;
13521f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mNumStssTableEntries = 0;
13531f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mNumStscTableEntries = 0;
13541f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mNumSttsTableEntries = 0;
13551f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mMdatSizeBytes = 0;
1356872a481558350634a3fd5cb67939de288af00ecbJames Dong    mIsMediaTimeAdjustmentOn = false;
1357872a481558350634a3fd5cb67939de288af00ecbJames Dong    mPrevMediaTimeAdjustTimestampUs = 0;
1358872a481558350634a3fd5cb67939de288af00ecbJames Dong    mMediaTimeAdjustNumFrames = 0;
1359872a481558350634a3fd5cb67939de288af00ecbJames Dong    mPrevMediaTimeAdjustSample = 0;
1360872a481558350634a3fd5cb67939de288af00ecbJames Dong    mTotalDriftTimeToAdjustUs = 0;
1361872a481558350634a3fd5cb67939de288af00ecbJames Dong    mPrevTotalAccumDriftTimeUs = 0;
136220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
136325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    pthread_create(&mThread, &attr, ThreadWrapper, this);
136420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_destroy(&attr);
136525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
136625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return OK;
136720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
136820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
136937187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::pause() {
1370a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mPaused = true;
137137187916a486504acaf83bea30147eb5fbf46ae5James Dong    return OK;
1372a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
1373a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
137437187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::stop() {
1375cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong    LOGD("Stopping %s track", mIsAudio? "Audio": "Video");
1376eaae38445a340c4857c1c5569475879a728e63b7James Dong    if (!mStarted) {
1377eaae38445a340c4857c1c5569475879a728e63b7James Dong        LOGE("Stop() called but track is not started");
1378eaae38445a340c4857c1c5569475879a728e63b7James Dong        return ERROR_END_OF_STREAM;
1379eaae38445a340c4857c1c5569475879a728e63b7James Dong    }
1380eaae38445a340c4857c1c5569475879a728e63b7James Dong
138120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mDone) {
138237187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
138320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
138420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mDone = true;
138520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
138620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    void *dummy;
138720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_join(mThread, &dummy);
138820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
138937187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = (status_t) dummy;
139037187916a486504acaf83bea30147eb5fbf46ae5James Dong
1391cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong    LOGD("Stopping %s track source", mIsAudio? "Audio": "Video");
139237187916a486504acaf83bea30147eb5fbf46ae5James Dong    {
139337187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = mSource->stop();
139437187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (err == OK && status != OK && status != ERROR_END_OF_STREAM) {
139537187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
139637187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
139737187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
139837187916a486504acaf83bea30147eb5fbf46ae5James Dong
1399cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong    LOGD("%s track stopped", mIsAudio? "Audio": "Video");
140037187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
140120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
140220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
140325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() {
140425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return mReachedEOS;
140525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber}
140625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
140720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static
140820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) {
140920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track *track = static_cast<Track *>(me);
141020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
141137187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = track->threadEntry();
141237187916a486504acaf83bea30147eb5fbf46ae5James Dong    return (void *) err;
141320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
141420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
14153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic void getNalUnitType(uint8_t byte, uint8_t* type) {
14163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("getNalUnitType: %d", byte);
14173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // nal_unit_type: 5-bit unsigned integer
14193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    *type = (byte & 0x1F);
14203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
14213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t *findNextStartCode(
14233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length) {
14243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("findNextStartCode: %p %d", data, length);
14263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t bytesLeft = length;
14283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    while (bytesLeft > 4  &&
14293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) {
14303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        --bytesLeft;
14313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
14323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (bytesLeft <= 4) {
14333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        bytesLeft = 0; // Last parameter set
14343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
14353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return &data[length - bytesLeft];
14363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
14373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongconst uint8_t *MPEG4Writer::Track::parseParamSet(
14393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length, int type, size_t *paramSetLen) {
14403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("parseParamSet");
14423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    CHECK(type == kNalUnitTypeSeqParamSet ||
14433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong          type == kNalUnitTypePicParamSet);
14443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *nextStartCode = findNextStartCode(data, length);
14463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    *paramSetLen = nextStartCode - data;
14473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (*paramSetLen == 0) {
14483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        LOGE("Param set is malformed, since its length is 0");
14493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return NULL;
14503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
14513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    AVCParamSet paramSet(*paramSetLen, data);
14533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (type == kNalUnitTypeSeqParamSet) {
14543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (*paramSetLen < 4) {
14553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Seq parameter set malformed");
14563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return NULL;
14573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
14583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (mSeqParamSets.empty()) {
14593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileIdc = data[1];
14603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileCompatible = data[2];
14613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mLevelIdc = data[3];
14623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else {
14633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (mProfileIdc != data[1] ||
14643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                mProfileCompatible != data[2] ||
14653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                mLevelIdc != data[3]) {
14663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                LOGE("Inconsistent profile/level found in seq parameter sets");
14673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return NULL;
14683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
14693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
14703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mSeqParamSets.push_back(paramSet);
14713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    } else {
14723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mPicParamSets.push_back(paramSet);
14733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
14743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return nextStartCode;
14753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
14763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::copyAVCCodecSpecificData(
14783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t size) {
14793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("copyAVCCodecSpecificData");
14803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 2 bytes for each of the parameter set length field
14823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // plus the 7 bytes for the header
14833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (size < 4 + 7) {
14843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        LOGE("Codec specific data length too short: %d", size);
14853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return ERROR_MALFORMED;
14863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
14873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize = size;
14893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificData = malloc(size);
14903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    memcpy(mCodecSpecificData, data, size);
14913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return OK;
14923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
14933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::parseAVCCodecSpecificData(
14953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t size) {
14963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("parseAVCCodecSpecificData");
14983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Data starts with a start code.
14993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // SPS and PPS are separated with start codes.
15003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Also, SPS must come before PPS
15013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t type = kNalUnitTypeSeqParamSet;
15023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    bool gotSps = false;
15033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    bool gotPps = false;
15043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *tmp = data;
15053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *nextStartCode = data;
15063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t bytesLeft = size;
15073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t paramSetLen = 0;
15083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize = 0;
15093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) {
15103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        getNalUnitType(*(tmp + 4), &type);
15113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (type == kNalUnitTypeSeqParamSet) {
15123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (gotPps) {
15133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                LOGE("SPS must come before PPS");
15143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return ERROR_MALFORMED;
15153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
15163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotSps) {
15173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                gotSps = true;
15183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
15193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
15203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else if (type == kNalUnitTypePicParamSet) {
15213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotSps) {
15223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                LOGE("SPS must come before PPS");
15233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return ERROR_MALFORMED;
15243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
15253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotPps) {
15263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                gotPps = true;
15273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
15283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
15293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else {
15303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Only SPS and PPS Nal units are expected");
15313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
15323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
15333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nextStartCode == NULL) {
15353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
15363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
15373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Move on to find the next parameter set
15393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        bytesLeft -= nextStartCode - tmp;
15403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        tmp = nextStartCode;
15413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mCodecSpecificDataSize += (2 + paramSetLen);
15423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
15433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
15453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the number of seq parameter sets
15463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        size_t nSeqParamSets = mSeqParamSets.size();
15473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nSeqParamSets == 0) {
15483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Cound not find sequence parameter set");
15493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
15503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
15513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nSeqParamSets > 0x1F) {
15533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Too many seq parameter sets (%d) found", nSeqParamSets);
15543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
15553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
15563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
15573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
15593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the number of pic parameter sets
15603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        size_t nPicParamSets = mPicParamSets.size();
15613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nPicParamSets == 0) {
15623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Cound not find picture parameter set");
15633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
15643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
15653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nPicParamSets > 0xFF) {
15663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Too many pic parameter sets (%d) found", nPicParamSets);
15673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
15683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
15693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
15703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
15723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the profiles
15733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // These profiles requires additional parameter set extensions
15743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (mProfileIdc == 100 || mProfileIdc == 110 ||
15753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileIdc == 122 || mProfileIdc == 144) {
15763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Sorry, no support for profile_idc: %d!", mProfileIdc);
15773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return BAD_VALUE;
15783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
15793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
15803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return OK;
15823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
1583548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
158403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData(
158503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        const uint8_t *data, size_t size) {
1586548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
158703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (mCodecSpecificData != NULL) {
1588548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber        LOGE("Already have codec specific data");
158903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
159003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
159103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
15923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (size < 4) {
15933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        LOGE("Codec specific data length too short: %d", size);
159403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
159503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
159603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
15973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Data is in the form of AVCCodecSpecificData
15983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (memcmp("\x00\x00\x00\x01", data, 4)) {
15993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return copyAVCCodecSpecificData(data, size);
160003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
160103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
16023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (parseAVCCodecSpecificData(data, size) != OK) {
160303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
160403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
160503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
16063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // ISO 14496-15: AVC file format
16073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize += 7;  // 7 more bytes in the header
160803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    mCodecSpecificData = malloc(mCodecSpecificDataSize);
160903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    uint8_t *header = (uint8_t *)mCodecSpecificData;
16103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[0] = 1;                     // version
16113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[1] = mProfileIdc;           // profile indication
16123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[2] = mProfileCompatible;    // profile compatibility
16133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[3] = mLevelIdc;
161403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
16153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne
1616b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    if (mOwner->useNalLengthFour()) {
1617b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        header[4] = 0xfc | 3;  // length size == 4 bytes
1618b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    } else {
1619b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        header[4] = 0xfc | 1;  // length size == 2 bytes
1620b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    }
162103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
16223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 3-bit '111' followed by 5-bit numSequenceParameterSets
16233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    int nSequenceParamSets = mSeqParamSets.size();
16243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[5] = 0xe0 | nSequenceParamSets;
16253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header += 6;
16263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    for (List<AVCParamSet>::iterator it = mSeqParamSets.begin();
16273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong         it != mSeqParamSets.end(); ++it) {
16283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // 16-bit sequence parameter set length
16293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t seqParamSetLength = it->mLength;
16303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[0] = seqParamSetLength >> 8;
16313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[1] = seqParamSetLength & 0xff;
16323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // SPS NAL unit (sequence parameter length bytes)
16343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        memcpy(&header[2], it->mData, seqParamSetLength);
16353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header += (2 + seqParamSetLength);
16363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
16373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 8-bit nPictureParameterSets
16393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    int nPictureParamSets = mPicParamSets.size();
16403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[0] = nPictureParamSets;
16413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header += 1;
16423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    for (List<AVCParamSet>::iterator it = mPicParamSets.begin();
16433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong         it != mPicParamSets.end(); ++it) {
16443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // 16-bit picture parameter set length
16453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t picParamSetLength = it->mLength;
16463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[0] = picParamSetLength >> 8;
16473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[1] = picParamSetLength & 0xff;
16483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // PPS Nal unit (picture parameter set length bytes)
16503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        memcpy(&header[2], it->mData, picParamSetLength);
16513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header += (2 + picParamSetLength);
16523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
165303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
165403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    return OK;
165503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber}
165603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
1657872a481558350634a3fd5cb67939de288af00ecbJames Dong/*
1658872a481558350634a3fd5cb67939de288af00ecbJames Dong* The video track's media time adjustment for real-time applications
1659872a481558350634a3fd5cb67939de288af00ecbJames Dong* is described as follows:
1660872a481558350634a3fd5cb67939de288af00ecbJames Dong*
1661872a481558350634a3fd5cb67939de288af00ecbJames Dong* First, the media time adjustment is done for every period of
1662872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs. kVideoMediaTimeAdjustPeriodTimeUs
1663872a481558350634a3fd5cb67939de288af00ecbJames Dong* is currently a fixed value chosen heuristically. The value of
1664872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs should not be very large or very small
1665872a481558350634a3fd5cb67939de288af00ecbJames Dong* for two considerations: on one hand, a relatively large value
1666872a481558350634a3fd5cb67939de288af00ecbJames Dong* helps reduce large fluctuation of drift time in the audio encoding
1667872a481558350634a3fd5cb67939de288af00ecbJames Dong* path; while on the other hand, a relatively small value helps keep
1668872a481558350634a3fd5cb67939de288af00ecbJames Dong* restoring synchronization in audio/video more frequently. Note for the
1669872a481558350634a3fd5cb67939de288af00ecbJames Dong* very first period of kVideoMediaTimeAdjustPeriodTimeUs, there is
1670872a481558350634a3fd5cb67939de288af00ecbJames Dong* no media time adjustment for the video track.
1671872a481558350634a3fd5cb67939de288af00ecbJames Dong*
1672872a481558350634a3fd5cb67939de288af00ecbJames Dong* Second, the total accumulated audio track time drift found
1673872a481558350634a3fd5cb67939de288af00ecbJames Dong* in a period of kVideoMediaTimeAdjustPeriodTimeUs is distributed
1674872a481558350634a3fd5cb67939de288af00ecbJames Dong* over a stream of incoming video frames. The number of video frames
1675872a481558350634a3fd5cb67939de288af00ecbJames Dong* affected is determined based on the number of recorded video frames
1676872a481558350634a3fd5cb67939de288af00ecbJames Dong* within the past kVideoMediaTimeAdjustPeriodTimeUs period.
1677872a481558350634a3fd5cb67939de288af00ecbJames Dong* We choose to distribute the drift time over only a portion
1678872a481558350634a3fd5cb67939de288af00ecbJames Dong* (rather than all) of the total number of recorded video frames
1679872a481558350634a3fd5cb67939de288af00ecbJames Dong* in order to make sure that the video track media time adjustment is
1680872a481558350634a3fd5cb67939de288af00ecbJames Dong* completed for the current period before the next video track media
1681872a481558350634a3fd5cb67939de288af00ecbJames Dong* time adjustment period starts. Currently, the portion chosen is a
1682872a481558350634a3fd5cb67939de288af00ecbJames Dong* half (0.5).
1683872a481558350634a3fd5cb67939de288af00ecbJames Dong*
1684872a481558350634a3fd5cb67939de288af00ecbJames Dong* Last, various additional checks are performed to ensure that
1685872a481558350634a3fd5cb67939de288af00ecbJames Dong* the actual audio encoding path does not have too much drift.
1686872a481558350634a3fd5cb67939de288af00ecbJames Dong* In particular, 1) we want to limit the average incremental time
1687872a481558350634a3fd5cb67939de288af00ecbJames Dong* adjustment for each video frame to be less than a threshold
1688872a481558350634a3fd5cb67939de288af00ecbJames Dong* for a single period of kVideoMediaTimeAdjustPeriodTimeUs.
1689872a481558350634a3fd5cb67939de288af00ecbJames Dong* Currently, the threshold is set to 5 ms. If the average incremental
1690872a481558350634a3fd5cb67939de288af00ecbJames Dong* media time adjustment for a video frame is larger than the
1691872a481558350634a3fd5cb67939de288af00ecbJames Dong* threshold, the audio encoding path has too much time drift.
1692872a481558350634a3fd5cb67939de288af00ecbJames Dong* 2) We also want to limit the total time drift in the audio
1693872a481558350634a3fd5cb67939de288af00ecbJames Dong* encoding path to be less than a threshold for a period of
1694872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs. Currently, the threshold
1695872a481558350634a3fd5cb67939de288af00ecbJames Dong* is 0.5% of kVideoMediaTimeAdjustPeriodTimeUs. If the time drift of
1696872a481558350634a3fd5cb67939de288af00ecbJames Dong* the audio encoding path is larger than the threshold, the audio
1697872a481558350634a3fd5cb67939de288af00ecbJames Dong* encoding path has too much time drift. We treat the large time
1698872a481558350634a3fd5cb67939de288af00ecbJames Dong* drift of the audio encoding path as errors, since there is no
1699872a481558350634a3fd5cb67939de288af00ecbJames Dong* way to keep audio/video in synchronization for real-time
1700872a481558350634a3fd5cb67939de288af00ecbJames Dong* applications if the time drift is too large unless we drop some
1701872a481558350634a3fd5cb67939de288af00ecbJames Dong* video frames, which has its own problems that we don't want
1702872a481558350634a3fd5cb67939de288af00ecbJames Dong* to get into for the time being.
1703872a481558350634a3fd5cb67939de288af00ecbJames Dong*/
1704872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::adjustMediaTime(int64_t *timestampUs) {
1705872a481558350634a3fd5cb67939de288af00ecbJames Dong    if (*timestampUs - mPrevMediaTimeAdjustTimestampUs >=
1706872a481558350634a3fd5cb67939de288af00ecbJames Dong        kVideoMediaTimeAdjustPeriodTimeUs) {
1707872a481558350634a3fd5cb67939de288af00ecbJames Dong
1708872a481558350634a3fd5cb67939de288af00ecbJames Dong        LOGV("New media time adjustment period at %lld us", *timestampUs);
1709872a481558350634a3fd5cb67939de288af00ecbJames Dong        mIsMediaTimeAdjustmentOn = true;
1710872a481558350634a3fd5cb67939de288af00ecbJames Dong        mMediaTimeAdjustNumFrames =
1711872a481558350634a3fd5cb67939de288af00ecbJames Dong                (mNumSamples - mPrevMediaTimeAdjustSample) >> 1;
1712872a481558350634a3fd5cb67939de288af00ecbJames Dong
1713872a481558350634a3fd5cb67939de288af00ecbJames Dong        mPrevMediaTimeAdjustTimestampUs = *timestampUs;
1714872a481558350634a3fd5cb67939de288af00ecbJames Dong        mPrevMediaTimeAdjustSample = mNumSamples;
1715872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t totalAccumDriftTimeUs = mOwner->getDriftTimeUs();
1716872a481558350634a3fd5cb67939de288af00ecbJames Dong        mTotalDriftTimeToAdjustUs =
1717872a481558350634a3fd5cb67939de288af00ecbJames Dong                totalAccumDriftTimeUs - mPrevTotalAccumDriftTimeUs;
1718872a481558350634a3fd5cb67939de288af00ecbJames Dong
1719872a481558350634a3fd5cb67939de288af00ecbJames Dong        mPrevTotalAccumDriftTimeUs = totalAccumDriftTimeUs;
1720872a481558350634a3fd5cb67939de288af00ecbJames Dong
1721872a481558350634a3fd5cb67939de288af00ecbJames Dong        // Check on incremental adjusted time per frame
1722872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t adjustTimePerFrameUs =
1723872a481558350634a3fd5cb67939de288af00ecbJames Dong                mTotalDriftTimeToAdjustUs / mMediaTimeAdjustNumFrames;
1724872a481558350634a3fd5cb67939de288af00ecbJames Dong
1725872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (adjustTimePerFrameUs < 0) {
1726872a481558350634a3fd5cb67939de288af00ecbJames Dong            adjustTimePerFrameUs = -adjustTimePerFrameUs;
1727872a481558350634a3fd5cb67939de288af00ecbJames Dong        }
1728872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (adjustTimePerFrameUs >= 5000) {
1729872a481558350634a3fd5cb67939de288af00ecbJames Dong            LOGE("Adjusted time per video frame is %lld us",
1730872a481558350634a3fd5cb67939de288af00ecbJames Dong                adjustTimePerFrameUs);
1731872a481558350634a3fd5cb67939de288af00ecbJames Dong            CHECK(!"Video frame time adjustment is too large!");
1732872a481558350634a3fd5cb67939de288af00ecbJames Dong        }
1733872a481558350634a3fd5cb67939de288af00ecbJames Dong
1734872a481558350634a3fd5cb67939de288af00ecbJames Dong        // Check on total accumulated time drift within a period of
1735872a481558350634a3fd5cb67939de288af00ecbJames Dong        // kVideoMediaTimeAdjustPeriodTimeUs.
1736872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t driftPercentage = (mTotalDriftTimeToAdjustUs * 1000)
1737872a481558350634a3fd5cb67939de288af00ecbJames Dong                / kVideoMediaTimeAdjustPeriodTimeUs;
1738872a481558350634a3fd5cb67939de288af00ecbJames Dong
1739872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (driftPercentage < 0) {
1740872a481558350634a3fd5cb67939de288af00ecbJames Dong            driftPercentage = -driftPercentage;
1741872a481558350634a3fd5cb67939de288af00ecbJames Dong        }
1742872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (driftPercentage > 5) {
1743872a481558350634a3fd5cb67939de288af00ecbJames Dong            LOGE("Audio track has time drift %lld us over %lld us",
1744872a481558350634a3fd5cb67939de288af00ecbJames Dong                mTotalDriftTimeToAdjustUs,
1745872a481558350634a3fd5cb67939de288af00ecbJames Dong                kVideoMediaTimeAdjustPeriodTimeUs);
1746872a481558350634a3fd5cb67939de288af00ecbJames Dong
1747872a481558350634a3fd5cb67939de288af00ecbJames Dong            CHECK(!"The audio track media time drifts too much!");
1748872a481558350634a3fd5cb67939de288af00ecbJames Dong        }
1749872a481558350634a3fd5cb67939de288af00ecbJames Dong
1750872a481558350634a3fd5cb67939de288af00ecbJames Dong    }
1751872a481558350634a3fd5cb67939de288af00ecbJames Dong
1752872a481558350634a3fd5cb67939de288af00ecbJames Dong    if (mIsMediaTimeAdjustmentOn) {
1753872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (mNumSamples - mPrevMediaTimeAdjustSample <=
1754872a481558350634a3fd5cb67939de288af00ecbJames Dong            mMediaTimeAdjustNumFrames) {
1755872a481558350634a3fd5cb67939de288af00ecbJames Dong
1756872a481558350634a3fd5cb67939de288af00ecbJames Dong            // Do media time incremental adjustment
1757872a481558350634a3fd5cb67939de288af00ecbJames Dong            int64_t incrementalAdjustTimeUs =
1758872a481558350634a3fd5cb67939de288af00ecbJames Dong                        (mTotalDriftTimeToAdjustUs *
1759872a481558350634a3fd5cb67939de288af00ecbJames Dong                            (mNumSamples - mPrevMediaTimeAdjustSample))
1760872a481558350634a3fd5cb67939de288af00ecbJames Dong                                / mMediaTimeAdjustNumFrames;
1761872a481558350634a3fd5cb67939de288af00ecbJames Dong
1762872a481558350634a3fd5cb67939de288af00ecbJames Dong            *timestampUs +=
1763872a481558350634a3fd5cb67939de288af00ecbJames Dong                (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs);
1764872a481558350634a3fd5cb67939de288af00ecbJames Dong
1765872a481558350634a3fd5cb67939de288af00ecbJames Dong            LOGV("Incremental video frame media time adjustment: %lld us",
1766872a481558350634a3fd5cb67939de288af00ecbJames Dong                (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs));
1767872a481558350634a3fd5cb67939de288af00ecbJames Dong        } else {
1768872a481558350634a3fd5cb67939de288af00ecbJames Dong            // Within the remaining adjustment period,
1769872a481558350634a3fd5cb67939de288af00ecbJames Dong            // no incremental adjustment is needed.
1770872a481558350634a3fd5cb67939de288af00ecbJames Dong            *timestampUs +=
1771872a481558350634a3fd5cb67939de288af00ecbJames Dong                (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs);
1772872a481558350634a3fd5cb67939de288af00ecbJames Dong
1773872a481558350634a3fd5cb67939de288af00ecbJames Dong            LOGV("Fixed video frame media time adjustment: %lld us",
1774872a481558350634a3fd5cb67939de288af00ecbJames Dong                (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs));
1775872a481558350634a3fd5cb67939de288af00ecbJames Dong        }
1776872a481558350634a3fd5cb67939de288af00ecbJames Dong    }
1777872a481558350634a3fd5cb67939de288af00ecbJames Dong}
1778872a481558350634a3fd5cb67939de288af00ecbJames Dong
1779872a481558350634a3fd5cb67939de288af00ecbJames Dong/*
1780872a481558350634a3fd5cb67939de288af00ecbJames Dong * Updates the drift time from the audio track so that
1781872a481558350634a3fd5cb67939de288af00ecbJames Dong * the video track can get the updated drift time information
1782872a481558350634a3fd5cb67939de288af00ecbJames Dong * from the file writer. The fluctuation of the drift time of the audio
1783872a481558350634a3fd5cb67939de288af00ecbJames Dong * encoding path is smoothed out with a simple filter by giving a larger
1784872a481558350634a3fd5cb67939de288af00ecbJames Dong * weight to more recently drift time. The filter coefficients, 0.5 and 0.5,
1785872a481558350634a3fd5cb67939de288af00ecbJames Dong * are heuristically determined.
1786872a481558350634a3fd5cb67939de288af00ecbJames Dong */
1787872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) {
1788872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t driftTimeUs = 0;
1789872a481558350634a3fd5cb67939de288af00ecbJames Dong    if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) {
1790872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t prevDriftTimeUs = mOwner->getDriftTimeUs();
1791872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1;
1792872a481558350634a3fd5cb67939de288af00ecbJames Dong        mOwner->setDriftTimeUs(timeUs);
1793872a481558350634a3fd5cb67939de288af00ecbJames Dong    }
1794872a481558350634a3fd5cb67939de288af00ecbJames Dong}
1795872a481558350634a3fd5cb67939de288af00ecbJames Dong
179637187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::threadEntry() {
179730ab66297501757d745b9ae10da61adcd891f497Andreas Huber    int32_t count = 0;
179813aec890216948b0c364f8f92792129d0335f506James Dong    const int64_t interleaveDurationUs = mOwner->interleaveDuration();
179913aec890216948b0c364f8f92792129d0335f506James Dong    int64_t chunkTimestampUs = 0;
180013aec890216948b0c364f8f92792129d0335f506James Dong    int32_t nChunks = 0;
180113aec890216948b0c364f8f92792129d0335f506James Dong    int32_t nZeroLengthFrames = 0;
18028f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t lastTimestampUs = 0;  // Previous sample time stamp in ms
18038f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t lastDurationUs = 0;   // Between the previous two samples in ms
1804c059860c73678a202bfa33062723e8f82fb779d9James Dong    int64_t currDurationTicks = 0;  // Timescale based ticks
1805c059860c73678a202bfa33062723e8f82fb779d9James Dong    int64_t lastDurationTicks = 0;  // Timescale based ticks
18068f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int32_t sampleCount = 1;      // Sample count in the current stts table entry
1807be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    uint32_t previousSampleSize = 0;  // Size of the previous sample
1808a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    int64_t previousPausedDurationUs = 0;
18091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    int64_t timestampUs;
1810e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
1811a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    if (mIsAudio) {
1812a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong        prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
1813a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    } else {
1814a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong        prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0);
1815a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    }
1816985f838934510983d8a887461e98dca60a6e858fJames Dong    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
1817985f838934510983d8a887461e98dca60a6e858fJames Dong
1818d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong    sp<MetaData> meta_data;
181920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1820ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    mNumSamples = 0;
182193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    status_t err = OK;
182220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    MediaBuffer *buffer;
182393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    while (!mDone && (err = mSource->read(&buffer)) == OK) {
182420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        if (buffer->range_length() == 0) {
182520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            buffer->release();
182620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            buffer = NULL;
182713aec890216948b0c364f8f92792129d0335f506James Dong            ++nZeroLengthFrames;
182820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            continue;
182920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
183020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1831a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // If the codec specific data has not been received yet, delay pause.
1832a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // After the codec specific data is received, discard what we received
1833a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // when the track is to be paused.
1834a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mPaused && !mResumed) {
1835a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            buffer->release();
1836a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            buffer = NULL;
1837a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            continue;
1838a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
1839a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
184030ab66297501757d745b9ae10da61adcd891f497Andreas Huber        ++count;
184130ab66297501757d745b9ae10da61adcd891f497Andreas Huber
184203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        int32_t isCodecConfig;
184303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
184403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                && isCodecConfig) {
1845548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            CHECK(!mGotAllCodecSpecificData);
1846548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
18471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            if (mIsAvc) {
184803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                status_t err = makeAVCCodecSpecificData(
184903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        (const uint8_t *)buffer->data()
185003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                            + buffer->range_offset(),
185103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        buffer->range_length());
1852be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                CHECK_EQ(OK, err);
18531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            } else if (mIsMPEG4) {
185403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                mCodecSpecificDataSize = buffer->range_length();
185503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                mCodecSpecificData = malloc(mCodecSpecificDataSize);
185603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                memcpy(mCodecSpecificData,
185703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        (const uint8_t *)buffer->data()
185803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                            + buffer->range_offset(),
185903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                       buffer->range_length());
186030ab66297501757d745b9ae10da61adcd891f497Andreas Huber            }
186130ab66297501757d745b9ae10da61adcd891f497Andreas Huber
186230ab66297501757d745b9ae10da61adcd891f497Andreas Huber            buffer->release();
186330ab66297501757d745b9ae10da61adcd891f497Andreas Huber            buffer = NULL;
186430ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1865548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            mGotAllCodecSpecificData = true;
186630ab66297501757d745b9ae10da61adcd891f497Andreas Huber            continue;
1867a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
1868a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
1869d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        // Make a deep copy of the MediaBuffer and Metadata and release
1870d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        // the original as soon as we can
1871d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        MediaBuffer *copy = new MediaBuffer(buffer->range_length());
1872d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(),
1873d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong                buffer->range_length());
1874d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        copy->set_range(0, buffer->range_length());
1875d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        meta_data = new MetaData(*buffer->meta_data().get());
1876d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        buffer->release();
1877d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        buffer = NULL;
1878d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
18791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (mIsAvc) StripStartcode(copy);
1880e136c3bb38e88315bf8797a464ebf2c788296b22James Dong
1881b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        size_t sampleSize = copy->range_length();
1882b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        if (mIsAvc) {
1883b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong            if (mOwner->useNalLengthFour()) {
1884b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong                sampleSize += 4;
1885b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong            } else {
1886b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong                sampleSize += 2;
1887b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong            }
1888b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        }
1889050b28a593350047845a45a14cc5026221ac1620James Dong
1890d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        // Max file size or duration handling
18911f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        mMdatSizeBytes += sampleSize;
18921f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        updateTrackSizeEstimate();
18931f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1894d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if (mOwner->exceedsFileSizeLimit()) {
1895d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
1896d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            break;
1897d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
1898d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if (mOwner->exceedsFileDurationLimit()) {
1899d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
1900d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            break;
1901d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
1902d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
1903050b28a593350047845a45a14cc5026221ac1620James Dong
1904d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        int32_t isSync = false;
1905d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        meta_data->findInt32(kKeyIsSyncFrame, &isSync);
1906d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
19078428af5381e835cc783b7ecb0d71cb60961c99c2James Dong        /*
19088428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * The original timestamp found in the data buffer will be modified as below:
19098428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         *
19108428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * There is a playback offset into this track if the track's start time
19118428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * is not the same as the movie start time, which will be recorded in edst
19128428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * box of the output file. The playback offset is to make sure that the
19138428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * starting time of the audio/video tracks are synchronized. Although the
19148428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * track's media timestamp may be subject to various modifications
19158428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * as outlined below, the track's playback offset time remains unchanged
19168428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * once the first data buffer of the track is received.
19178428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         *
19188428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * The media time stamp will be calculated by subtracting the playback offset
19198428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * (and potential pause durations) from the original timestamp in the buffer.
19208428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         *
19218428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * If this track is a video track for a real-time recording application with
19228428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * both audio and video tracks, its media timestamp will subject to further
19238428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * modification based on the media clock of the audio track. This modification
19248428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * is needed for the purpose of maintaining good audio/video synchronization.
19258428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         *
19268428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * If the recording session is paused and resumed multiple times, the track
19278428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * media timestamp will be modified as if the  recording session had never been
19288428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * paused at all during playback of the recorded output file. In other words,
19298428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * the output file will have no memory of pause/resume durations.
19308428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         *
19318428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         */
1932d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
19338428af5381e835cc783b7ecb0d71cb60961c99c2James Dong        LOGV("%s timestampUs: %lld", mIsAudio? "Audio": "Video", timestampUs);
1934d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
1935d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong////////////////////////////////////////////////////////////////////////////////
19368644c14618d30d9e57a69df40ed939986ebf02c4James Dong        if (mSampleSizes.empty()) {
1937f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong            mStartTimestampUs = timestampUs;
1938f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong            mOwner->setStartTimestampUs(mStartTimestampUs);
19398428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            previousPausedDurationUs = mStartTimestampUs;
19403c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong        }
194148c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber
1942a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mResumed) {
19438428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
19448428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            CHECK(durExcludingEarlierPausesUs >= 0);
19458428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
19468428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            CHECK(pausedDurationUs >= lastDurationUs);
19478428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            previousPausedDurationUs += pausedDurationUs - lastDurationUs;
1948a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            mResumed = false;
1949a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
1950a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
1951a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        timestampUs -= previousPausedDurationUs;
19528428af5381e835cc783b7ecb0d71cb60961c99c2James Dong        CHECK(timestampUs >= 0);
1953872a481558350634a3fd5cb67939de288af00ecbJames Dong
1954872a481558350634a3fd5cb67939de288af00ecbJames Dong        // Media time adjustment for real-time applications
1955872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (mIsRealTimeRecording) {
1956872a481558350634a3fd5cb67939de288af00ecbJames Dong            if (mIsAudio) {
1957872a481558350634a3fd5cb67939de288af00ecbJames Dong                updateDriftTime(meta_data);
1958872a481558350634a3fd5cb67939de288af00ecbJames Dong            } else {
1959872a481558350634a3fd5cb67939de288af00ecbJames Dong                adjustMediaTime(&timestampUs);
1960e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            }
1961e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        }
1962872a481558350634a3fd5cb67939de288af00ecbJames Dong
1963e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        CHECK(timestampUs >= 0);
1964e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        if (mNumSamples > 1) {
1965e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            if (timestampUs <= lastTimestampUs) {
19664f86a980fee1880dca61b828599fa6d76755a485James Dong                LOGW("Frame arrives too late!");
19674f86a980fee1880dca61b828599fa6d76755a485James Dong                // Don't drop the late frame, since dropping a frame may cause
19684f86a980fee1880dca61b828599fa6d76755a485James Dong                // problems later during playback
19694f86a980fee1880dca61b828599fa6d76755a485James Dong
19704f86a980fee1880dca61b828599fa6d76755a485James Dong                // The idea here is to avoid having two or more samples with the
19714f86a980fee1880dca61b828599fa6d76755a485James Dong                // same timestamp in the output file.
19724f86a980fee1880dca61b828599fa6d76755a485James Dong                if (mTimeScale >= 1000000LL) {
197340e9940fadf22daa64c1e766fa8a855c7b149c17James Dong                    timestampUs = lastTimestampUs + 1;
19744f86a980fee1880dca61b828599fa6d76755a485James Dong                } else {
197540e9940fadf22daa64c1e766fa8a855c7b149c17James Dong                    timestampUs = lastTimestampUs + (1000000LL + (mTimeScale >> 1)) / mTimeScale;
19764f86a980fee1880dca61b828599fa6d76755a485James Dong                }
1977e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            }
1978e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        }
1979e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
19808428af5381e835cc783b7ecb0d71cb60961c99c2James Dong        LOGV("%s media time stamp: %lld and previous paused duration %lld",
19818428af5381e835cc783b7ecb0d71cb60961c99c2James Dong                mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs);
1982c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong        if (timestampUs > mTrackDurationUs) {
1983c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong            mTrackDurationUs = timestampUs;
19843b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber        }
19853b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber
19868644c14618d30d9e57a69df40ed939986ebf02c4James Dong        mSampleSizes.push_back(sampleSize);
1987ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong        ++mNumSamples;
1988ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong        if (mNumSamples > 2) {
1989c059860c73678a202bfa33062723e8f82fb779d9James Dong            // We need to use the time scale based ticks, rather than the
1990c059860c73678a202bfa33062723e8f82fb779d9James Dong            // timestamp itself to determine whether we have to use a new
1991c059860c73678a202bfa33062723e8f82fb779d9James Dong            // stts entry, since we may have rounding errors.
1992c059860c73678a202bfa33062723e8f82fb779d9James Dong            // The calculation is intended to reduce the accumulated
1993c059860c73678a202bfa33062723e8f82fb779d9James Dong            // rounding errors.
1994c059860c73678a202bfa33062723e8f82fb779d9James Dong            currDurationTicks =
1995c059860c73678a202bfa33062723e8f82fb779d9James Dong                     ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
1996c059860c73678a202bfa33062723e8f82fb779d9James Dong                     (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
1997c059860c73678a202bfa33062723e8f82fb779d9James Dong
1998a472613aec322e25891abf5c77bf3f7e3c244920James Dong            // Force the first sample to have its own stts entry so that
1999a472613aec322e25891abf5c77bf3f7e3c244920James Dong            // we can adjust its value later to maintain the A/V sync.
2000a472613aec322e25891abf5c77bf3f7e3c244920James Dong            if (mNumSamples == 3 || currDurationTicks != lastDurationTicks) {
2001a472613aec322e25891abf5c77bf3f7e3c244920James Dong                LOGV("%s lastDurationUs: %lld us, currDurationTicks: %lld us",
2002a472613aec322e25891abf5c77bf3f7e3c244920James Dong                        mIsAudio? "Audio": "Video", lastDurationUs, currDurationTicks);
20031f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                addOneSttsTableEntry(sampleCount, lastDurationUs);
2004be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                sampleCount = 1;
2005be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            } else {
2006be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                ++sampleCount;
2007be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            }
2008be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        }
2009be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        if (mSamplesHaveSameSize) {
2010ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong            if (mNumSamples >= 2 && previousSampleSize != sampleSize) {
2011be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                mSamplesHaveSameSize = false;
2012be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            }
20138644c14618d30d9e57a69df40ed939986ebf02c4James Dong            previousSampleSize = sampleSize;
2014be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        }
2015a472613aec322e25891abf5c77bf3f7e3c244920James Dong        LOGV("%s timestampUs/lastTimestampUs: %lld/%lld",
2016a472613aec322e25891abf5c77bf3f7e3c244920James Dong                mIsAudio? "Audio": "Video", timestampUs, lastTimestampUs);
20178644c14618d30d9e57a69df40ed939986ebf02c4James Dong        lastDurationUs = timestampUs - lastTimestampUs;
2018c059860c73678a202bfa33062723e8f82fb779d9James Dong        lastDurationTicks = currDurationTicks;
20198644c14618d30d9e57a69df40ed939986ebf02c4James Dong        lastTimestampUs = timestampUs;
202020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2021d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        if (isSync != 0) {
20221f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            addOneStssTableEntry(mNumSamples);
2023d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        }
2024d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
202593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        if (mTrackingProgressStatus) {
202693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            if (mPreviousTrackTimeUs <= 0) {
202793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong                mPreviousTrackTimeUs = mStartTimestampUs;
202893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            }
2029faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong            trackProgressStatus(timestampUs);
203093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        }
203158ae9c530247668f8af36e30d228c716c226b3d4James Dong        if (mOwner->numTracks() == 1) {
2032c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong            off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy)
203358ae9c530247668f8af36e30d228c716c226b3d4James Dong                                 : mOwner->addSample_l(copy);
203458ae9c530247668f8af36e30d228c716c226b3d4James Dong            if (mChunkOffsets.empty()) {
20351f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                addChunkOffset(offset);
203658ae9c530247668f8af36e30d228c716c226b3d4James Dong            }
203758ae9c530247668f8af36e30d228c716c226b3d4James Dong            copy->release();
203858ae9c530247668f8af36e30d228c716c226b3d4James Dong            copy = NULL;
203958ae9c530247668f8af36e30d228c716c226b3d4James Dong            continue;
204058ae9c530247668f8af36e30d228c716c226b3d4James Dong        }
204113aec890216948b0c364f8f92792129d0335f506James Dong
204213aec890216948b0c364f8f92792129d0335f506James Dong        mChunkSamples.push_back(copy);
204313aec890216948b0c364f8f92792129d0335f506James Dong        if (interleaveDurationUs == 0) {
20441f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            addOneStscTableEntry(++nChunks, 1);
20451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            bufferChunk(timestampUs);
204613aec890216948b0c364f8f92792129d0335f506James Dong        } else {
204713aec890216948b0c364f8f92792129d0335f506James Dong            if (chunkTimestampUs == 0) {
204813aec890216948b0c364f8f92792129d0335f506James Dong                chunkTimestampUs = timestampUs;
204913aec890216948b0c364f8f92792129d0335f506James Dong            } else {
205013aec890216948b0c364f8f92792129d0335f506James Dong                if (timestampUs - chunkTimestampUs > interleaveDurationUs) {
205113aec890216948b0c364f8f92792129d0335f506James Dong                    ++nChunks;
205213aec890216948b0c364f8f92792129d0335f506James Dong                    if (nChunks == 1 ||  // First chunk
205313aec890216948b0c364f8f92792129d0335f506James Dong                        (--(mStscTableEntries.end()))->samplesPerChunk !=
205413aec890216948b0c364f8f92792129d0335f506James Dong                         mChunkSamples.size()) {
20551f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                        addOneStscTableEntry(nChunks, mChunkSamples.size());
205613aec890216948b0c364f8f92792129d0335f506James Dong                    }
20571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                    bufferChunk(timestampUs);
205813aec890216948b0c364f8f92792129d0335f506James Dong                    chunkTimestampUs = timestampUs;
205913aec890216948b0c364f8f92792129d0335f506James Dong                }
206013aec890216948b0c364f8f92792129d0335f506James Dong            }
206113aec890216948b0c364f8f92792129d0335f506James Dong        }
206213aec890216948b0c364f8f92792129d0335f506James Dong
206320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
206425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
2065a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong    if (mSampleSizes.empty() ||                      // no samples written
2066a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong        (!mIsAudio && mNumStssTableEntries == 0) ||  // no sync frames for video
2067a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong        (OK != checkCodecSpecificData())) {          // no codec specific data
2068690f546b0ee548dbfe997df36418e5302ec2d786James Dong        err = ERROR_MALFORMED;
2069f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong    }
2070bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    mOwner->trackProgressStatus(mTrackId, -1, err);
2071be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
207213aec890216948b0c364f8f92792129d0335f506James Dong    // Last chunk
207358ae9c530247668f8af36e30d228c716c226b3d4James Dong    if (mOwner->numTracks() == 1) {
20741f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        addOneStscTableEntry(1, mNumSamples);
207558ae9c530247668f8af36e30d228c716c226b3d4James Dong    } else if (!mChunkSamples.empty()) {
20761f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        addOneStscTableEntry(++nChunks, mChunkSamples.size());
20771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        bufferChunk(timestampUs);
207813aec890216948b0c364f8f92792129d0335f506James Dong    }
207913aec890216948b0c364f8f92792129d0335f506James Dong
2080be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // We don't really know how long the last frame lasts, since
2081be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // there is no frame time after it, just repeat the previous
2082be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // frame's duration.
2083ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    if (mNumSamples == 1) {
20848f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        lastDurationUs = 0;  // A single sample's duration
2085be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    } else {
2086be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        ++sampleCount;  // Count for the last sample
2087be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    }
2088a472613aec322e25891abf5c77bf3f7e3c244920James Dong
2089a472613aec322e25891abf5c77bf3f7e3c244920James Dong    if (mNumSamples <= 2) {
2090a472613aec322e25891abf5c77bf3f7e3c244920James Dong        addOneSttsTableEntry(1, lastDurationUs);
2091a472613aec322e25891abf5c77bf3f7e3c244920James Dong        if (sampleCount - 1 > 0) {
2092a472613aec322e25891abf5c77bf3f7e3c244920James Dong            addOneSttsTableEntry(sampleCount - 1, lastDurationUs);
2093a472613aec322e25891abf5c77bf3f7e3c244920James Dong        }
2094a472613aec322e25891abf5c77bf3f7e3c244920James Dong    } else {
2095a472613aec322e25891abf5c77bf3f7e3c244920James Dong        addOneSttsTableEntry(sampleCount, lastDurationUs);
2096a472613aec322e25891abf5c77bf3f7e3c244920James Dong    }
2097a472613aec322e25891abf5c77bf3f7e3c244920James Dong
2098c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    mTrackDurationUs += lastDurationUs;
209925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    mReachedEOS = true;
21001f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s",
21011f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            count, nZeroLengthFrames, mNumSamples, mIsAudio? "audio": "video");
2102872a481558350634a3fd5cb67939de288af00ecbJames Dong    if (mIsAudio) {
2103872a481558350634a3fd5cb67939de288af00ecbJames Dong        LOGI("Audio track drift time: %lld us", mOwner->getDriftTimeUs());
2104872a481558350634a3fd5cb67939de288af00ecbJames Dong    }
2105365a963142093a1cd8efdcea76b5f65096a5b115James Dong
210637187916a486504acaf83bea30147eb5fbf46ae5James Dong    if (err == ERROR_END_OF_STREAM) {
210737187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
210837187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
210937187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
2110365a963142093a1cd8efdcea76b5f65096a5b115James Dong}
2111365a963142093a1cd8efdcea76b5f65096a5b115James Dong
2112faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) {
2113faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    LOGV("trackProgressStatus: %lld us", timeUs);
2114215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    if (mTrackEveryTimeDurationUs > 0 &&
2115215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong        timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) {
211693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        LOGV("Fire time tracking progress status at %lld us", timeUs);
2117bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err);
211893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        mPreviousTrackTimeUs = timeUs;
211993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    }
212093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong}
212193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
2122faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::trackProgressStatus(
2123bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        size_t trackId, int64_t timeUs, status_t err) {
2124faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    Mutex::Autolock lock(mLock);
2125bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    int32_t trackNum = (trackId << 28);
2126faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
2127faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    // Error notification
2128faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    // Do not consider ERROR_END_OF_STREAM an error
2129faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    if (err != OK && err != ERROR_END_OF_STREAM) {
2130bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_ERROR,
2131bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong               trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL,
2132faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               err);
2133faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        return;
2134faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    }
2135faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
2136faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    if (timeUs == -1) {
2137faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        // Send completion notification
2138bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2139bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong               trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS,
2140faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               err);
2141faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    } else {
2142faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        // Send progress status
2143bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2144bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong               trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME,
2145faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               timeUs / 1000);
2146faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    }
2147faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong}
2148faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
2149d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dongvoid MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) {
2150d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong    LOGV("setDriftTimeUs: %lld us", driftTimeUs);
2151e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    Mutex::Autolock autolock(mLock);
2152d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong    mDriftTimeUs = driftTimeUs;
2153e259531ce59ab1f31de5a23124b22536f6a5a767James Dong}
2154e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
2155e259531ce59ab1f31de5a23124b22536f6a5a767James Dongint64_t MPEG4Writer::getDriftTimeUs() {
2156e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    LOGV("getDriftTimeUs: %lld us", mDriftTimeUs);
2157e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    Mutex::Autolock autolock(mLock);
2158e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    return mDriftTimeUs;
2159e259531ce59ab1f31de5a23124b22536f6a5a767James Dong}
2160e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
2161b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dongbool MPEG4Writer::useNalLengthFour() {
2162b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    return mUse4ByteNalLength;
2163b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong}
2164b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong
21651c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
21661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("bufferChunk");
21671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
21681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Chunk chunk(this, timestampUs, mChunkSamples);
21691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mOwner->bufferChunk(chunk);
217013aec890216948b0c364f8f92792129d0335f506James Dong    mChunkSamples.clear();
217120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
217220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
21733b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const {
2174c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    return mTrackDurationUs;
217520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
217620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2177d599cd4573b5a2d5914c5040e0565ef866749b77James Dongint64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
2178d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    return mEstimatedTrackSizeBytes;
2179d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
2180d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
2181690f546b0ee548dbfe997df36418e5302ec2d786James Dongstatus_t MPEG4Writer::Track::checkCodecSpecificData() const {
2182690f546b0ee548dbfe997df36418e5302ec2d786James Dong    const char *mime;
2183690f546b0ee548dbfe997df36418e5302ec2d786James Dong    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
2184690f546b0ee548dbfe997df36418e5302ec2d786James Dong    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) ||
2185690f546b0ee548dbfe997df36418e5302ec2d786James Dong        !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
2186690f546b0ee548dbfe997df36418e5302ec2d786James Dong        !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2187690f546b0ee548dbfe997df36418e5302ec2d786James Dong        if (!mCodecSpecificData ||
2188690f546b0ee548dbfe997df36418e5302ec2d786James Dong            mCodecSpecificDataSize <= 0) {
2189a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong            LOGE("Missing codec specific data");
2190690f546b0ee548dbfe997df36418e5302ec2d786James Dong            return ERROR_MALFORMED;
2191690f546b0ee548dbfe997df36418e5302ec2d786James Dong        }
2192690f546b0ee548dbfe997df36418e5302ec2d786James Dong    } else {
2193690f546b0ee548dbfe997df36418e5302ec2d786James Dong        if (mCodecSpecificData ||
2194690f546b0ee548dbfe997df36418e5302ec2d786James Dong            mCodecSpecificDataSize > 0) {
2195a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong            LOGE("Unexepected codec specific data found");
2196690f546b0ee548dbfe997df36418e5302ec2d786James Dong            return ERROR_MALFORMED;
2197690f546b0ee548dbfe997df36418e5302ec2d786James Dong        }
2198690f546b0ee548dbfe997df36418e5302ec2d786James Dong    }
2199690f546b0ee548dbfe997df36418e5302ec2d786James Dong    return OK;
2200690f546b0ee548dbfe997df36418e5302ec2d786James Dong}
2201690f546b0ee548dbfe997df36418e5302ec2d786James Dong
2202b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) {
220320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
22048f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    LOGV("%s track time scale: %d",
22051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mIsAudio? "Audio": "Video", mTimeScale);
22068f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
220720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    time_t now = time(NULL);
2208b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("trak");
2209b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeTkhdBox(now);
2210b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("mdia");
2211b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            writeMdhdBox(now);
2212b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            writeHdlrBox();
2213b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->beginBox("minf");
2214b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                if (mIsAudio) {
2215b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                    writeSmhdBox();
2216b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                } else {
2217b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                    writeVmhdBox();
2218b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                }
2219b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                writeDinfBox();
2220b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                writeStblBox(use32BitOffset);
2221b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->endBox();  // minf
2222b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->endBox();  // mdia
2223b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // trak
2224b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2225b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2226b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStblBox(bool use32BitOffset) {
2227b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stbl");
2228b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stsd");
2229b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);               // version=0, flags=0
2230b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1);               // entry count
2231b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mIsAudio) {
2232b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeAudioFourCCBox();
2233b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2234b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeVideoFourCCBox();
2235b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2236b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stsd
2237b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeSttsBox();
2238b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!mIsAudio) {
2239b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeStssBox();
2240b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2241b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeStszBox();
2242b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeStscBox();
2243b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeStcoBox(use32BitOffset);
2244b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stbl
2245b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2246b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2247b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVideoFourCCBox() {
2248b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    const char *mime;
2249b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    bool success = mMeta->findCString(kKeyMIMEType, &mime);
2250b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2251b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2252b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("mp4v");
2253b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2254b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("s263");
2255b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2256b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("avc1");
2257b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2258b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        LOGE("Unknown mime type '%s'.", mime);
2259b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(!"should not be here, unknown mime type.");
2260b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2261b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2262b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2263b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2264b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(1);           // data ref index
2265b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // predefined
2266b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2267b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // predefined
2268b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // predefined
2269b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // predefined
2270b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2271b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t width, height;
2272b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    success = mMeta->findInt32(kKeyWidth, &width);
2273b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    success = success && mMeta->findInt32(kKeyHeight, &height);
2274b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2275b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2276b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(width);
2277b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(height);
2278b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x480000);    // horiz resolution
2279b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x480000);    // vert resolution
2280b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2281b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(1);           // frame count
2282b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write("                                ", 32);
2283b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x18);        // depth
2284b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(-1);          // predefined
2285b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2286b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(23 + mCodecSpecificDataSize < 128);
2287b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2288b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2289b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeMp4vEsdsBox();
2290b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2291b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeD263Box();
2292b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2293b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeAvccBox();
2294b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2295b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2296b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writePaspBox();
2297b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // mp4v, s263 or avc1
2298b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2299b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2300b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAudioFourCCBox() {
2301b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    const char *mime;
2302b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    bool success = mMeta->findCString(kKeyMIMEType, &mime);
2303b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2304b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    const char *fourcc = NULL;
2305b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
2306b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fourcc = "samr";
2307b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2308b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fourcc = "sawb";
2309b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2310b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fourcc = "mp4a";
2311b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2312b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        LOGE("Unknown mime type '%s'.", mime);
2313b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(!"should not be here, unknown mime type.");
2314b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2315b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2316b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox(fourcc);        // audio format
2317b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2318b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2319b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x1);         // data ref index
2320b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2321b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2322b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t nChannels;
2323b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels));
2324b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(nChannels);   // channel count
2325b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(16);          // sample size
2326b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // predefined
2327b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2328b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2329b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t samplerate;
2330b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    success = mMeta->findInt32(kKeySampleRate, &samplerate);
2331b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2332b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(samplerate << 16);
2333b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2334b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeMp4aEsdsBox();
2335b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) ||
2336b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong               !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2337b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeDamrBox();
2338b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2339b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2340b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2341b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2342b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4aEsdsBox() {
2343b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("esds");
2344b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificData);
2345b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificDataSize > 0);
2346b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2347b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Make sure all sizes encode to a single byte.
2348b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificDataSize + 23 < 128);
2349b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2350b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);     // version=0, flags=0
2351b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x03);   // ES_DescrTag
2352b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(23 + mCodecSpecificDataSize);
2353b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x0000);// ES_ID
2354b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x00);
2355b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2356b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x04);   // DecoderConfigDescrTag
2357b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(15 + mCodecSpecificDataSize);
2358b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x40);   // objectTypeIndication ISO/IEC 14492-2
2359b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x15);   // streamType AudioStream
2360b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2361b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x03);  // XXX
2362b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x00);   // buffer size 24-bit
2363b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(96000); // max bit rate
2364b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(96000); // avg bit rate
2365b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2366b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x05);   // DecoderSpecificInfoTag
2367b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(mCodecSpecificDataSize);
2368b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2369b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2370b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    static const uint8_t kData2[] = {
2371b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x06,  // SLConfigDescriptorTag
2372b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x01,
2373b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x02
2374b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    };
2375b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(kData2, sizeof(kData2));
2376b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2377b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // esds
2378b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2379b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2380b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4vEsdsBox() {
2381b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificData);
2382b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificDataSize > 0);
2383b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("esds");
2384b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2385b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);    // version=0, flags=0
2386b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2387b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x03);  // ES_DescrTag
2388b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(23 + mCodecSpecificDataSize);
2389b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x0000);  // ES_ID
2390b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x1f);
2391b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2392b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x04);  // DecoderConfigDescrTag
2393b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(15 + mCodecSpecificDataSize);
2394b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x20);  // objectTypeIndication ISO/IEC 14492-2
2395b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x11);  // streamType VisualStream
2396b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2397b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    static const uint8_t kData[] = {
2398b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x01, 0x77, 0x00,
2399b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x00, 0x03, 0xe8, 0x00,
2400b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x00, 0x03, 0xe8, 0x00
2401b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    };
2402b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(kData, sizeof(kData));
2403b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2404b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
2405b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2406b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(mCodecSpecificDataSize);
2407b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2408b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2409b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    static const uint8_t kData2[] = {
2410b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x06,  // SLConfigDescriptorTag
2411b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x01,
2412b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x02
2413b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    };
2414b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(kData2, sizeof(kData2));
2415b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2416b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // esds
2417b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2418b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2419b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeTkhdBox(time_t now) {
2420b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("tkhd");
2421b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Flags = 7 to indicate that the track is enabled, and
2422b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // part of the presentation
2423b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x07);          // version=0, flags=7
2424b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // creation time
2425b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // modification time
2426b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mTrackId);
2427b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
24288f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t trakDurationUs = getDurationUs();
2429b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t mvhdTimeScale = mOwner->getTimeScale();
2430b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t tkhdDuration =
2431b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        (trakDurationUs * mvhdTimeScale + 5E5) / 1E6;
2432b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(tkhdDuration);  // in mvhd timescale
2433b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2434b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2435b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // layer
2436b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // alternate group
2437b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(mIsAudio ? 0x100 : 0);  // volume
2438b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // reserved
2439b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2440b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeCompositionMatrix(mRotation);       // matrix
244120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2442b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mIsAudio) {
2443b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(0);
2444b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(0);
2445b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2446b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        int32_t width, height;
2447b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        bool success = mMeta->findInt32(kKeyWidth, &width);
2448b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        success = success && mMeta->findInt32(kKeyHeight, &height);
2449b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(success);
2450b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2451b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(width << 16);   // 32-bit fixed-point value
2452b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(height << 16);  // 32-bit fixed-point value
2453b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2454b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // tkhd
2455b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2456b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2457b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVmhdBox() {
2458b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("vmhd");
2459b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x01);        // version=0, flags=1
2460b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // graphics mode
2461b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // opcolor
2462b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);
2463b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);
2464b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2465b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2466b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2467b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeSmhdBox() {
2468b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("smhd");
2469b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // version=0, flags=0
2470b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // balance
2471b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2472b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2473b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2474b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2475b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeHdlrBox() {
2476b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("hdlr");
2477b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // version=0, flags=0
2478b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // component type: should be mhlr
2479b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeFourcc(mIsAudio ? "soun" : "vide");  // component subtype
2480b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2481b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2482b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2483b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Removing "r" for the name string just makes the string 4 byte aligned
2484b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle");  // name
2485b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2486b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2487b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2488b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMdhdBox(time_t now) {
2489b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int64_t trakDurationUs = getDurationUs();
2490b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("mdhd");
2491b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // version=0, flags=0
2492b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // creation time
2493b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // modification time
2494b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mTimeScale);    // media timescale
2495b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6;
2496b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mdhdDuration);  // use media timescale
2497b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Language follows the three letter standard ISO-639-2/T
2498b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // 'e', 'n', 'g' for "English", for instance.
2499b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Each character is packed as the difference between its ASCII value and 0x60.
2500b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // For "English", these are 00101, 01110, 00111.
2501b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // XXX: Where is the padding bit located: 0x15C7?
2502b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // language code
2503b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // predefined
2504b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2505b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2506b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2507b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDamrBox() {
2508b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // 3gpp2 Spec AMRSampleEntry fields
2509b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("damr");
2510b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeCString("   ");  // vendor: 4 bytes
2511b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);         // decoder version
2512b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x83FF);   // mode set: all enabled
2513b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);         // mode change period
2514b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(1);         // frames per sample
2515b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2516b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2517b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2518b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeUrlBox() {
2519b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // The table index here refers to the sample description index
2520b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // in the sample table entries.
2521b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("url ");
2522b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1);  // version=0, flags=1 (self-contained)
2523b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // url
2524b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2525b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2526b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDrefBox() {
2527b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("dref");
2528b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2529b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1);  // entry count (either url or urn)
2530b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeUrlBox();
2531b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // dref
2532b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2533b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2534b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDinfBox() {
2535b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("dinf");
2536b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeDrefBox();
2537b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // dinf
2538b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2539b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2540b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAvccBox() {
2541b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificData);
2542b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificDataSize >= 5);
2543b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2544b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Patch avcc's lengthSize field to match the number
2545b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // of bytes we use to indicate the size of a nal unit.
2546b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    uint8_t *ptr = (uint8_t *)mCodecSpecificData;
2547b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    ptr[4] = (ptr[4] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1);
2548b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("avcC");
2549b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2550b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // avcC
2551b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2552b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2553b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeD263Box() {
2554b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("d263");
2555b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // vendor
2556b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);   // decoder version
2557b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(10);  // level: 10
2558b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);   // profile: 0
2559b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // d263
2560b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2561b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2562b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong// This is useful if the pixel is not square
2563b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writePaspBox() {
2564b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("pasp");
2565b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1 << 16);  // hspacing
2566b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1 << 16);  // vspacing
2567b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // pasp
2568b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2569b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2570b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeSttsBox() {
2571b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stts");
2572b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2573b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mNumSttsTableEntries);
2574a472613aec322e25891abf5c77bf3f7e3c244920James Dong    // Compensate for small start time difference from different media tracks
2575a472613aec322e25891abf5c77bf3f7e3c244920James Dong    int64_t trackStartTimeOffsetUs = 0;
2576b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
2577b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mStartTimestampUs != moovStartTimeUs) {
2578b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(mStartTimestampUs > moovStartTimeUs);
2579b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
2580b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2581b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int64_t prevTimestampUs = trackStartTimeOffsetUs;
2582b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
2583b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mSttsTableEntries.end(); ++it) {
2584b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(it->sampleCount);
2585a472613aec322e25891abf5c77bf3f7e3c244920James Dong
2586b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        // Make sure that we are calculating the sample duration the exactly
2587b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        // same way as we made decision on how to create stts entries.
2588b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        int64_t currTimestampUs = prevTimestampUs + it->sampleDurationUs;
2589b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        int32_t dur = ((currTimestampUs * mTimeScale + 500000LL) / 1000000LL -
2590b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            (prevTimestampUs * mTimeScale + 500000LL) / 1000000LL);
2591b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        prevTimestampUs += (it->sampleCount * it->sampleDurationUs);
259220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2593b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(dur);
2594b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2595b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stts
2596b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
259720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2598b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStssBox() {
2599b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stss");
2600b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2601b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mNumStssTableEntries);  // number of sync frames
2602b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<int32_t>::iterator it = mStssTableEntries.begin();
2603b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mStssTableEntries.end(); ++it) {
2604b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(*it);
2605b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2606b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stss
2607b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
260825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
2609b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStszBox() {
2610b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stsz");
2611b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2612b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mSamplesHaveSameSize) {
2613b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        List<size_t>::iterator it = mSampleSizes.begin();
2614b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(*it);  // default sample size
2615b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2616b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(0);
2617b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2618b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mNumSamples);
2619b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!mSamplesHaveSameSize) {
2620b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        for (List<size_t>::iterator it = mSampleSizes.begin();
2621b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            it != mSampleSizes.end(); ++it) {
2622b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->writeInt32(*it);
2623b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        }
2624b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2625b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stsz
2626b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
262720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2628b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStscBox() {
2629b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stsc");
2630b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2631b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mNumStscTableEntries);
2632b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<StscTableEntry>::iterator it = mStscTableEntries.begin();
2633b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mStscTableEntries.end(); ++it) {
2634b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(it->firstChunk);
2635b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(it->samplesPerChunk);
2636b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(it->sampleDescriptionId);
2637b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2638b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stsc
2639b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
264020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2641b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) {
2642b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox(use32BitOffset? "stco": "co64");
2643b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2644b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mNumStcoTableEntries);
2645b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<off64_t>::iterator it = mChunkOffsets.begin();
2646b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mChunkOffsets.end(); ++it) {
2647b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        if (use32BitOffset) {
2648b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->writeInt32(static_cast<int32_t>(*it));
2649b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        } else {
2650b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->writeInt64((*it));
2651b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        }
2652b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2653b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stco or co64
265420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
265520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
265620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}  // namespace android
2657