MPEG4Writer.cpp revision e9f6d0579603372fd2547e6c5ba6e114c6f8cba7
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>
3607ec01904613a0bac32caaa8444b4690998faed7James Dong#include <cutils/properties.h>
37674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <sys/types.h>
38674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <sys/stat.h>
39674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <fcntl.h>
40674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <unistd.h>
4120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
4219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber#include "include/ESDS.h"
4319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
4420111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubernamespace android {
4520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
461f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongstatic const int64_t kMax32BitFileSize = 0x007fffffffLL;
473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypeSeqParamSet = 0x07;
483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypePicParamSet = 0x08;
4970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dongstatic const int64_t kInitialDelayTimeUs     = 700000LL;
505b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong
515b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong// Using longer adjustment period to suppress fluctuations in
525b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong// the audio encoding paths
535b6a01e65aa4129a9226667536d1bc1dad5980d8James Dongstatic const int64_t kVideoMediaTimeAdjustPeriodTimeUs = 600000000LL;  // 10 minutes
543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
5520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberclass MPEG4Writer::Track {
5620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberpublic:
57bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId);
588f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
5920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    ~Track();
6020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    status_t start(MetaData *params);
6237187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t stop();
6337187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t pause();
6425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool reachedEOS();
6520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
663b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber    int64_t getDurationUs() const;
67d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    int64_t getEstimatedTrackSizeBytes() const;
68b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeTrackHeader(bool use32BitOffset = true);
691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    void bufferChunk(int64_t timestampUs);
701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool isAvc() const { return mIsAvc; }
711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool isAudio() const { return mIsAudio; }
721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool isMPEG4() const { return mIsMPEG4; }
73c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    void addChunkOffset(off64_t offset);
7470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    int32_t getTrackId() const { return mTrackId; }
75dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    status_t dump(int fd, const Vector<String16>& args) const;
7620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
7720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberprivate:
7820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    MPEG4Writer *mOwner;
7920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    sp<MetaData> mMeta;
80693d271e62a3726689ff68f4505ba49228eb94b2Andreas Huber    sp<MediaSource> mSource;
8120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    volatile bool mDone;
82a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    volatile bool mPaused;
83a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    volatile bool mResumed;
84eaae38445a340c4857c1c5569475879a728e63b7James Dong    volatile bool mStarted;
851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool mIsAvc;
861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool mIsAudio;
871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool mIsMPEG4;
88bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    int32_t mTrackId;
89c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    int64_t mTrackDurationUs;
9043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    int64_t mMaxChunkDurationUs;
91e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
92e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    // For realtime applications, we need to adjust the media clock
93e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    // for video track based on the audio media clock
94e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    bool mIsRealTimeRecording;
95e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    int64_t mMaxTimeStampUs;
96d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    int64_t mEstimatedTrackSizeBytes;
971f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    int64_t mMdatSizeBytes;
988f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int32_t mTimeScale;
9920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
10020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_t mThread;
10120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
102ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    // mNumSamples is used to track how many samples in mSampleSizes List.
103ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    // This is to reduce the cost associated with mSampleSizes.size() call,
104ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    // since it is O(n). Ideally, the fix should be in List class.
105ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    size_t              mNumSamples;
1068644c14618d30d9e57a69df40ed939986ebf02c4James Dong    List<size_t>        mSampleSizes;
107be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    bool                mSamplesHaveSameSize;
108be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
10913aec890216948b0c364f8f92792129d0335f506James Dong    List<MediaBuffer *> mChunkSamples;
1101f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1111f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    size_t              mNumStcoTableEntries;
112c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    List<off64_t>         mChunkOffsets;
11313aec890216948b0c364f8f92792129d0335f506James Dong
1141f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    size_t              mNumStscTableEntries;
11513aec890216948b0c364f8f92792129d0335f506James Dong    struct StscTableEntry {
11613aec890216948b0c364f8f92792129d0335f506James Dong
11713aec890216948b0c364f8f92792129d0335f506James Dong        StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id)
11813aec890216948b0c364f8f92792129d0335f506James Dong            : firstChunk(chunk),
11913aec890216948b0c364f8f92792129d0335f506James Dong              samplesPerChunk(samples),
12013aec890216948b0c364f8f92792129d0335f506James Dong              sampleDescriptionId(id) {}
12113aec890216948b0c364f8f92792129d0335f506James Dong
12213aec890216948b0c364f8f92792129d0335f506James Dong        uint32_t firstChunk;
12313aec890216948b0c364f8f92792129d0335f506James Dong        uint32_t samplesPerChunk;
12413aec890216948b0c364f8f92792129d0335f506James Dong        uint32_t sampleDescriptionId;
12513aec890216948b0c364f8f92792129d0335f506James Dong    };
12613aec890216948b0c364f8f92792129d0335f506James Dong    List<StscTableEntry> mStscTableEntries;
12720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1281f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    size_t        mNumStssTableEntries;
129050b28a593350047845a45a14cc5026221ac1620James Dong    List<int32_t> mStssTableEntries;
130050b28a593350047845a45a14cc5026221ac1620James Dong
1311f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    size_t        mNumSttsTableEntries;
132be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    struct SttsTableEntry {
133be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
1348f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        SttsTableEntry(uint32_t count, uint32_t durationUs)
1358f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            : sampleCount(count), sampleDurationUs(durationUs) {}
136be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
137be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        uint32_t sampleCount;
1388f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        uint32_t sampleDurationUs;
139be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    };
140be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    List<SttsTableEntry> mSttsTableEntries;
141be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
1423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Sequence parameter set or picture parameter set
1433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    struct AVCParamSet {
1443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        AVCParamSet(uint16_t length, const uint8_t *data)
1453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            : mLength(length), mData(data) {}
1463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
1473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t mLength;
1483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *mData;
1493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    };
1503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    List<AVCParamSet> mSeqParamSets;
1513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    List<AVCParamSet> mPicParamSets;
1523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mProfileIdc;
1533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mProfileCompatible;
1543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mLevelIdc;
1553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    void *mCodecSpecificData;
15720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    size_t mCodecSpecificDataSize;
158548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber    bool mGotAllCodecSpecificData;
15993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    bool mTrackingProgressStatus;
16020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
16125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool mReachedEOS;
1623c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    int64_t mStartTimestampUs;
16370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    int64_t mStartTimeRealUs;
16470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    int64_t mFirstSampleTimeRealUs;
16593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t mPreviousTrackTimeUs;
16693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t mTrackEveryTimeDurationUs;
16725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
168872a481558350634a3fd5cb67939de288af00ecbJames Dong    // Has the media time adjustment for video started?
169872a481558350634a3fd5cb67939de288af00ecbJames Dong    bool    mIsMediaTimeAdjustmentOn;
170872a481558350634a3fd5cb67939de288af00ecbJames Dong    // The time stamp when previous media time adjustment period starts
171872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t mPrevMediaTimeAdjustTimestampUs;
172872a481558350634a3fd5cb67939de288af00ecbJames Dong    // Number of vidoe frames whose time stamp may be adjusted
173872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t mMediaTimeAdjustNumFrames;
174872a481558350634a3fd5cb67939de288af00ecbJames Dong    // The sample number when previous meida time adjustmnet period starts
175872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t mPrevMediaTimeAdjustSample;
176872a481558350634a3fd5cb67939de288af00ecbJames Dong    // The total accumulated drift time within a period of
177872a481558350634a3fd5cb67939de288af00ecbJames Dong    // kVideoMediaTimeAdjustPeriodTimeUs.
178872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t mTotalDriftTimeToAdjustUs;
179872a481558350634a3fd5cb67939de288af00ecbJames Dong    // The total accumalated drift time since the start of the recording
180872a481558350634a3fd5cb67939de288af00ecbJames Dong    // excluding the current time adjustment period
181872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t mPrevTotalAccumDriftTimeUs;
182872a481558350634a3fd5cb67939de288af00ecbJames Dong
183872a481558350634a3fd5cb67939de288af00ecbJames Dong    // Update the audio track's drift information.
184872a481558350634a3fd5cb67939de288af00ecbJames Dong    void updateDriftTime(const sp<MetaData>& meta);
185872a481558350634a3fd5cb67939de288af00ecbJames Dong
186872a481558350634a3fd5cb67939de288af00ecbJames Dong    // Adjust the time stamp of the video track according to
187872a481558350634a3fd5cb67939de288af00ecbJames Dong    // the drift time information from the audio track.
188872a481558350634a3fd5cb67939de288af00ecbJames Dong    void adjustMediaTime(int64_t *timestampUs);
189872a481558350634a3fd5cb67939de288af00ecbJames Dong
19020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    static void *ThreadWrapper(void *me);
19137187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t threadEntry();
19220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *parseParamSet(
1943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length, int type, size_t *paramSetLen);
1953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
196b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    status_t makeAVCCodecSpecificData(const uint8_t *data, size_t size);
197b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    status_t copyAVCCodecSpecificData(const uint8_t *data, size_t size);
198b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    status_t parseAVCCodecSpecificData(const uint8_t *data, size_t size);
199215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong
200215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    // Track authoring progress status
201faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    void trackProgressStatus(int64_t timeUs, status_t err = OK);
20293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    void initTrackingProgressStatus(MetaData *params);
20303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
20419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    void getCodecSpecificDataFromInputFormatIfPossible();
20519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
206c059860c73678a202bfa33062723e8f82fb779d9James Dong    // Determine the track time scale
207c059860c73678a202bfa33062723e8f82fb779d9James Dong    // If it is an audio track, try to use the sampling rate as
208c059860c73678a202bfa33062723e8f82fb779d9James Dong    // the time scale; however, if user chooses the overwrite
209c059860c73678a202bfa33062723e8f82fb779d9James Dong    // value, the user-supplied time scale will be used.
210c059860c73678a202bfa33062723e8f82fb779d9James Dong    void setTimeScale();
211c059860c73678a202bfa33062723e8f82fb779d9James Dong
212690f546b0ee548dbfe997df36418e5302ec2d786James Dong    // Simple validation on the codec specific data
213690f546b0ee548dbfe997df36418e5302ec2d786James Dong    status_t checkCodecSpecificData() const;
21413f6284305e4b27395a23db7882d670bdb1bcae1James Dong    int32_t mRotation;
215690f546b0ee548dbfe997df36418e5302ec2d786James Dong
2161f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void updateTrackSizeEstimate();
2171f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void addOneStscTableEntry(size_t chunkId, size_t sampleId);
2181f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void addOneStssTableEntry(size_t sampleId);
2191f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void addOneSttsTableEntry(size_t sampleCount, int64_t durationUs);
22043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    void sendTrackSummary(bool hasMultipleTracks);
2211f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
222b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Write the boxes
223b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStcoBox(bool use32BitOffset);
224b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStscBox();
225b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStszBox();
226b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStssBox();
227b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeSttsBox();
228b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeD263Box();
229b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writePaspBox();
230b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeAvccBox();
231b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeUrlBox();
232b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeDrefBox();
233b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeDinfBox();
234b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeDamrBox();
235b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeMdhdBox(time_t now);
236b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeSmhdBox();
237b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeVmhdBox();
238b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeHdlrBox();
239b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeTkhdBox(time_t now);
240b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeMp4aEsdsBox();
241b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeMp4vEsdsBox();
242b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeAudioFourCCBox();
243b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeVideoFourCCBox();
244b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStblBox(bool use32BitOffset);
245b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
24620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track(const Track &);
24720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track &operator=(const Track &);
24820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber};
24920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
25020111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::MPEG4Writer(const char *filename)
251674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    : mFd(-1),
252674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong      mInitCheck(NO_INIT),
253b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong      mUse4ByteNalLength(true),
2541acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong      mUse32BitOffset(true),
255a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong      mIsFileSizeLimitExplicitlyRequested(false),
256a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
257a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mStarted(false),
25820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mOffset(0),
25913aec890216948b0c364f8f92792129d0335f506James Dong      mMdatOffset(0),
2607837c17063a4c50bc856ba59418516fdab731de7James Dong      mEstimatedMoovBoxSize(0),
26107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mInterleaveDurationUs(1000000),
26207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mLatitudex10000(0),
26307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mLongitudex10000(0),
26486b7f47aa7482424cf8fd248f1315311919be3b0James Dong      mAreGeoTagsAvailable(false),
26586b7f47aa7482424cf8fd248f1315311919be3b0James Dong      mStartTimeOffsetMs(-1) {
266674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong
26703f6f4e7e2ce09357cbc05bb546cd8a6e54b5baeJames Dong    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR);
268674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mFd >= 0) {
269674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        mInitCheck = OK;
270674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    }
27120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
27220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
27330ab66297501757d745b9ae10da61adcd891f497Andreas HuberMPEG4Writer::MPEG4Writer(int fd)
274674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    : mFd(dup(fd)),
275674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong      mInitCheck(mFd < 0? NO_INIT: OK),
276b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong      mUse4ByteNalLength(true),
2771acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong      mUse32BitOffset(true),
278a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong      mIsFileSizeLimitExplicitlyRequested(false),
279a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
280a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mStarted(false),
28130ab66297501757d745b9ae10da61adcd891f497Andreas Huber      mOffset(0),
28213aec890216948b0c364f8f92792129d0335f506James Dong      mMdatOffset(0),
2837837c17063a4c50bc856ba59418516fdab731de7James Dong      mEstimatedMoovBoxSize(0),
28407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mInterleaveDurationUs(1000000),
28507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mLatitudex10000(0),
28607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mLongitudex10000(0),
28786b7f47aa7482424cf8fd248f1315311919be3b0James Dong      mAreGeoTagsAvailable(false),
28886b7f47aa7482424cf8fd248f1315311919be3b0James Dong      mStartTimeOffsetMs(-1) {
28930ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
29030ab66297501757d745b9ae10da61adcd891f497Andreas Huber
29120111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() {
29220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    stop();
29320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2941f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    while (!mTracks.empty()) {
2951f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        List<Track *>::iterator it = mTracks.begin();
29620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        delete *it;
2971f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        (*it) = NULL;
2981f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        mTracks.erase(it);
29920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
30020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mTracks.clear();
30120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
30220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
303dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::dump(
304dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        int fd, const Vector<String16>& args) {
305dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    const size_t SIZE = 256;
306dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    char buffer[SIZE];
307dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    String8 result;
308dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "   MPEG4Writer %p\n", this);
309dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
310dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "     mStarted: %s\n", mStarted? "true": "false");
311dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
312dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    ::write(fd, result.string(), result.size());
313dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    for (List<Track *>::iterator it = mTracks.begin();
314dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong         it != mTracks.end(); ++it) {
315dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        (*it)->dump(fd, args);
316dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    }
317dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    return OK;
318dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong}
319dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong
320dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::Track::dump(
321dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        int fd, const Vector<String16>& args) const {
322dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    const size_t SIZE = 256;
323dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    char buffer[SIZE];
324dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    String8 result;
325dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "     %s track\n", mIsAudio? "Audio": "Video");
326dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
327dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "       reached EOS: %s\n",
328dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong            mReachedEOS? "true": "false");
329dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
330dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    ::write(fd, result.string(), result.size());
331dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    return OK;
332dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong}
333dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong
3342dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
335bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    Mutex::Autolock l(mLock);
336bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    if (mStarted) {
337bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        LOGE("Attempt to add source AFTER recording is started");
338bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        return UNKNOWN_ERROR;
339bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    }
340bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    Track *track = new Track(this, source, mTracks.size());
34120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mTracks.push_back(track);
3422dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
3432dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    return OK;
34420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
34520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
34693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::startTracks(MetaData *params) {
347a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    for (List<Track *>::iterator it = mTracks.begin();
348a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong         it != mTracks.end(); ++it) {
34993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        status_t err = (*it)->start(params);
350a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
351a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (err != OK) {
352a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            for (List<Track *>::iterator it2 = mTracks.begin();
353a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong                 it2 != it; ++it2) {
354a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong                (*it2)->stop();
355a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            }
356a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
357a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            return err;
358a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
359a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
360a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    return OK;
361a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
362a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
3632dec2b5be2056c6d9428897dc672185872d30d17James Dongint64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) {
3642dec2b5be2056c6d9428897dc672185872d30d17James Dong    // This implementation is highly experimental/heurisitic.
3652dec2b5be2056c6d9428897dc672185872d30d17James Dong    //
3662dec2b5be2056c6d9428897dc672185872d30d17James Dong    // Statistical analysis shows that metadata usually accounts
3672dec2b5be2056c6d9428897dc672185872d30d17James Dong    // for a small portion of the total file size, usually < 0.6%.
3682dec2b5be2056c6d9428897dc672185872d30d17James Dong
36978a1a286f736888ae7af8860b2c424af0d978848James Dong    // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2,
3702dec2b5be2056c6d9428897dc672185872d30d17James Dong    // where 1MB is the common file size limit for MMS application.
37178a1a286f736888ae7af8860b2c424af0d978848James Dong    // The default MAX _MOOV_BOX_SIZE value is based on about 3
3722dec2b5be2056c6d9428897dc672185872d30d17James Dong    // minute video recording with a bit rate about 3 Mbps, because
3732dec2b5be2056c6d9428897dc672185872d30d17James Dong    // statistics also show that most of the video captured are going
3742dec2b5be2056c6d9428897dc672185872d30d17James Dong    // to be less than 3 minutes.
3752dec2b5be2056c6d9428897dc672185872d30d17James Dong
3762dec2b5be2056c6d9428897dc672185872d30d17James Dong    // If the estimation is wrong, we will pay the price of wasting
3772dec2b5be2056c6d9428897dc672185872d30d17James Dong    // some reserved space. This should not happen so often statistically.
3782dec2b5be2056c6d9428897dc672185872d30d17James Dong    static const int32_t factor = mUse32BitOffset? 1: 2;
37978a1a286f736888ae7af8860b2c424af0d978848James Dong    static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024;  // 3 KB
3802dec2b5be2056c6d9428897dc672185872d30d17James Dong    static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000);
3812dec2b5be2056c6d9428897dc672185872d30d17James Dong    int64_t size = MIN_MOOV_BOX_SIZE;
3822dec2b5be2056c6d9428897dc672185872d30d17James Dong
38378a1a286f736888ae7af8860b2c424af0d978848James Dong    // Max file size limit is set
384a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
38578a1a286f736888ae7af8860b2c424af0d978848James Dong        size = mMaxFileSizeLimitBytes * 6 / 1000;
38678a1a286f736888ae7af8860b2c424af0d978848James Dong    }
38778a1a286f736888ae7af8860b2c424af0d978848James Dong
38878a1a286f736888ae7af8860b2c424af0d978848James Dong    // Max file duration limit is set
38978a1a286f736888ae7af8860b2c424af0d978848James Dong    if (mMaxFileDurationLimitUs != 0) {
39078a1a286f736888ae7af8860b2c424af0d978848James Dong        if (bitRate > 0) {
39178a1a286f736888ae7af8860b2c424af0d978848James Dong            int64_t size2 =
39278a1a286f736888ae7af8860b2c424af0d978848James Dong                ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000);
39378a1a286f736888ae7af8860b2c424af0d978848James Dong            if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
39478a1a286f736888ae7af8860b2c424af0d978848James Dong                // When both file size and duration limits are set,
39578a1a286f736888ae7af8860b2c424af0d978848James Dong                // we use the smaller limit of the two.
39678a1a286f736888ae7af8860b2c424af0d978848James Dong                if (size > size2) {
39778a1a286f736888ae7af8860b2c424af0d978848James Dong                    size = size2;
39878a1a286f736888ae7af8860b2c424af0d978848James Dong                }
39978a1a286f736888ae7af8860b2c424af0d978848James Dong            } else {
40078a1a286f736888ae7af8860b2c424af0d978848James Dong                // Only max file duration limit is set
40178a1a286f736888ae7af8860b2c424af0d978848James Dong                size = size2;
40278a1a286f736888ae7af8860b2c424af0d978848James Dong            }
4032dec2b5be2056c6d9428897dc672185872d30d17James Dong        }
4042dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
40578a1a286f736888ae7af8860b2c424af0d978848James Dong
4062dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (size < MIN_MOOV_BOX_SIZE) {
4072dec2b5be2056c6d9428897dc672185872d30d17James Dong        size = MIN_MOOV_BOX_SIZE;
4082dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
4092dec2b5be2056c6d9428897dc672185872d30d17James Dong
4102dec2b5be2056c6d9428897dc672185872d30d17James Dong    // Any long duration recording will be probably end up with
4112dec2b5be2056c6d9428897dc672185872d30d17James Dong    // non-streamable mp4 file.
4122dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (size > MAX_MOOV_BOX_SIZE) {
4132dec2b5be2056c6d9428897dc672185872d30d17James Dong        size = MAX_MOOV_BOX_SIZE;
4142dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
4152dec2b5be2056c6d9428897dc672185872d30d17James Dong
416a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated"
4172dec2b5be2056c6d9428897dc672185872d30d17James Dong         " moov size %lld bytes",
4182dec2b5be2056c6d9428897dc672185872d30d17James Dong         mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size);
4192dec2b5be2056c6d9428897dc672185872d30d17James Dong    return factor * size;
4202dec2b5be2056c6d9428897dc672185872d30d17James Dong}
4212dec2b5be2056c6d9428897dc672185872d30d17James Dong
4222dec2b5be2056c6d9428897dc672185872d30d17James Dongstatus_t MPEG4Writer::start(MetaData *param) {
423674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mInitCheck != OK) {
42425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        return UNKNOWN_ERROR;
42520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
42620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
427a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    /*
428a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * Check mMaxFileSizeLimitBytes at the beginning
429a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * since mMaxFileSizeLimitBytes may be implicitly
430a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * changed later for 32-bit file offset even if
431a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * user does not ask to set it explicitly.
432a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     */
433a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    if (mMaxFileSizeLimitBytes != 0) {
434a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong        mIsFileSizeLimitExplicitlyRequested = true;
435a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    }
436a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong
4372dec2b5be2056c6d9428897dc672185872d30d17James Dong    int32_t use64BitOffset;
4382dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (param &&
4392dec2b5be2056c6d9428897dc672185872d30d17James Dong        param->findInt32(kKey64BitFileOffset, &use64BitOffset) &&
4402dec2b5be2056c6d9428897dc672185872d30d17James Dong        use64BitOffset) {
4412dec2b5be2056c6d9428897dc672185872d30d17James Dong        mUse32BitOffset = false;
4422dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
4432dec2b5be2056c6d9428897dc672185872d30d17James Dong
4441f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    if (mUse32BitOffset) {
4451f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        // Implicit 32 bit file size limit
4461f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        if (mMaxFileSizeLimitBytes == 0) {
4471f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            mMaxFileSizeLimitBytes = kMax32BitFileSize;
4481f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        }
4491f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
4501f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        // If file size is set to be larger than the 32 bit file
4511f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        // size limit, treat it as an error.
4521f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        if (mMaxFileSizeLimitBytes > kMax32BitFileSize) {
453872a481558350634a3fd5cb67939de288af00ecbJames Dong            LOGW("32-bit file size limit (%lld bytes) too big. "
454d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong                 "It is changed to %lld bytes",
455d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong                mMaxFileSizeLimitBytes, kMax32BitFileSize);
456d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong            mMaxFileSizeLimitBytes = kMax32BitFileSize;
4571f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        }
4581f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    }
4591f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
460b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    int32_t use2ByteNalLength;
461b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    if (param &&
462b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) &&
463b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        use2ByteNalLength) {
464b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        mUse4ByteNalLength = false;
4652dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
4662dec2b5be2056c6d9428897dc672185872d30d17James Dong
467065d1aff96818df54456053f1574aec8a234d0deJames Dong    mStartTimestampUs = -1;
46893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
469a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (mStarted) {
470a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mPaused) {
471a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            mPaused = false;
47293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            return startTracks(param);
473a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
474a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return OK;
475a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
476a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
4778f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    if (!param ||
4788f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        !param->findInt32(kKeyTimeScale, &mTimeScale)) {
4798f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        mTimeScale = 1000;
4808f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    }
4818f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    CHECK(mTimeScale > 0);
4828f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    LOGV("movie time scale: %d", mTimeScale);
4838f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
4847837c17063a4c50bc856ba59418516fdab731de7James Dong    mStreamableFile = true;
4857837c17063a4c50bc856ba59418516fdab731de7James Dong    mWriteMoovBoxToMemory = false;
4867837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBuffer = NULL;
4877837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBufferOffset = 0;
4887837c17063a4c50bc856ba59418516fdab731de7James Dong
489b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeFtypBox(param);
49020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
4917837c17063a4c50bc856ba59418516fdab731de7James Dong    mFreeBoxOffset = mOffset;
49220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
4937837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mEstimatedMoovBoxSize == 0) {
4942dec2b5be2056c6d9428897dc672185872d30d17James Dong        int32_t bitRate = -1;
4952dec2b5be2056c6d9428897dc672185872d30d17James Dong        if (param) {
4962dec2b5be2056c6d9428897dc672185872d30d17James Dong            param->findInt32(kKeyBitRate, &bitRate);
4972dec2b5be2056c6d9428897dc672185872d30d17James Dong        }
4982dec2b5be2056c6d9428897dc672185872d30d17James Dong        mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate);
4997837c17063a4c50bc856ba59418516fdab731de7James Dong    }
5007837c17063a4c50bc856ba59418516fdab731de7James Dong    CHECK(mEstimatedMoovBoxSize >= 8);
501c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    lseek64(mFd, mFreeBoxOffset, SEEK_SET);
5027837c17063a4c50bc856ba59418516fdab731de7James Dong    writeInt32(mEstimatedMoovBoxSize);
5037837c17063a4c50bc856ba59418516fdab731de7James Dong    write("free", 4);
5047837c17063a4c50bc856ba59418516fdab731de7James Dong
5057837c17063a4c50bc856ba59418516fdab731de7James Dong    mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize;
5067837c17063a4c50bc856ba59418516fdab731de7James Dong    mOffset = mMdatOffset;
507c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    lseek64(mFd, mMdatOffset, SEEK_SET);
5081acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    if (mUse32BitOffset) {
5091acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        write("????mdat", 8);
5101acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    } else {
5111acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        write("\x00\x00\x00\x01mdat????????", 16);
5121acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    }
5131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
5141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    status_t err = startWriterThread();
5151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (err != OK) {
5161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        return err;
5171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
5181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
5191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    err = startTracks(param);
520a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (err != OK) {
521a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return err;
52220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
5231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
524a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mStarted = true;
52525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return OK;
52620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
52720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
5281f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongbool MPEG4Writer::use32BitFileOffset() const {
5291f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    return mUse32BitOffset;
5301f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
5311f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
53237187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::pause() {
533674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mInitCheck != OK) {
53437187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
535a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
536a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mPaused = true;
53737187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = OK;
538a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    for (List<Track *>::iterator it = mTracks.begin();
539a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong         it != mTracks.end(); ++it) {
54037187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = (*it)->pause();
54137187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (status != OK) {
54237187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
54337187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
544a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
54537187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
546a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
547a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
5481c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::stopWriterThread() {
549cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong    LOGD("Stopping writer thread");
5501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
5511c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    {
5521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        Mutex::Autolock autolock(mLock);
5531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
5541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mDone = true;
5551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mChunkReadyCondition.signal();
5561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
5571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
5581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    void *dummy;
5591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_join(mThread, &dummy);
560cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong    LOGD("Writer thread stopped");
5611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
5621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
56313f6284305e4b27395a23db7882d670bdb1bcae1James Dong/*
56413f6284305e4b27395a23db7882d670bdb1bcae1James Dong * MP4 file standard defines a composition matrix:
56513f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | a  b  u |
56613f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | c  d  v |
56713f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | x  y  w |
56813f6284305e4b27395a23db7882d670bdb1bcae1James Dong *
56913f6284305e4b27395a23db7882d670bdb1bcae1James Dong * the element in the matrix is stored in the following
57013f6284305e4b27395a23db7882d670bdb1bcae1James Dong * order: {a, b, u, c, d, v, x, y, w},
57113f6284305e4b27395a23db7882d670bdb1bcae1James Dong * where a, b, c, d, x, and y is in 16.16 format, while
57213f6284305e4b27395a23db7882d670bdb1bcae1James Dong * u, v and w is in 2.30 format.
57313f6284305e4b27395a23db7882d670bdb1bcae1James Dong */
57413f6284305e4b27395a23db7882d670bdb1bcae1James Dongvoid MPEG4Writer::writeCompositionMatrix(int degrees) {
57513f6284305e4b27395a23db7882d670bdb1bcae1James Dong    LOGV("writeCompositionMatrix");
57613f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t a = 0x00010000;
57713f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t b = 0;
57813f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t c = 0;
57913f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t d = 0x00010000;
58013f6284305e4b27395a23db7882d670bdb1bcae1James Dong    switch (degrees) {
58113f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 0:
58213f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
58313f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 90:
58413f6284305e4b27395a23db7882d670bdb1bcae1James Dong            a = 0;
58513f6284305e4b27395a23db7882d670bdb1bcae1James Dong            b = 0x00010000;
58613f6284305e4b27395a23db7882d670bdb1bcae1James Dong            c = 0xFFFF0000;
58713f6284305e4b27395a23db7882d670bdb1bcae1James Dong            d = 0;
58813f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
58913f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 180:
59013f6284305e4b27395a23db7882d670bdb1bcae1James Dong            a = 0xFFFF0000;
59113f6284305e4b27395a23db7882d670bdb1bcae1James Dong            d = 0xFFFF0000;
59213f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
59313f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 270:
59413f6284305e4b27395a23db7882d670bdb1bcae1James Dong            a = 0;
59513f6284305e4b27395a23db7882d670bdb1bcae1James Dong            b = 0xFFFF0000;
59613f6284305e4b27395a23db7882d670bdb1bcae1James Dong            c = 0x00010000;
59713f6284305e4b27395a23db7882d670bdb1bcae1James Dong            d = 0;
59813f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
59913f6284305e4b27395a23db7882d670bdb1bcae1James Dong        default:
60013f6284305e4b27395a23db7882d670bdb1bcae1James Dong            CHECK(!"Should never reach this unknown rotation");
60113f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
60213f6284305e4b27395a23db7882d670bdb1bcae1James Dong    }
60313f6284305e4b27395a23db7882d670bdb1bcae1James Dong
60413f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(a);           // a
60513f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(b);           // b
60613f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // u
60713f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(c);           // c
60813f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(d);           // d
60913f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // v
61013f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // x
61113f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // y
61213f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0x40000000);  // w
61313f6284305e4b27395a23db7882d670bdb1bcae1James Dong}
61413f6284305e4b27395a23db7882d670bdb1bcae1James Dong
61513f6284305e4b27395a23db7882d670bdb1bcae1James Dong
61637187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::stop() {
617674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mInitCheck != OK) {
61837187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
61920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
62020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
62137187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = OK;
6228f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t maxDurationUs = 0;
62365b3d76025c71d755b0fb3b6ead90255f25417edJames Dong    int64_t minDurationUs = 0x7fffffffffffffffLL;
62420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    for (List<Track *>::iterator it = mTracks.begin();
62520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber         it != mTracks.end(); ++it) {
62637187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = (*it)->stop();
62737187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (err == OK && status != OK) {
62837187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
62937187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
63020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6318f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        int64_t durationUs = (*it)->getDurationUs();
6328f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        if (durationUs > maxDurationUs) {
6338f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            maxDurationUs = durationUs;
63420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
63565b3d76025c71d755b0fb3b6ead90255f25417edJames Dong        if (durationUs < minDurationUs) {
63665b3d76025c71d755b0fb3b6ead90255f25417edJames Dong            minDurationUs = durationUs;
63765b3d76025c71d755b0fb3b6ead90255f25417edJames Dong        }
63865b3d76025c71d755b0fb3b6ead90255f25417edJames Dong    }
63965b3d76025c71d755b0fb3b6ead90255f25417edJames Dong
64065b3d76025c71d755b0fb3b6ead90255f25417edJames Dong    if (mTracks.size() > 1) {
64165b3d76025c71d755b0fb3b6ead90255f25417edJames Dong        LOGD("Duration from tracks range is [%lld, %lld] us",
64265b3d76025c71d755b0fb3b6ead90255f25417edJames Dong            minDurationUs, maxDurationUs);
64320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
64420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    stopWriterThread();
6467837c17063a4c50bc856ba59418516fdab731de7James Dong
64737187916a486504acaf83bea30147eb5fbf46ae5James Dong    // Do not write out movie header on error.
64837187916a486504acaf83bea30147eb5fbf46ae5James Dong    if (err != OK) {
649674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        close(mFd);
650674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        mFd = -1;
651674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        mInitCheck = NO_INIT;
65237187916a486504acaf83bea30147eb5fbf46ae5James Dong        mStarted = false;
65337187916a486504acaf83bea30147eb5fbf46ae5James Dong        return err;
65437187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
65537187916a486504acaf83bea30147eb5fbf46ae5James Dong
65620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    // Fix up the size of the 'mdat' chunk.
6571acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    if (mUse32BitOffset) {
658c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mMdatOffset, SEEK_SET);
6591acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset));
660c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &size, 4);
6611acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    } else {
662c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mMdatOffset + 8, SEEK_SET);
6631acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        int64_t size = mOffset - mMdatOffset;
6641acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        size = hton64(size);
665c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &size, 8);
6661acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    }
667c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    lseek64(mFd, mOffset, SEEK_SET);
66820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
669c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    const off64_t moovOffset = mOffset;
6707837c17063a4c50bc856ba59418516fdab731de7James Dong    mWriteMoovBoxToMemory = true;
6717837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
6727837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBufferOffset = 0;
6737837c17063a4c50bc856ba59418516fdab731de7James Dong    CHECK(mMoovBoxBuffer != NULL);
674b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeMoovBox(maxDurationUs);
67520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6767837c17063a4c50bc856ba59418516fdab731de7James Dong    mWriteMoovBoxToMemory = false;
6777837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mStreamableFile) {
6787837c17063a4c50bc856ba59418516fdab731de7James Dong        CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize);
6797837c17063a4c50bc856ba59418516fdab731de7James Dong
6807837c17063a4c50bc856ba59418516fdab731de7James Dong        // Moov box
681c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mFreeBoxOffset, SEEK_SET);
6827837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset = mFreeBoxOffset;
683674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset);
6847837c17063a4c50bc856ba59418516fdab731de7James Dong
6857837c17063a4c50bc856ba59418516fdab731de7James Dong        // Free box
686c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mOffset, SEEK_SET);
6877837c17063a4c50bc856ba59418516fdab731de7James Dong        writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset);
6887837c17063a4c50bc856ba59418516fdab731de7James Dong        write("free", 4);
6897837c17063a4c50bc856ba59418516fdab731de7James Dong
6907837c17063a4c50bc856ba59418516fdab731de7James Dong        // Free temp memory
6917837c17063a4c50bc856ba59418516fdab731de7James Dong        free(mMoovBoxBuffer);
6927837c17063a4c50bc856ba59418516fdab731de7James Dong        mMoovBoxBuffer = NULL;
6937837c17063a4c50bc856ba59418516fdab731de7James Dong        mMoovBoxBufferOffset = 0;
6942dec2b5be2056c6d9428897dc672185872d30d17James Dong    } else {
6952dec2b5be2056c6d9428897dc672185872d30d17James Dong        LOGI("The mp4 file will not be streamable.");
6967837c17063a4c50bc856ba59418516fdab731de7James Dong    }
6977837c17063a4c50bc856ba59418516fdab731de7James Dong
6980c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(mBoxes.empty());
69920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
700674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    close(mFd);
701674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    mFd = -1;
702674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    mInitCheck = NO_INIT;
703a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mStarted = false;
70470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
70537187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
70620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
70720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
708b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::writeMvhdBox(int64_t durationUs) {
709b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    time_t now = time(NULL);
710b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    beginBox("mvhd");
711b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // version=0, flags=0
712b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(now);           // creation time
713b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(now);           // modification time
714b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(mTimeScale);    // mvhd timescale
715b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t duration = (durationUs * mTimeScale + 5E5) / 1E6;
716b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(duration);
717b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0x10000);       // rate: 1.0
718b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt16(0x100);         // volume
719b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt16(0);             // reserved
720b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // reserved
721b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // reserved
722b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeCompositionMatrix(0); // matrix
723b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
724b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
725b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
726b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
727b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
728b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
729b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(mTracks.size() + 1);  // nextTrackID
730b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    endBox();  // mvhd
731b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
732b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
733b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::writeMoovBox(int64_t durationUs) {
734b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    beginBox("moov");
735b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeMvhdBox(durationUs);
73607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (mAreGeoTagsAvailable) {
73707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        writeUdtaBox();
73807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
739b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t id = 1;
740b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<Track *>::iterator it = mTracks.begin();
741b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mTracks.end(); ++it, ++id) {
742b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        (*it)->writeTrackHeader(mUse32BitOffset);
743b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
744b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    endBox();  // moov
745b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
746b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
7472cf9c5073ca3342ee52673ad68763fadd2c2be79James Dongvoid MPEG4Writer::writeFtypBox(MetaData *param) {
748b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    beginBox("ftyp");
749b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
750b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t fileType;
751b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (param && param->findInt32(kKeyFileType, &fileType) &&
752b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fileType != OUTPUT_FORMAT_MPEG_4) {
753b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeFourcc("3gp4");
754b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
755b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeFourcc("isom");
756b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
757b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
758b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);
759b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeFourcc("isom");
760b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeFourcc("3gp4");
761b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    endBox();
762b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
763b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
76407ec01904613a0bac32caaa8444b4690998faed7James Dongstatic bool isTestModeEnabled() {
76507ec01904613a0bac32caaa8444b4690998faed7James Dong#if (PROPERTY_VALUE_MAX < 5)
76607ec01904613a0bac32caaa8444b4690998faed7James Dong#error "PROPERTY_VALUE_MAX must be at least 5"
76707ec01904613a0bac32caaa8444b4690998faed7James Dong#endif
76807ec01904613a0bac32caaa8444b4690998faed7James Dong
76907ec01904613a0bac32caaa8444b4690998faed7James Dong    // Test mode is enabled only if rw.media.record.test system
77007ec01904613a0bac32caaa8444b4690998faed7James Dong    // property is enabled.
77107ec01904613a0bac32caaa8444b4690998faed7James Dong    char value[PROPERTY_VALUE_MAX];
77207ec01904613a0bac32caaa8444b4690998faed7James Dong    if (property_get("rw.media.record.test", value, NULL) &&
77307ec01904613a0bac32caaa8444b4690998faed7James Dong        (!strcasecmp(value, "true") || !strcasecmp(value, "1"))) {
77407ec01904613a0bac32caaa8444b4690998faed7James Dong        return true;
77507ec01904613a0bac32caaa8444b4690998faed7James Dong    }
77607ec01904613a0bac32caaa8444b4690998faed7James Dong    return false;
77707ec01904613a0bac32caaa8444b4690998faed7James Dong}
77807ec01904613a0bac32caaa8444b4690998faed7James Dong
77970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dongvoid MPEG4Writer::sendSessionSummary() {
78007ec01904613a0bac32caaa8444b4690998faed7James Dong    // Send session summary only if test mode is enabled
78107ec01904613a0bac32caaa8444b4690998faed7James Dong    if (!isTestModeEnabled()) {
78207ec01904613a0bac32caaa8444b4690998faed7James Dong        return;
78307ec01904613a0bac32caaa8444b4690998faed7James Dong    }
78407ec01904613a0bac32caaa8444b4690998faed7James Dong
78570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
78670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong         it != mChunkInfos.end(); ++it) {
78770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        int trackNum = it->mTrack->getTrackId() << 28;
78870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
78970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                trackNum | MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS,
79070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                it->mMaxInterChunkDurUs);
79170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    }
79270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong}
79370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
79413aec890216948b0c364f8f92792129d0335f506James Dongstatus_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) {
79513aec890216948b0c364f8f92792129d0335f506James Dong    mInterleaveDurationUs = durationUs;
79613aec890216948b0c364f8f92792129d0335f506James Dong    return OK;
79713aec890216948b0c364f8f92792129d0335f506James Dong}
79813aec890216948b0c364f8f92792129d0335f506James Dong
79913aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::lock() {
80013aec890216948b0c364f8f92792129d0335f506James Dong    mLock.lock();
80113aec890216948b0c364f8f92792129d0335f506James Dong}
80213aec890216948b0c364f8f92792129d0335f506James Dong
80313aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::unlock() {
80413aec890216948b0c364f8f92792129d0335f506James Dong    mLock.unlock();
80513aec890216948b0c364f8f92792129d0335f506James Dong}
80620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
807c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addSample_l(MediaBuffer *buffer) {
808c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t old_offset = mOffset;
80920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
810c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    ::write(mFd,
811c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong          (const uint8_t *)buffer->data() + buffer->range_offset(),
812c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong          buffer->range_length());
81320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
81420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mOffset += buffer->range_length();
81520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
81620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    return old_offset;
81720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
81820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
81903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) {
82003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (buffer->range_length() < 4) {
82103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return;
82203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
82303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
82403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    const uint8_t *ptr =
82503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        (const uint8_t *)buffer->data() + buffer->range_offset();
82603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
82703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
82803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        buffer->set_range(
82903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                buffer->range_offset() + 4, buffer->range_length() - 4);
83003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
83103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber}
83203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
833c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
834c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t old_offset = mOffset;
83530ab66297501757d745b9ae10da61adcd891f497Andreas Huber
83630ab66297501757d745b9ae10da61adcd891f497Andreas Huber    size_t length = buffer->range_length();
83703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
838b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    if (mUse4ByteNalLength) {
839b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        uint8_t x = length >> 24;
840c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
841b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = (length >> 16) & 0xff;
842c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
843b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = (length >> 8) & 0xff;
844c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
845b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = length & 0xff;
846c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
847c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong
848c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd,
849c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong              (const uint8_t *)buffer->data() + buffer->range_offset(),
850c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong              length);
851b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong
852b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        mOffset += length + 4;
853b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    } else {
854b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        CHECK(length < 65536);
85530ab66297501757d745b9ae10da61adcd891f497Andreas Huber
856b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        uint8_t x = length >> 8;
857c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
858b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = length & 0xff;
859c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
860c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length);
861b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        mOffset += length + 2;
862b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    }
86330ab66297501757d745b9ae10da61adcd891f497Andreas Huber
86430ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return old_offset;
86530ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
86630ab66297501757d745b9ae10da61adcd891f497Andreas Huber
8677837c17063a4c50bc856ba59418516fdab731de7James Dongsize_t MPEG4Writer::write(
868674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        const void *ptr, size_t size, size_t nmemb) {
8697837c17063a4c50bc856ba59418516fdab731de7James Dong
8707837c17063a4c50bc856ba59418516fdab731de7James Dong    const size_t bytes = size * nmemb;
8717837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mWriteMoovBoxToMemory) {
872674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        // This happens only when we write the moov box at the end of
873674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        // recording, not for each output video/audio frame we receive.
874c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        off64_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes;
8751acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        if (moovBoxSize > mEstimatedMoovBoxSize) {
876c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong            for (List<off64_t>::iterator it = mBoxes.begin();
8777837c17063a4c50bc856ba59418516fdab731de7James Dong                 it != mBoxes.end(); ++it) {
8787837c17063a4c50bc856ba59418516fdab731de7James Dong                (*it) += mOffset;
8797837c17063a4c50bc856ba59418516fdab731de7James Dong            }
880674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong            lseek64(mFd, mOffset, SEEK_SET);
881674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong            ::write(mFd, mMoovBoxBuffer, mMoovBoxBufferOffset);
882674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong            ::write(mFd, ptr, size * nmemb);
8837837c17063a4c50bc856ba59418516fdab731de7James Dong            mOffset += (bytes + mMoovBoxBufferOffset);
8847837c17063a4c50bc856ba59418516fdab731de7James Dong            free(mMoovBoxBuffer);
8857837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBuffer = NULL;
8867837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBufferOffset = 0;
8877837c17063a4c50bc856ba59418516fdab731de7James Dong            mWriteMoovBoxToMemory = false;
8887837c17063a4c50bc856ba59418516fdab731de7James Dong            mStreamableFile = false;
8897837c17063a4c50bc856ba59418516fdab731de7James Dong        } else {
8907837c17063a4c50bc856ba59418516fdab731de7James Dong            memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes);
8917837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBufferOffset += bytes;
8927837c17063a4c50bc856ba59418516fdab731de7James Dong        }
8937837c17063a4c50bc856ba59418516fdab731de7James Dong    } else {
894674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        ::write(mFd, ptr, size * nmemb);
8957837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset += bytes;
8967837c17063a4c50bc856ba59418516fdab731de7James Dong    }
8977837c17063a4c50bc856ba59418516fdab731de7James Dong    return bytes;
8987837c17063a4c50bc856ba59418516fdab731de7James Dong}
8997837c17063a4c50bc856ba59418516fdab731de7James Dong
90020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) {
9010c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK_EQ(strlen(fourcc), 4);
90220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
9037837c17063a4c50bc856ba59418516fdab731de7James Dong    mBoxes.push_back(mWriteMoovBoxToMemory?
9047837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBufferOffset: mOffset);
90520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
90620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    writeInt32(0);
90720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    writeFourcc(fourcc);
90820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
90920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
91020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() {
9110c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(!mBoxes.empty());
91220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
913c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t offset = *--mBoxes.end();
91420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mBoxes.erase(--mBoxes.end());
91520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
9167837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mWriteMoovBoxToMemory) {
9177837c17063a4c50bc856ba59418516fdab731de7James Dong       int32_t x = htonl(mMoovBoxBufferOffset - offset);
9187837c17063a4c50bc856ba59418516fdab731de7James Dong       memcpy(mMoovBoxBuffer + offset, &x, 4);
9197837c17063a4c50bc856ba59418516fdab731de7James Dong    } else {
920c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, offset, SEEK_SET);
9217837c17063a4c50bc856ba59418516fdab731de7James Dong        writeInt32(mOffset - offset);
9227837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset -= 4;
923c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mOffset, SEEK_SET);
9247837c17063a4c50bc856ba59418516fdab731de7James Dong    }
92520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
92620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
92720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) {
928674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 1);
92920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
93020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
93120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) {
93220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = htons(x);
933674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 2);
93420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
93520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
93620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) {
93720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = htonl(x);
938674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 4);
93920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
94020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
94120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) {
94220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = hton64(x);
943674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 8);
94420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
94520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
94620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) {
94720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    size_t n = strlen(s);
948674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(s, 1, n + 1);
94920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
95020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
95120111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) {
9520c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK_EQ(strlen(s), 4);
953674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(s, 1, 4);
95420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
95520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
95607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
95707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong// Written in +/-DD.DDDD format
95807b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeLatitude(int degreex10000) {
95907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    bool isNegative = (degreex10000 < 0);
96007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    char sign = isNegative? '-': '+';
96107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
96207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Handle the whole part
96307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    char str[9];
96407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    int wholePart = degreex10000 / 10000;
96507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (wholePart == 0) {
96607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        snprintf(str, 5, "%c%.2d.", sign, wholePart);
96707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    } else {
96807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        snprintf(str, 5, "%+.2d.", wholePart);
96907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
97007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
97107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Handle the fractional part
97207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    int fractionalPart = degreex10000 - (wholePart * 10000);
97307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (fractionalPart < 0) {
97407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        fractionalPart = -fractionalPart;
97507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
97607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    snprintf(&str[4], 5, "%.4d", fractionalPart);
97707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
97807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Do not write the null terminator
97907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    write(str, 1, 8);
98007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
98107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
98207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong// Written in +/- DDD.DDDD format
98307b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeLongitude(int degreex10000) {
98407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    bool isNegative = (degreex10000 < 0);
98507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    char sign = isNegative? '-': '+';
98607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
98707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Handle the whole part
98807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    char str[10];
98907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    int wholePart = degreex10000 / 10000;
99007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (wholePart == 0) {
99107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        snprintf(str, 6, "%c%.3d.", sign, wholePart);
99207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    } else {
99307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        snprintf(str, 6, "%+.3d.", wholePart);
99407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
99507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
99607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Handle the fractional part
99707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    int fractionalPart = degreex10000 - (wholePart * 10000);
99807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (fractionalPart < 0) {
99907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        fractionalPart = -fractionalPart;
100007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
100107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    snprintf(&str[5], 5, "%.4d", fractionalPart);
100207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
100307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Do not write the null terminator
100407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    write(str, 1, 9);
100507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
100607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
100707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong/*
100807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * Geodata is stored according to ISO-6709 standard.
100907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * latitudex10000 is latitude in degrees times 10000, and
101007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * longitudex10000 is longitude in degrees times 10000.
101107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * The range for the latitude is in [-90, +90], and
101207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * The range for the longitude is in [-180, +180]
101307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */
101407b1bb529a1ae76c46a71b01338c166f9490629dJames Dongstatus_t MPEG4Writer::setGeoData(int latitudex10000, int longitudex10000) {
101507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Is latitude or longitude out of range?
101607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (latitudex10000 < -900000 || latitudex10000 > 900000 ||
101707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        longitudex10000 < -1800000 || longitudex10000 > 1800000) {
101807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        return BAD_VALUE;
101907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
102007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
102107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    mLatitudex10000 = latitudex10000;
102207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    mLongitudex10000 = longitudex10000;
102307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    mAreGeoTagsAvailable = true;
102407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    return OK;
102507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
102607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
102720111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) {
1028674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(data, 1, size);
102920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
103020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
103178a1a286f736888ae7af8860b2c424af0d978848James Dongbool MPEG4Writer::isFileStreamable() const {
103278a1a286f736888ae7af8860b2c424af0d978848James Dong    return mStreamableFile;
103378a1a286f736888ae7af8860b2c424af0d978848James Dong}
103478a1a286f736888ae7af8860b2c424af0d978848James Dong
1035d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileSizeLimit() {
1036d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    // No limit
1037d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    if (mMaxFileSizeLimitBytes == 0) {
1038d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        return false;
1039d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
1040d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
1041956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize);
1042d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    for (List<Track *>::iterator it = mTracks.begin();
1043d599cd4573b5a2d5914c5040e0565ef866749b77James Dong         it != mTracks.end(); ++it) {
1044d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
1045d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
10461f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1047acd234bba9f048971d66890009eeff9a8db94be3James Dong    // Be conservative in the estimate: do not exceed 95% of
1048acd234bba9f048971d66890009eeff9a8db94be3James Dong    // the target file limit. For small target file size limit, though,
1049acd234bba9f048971d66890009eeff9a8db94be3James Dong    // this will not help.
1050acd234bba9f048971d66890009eeff9a8db94be3James Dong    return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100);
1051d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
1052d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
1053d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileDurationLimit() {
1054d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    // No limit
1055d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    if (mMaxFileDurationLimitUs == 0) {
1056d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        return false;
1057d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
1058d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
1059d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    for (List<Track *>::iterator it = mTracks.begin();
1060d599cd4573b5a2d5914c5040e0565ef866749b77James Dong         it != mTracks.end(); ++it) {
1061d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) {
1062d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            return true;
1063d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
1064d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
1065d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    return false;
1066d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
1067d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
106825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() {
106925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool allDone = true;
107025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    for (List<Track *>::iterator it = mTracks.begin();
107125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber         it != mTracks.end(); ++it) {
107225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        if (!(*it)->reachedEOS()) {
107325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber            allDone = false;
107425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber            break;
107525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        }
107625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    }
107725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
107825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return allDone;
107925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber}
108025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
1081f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongvoid MPEG4Writer::setStartTimestampUs(int64_t timeUs) {
1082f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    LOGI("setStartTimestampUs: %lld", timeUs);
1083f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    CHECK(timeUs >= 0);
10843c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    Mutex::Autolock autoLock(mLock);
1085065d1aff96818df54456053f1574aec8a234d0deJames Dong    if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) {
1086f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong        mStartTimestampUs = timeUs;
1087f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong        LOGI("Earliest track starting time: %lld", mStartTimestampUs);
10883c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    }
10893c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong}
10903c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong
1091f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongint64_t MPEG4Writer::getStartTimestampUs() {
10923c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    Mutex::Autolock autoLock(mLock);
10933c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    return mStartTimestampUs;
10943c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong}
10953c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong
109658ae9c530247668f8af36e30d228c716c226b3d4James Dongsize_t MPEG4Writer::numTracks() {
109758ae9c530247668f8af36e30d228c716c226b3d4James Dong    Mutex::Autolock autolock(mLock);
109858ae9c530247668f8af36e30d228c716c226b3d4James Dong    return mTracks.size();
109958ae9c530247668f8af36e30d228c716c226b3d4James Dong}
110058ae9c530247668f8af36e30d228c716c226b3d4James Dong
110120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber////////////////////////////////////////////////////////////////////////////////
110220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
110320111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track(
1104bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId)
110520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    : mOwner(owner),
110625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber      mMeta(source->getFormat()),
110720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mSource(source),
110820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mDone(false),
1109a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
1110a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mResumed(false),
1111eaae38445a340c4857c1c5569475879a728e63b7James Dong      mStarted(false),
1112bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong      mTrackId(trackId),
1113c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong      mTrackDurationUs(0),
1114956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      mEstimatedTrackSizeBytes(0),
1115be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong      mSamplesHaveSameSize(true),
111620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mCodecSpecificData(NULL),
111725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber      mCodecSpecificDataSize(0),
1118548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber      mGotAllCodecSpecificData(false),
111913f6284305e4b27395a23db7882d670bdb1bcae1James Dong      mReachedEOS(false),
112013f6284305e4b27395a23db7882d670bdb1bcae1James Dong      mRotation(0) {
112119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    getCodecSpecificDataFromInputFormatIfPossible();
11228f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
11231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    const char *mime;
11241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mMeta->findCString(kKeyMIMEType, &mime);
11251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
11261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsAudio = !strncasecmp(mime, "audio/", 6);
11271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
11281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong               !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
11291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1130c059860c73678a202bfa33062723e8f82fb779d9James Dong    setTimeScale();
1131c059860c73678a202bfa33062723e8f82fb779d9James Dong}
1132c059860c73678a202bfa33062723e8f82fb779d9James Dong
11331f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::updateTrackSizeEstimate() {
11341f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
11351f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    int64_t stcoBoxSizeBytes = mOwner->use32BitFileOffset()
11361f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                                ? mNumStcoTableEntries * 4
11371f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                                : mNumStcoTableEntries * 8;
11381f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
11391f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mNumSamples * 4);
11401f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
114178a1a286f736888ae7af8860b2c424af0d978848James Dong    mEstimatedTrackSizeBytes = mMdatSizeBytes;  // media data size
114278a1a286f736888ae7af8860b2c424af0d978848James Dong    if (!mOwner->isFileStreamable()) {
114378a1a286f736888ae7af8860b2c424af0d978848James Dong        // Reserved free space is not large enough to hold
114478a1a286f736888ae7af8860b2c424af0d978848James Dong        // all meta data and thus wasted.
114578a1a286f736888ae7af8860b2c424af0d978848James Dong        mEstimatedTrackSizeBytes += mNumStscTableEntries * 12 +  // stsc box size
114678a1a286f736888ae7af8860b2c424af0d978848James Dong                                    mNumStssTableEntries * 4 +   // stss box size
114778a1a286f736888ae7af8860b2c424af0d978848James Dong                                    mNumSttsTableEntries * 8 +   // stts box size
114878a1a286f736888ae7af8860b2c424af0d978848James Dong                                    stcoBoxSizeBytes +           // stco box size
114978a1a286f736888ae7af8860b2c424af0d978848James Dong                                    stszBoxSizeBytes;            // stsz box size
115078a1a286f736888ae7af8860b2c424af0d978848James Dong    }
11511f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
11521f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
11531f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStscTableEntry(
11541f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        size_t chunkId, size_t sampleId) {
11551f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
11561f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        StscTableEntry stscEntry(chunkId, sampleId, 1);
11571f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        mStscTableEntries.push_back(stscEntry);
11581f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        ++mNumStscTableEntries;
11591f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
11601f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
11611f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) {
11621f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mStssTableEntries.push_back(sampleId);
11631f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    ++mNumStssTableEntries;
11641f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
11651f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
11661f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneSttsTableEntry(
11671f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        size_t sampleCount, int64_t durationUs) {
11681f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
11691f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    SttsTableEntry sttsEntry(sampleCount, durationUs);
11701f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mSttsTableEntries.push_back(sttsEntry);
11711f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    ++mNumSttsTableEntries;
11721f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
11731f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1174c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongvoid MPEG4Writer::Track::addChunkOffset(off64_t offset) {
11751f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    ++mNumStcoTableEntries;
11761f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mChunkOffsets.push_back(offset);
11771f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
11781f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1179c059860c73678a202bfa33062723e8f82fb779d9James Dongvoid MPEG4Writer::Track::setTimeScale() {
1180c059860c73678a202bfa33062723e8f82fb779d9James Dong    LOGV("setTimeScale");
1181c059860c73678a202bfa33062723e8f82fb779d9James Dong    // Default time scale
1182c059860c73678a202bfa33062723e8f82fb779d9James Dong    mTimeScale = 90000;
1183c059860c73678a202bfa33062723e8f82fb779d9James Dong
1184c059860c73678a202bfa33062723e8f82fb779d9James Dong    if (mIsAudio) {
1185c059860c73678a202bfa33062723e8f82fb779d9James Dong        // Use the sampling rate as the default time scale for audio track.
1186c059860c73678a202bfa33062723e8f82fb779d9James Dong        int32_t sampleRate;
1187c059860c73678a202bfa33062723e8f82fb779d9James Dong        bool success = mMeta->findInt32(kKeySampleRate, &sampleRate);
1188c059860c73678a202bfa33062723e8f82fb779d9James Dong        CHECK(success);
1189c059860c73678a202bfa33062723e8f82fb779d9James Dong        mTimeScale = sampleRate;
1190c059860c73678a202bfa33062723e8f82fb779d9James Dong    }
1191c059860c73678a202bfa33062723e8f82fb779d9James Dong
1192c059860c73678a202bfa33062723e8f82fb779d9James Dong    // If someone would like to overwrite the timescale, use user-supplied value.
1193c059860c73678a202bfa33062723e8f82fb779d9James Dong    int32_t timeScale;
1194c059860c73678a202bfa33062723e8f82fb779d9James Dong    if (mMeta->findInt32(kKeyTimeScale, &timeScale)) {
1195c059860c73678a202bfa33062723e8f82fb779d9James Dong        mTimeScale = timeScale;
1196c059860c73678a202bfa33062723e8f82fb779d9James Dong    }
1197c059860c73678a202bfa33062723e8f82fb779d9James Dong
11988f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    CHECK(mTimeScale > 0);
119919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber}
120019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
120119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Hubervoid MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
120219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    const char *mime;
120319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
120419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
120519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
120619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        uint32_t type;
120719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        const void *data;
120819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        size_t size;
120919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        if (mMeta->findData(kKeyAVCC, &type, &data, &size)) {
121019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mCodecSpecificData = malloc(size);
121119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mCodecSpecificDataSize = size;
121219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            memcpy(mCodecSpecificData, data, size);
121319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mGotAllCodecSpecificData = true;
121419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        }
121519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
121619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
121719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        uint32_t type;
121819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        const void *data;
121919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        size_t size;
122019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
122119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            ESDS esds(data, size);
122219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            if (esds.getCodecSpecificInfo(&data, &size) == OK) {
122319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mCodecSpecificData = malloc(size);
122419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mCodecSpecificDataSize = size;
122519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                memcpy(mCodecSpecificData, data, size);
122619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mGotAllCodecSpecificData = true;
122719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            }
122819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        }
122919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    }
123020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
123120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
123220111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() {
123320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    stop();
123420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
123520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mCodecSpecificData != NULL) {
123620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        free(mCodecSpecificData);
123720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mCodecSpecificData = NULL;
123820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
123920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
124020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
124193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongvoid MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) {
124293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    LOGV("initTrackingProgressStatus");
124393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mPreviousTrackTimeUs = -1;
124493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mTrackingProgressStatus = false;
124593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mTrackEveryTimeDurationUs = 0;
124693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    {
124793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        int64_t timeUs;
124893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) {
124993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            LOGV("Receive request to track progress status for every %lld us", timeUs);
125093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            mTrackEveryTimeDurationUs = timeUs;
125193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            mTrackingProgressStatus = true;
125293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        }
125393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    }
125493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong}
125593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
12561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong// static
12571c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid *MPEG4Writer::ThreadWrapper(void *me) {
12581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("ThreadWrapper: %p", me);
12591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    MPEG4Writer *writer = static_cast<MPEG4Writer *>(me);
12601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    writer->threadFunc();
12611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    return NULL;
12621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
12631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
12641c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::bufferChunk(const Chunk& chunk) {
12651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("bufferChunk: %p", chunk.mTrack);
12661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Mutex::Autolock autolock(mLock);
12671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    CHECK_EQ(mDone, false);
12681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
12691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
12701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
12711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
12721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (chunk.mTrack == it->mTrack) {  // Found owner
12731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            it->mChunks.push_back(chunk);
12741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            mChunkReadyCondition.signal();
12751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            return;
12761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
12771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
12781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
12791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    CHECK("Received a chunk for a unknown track" == 0);
12801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
12811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1282fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeChunkToFile(Chunk* chunk) {
1283fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    LOGV("writeChunkToFile: %lld from %s track",
1284fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        chunk.mTimestampUs, chunk.mTrack->isAudio()? "audio": "video");
1285fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1286fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    int32_t isFirstSample = true;
1287fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    while (!chunk->mSamples.empty()) {
1288fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        List<MediaBuffer *>::iterator it = chunk->mSamples.begin();
1289fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1290fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        off64_t offset = chunk->mTrack->isAvc()
1291fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong                                ? addLengthPrefixedSample_l(*it)
1292fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong                                : addSample_l(*it);
1293fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1294fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        if (isFirstSample) {
1295fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            chunk->mTrack->addChunkOffset(offset);
1296fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            isFirstSample = false;
12971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
12981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
12991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        (*it)->release();
13001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        (*it) = NULL;
1301fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        chunk->mSamples.erase(it);
13021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1303fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    chunk->mSamples.clear();
13041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
13051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1306fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeAllChunks() {
1307fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    LOGV("writeAllChunks");
13081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    size_t outstandingChunks = 0;
130970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    Chunk chunk;
131070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    while (findChunkToWrite(&chunk)) {
1311e9f6d0579603372fd2547e6c5ba6e114c6f8cba7James Dong        writeChunkToFile(&chunk);
131270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        ++outstandingChunks;
13131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
131470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
131570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    sendSessionSummary();
131670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
13171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mChunkInfos.clear();
13181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGD("%d chunks are written in the last batch", outstandingChunks);
13191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
13201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1321fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongbool MPEG4Writer::findChunkToWrite(Chunk *chunk) {
1322fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    LOGV("findChunkToWrite");
13231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
13241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL;
13251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Track *track = NULL;
13261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
13271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
13281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (!it->mChunks.empty()) {
13291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            List<Chunk>::iterator chunkIt = it->mChunks.begin();
13301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            if (chunkIt->mTimeStampUs < minTimestampUs) {
13311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                minTimestampUs = chunkIt->mTimeStampUs;
13321c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                track = it->mTrack;
13331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            }
13341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
13351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
13361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
13371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (track == NULL) {
13381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        LOGV("Nothing to be written after all");
1339fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        return false;
13401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
13411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
13421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (mIsFirstChunk) {
13431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mIsFirstChunk = false;
13441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1345fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
13461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
13471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
13481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (it->mTrack == track) {
1349fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            *chunk = *(it->mChunks.begin());
1350fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            it->mChunks.erase(it->mChunks.begin());
1351fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            CHECK_EQ(chunk->mTrack, track);
135270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
135370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            int64_t interChunkTimeUs =
135470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                chunk->mTimeStampUs - it->mPrevChunkTimestampUs;
135570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            if (interChunkTimeUs > it->mPrevChunkTimestampUs) {
135670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                it->mMaxInterChunkDurUs = interChunkTimeUs;
135770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            }
135870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
1359fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            return true;
13601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
13611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1362fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1363fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    return false;
13641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
13651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
13661c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::threadFunc() {
13671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("threadFunc");
13681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1369a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0);
1370fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1371fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    Mutex::Autolock autoLock(mLock);
13721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    while (!mDone) {
1373fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        Chunk chunk;
1374fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        bool chunkFound = false;
1375fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1376fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) {
13771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            mChunkReadyCondition.wait(mLock);
13781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
13791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1380fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        // Actual write without holding the lock in order to
1381fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        // reduce the blocking time for media track threads.
1382fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        if (chunkFound) {
1383fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            mLock.unlock();
1384fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            writeChunkToFile(&chunk);
1385fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            mLock.lock();
1386fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        }
13871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1388fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1389fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    writeAllChunks();
13901c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
13911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
13921c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::startWriterThread() {
13931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("startWriterThread");
13941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
13951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mDone = false;
13961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsFirstChunk = true;
1397e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    mDriftTimeUs = 0;
13981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<Track *>::iterator it = mTracks.begin();
13991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mTracks.end(); ++it) {
14001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        ChunkInfo info;
14011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        info.mTrack = *it;
140270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        info.mPrevChunkTimestampUs = 0;
140370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        info.mMaxInterChunkDurUs = 0;
14041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mChunkInfos.push_back(info);
14051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
14061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
14071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_t attr;
14081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_init(&attr);
14091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
14101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_create(&mThread, &attr, ThreadWrapper, this);
14111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_destroy(&attr);
14121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    return OK;
14131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
14141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
14151f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
141693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::Track::start(MetaData *params) {
1417a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (!mDone && mPaused) {
1418a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        mPaused = false;
1419a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        mResumed = true;
1420a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return OK;
1421a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
142225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
142393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t startTimeUs;
142419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) {
142519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        startTimeUs = 0;
142619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    }
142770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    mStartTimeRealUs = startTimeUs;
142819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
142913f6284305e4b27395a23db7882d670bdb1bcae1James Dong    int32_t rotationDegrees;
143013f6284305e4b27395a23db7882d670bdb1bcae1James Dong    if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) {
143113f6284305e4b27395a23db7882d670bdb1bcae1James Dong        mRotation = rotationDegrees;
143213f6284305e4b27395a23db7882d670bdb1bcae1James Dong    }
143313f6284305e4b27395a23db7882d670bdb1bcae1James Dong
14345b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong    mIsRealTimeRecording = true;
1435e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    {
1436e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        int32_t isNotRealTime;
1437e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) {
1438e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            mIsRealTimeRecording = (isNotRealTime == 0);
1439e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        }
1440e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    }
1441e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
144293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    initTrackingProgressStatus(params);
144393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
1444f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    sp<MetaData> meta = new MetaData;
1445a472613aec322e25891abf5c77bf3f7e3c244920James Dong    if (mIsRealTimeRecording && mOwner->numTracks() > 1) {
1446a472613aec322e25891abf5c77bf3f7e3c244920James Dong        /*
1447a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * This extra delay of accepting incoming audio/video signals
1448a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * helps to align a/v start time at the beginning of a recording
1449a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * session, and it also helps eliminate the "recording" sound for
1450a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * camcorder applications.
1451a472613aec322e25891abf5c77bf3f7e3c244920James Dong         *
145286b7f47aa7482424cf8fd248f1315311919be3b0James Dong         * If client does not set the start time offset, we fall back to
145386b7f47aa7482424cf8fd248f1315311919be3b0James Dong         * use the default initial delay value.
1454a472613aec322e25891abf5c77bf3f7e3c244920James Dong         */
145586b7f47aa7482424cf8fd248f1315311919be3b0James Dong        int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL;
145686b7f47aa7482424cf8fd248f1315311919be3b0James Dong        if (startTimeOffsetUs < 0) {  // Start time offset was not set
145786b7f47aa7482424cf8fd248f1315311919be3b0James Dong            startTimeOffsetUs = kInitialDelayTimeUs;
145886b7f47aa7482424cf8fd248f1315311919be3b0James Dong        }
145986b7f47aa7482424cf8fd248f1315311919be3b0James Dong        startTimeUs += startTimeOffsetUs;
146086b7f47aa7482424cf8fd248f1315311919be3b0James Dong        LOGI("Start time offset: %lld us", startTimeOffsetUs);
1461a472613aec322e25891abf5c77bf3f7e3c244920James Dong    }
1462a472613aec322e25891abf5c77bf3f7e3c244920James Dong
1463f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    meta->setInt64(kKeyTime, startTimeUs);
1464a472613aec322e25891abf5c77bf3f7e3c244920James Dong
1465f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    status_t err = mSource->start(meta.get());
146625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    if (err != OK) {
146725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        mDone = mReachedEOS = true;
146825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        return err;
146925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    }
147020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
147120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_t attr;
147220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_init(&attr);
147320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
147420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
147520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mDone = false;
1476eaae38445a340c4857c1c5569475879a728e63b7James Dong    mStarted = true;
1477c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    mTrackDurationUs = 0;
147825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    mReachedEOS = false;
1479956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    mEstimatedTrackSizeBytes = 0;
14801f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mNumStcoTableEntries = 0;
14811f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mNumStssTableEntries = 0;
14821f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mNumStscTableEntries = 0;
14831f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mNumSttsTableEntries = 0;
14841f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mMdatSizeBytes = 0;
1485872a481558350634a3fd5cb67939de288af00ecbJames Dong    mIsMediaTimeAdjustmentOn = false;
1486872a481558350634a3fd5cb67939de288af00ecbJames Dong    mPrevMediaTimeAdjustTimestampUs = 0;
1487872a481558350634a3fd5cb67939de288af00ecbJames Dong    mMediaTimeAdjustNumFrames = 0;
1488872a481558350634a3fd5cb67939de288af00ecbJames Dong    mPrevMediaTimeAdjustSample = 0;
1489872a481558350634a3fd5cb67939de288af00ecbJames Dong    mTotalDriftTimeToAdjustUs = 0;
1490872a481558350634a3fd5cb67939de288af00ecbJames Dong    mPrevTotalAccumDriftTimeUs = 0;
149143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mMaxChunkDurationUs = 0;
149220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
149325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    pthread_create(&mThread, &attr, ThreadWrapper, this);
149420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_destroy(&attr);
149525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
149625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return OK;
149720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
149820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
149937187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::pause() {
1500a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mPaused = true;
150137187916a486504acaf83bea30147eb5fbf46ae5James Dong    return OK;
1502a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
1503a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
150437187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::stop() {
1505cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong    LOGD("Stopping %s track", mIsAudio? "Audio": "Video");
1506eaae38445a340c4857c1c5569475879a728e63b7James Dong    if (!mStarted) {
1507eaae38445a340c4857c1c5569475879a728e63b7James Dong        LOGE("Stop() called but track is not started");
1508eaae38445a340c4857c1c5569475879a728e63b7James Dong        return ERROR_END_OF_STREAM;
1509eaae38445a340c4857c1c5569475879a728e63b7James Dong    }
1510eaae38445a340c4857c1c5569475879a728e63b7James Dong
151120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mDone) {
151237187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
151320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
151420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mDone = true;
151520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
151620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    void *dummy;
151720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_join(mThread, &dummy);
151820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
151937187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = (status_t) dummy;
152037187916a486504acaf83bea30147eb5fbf46ae5James Dong
1521cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong    LOGD("Stopping %s track source", mIsAudio? "Audio": "Video");
152237187916a486504acaf83bea30147eb5fbf46ae5James Dong    {
152337187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = mSource->stop();
152437187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (err == OK && status != OK && status != ERROR_END_OF_STREAM) {
152537187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
152637187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
152737187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
152837187916a486504acaf83bea30147eb5fbf46ae5James Dong
1529cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong    LOGD("%s track stopped", mIsAudio? "Audio": "Video");
153037187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
153120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
153220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
153325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() {
153425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return mReachedEOS;
153525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber}
153625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
153720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static
153820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) {
153920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track *track = static_cast<Track *>(me);
154020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
154137187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = track->threadEntry();
154237187916a486504acaf83bea30147eb5fbf46ae5James Dong    return (void *) err;
154320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
154420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
15453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic void getNalUnitType(uint8_t byte, uint8_t* type) {
15463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("getNalUnitType: %d", byte);
15473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // nal_unit_type: 5-bit unsigned integer
15493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    *type = (byte & 0x1F);
15503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
15513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t *findNextStartCode(
15533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length) {
15543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("findNextStartCode: %p %d", data, length);
15563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t bytesLeft = length;
15583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    while (bytesLeft > 4  &&
15593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) {
15603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        --bytesLeft;
15613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
15623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (bytesLeft <= 4) {
15633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        bytesLeft = 0; // Last parameter set
15643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
15653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return &data[length - bytesLeft];
15663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
15673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongconst uint8_t *MPEG4Writer::Track::parseParamSet(
15693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length, int type, size_t *paramSetLen) {
15703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("parseParamSet");
15723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    CHECK(type == kNalUnitTypeSeqParamSet ||
15733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong          type == kNalUnitTypePicParamSet);
15743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *nextStartCode = findNextStartCode(data, length);
15763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    *paramSetLen = nextStartCode - data;
15773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (*paramSetLen == 0) {
15783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        LOGE("Param set is malformed, since its length is 0");
15793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return NULL;
15803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
15813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    AVCParamSet paramSet(*paramSetLen, data);
15833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (type == kNalUnitTypeSeqParamSet) {
15843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (*paramSetLen < 4) {
15853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Seq parameter set malformed");
15863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return NULL;
15873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
15883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (mSeqParamSets.empty()) {
15893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileIdc = data[1];
15903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileCompatible = data[2];
15913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mLevelIdc = data[3];
15923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else {
15933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (mProfileIdc != data[1] ||
15943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                mProfileCompatible != data[2] ||
15953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                mLevelIdc != data[3]) {
15963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                LOGE("Inconsistent profile/level found in seq parameter sets");
15973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return NULL;
15983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
15993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
16003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mSeqParamSets.push_back(paramSet);
16013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    } else {
16023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mPicParamSets.push_back(paramSet);
16033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
16043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return nextStartCode;
16053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
16063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::copyAVCCodecSpecificData(
16083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t size) {
16093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("copyAVCCodecSpecificData");
16103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 2 bytes for each of the parameter set length field
16123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // plus the 7 bytes for the header
16133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (size < 4 + 7) {
16143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        LOGE("Codec specific data length too short: %d", size);
16153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return ERROR_MALFORMED;
16163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
16173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize = size;
16193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificData = malloc(size);
16203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    memcpy(mCodecSpecificData, data, size);
16213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return OK;
16223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
16233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::parseAVCCodecSpecificData(
16253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t size) {
16263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("parseAVCCodecSpecificData");
16283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Data starts with a start code.
16293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // SPS and PPS are separated with start codes.
16303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Also, SPS must come before PPS
16313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t type = kNalUnitTypeSeqParamSet;
16323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    bool gotSps = false;
16333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    bool gotPps = false;
16343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *tmp = data;
16353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *nextStartCode = data;
16363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t bytesLeft = size;
16373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t paramSetLen = 0;
16383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize = 0;
16393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) {
16403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        getNalUnitType(*(tmp + 4), &type);
16413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (type == kNalUnitTypeSeqParamSet) {
16423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (gotPps) {
16433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                LOGE("SPS must come before PPS");
16443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return ERROR_MALFORMED;
16453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
16463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotSps) {
16473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                gotSps = true;
16483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
16493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
16503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else if (type == kNalUnitTypePicParamSet) {
16513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotSps) {
16523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                LOGE("SPS must come before PPS");
16533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return ERROR_MALFORMED;
16543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
16553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotPps) {
16563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                gotPps = true;
16573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
16583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
16593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else {
16603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Only SPS and PPS Nal units are expected");
16613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
16623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
16633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nextStartCode == NULL) {
16653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
16663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
16673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Move on to find the next parameter set
16693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        bytesLeft -= nextStartCode - tmp;
16703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        tmp = nextStartCode;
16713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mCodecSpecificDataSize += (2 + paramSetLen);
16723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
16733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
16753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the number of seq parameter sets
16763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        size_t nSeqParamSets = mSeqParamSets.size();
16773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nSeqParamSets == 0) {
16783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Cound not find sequence parameter set");
16793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
16803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
16813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nSeqParamSets > 0x1F) {
16833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Too many seq parameter sets (%d) found", nSeqParamSets);
16843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
16853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
16863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
16873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
16893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the number of pic parameter sets
16903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        size_t nPicParamSets = mPicParamSets.size();
16913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nPicParamSets == 0) {
16923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Cound not find picture parameter set");
16933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
16943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
16953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nPicParamSets > 0xFF) {
16963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Too many pic parameter sets (%d) found", nPicParamSets);
16973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
16983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
16993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
17003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
17013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
17023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the profiles
17033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // These profiles requires additional parameter set extensions
17043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (mProfileIdc == 100 || mProfileIdc == 110 ||
17053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileIdc == 122 || mProfileIdc == 144) {
17063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Sorry, no support for profile_idc: %d!", mProfileIdc);
17073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return BAD_VALUE;
17083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
17093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
17103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
17113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return OK;
17123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
1713548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
171403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData(
171503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        const uint8_t *data, size_t size) {
1716548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
171703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (mCodecSpecificData != NULL) {
1718548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber        LOGE("Already have codec specific data");
171903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
172003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
172103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
17223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (size < 4) {
17233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        LOGE("Codec specific data length too short: %d", size);
172403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
172503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
172603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
17273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Data is in the form of AVCCodecSpecificData
17283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (memcmp("\x00\x00\x00\x01", data, 4)) {
17293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return copyAVCCodecSpecificData(data, size);
173003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
173103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
17323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (parseAVCCodecSpecificData(data, size) != OK) {
173303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
173403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
173503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
17363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // ISO 14496-15: AVC file format
17373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize += 7;  // 7 more bytes in the header
173803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    mCodecSpecificData = malloc(mCodecSpecificDataSize);
173903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    uint8_t *header = (uint8_t *)mCodecSpecificData;
17403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[0] = 1;                     // version
17413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[1] = mProfileIdc;           // profile indication
17423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[2] = mProfileCompatible;    // profile compatibility
17433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[3] = mLevelIdc;
174403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
17453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne
1746b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    if (mOwner->useNalLengthFour()) {
1747b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        header[4] = 0xfc | 3;  // length size == 4 bytes
1748b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    } else {
1749b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        header[4] = 0xfc | 1;  // length size == 2 bytes
1750b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    }
175103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
17523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 3-bit '111' followed by 5-bit numSequenceParameterSets
17533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    int nSequenceParamSets = mSeqParamSets.size();
17543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[5] = 0xe0 | nSequenceParamSets;
17553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header += 6;
17563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    for (List<AVCParamSet>::iterator it = mSeqParamSets.begin();
17573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong         it != mSeqParamSets.end(); ++it) {
17583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // 16-bit sequence parameter set length
17593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t seqParamSetLength = it->mLength;
17603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[0] = seqParamSetLength >> 8;
17613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[1] = seqParamSetLength & 0xff;
17623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
17633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // SPS NAL unit (sequence parameter length bytes)
17643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        memcpy(&header[2], it->mData, seqParamSetLength);
17653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header += (2 + seqParamSetLength);
17663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
17673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
17683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 8-bit nPictureParameterSets
17693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    int nPictureParamSets = mPicParamSets.size();
17703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[0] = nPictureParamSets;
17713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header += 1;
17723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    for (List<AVCParamSet>::iterator it = mPicParamSets.begin();
17733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong         it != mPicParamSets.end(); ++it) {
17743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // 16-bit picture parameter set length
17753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t picParamSetLength = it->mLength;
17763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[0] = picParamSetLength >> 8;
17773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[1] = picParamSetLength & 0xff;
17783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
17793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // PPS Nal unit (picture parameter set length bytes)
17803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        memcpy(&header[2], it->mData, picParamSetLength);
17813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header += (2 + picParamSetLength);
17823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
178303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
178403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    return OK;
178503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber}
178603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
1787872a481558350634a3fd5cb67939de288af00ecbJames Dong/*
1788872a481558350634a3fd5cb67939de288af00ecbJames Dong* The video track's media time adjustment for real-time applications
1789872a481558350634a3fd5cb67939de288af00ecbJames Dong* is described as follows:
1790872a481558350634a3fd5cb67939de288af00ecbJames Dong*
1791872a481558350634a3fd5cb67939de288af00ecbJames Dong* First, the media time adjustment is done for every period of
1792872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs. kVideoMediaTimeAdjustPeriodTimeUs
1793872a481558350634a3fd5cb67939de288af00ecbJames Dong* is currently a fixed value chosen heuristically. The value of
1794872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs should not be very large or very small
1795872a481558350634a3fd5cb67939de288af00ecbJames Dong* for two considerations: on one hand, a relatively large value
1796872a481558350634a3fd5cb67939de288af00ecbJames Dong* helps reduce large fluctuation of drift time in the audio encoding
1797872a481558350634a3fd5cb67939de288af00ecbJames Dong* path; while on the other hand, a relatively small value helps keep
1798872a481558350634a3fd5cb67939de288af00ecbJames Dong* restoring synchronization in audio/video more frequently. Note for the
1799872a481558350634a3fd5cb67939de288af00ecbJames Dong* very first period of kVideoMediaTimeAdjustPeriodTimeUs, there is
1800872a481558350634a3fd5cb67939de288af00ecbJames Dong* no media time adjustment for the video track.
1801872a481558350634a3fd5cb67939de288af00ecbJames Dong*
1802872a481558350634a3fd5cb67939de288af00ecbJames Dong* Second, the total accumulated audio track time drift found
1803872a481558350634a3fd5cb67939de288af00ecbJames Dong* in a period of kVideoMediaTimeAdjustPeriodTimeUs is distributed
1804872a481558350634a3fd5cb67939de288af00ecbJames Dong* over a stream of incoming video frames. The number of video frames
1805872a481558350634a3fd5cb67939de288af00ecbJames Dong* affected is determined based on the number of recorded video frames
1806872a481558350634a3fd5cb67939de288af00ecbJames Dong* within the past kVideoMediaTimeAdjustPeriodTimeUs period.
1807872a481558350634a3fd5cb67939de288af00ecbJames Dong* We choose to distribute the drift time over only a portion
1808872a481558350634a3fd5cb67939de288af00ecbJames Dong* (rather than all) of the total number of recorded video frames
1809872a481558350634a3fd5cb67939de288af00ecbJames Dong* in order to make sure that the video track media time adjustment is
1810872a481558350634a3fd5cb67939de288af00ecbJames Dong* completed for the current period before the next video track media
1811872a481558350634a3fd5cb67939de288af00ecbJames Dong* time adjustment period starts. Currently, the portion chosen is a
1812872a481558350634a3fd5cb67939de288af00ecbJames Dong* half (0.5).
1813872a481558350634a3fd5cb67939de288af00ecbJames Dong*
1814872a481558350634a3fd5cb67939de288af00ecbJames Dong* Last, various additional checks are performed to ensure that
1815872a481558350634a3fd5cb67939de288af00ecbJames Dong* the actual audio encoding path does not have too much drift.
1816872a481558350634a3fd5cb67939de288af00ecbJames Dong* In particular, 1) we want to limit the average incremental time
1817872a481558350634a3fd5cb67939de288af00ecbJames Dong* adjustment for each video frame to be less than a threshold
1818872a481558350634a3fd5cb67939de288af00ecbJames Dong* for a single period of kVideoMediaTimeAdjustPeriodTimeUs.
1819872a481558350634a3fd5cb67939de288af00ecbJames Dong* Currently, the threshold is set to 5 ms. If the average incremental
1820872a481558350634a3fd5cb67939de288af00ecbJames Dong* media time adjustment for a video frame is larger than the
1821872a481558350634a3fd5cb67939de288af00ecbJames Dong* threshold, the audio encoding path has too much time drift.
1822872a481558350634a3fd5cb67939de288af00ecbJames Dong* 2) We also want to limit the total time drift in the audio
1823872a481558350634a3fd5cb67939de288af00ecbJames Dong* encoding path to be less than a threshold for a period of
1824872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs. Currently, the threshold
1825872a481558350634a3fd5cb67939de288af00ecbJames Dong* is 0.5% of kVideoMediaTimeAdjustPeriodTimeUs. If the time drift of
1826872a481558350634a3fd5cb67939de288af00ecbJames Dong* the audio encoding path is larger than the threshold, the audio
1827872a481558350634a3fd5cb67939de288af00ecbJames Dong* encoding path has too much time drift. We treat the large time
1828872a481558350634a3fd5cb67939de288af00ecbJames Dong* drift of the audio encoding path as errors, since there is no
1829872a481558350634a3fd5cb67939de288af00ecbJames Dong* way to keep audio/video in synchronization for real-time
1830872a481558350634a3fd5cb67939de288af00ecbJames Dong* applications if the time drift is too large unless we drop some
1831872a481558350634a3fd5cb67939de288af00ecbJames Dong* video frames, which has its own problems that we don't want
1832872a481558350634a3fd5cb67939de288af00ecbJames Dong* to get into for the time being.
1833872a481558350634a3fd5cb67939de288af00ecbJames Dong*/
1834872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::adjustMediaTime(int64_t *timestampUs) {
1835872a481558350634a3fd5cb67939de288af00ecbJames Dong    if (*timestampUs - mPrevMediaTimeAdjustTimestampUs >=
1836872a481558350634a3fd5cb67939de288af00ecbJames Dong        kVideoMediaTimeAdjustPeriodTimeUs) {
1837872a481558350634a3fd5cb67939de288af00ecbJames Dong
1838872a481558350634a3fd5cb67939de288af00ecbJames Dong        LOGV("New media time adjustment period at %lld us", *timestampUs);
1839872a481558350634a3fd5cb67939de288af00ecbJames Dong        mIsMediaTimeAdjustmentOn = true;
1840872a481558350634a3fd5cb67939de288af00ecbJames Dong        mMediaTimeAdjustNumFrames =
1841872a481558350634a3fd5cb67939de288af00ecbJames Dong                (mNumSamples - mPrevMediaTimeAdjustSample) >> 1;
1842872a481558350634a3fd5cb67939de288af00ecbJames Dong
1843872a481558350634a3fd5cb67939de288af00ecbJames Dong        mPrevMediaTimeAdjustTimestampUs = *timestampUs;
1844872a481558350634a3fd5cb67939de288af00ecbJames Dong        mPrevMediaTimeAdjustSample = mNumSamples;
1845872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t totalAccumDriftTimeUs = mOwner->getDriftTimeUs();
1846872a481558350634a3fd5cb67939de288af00ecbJames Dong        mTotalDriftTimeToAdjustUs =
1847872a481558350634a3fd5cb67939de288af00ecbJames Dong                totalAccumDriftTimeUs - mPrevTotalAccumDriftTimeUs;
1848872a481558350634a3fd5cb67939de288af00ecbJames Dong
1849872a481558350634a3fd5cb67939de288af00ecbJames Dong        mPrevTotalAccumDriftTimeUs = totalAccumDriftTimeUs;
1850872a481558350634a3fd5cb67939de288af00ecbJames Dong
1851872a481558350634a3fd5cb67939de288af00ecbJames Dong        // Check on incremental adjusted time per frame
1852872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t adjustTimePerFrameUs =
1853872a481558350634a3fd5cb67939de288af00ecbJames Dong                mTotalDriftTimeToAdjustUs / mMediaTimeAdjustNumFrames;
1854872a481558350634a3fd5cb67939de288af00ecbJames Dong
1855872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (adjustTimePerFrameUs < 0) {
1856872a481558350634a3fd5cb67939de288af00ecbJames Dong            adjustTimePerFrameUs = -adjustTimePerFrameUs;
1857872a481558350634a3fd5cb67939de288af00ecbJames Dong        }
1858872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (adjustTimePerFrameUs >= 5000) {
1859872a481558350634a3fd5cb67939de288af00ecbJames Dong            LOGE("Adjusted time per video frame is %lld us",
1860872a481558350634a3fd5cb67939de288af00ecbJames Dong                adjustTimePerFrameUs);
1861872a481558350634a3fd5cb67939de288af00ecbJames Dong            CHECK(!"Video frame time adjustment is too large!");
1862872a481558350634a3fd5cb67939de288af00ecbJames Dong        }
1863872a481558350634a3fd5cb67939de288af00ecbJames Dong
1864872a481558350634a3fd5cb67939de288af00ecbJames Dong        // Check on total accumulated time drift within a period of
1865872a481558350634a3fd5cb67939de288af00ecbJames Dong        // kVideoMediaTimeAdjustPeriodTimeUs.
1866872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t driftPercentage = (mTotalDriftTimeToAdjustUs * 1000)
1867872a481558350634a3fd5cb67939de288af00ecbJames Dong                / kVideoMediaTimeAdjustPeriodTimeUs;
1868872a481558350634a3fd5cb67939de288af00ecbJames Dong
1869872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (driftPercentage < 0) {
1870872a481558350634a3fd5cb67939de288af00ecbJames Dong            driftPercentage = -driftPercentage;
1871872a481558350634a3fd5cb67939de288af00ecbJames Dong        }
1872872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (driftPercentage > 5) {
1873872a481558350634a3fd5cb67939de288af00ecbJames Dong            LOGE("Audio track has time drift %lld us over %lld us",
1874872a481558350634a3fd5cb67939de288af00ecbJames Dong                mTotalDriftTimeToAdjustUs,
1875872a481558350634a3fd5cb67939de288af00ecbJames Dong                kVideoMediaTimeAdjustPeriodTimeUs);
1876872a481558350634a3fd5cb67939de288af00ecbJames Dong
1877872a481558350634a3fd5cb67939de288af00ecbJames Dong            CHECK(!"The audio track media time drifts too much!");
1878872a481558350634a3fd5cb67939de288af00ecbJames Dong        }
1879872a481558350634a3fd5cb67939de288af00ecbJames Dong
1880872a481558350634a3fd5cb67939de288af00ecbJames Dong    }
1881872a481558350634a3fd5cb67939de288af00ecbJames Dong
1882872a481558350634a3fd5cb67939de288af00ecbJames Dong    if (mIsMediaTimeAdjustmentOn) {
1883872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (mNumSamples - mPrevMediaTimeAdjustSample <=
1884872a481558350634a3fd5cb67939de288af00ecbJames Dong            mMediaTimeAdjustNumFrames) {
1885872a481558350634a3fd5cb67939de288af00ecbJames Dong
1886872a481558350634a3fd5cb67939de288af00ecbJames Dong            // Do media time incremental adjustment
1887872a481558350634a3fd5cb67939de288af00ecbJames Dong            int64_t incrementalAdjustTimeUs =
1888872a481558350634a3fd5cb67939de288af00ecbJames Dong                        (mTotalDriftTimeToAdjustUs *
1889872a481558350634a3fd5cb67939de288af00ecbJames Dong                            (mNumSamples - mPrevMediaTimeAdjustSample))
1890872a481558350634a3fd5cb67939de288af00ecbJames Dong                                / mMediaTimeAdjustNumFrames;
1891872a481558350634a3fd5cb67939de288af00ecbJames Dong
1892872a481558350634a3fd5cb67939de288af00ecbJames Dong            *timestampUs +=
1893872a481558350634a3fd5cb67939de288af00ecbJames Dong                (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs);
1894872a481558350634a3fd5cb67939de288af00ecbJames Dong
1895872a481558350634a3fd5cb67939de288af00ecbJames Dong            LOGV("Incremental video frame media time adjustment: %lld us",
1896872a481558350634a3fd5cb67939de288af00ecbJames Dong                (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs));
1897872a481558350634a3fd5cb67939de288af00ecbJames Dong        } else {
1898872a481558350634a3fd5cb67939de288af00ecbJames Dong            // Within the remaining adjustment period,
1899872a481558350634a3fd5cb67939de288af00ecbJames Dong            // no incremental adjustment is needed.
1900872a481558350634a3fd5cb67939de288af00ecbJames Dong            *timestampUs +=
1901872a481558350634a3fd5cb67939de288af00ecbJames Dong                (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs);
1902872a481558350634a3fd5cb67939de288af00ecbJames Dong
1903872a481558350634a3fd5cb67939de288af00ecbJames Dong            LOGV("Fixed video frame media time adjustment: %lld us",
1904872a481558350634a3fd5cb67939de288af00ecbJames Dong                (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs));
1905872a481558350634a3fd5cb67939de288af00ecbJames Dong        }
1906872a481558350634a3fd5cb67939de288af00ecbJames Dong    }
1907872a481558350634a3fd5cb67939de288af00ecbJames Dong}
1908872a481558350634a3fd5cb67939de288af00ecbJames Dong
1909872a481558350634a3fd5cb67939de288af00ecbJames Dong/*
1910872a481558350634a3fd5cb67939de288af00ecbJames Dong * Updates the drift time from the audio track so that
1911872a481558350634a3fd5cb67939de288af00ecbJames Dong * the video track can get the updated drift time information
1912872a481558350634a3fd5cb67939de288af00ecbJames Dong * from the file writer. The fluctuation of the drift time of the audio
1913872a481558350634a3fd5cb67939de288af00ecbJames Dong * encoding path is smoothed out with a simple filter by giving a larger
1914872a481558350634a3fd5cb67939de288af00ecbJames Dong * weight to more recently drift time. The filter coefficients, 0.5 and 0.5,
1915872a481558350634a3fd5cb67939de288af00ecbJames Dong * are heuristically determined.
1916872a481558350634a3fd5cb67939de288af00ecbJames Dong */
1917872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) {
1918872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t driftTimeUs = 0;
1919872a481558350634a3fd5cb67939de288af00ecbJames Dong    if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) {
1920872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t prevDriftTimeUs = mOwner->getDriftTimeUs();
1921872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1;
1922872a481558350634a3fd5cb67939de288af00ecbJames Dong        mOwner->setDriftTimeUs(timeUs);
1923872a481558350634a3fd5cb67939de288af00ecbJames Dong    }
1924872a481558350634a3fd5cb67939de288af00ecbJames Dong}
1925872a481558350634a3fd5cb67939de288af00ecbJames Dong
192637187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::threadEntry() {
192730ab66297501757d745b9ae10da61adcd891f497Andreas Huber    int32_t count = 0;
192813aec890216948b0c364f8f92792129d0335f506James Dong    const int64_t interleaveDurationUs = mOwner->interleaveDuration();
192943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    const bool hasMultipleTracks = (mOwner->numTracks() > 1);
193013aec890216948b0c364f8f92792129d0335f506James Dong    int64_t chunkTimestampUs = 0;
193113aec890216948b0c364f8f92792129d0335f506James Dong    int32_t nChunks = 0;
193213aec890216948b0c364f8f92792129d0335f506James Dong    int32_t nZeroLengthFrames = 0;
19338f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t lastTimestampUs = 0;  // Previous sample time stamp in ms
19348f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t lastDurationUs = 0;   // Between the previous two samples in ms
1935c059860c73678a202bfa33062723e8f82fb779d9James Dong    int64_t currDurationTicks = 0;  // Timescale based ticks
1936c059860c73678a202bfa33062723e8f82fb779d9James Dong    int64_t lastDurationTicks = 0;  // Timescale based ticks
19378f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int32_t sampleCount = 1;      // Sample count in the current stts table entry
1938be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    uint32_t previousSampleSize = 0;  // Size of the previous sample
1939a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    int64_t previousPausedDurationUs = 0;
19401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    int64_t timestampUs;
1941e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
1942a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    if (mIsAudio) {
1943a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong        prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
1944a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    } else {
1945a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong        prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0);
1946a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    }
1947985f838934510983d8a887461e98dca60a6e858fJames Dong    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
1948985f838934510983d8a887461e98dca60a6e858fJames Dong
1949d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong    sp<MetaData> meta_data;
195020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1951ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    mNumSamples = 0;
195293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    status_t err = OK;
195320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    MediaBuffer *buffer;
195493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    while (!mDone && (err = mSource->read(&buffer)) == OK) {
195520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        if (buffer->range_length() == 0) {
195620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            buffer->release();
195720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            buffer = NULL;
195813aec890216948b0c364f8f92792129d0335f506James Dong            ++nZeroLengthFrames;
195920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            continue;
196020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
196120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1962a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // If the codec specific data has not been received yet, delay pause.
1963a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // After the codec specific data is received, discard what we received
1964a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // when the track is to be paused.
1965a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mPaused && !mResumed) {
1966a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            buffer->release();
1967a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            buffer = NULL;
1968a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            continue;
1969a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
1970a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
197130ab66297501757d745b9ae10da61adcd891f497Andreas Huber        ++count;
197230ab66297501757d745b9ae10da61adcd891f497Andreas Huber
197303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        int32_t isCodecConfig;
197403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
197503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                && isCodecConfig) {
1976548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            CHECK(!mGotAllCodecSpecificData);
1977548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
19781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            if (mIsAvc) {
197903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                status_t err = makeAVCCodecSpecificData(
198003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        (const uint8_t *)buffer->data()
198103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                            + buffer->range_offset(),
198203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        buffer->range_length());
1983be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                CHECK_EQ(OK, err);
19841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            } else if (mIsMPEG4) {
198503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                mCodecSpecificDataSize = buffer->range_length();
198603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                mCodecSpecificData = malloc(mCodecSpecificDataSize);
198703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                memcpy(mCodecSpecificData,
198803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        (const uint8_t *)buffer->data()
198903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                            + buffer->range_offset(),
199003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                       buffer->range_length());
199130ab66297501757d745b9ae10da61adcd891f497Andreas Huber            }
199230ab66297501757d745b9ae10da61adcd891f497Andreas Huber
199330ab66297501757d745b9ae10da61adcd891f497Andreas Huber            buffer->release();
199430ab66297501757d745b9ae10da61adcd891f497Andreas Huber            buffer = NULL;
199530ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1996548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            mGotAllCodecSpecificData = true;
199730ab66297501757d745b9ae10da61adcd891f497Andreas Huber            continue;
1998a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
1999a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
2000d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        // Make a deep copy of the MediaBuffer and Metadata and release
2001d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        // the original as soon as we can
2002d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        MediaBuffer *copy = new MediaBuffer(buffer->range_length());
2003d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(),
2004d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong                buffer->range_length());
2005d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        copy->set_range(0, buffer->range_length());
2006d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        meta_data = new MetaData(*buffer->meta_data().get());
2007d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        buffer->release();
2008d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        buffer = NULL;
2009d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
20101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (mIsAvc) StripStartcode(copy);
2011e136c3bb38e88315bf8797a464ebf2c788296b22James Dong
2012b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        size_t sampleSize = copy->range_length();
2013b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        if (mIsAvc) {
2014b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong            if (mOwner->useNalLengthFour()) {
2015b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong                sampleSize += 4;
2016b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong            } else {
2017b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong                sampleSize += 2;
2018b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong            }
2019b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        }
2020050b28a593350047845a45a14cc5026221ac1620James Dong
2021d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        // Max file size or duration handling
20221f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        mMdatSizeBytes += sampleSize;
20231f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        updateTrackSizeEstimate();
20241f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
2025d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if (mOwner->exceedsFileSizeLimit()) {
2026d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
2027d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            break;
2028d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
2029d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if (mOwner->exceedsFileDurationLimit()) {
2030d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
2031d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            break;
2032d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
2033d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
2034050b28a593350047845a45a14cc5026221ac1620James Dong
2035d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        int32_t isSync = false;
2036d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        meta_data->findInt32(kKeyIsSyncFrame, &isSync);
2037d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
20388428af5381e835cc783b7ecb0d71cb60961c99c2James Dong        /*
20398428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * The original timestamp found in the data buffer will be modified as below:
20408428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         *
20418428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * There is a playback offset into this track if the track's start time
20428428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * is not the same as the movie start time, which will be recorded in edst
20438428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * box of the output file. The playback offset is to make sure that the
20448428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * starting time of the audio/video tracks are synchronized. Although the
20458428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * track's media timestamp may be subject to various modifications
20468428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * as outlined below, the track's playback offset time remains unchanged
20478428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * once the first data buffer of the track is received.
20488428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         *
20498428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * The media time stamp will be calculated by subtracting the playback offset
20508428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * (and potential pause durations) from the original timestamp in the buffer.
20518428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         *
20528428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * If this track is a video track for a real-time recording application with
20538428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * both audio and video tracks, its media timestamp will subject to further
20548428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * modification based on the media clock of the audio track. This modification
20558428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * is needed for the purpose of maintaining good audio/video synchronization.
20568428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         *
20578428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * If the recording session is paused and resumed multiple times, the track
20588428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * media timestamp will be modified as if the  recording session had never been
20598428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * paused at all during playback of the recorded output file. In other words,
20608428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * the output file will have no memory of pause/resume durations.
20618428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         *
20628428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         */
2063d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
20648428af5381e835cc783b7ecb0d71cb60961c99c2James Dong        LOGV("%s timestampUs: %lld", mIsAudio? "Audio": "Video", timestampUs);
2065d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
2066d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong////////////////////////////////////////////////////////////////////////////////
206770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        if (mNumSamples == 0) {
206870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            mFirstSampleTimeRealUs = systemTime() / 1000;
2069f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong            mStartTimestampUs = timestampUs;
2070f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong            mOwner->setStartTimestampUs(mStartTimestampUs);
20718428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            previousPausedDurationUs = mStartTimestampUs;
20723c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong        }
207348c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber
2074a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mResumed) {
20758428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
20768428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            CHECK(durExcludingEarlierPausesUs >= 0);
20778428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
20788428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            CHECK(pausedDurationUs >= lastDurationUs);
20798428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            previousPausedDurationUs += pausedDurationUs - lastDurationUs;
2080a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            mResumed = false;
2081a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
2082a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
2083a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        timestampUs -= previousPausedDurationUs;
20848428af5381e835cc783b7ecb0d71cb60961c99c2James Dong        CHECK(timestampUs >= 0);
2085872a481558350634a3fd5cb67939de288af00ecbJames Dong
2086872a481558350634a3fd5cb67939de288af00ecbJames Dong        // Media time adjustment for real-time applications
2087872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (mIsRealTimeRecording) {
2088872a481558350634a3fd5cb67939de288af00ecbJames Dong            if (mIsAudio) {
2089872a481558350634a3fd5cb67939de288af00ecbJames Dong                updateDriftTime(meta_data);
2090872a481558350634a3fd5cb67939de288af00ecbJames Dong            } else {
2091872a481558350634a3fd5cb67939de288af00ecbJames Dong                adjustMediaTime(&timestampUs);
2092e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            }
2093e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        }
2094872a481558350634a3fd5cb67939de288af00ecbJames Dong
2095e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        CHECK(timestampUs >= 0);
2096e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        if (mNumSamples > 1) {
2097e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            if (timestampUs <= lastTimestampUs) {
20984f86a980fee1880dca61b828599fa6d76755a485James Dong                LOGW("Frame arrives too late!");
20994f86a980fee1880dca61b828599fa6d76755a485James Dong                // Don't drop the late frame, since dropping a frame may cause
21004f86a980fee1880dca61b828599fa6d76755a485James Dong                // problems later during playback
21014f86a980fee1880dca61b828599fa6d76755a485James Dong
21024f86a980fee1880dca61b828599fa6d76755a485James Dong                // The idea here is to avoid having two or more samples with the
21034f86a980fee1880dca61b828599fa6d76755a485James Dong                // same timestamp in the output file.
21044f86a980fee1880dca61b828599fa6d76755a485James Dong                if (mTimeScale >= 1000000LL) {
210540e9940fadf22daa64c1e766fa8a855c7b149c17James Dong                    timestampUs = lastTimestampUs + 1;
21064f86a980fee1880dca61b828599fa6d76755a485James Dong                } else {
210740e9940fadf22daa64c1e766fa8a855c7b149c17James Dong                    timestampUs = lastTimestampUs + (1000000LL + (mTimeScale >> 1)) / mTimeScale;
21084f86a980fee1880dca61b828599fa6d76755a485James Dong                }
2109e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            }
2110e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        }
2111e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
21128428af5381e835cc783b7ecb0d71cb60961c99c2James Dong        LOGV("%s media time stamp: %lld and previous paused duration %lld",
21138428af5381e835cc783b7ecb0d71cb60961c99c2James Dong                mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs);
2114c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong        if (timestampUs > mTrackDurationUs) {
2115c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong            mTrackDurationUs = timestampUs;
21163b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber        }
21173b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber
21188644c14618d30d9e57a69df40ed939986ebf02c4James Dong        mSampleSizes.push_back(sampleSize);
2119ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong        ++mNumSamples;
2120ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong        if (mNumSamples > 2) {
2121c059860c73678a202bfa33062723e8f82fb779d9James Dong            // We need to use the time scale based ticks, rather than the
2122c059860c73678a202bfa33062723e8f82fb779d9James Dong            // timestamp itself to determine whether we have to use a new
2123c059860c73678a202bfa33062723e8f82fb779d9James Dong            // stts entry, since we may have rounding errors.
2124c059860c73678a202bfa33062723e8f82fb779d9James Dong            // The calculation is intended to reduce the accumulated
2125c059860c73678a202bfa33062723e8f82fb779d9James Dong            // rounding errors.
2126c059860c73678a202bfa33062723e8f82fb779d9James Dong            currDurationTicks =
2127c059860c73678a202bfa33062723e8f82fb779d9James Dong                     ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
2128c059860c73678a202bfa33062723e8f82fb779d9James Dong                     (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
2129c059860c73678a202bfa33062723e8f82fb779d9James Dong
2130a472613aec322e25891abf5c77bf3f7e3c244920James Dong            // Force the first sample to have its own stts entry so that
2131a472613aec322e25891abf5c77bf3f7e3c244920James Dong            // we can adjust its value later to maintain the A/V sync.
2132a472613aec322e25891abf5c77bf3f7e3c244920James Dong            if (mNumSamples == 3 || currDurationTicks != lastDurationTicks) {
2133a472613aec322e25891abf5c77bf3f7e3c244920James Dong                LOGV("%s lastDurationUs: %lld us, currDurationTicks: %lld us",
2134a472613aec322e25891abf5c77bf3f7e3c244920James Dong                        mIsAudio? "Audio": "Video", lastDurationUs, currDurationTicks);
21351f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                addOneSttsTableEntry(sampleCount, lastDurationUs);
2136be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                sampleCount = 1;
2137be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            } else {
2138be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                ++sampleCount;
2139be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            }
2140be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        }
2141be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        if (mSamplesHaveSameSize) {
2142ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong            if (mNumSamples >= 2 && previousSampleSize != sampleSize) {
2143be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                mSamplesHaveSameSize = false;
2144be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            }
21458644c14618d30d9e57a69df40ed939986ebf02c4James Dong            previousSampleSize = sampleSize;
2146be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        }
2147a472613aec322e25891abf5c77bf3f7e3c244920James Dong        LOGV("%s timestampUs/lastTimestampUs: %lld/%lld",
2148a472613aec322e25891abf5c77bf3f7e3c244920James Dong                mIsAudio? "Audio": "Video", timestampUs, lastTimestampUs);
21498644c14618d30d9e57a69df40ed939986ebf02c4James Dong        lastDurationUs = timestampUs - lastTimestampUs;
2150c059860c73678a202bfa33062723e8f82fb779d9James Dong        lastDurationTicks = currDurationTicks;
21518644c14618d30d9e57a69df40ed939986ebf02c4James Dong        lastTimestampUs = timestampUs;
215220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2153d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        if (isSync != 0) {
21541f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            addOneStssTableEntry(mNumSamples);
2155d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        }
2156d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
215793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        if (mTrackingProgressStatus) {
215893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            if (mPreviousTrackTimeUs <= 0) {
215993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong                mPreviousTrackTimeUs = mStartTimestampUs;
216093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            }
2161faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong            trackProgressStatus(timestampUs);
216293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        }
216343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong        if (!hasMultipleTracks) {
2164c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong            off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy)
216558ae9c530247668f8af36e30d228c716c226b3d4James Dong                                 : mOwner->addSample_l(copy);
216658ae9c530247668f8af36e30d228c716c226b3d4James Dong            if (mChunkOffsets.empty()) {
21671f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                addChunkOffset(offset);
216858ae9c530247668f8af36e30d228c716c226b3d4James Dong            }
216958ae9c530247668f8af36e30d228c716c226b3d4James Dong            copy->release();
217058ae9c530247668f8af36e30d228c716c226b3d4James Dong            copy = NULL;
217158ae9c530247668f8af36e30d228c716c226b3d4James Dong            continue;
217258ae9c530247668f8af36e30d228c716c226b3d4James Dong        }
217313aec890216948b0c364f8f92792129d0335f506James Dong
217413aec890216948b0c364f8f92792129d0335f506James Dong        mChunkSamples.push_back(copy);
217513aec890216948b0c364f8f92792129d0335f506James Dong        if (interleaveDurationUs == 0) {
21761f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            addOneStscTableEntry(++nChunks, 1);
21771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            bufferChunk(timestampUs);
217813aec890216948b0c364f8f92792129d0335f506James Dong        } else {
217913aec890216948b0c364f8f92792129d0335f506James Dong            if (chunkTimestampUs == 0) {
218013aec890216948b0c364f8f92792129d0335f506James Dong                chunkTimestampUs = timestampUs;
218113aec890216948b0c364f8f92792129d0335f506James Dong            } else {
218243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                int64_t chunkDurationUs = timestampUs - chunkTimestampUs;
218343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                if (chunkDurationUs > interleaveDurationUs) {
218443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    if (chunkDurationUs > mMaxChunkDurationUs) {
218543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                        mMaxChunkDurationUs = chunkDurationUs;
218643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    }
218713aec890216948b0c364f8f92792129d0335f506James Dong                    ++nChunks;
218813aec890216948b0c364f8f92792129d0335f506James Dong                    if (nChunks == 1 ||  // First chunk
218913aec890216948b0c364f8f92792129d0335f506James Dong                        (--(mStscTableEntries.end()))->samplesPerChunk !=
219013aec890216948b0c364f8f92792129d0335f506James Dong                         mChunkSamples.size()) {
21911f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                        addOneStscTableEntry(nChunks, mChunkSamples.size());
219213aec890216948b0c364f8f92792129d0335f506James Dong                    }
21931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                    bufferChunk(timestampUs);
219413aec890216948b0c364f8f92792129d0335f506James Dong                    chunkTimestampUs = timestampUs;
219513aec890216948b0c364f8f92792129d0335f506James Dong                }
219613aec890216948b0c364f8f92792129d0335f506James Dong            }
219713aec890216948b0c364f8f92792129d0335f506James Dong        }
219813aec890216948b0c364f8f92792129d0335f506James Dong
219920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
220025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
2201a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong    if (mSampleSizes.empty() ||                      // no samples written
2202a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong        (!mIsAudio && mNumStssTableEntries == 0) ||  // no sync frames for video
2203a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong        (OK != checkCodecSpecificData())) {          // no codec specific data
2204690f546b0ee548dbfe997df36418e5302ec2d786James Dong        err = ERROR_MALFORMED;
2205f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong    }
2206bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    mOwner->trackProgressStatus(mTrackId, -1, err);
2207be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
220813aec890216948b0c364f8f92792129d0335f506James Dong    // Last chunk
220943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    if (!hasMultipleTracks) {
22101f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        addOneStscTableEntry(1, mNumSamples);
221158ae9c530247668f8af36e30d228c716c226b3d4James Dong    } else if (!mChunkSamples.empty()) {
22121f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        addOneStscTableEntry(++nChunks, mChunkSamples.size());
22131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        bufferChunk(timestampUs);
221413aec890216948b0c364f8f92792129d0335f506James Dong    }
221513aec890216948b0c364f8f92792129d0335f506James Dong
2216be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // We don't really know how long the last frame lasts, since
2217be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // there is no frame time after it, just repeat the previous
2218be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // frame's duration.
2219ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    if (mNumSamples == 1) {
22208f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        lastDurationUs = 0;  // A single sample's duration
2221be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    } else {
2222be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        ++sampleCount;  // Count for the last sample
2223be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    }
2224a472613aec322e25891abf5c77bf3f7e3c244920James Dong
2225a472613aec322e25891abf5c77bf3f7e3c244920James Dong    if (mNumSamples <= 2) {
2226a472613aec322e25891abf5c77bf3f7e3c244920James Dong        addOneSttsTableEntry(1, lastDurationUs);
2227a472613aec322e25891abf5c77bf3f7e3c244920James Dong        if (sampleCount - 1 > 0) {
2228a472613aec322e25891abf5c77bf3f7e3c244920James Dong            addOneSttsTableEntry(sampleCount - 1, lastDurationUs);
2229a472613aec322e25891abf5c77bf3f7e3c244920James Dong        }
2230a472613aec322e25891abf5c77bf3f7e3c244920James Dong    } else {
2231a472613aec322e25891abf5c77bf3f7e3c244920James Dong        addOneSttsTableEntry(sampleCount, lastDurationUs);
2232a472613aec322e25891abf5c77bf3f7e3c244920James Dong    }
2233a472613aec322e25891abf5c77bf3f7e3c244920James Dong
2234c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    mTrackDurationUs += lastDurationUs;
223525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    mReachedEOS = true;
223643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
223743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    sendTrackSummary(hasMultipleTracks);
223843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
22391f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s",
22401f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            count, nZeroLengthFrames, mNumSamples, mIsAudio? "audio": "video");
2241872a481558350634a3fd5cb67939de288af00ecbJames Dong    if (mIsAudio) {
2242872a481558350634a3fd5cb67939de288af00ecbJames Dong        LOGI("Audio track drift time: %lld us", mOwner->getDriftTimeUs());
2243872a481558350634a3fd5cb67939de288af00ecbJames Dong    }
2244365a963142093a1cd8efdcea76b5f65096a5b115James Dong
224537187916a486504acaf83bea30147eb5fbf46ae5James Dong    if (err == ERROR_END_OF_STREAM) {
224637187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
224737187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
224837187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
2249365a963142093a1cd8efdcea76b5f65096a5b115James Dong}
2250365a963142093a1cd8efdcea76b5f65096a5b115James Dong
225143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dongvoid MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) {
225207ec01904613a0bac32caaa8444b4690998faed7James Dong
225307ec01904613a0bac32caaa8444b4690998faed7James Dong    // Send track summary only if test mode is enabled.
225407ec01904613a0bac32caaa8444b4690998faed7James Dong    if (!isTestModeEnabled()) {
225507ec01904613a0bac32caaa8444b4690998faed7James Dong        return;
225607ec01904613a0bac32caaa8444b4690998faed7James Dong    }
225707ec01904613a0bac32caaa8444b4690998faed7James Dong
225843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    int trackNum = (mTrackId << 28);
225943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
226043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
226143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_TYPE,
226243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    mIsAudio? 0: 1);
226343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
226443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
226543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_DURATION_MS,
226643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    mTrackDurationUs / 1000);
226743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
226843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
226943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES,
227043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    mNumSamples);
227143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
227286b7f47aa7482424cf8fd248f1315311919be3b0James Dong    {
227386b7f47aa7482424cf8fd248f1315311919be3b0James Dong        // The system delay time excluding the requested initial delay that
227486b7f47aa7482424cf8fd248f1315311919be3b0James Dong        // is used to eliminate the recording sound.
227586b7f47aa7482424cf8fd248f1315311919be3b0James Dong        int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL;
227686b7f47aa7482424cf8fd248f1315311919be3b0James Dong        if (startTimeOffsetUs < 0) {  // Start time offset was not set
227786b7f47aa7482424cf8fd248f1315311919be3b0James Dong            startTimeOffsetUs = kInitialDelayTimeUs;
227886b7f47aa7482424cf8fd248f1315311919be3b0James Dong        }
227986b7f47aa7482424cf8fd248f1315311919be3b0James Dong        int64_t initialDelayUs =
228086b7f47aa7482424cf8fd248f1315311919be3b0James Dong            mFirstSampleTimeRealUs - mStartTimeRealUs - startTimeOffsetUs;
228186b7f47aa7482424cf8fd248f1315311919be3b0James Dong
228286b7f47aa7482424cf8fd248f1315311919be3b0James Dong        mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
228370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS,
228470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    (initialDelayUs) / 1000);
228586b7f47aa7482424cf8fd248f1315311919be3b0James Dong    }
228670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
228707ec01904613a0bac32caaa8444b4690998faed7James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
228807ec01904613a0bac32caaa8444b4690998faed7James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES,
228907ec01904613a0bac32caaa8444b4690998faed7James Dong                    mMdatSizeBytes / 1024);
229007ec01904613a0bac32caaa8444b4690998faed7James Dong
229143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    if (hasMultipleTracks) {
229243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong        mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
229343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS,
229443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    mMaxChunkDurationUs / 1000);
229570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
229670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
229770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        if (mStartTimestampUs != moovStartTimeUs) {
229870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            int64_t startTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
229970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
230070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS,
230170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    startTimeOffsetUs / 1000);
230270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        }
230343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    }
230443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong}
230543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
2306faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) {
2307faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    LOGV("trackProgressStatus: %lld us", timeUs);
2308215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    if (mTrackEveryTimeDurationUs > 0 &&
2309215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong        timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) {
231093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        LOGV("Fire time tracking progress status at %lld us", timeUs);
2311bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err);
231293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        mPreviousTrackTimeUs = timeUs;
231393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    }
231493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong}
231593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
2316faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::trackProgressStatus(
2317bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        size_t trackId, int64_t timeUs, status_t err) {
2318faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    Mutex::Autolock lock(mLock);
2319bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    int32_t trackNum = (trackId << 28);
2320faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
2321faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    // Error notification
2322faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    // Do not consider ERROR_END_OF_STREAM an error
2323faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    if (err != OK && err != ERROR_END_OF_STREAM) {
2324bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_ERROR,
2325bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong               trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL,
2326faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               err);
2327faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        return;
2328faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    }
2329faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
2330faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    if (timeUs == -1) {
2331faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        // Send completion notification
2332bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2333bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong               trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS,
2334faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               err);
2335faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    } else {
2336faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        // Send progress status
2337bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2338bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong               trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME,
2339faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               timeUs / 1000);
2340faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    }
2341faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong}
2342faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
2343d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dongvoid MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) {
2344d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong    LOGV("setDriftTimeUs: %lld us", driftTimeUs);
2345e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    Mutex::Autolock autolock(mLock);
2346d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong    mDriftTimeUs = driftTimeUs;
2347e259531ce59ab1f31de5a23124b22536f6a5a767James Dong}
2348e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
2349e259531ce59ab1f31de5a23124b22536f6a5a767James Dongint64_t MPEG4Writer::getDriftTimeUs() {
2350e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    LOGV("getDriftTimeUs: %lld us", mDriftTimeUs);
2351e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    Mutex::Autolock autolock(mLock);
2352e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    return mDriftTimeUs;
2353e259531ce59ab1f31de5a23124b22536f6a5a767James Dong}
2354e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
2355b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dongbool MPEG4Writer::useNalLengthFour() {
2356b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    return mUse4ByteNalLength;
2357b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong}
2358b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong
23591c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
23601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("bufferChunk");
23611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
23621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Chunk chunk(this, timestampUs, mChunkSamples);
23631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mOwner->bufferChunk(chunk);
236413aec890216948b0c364f8f92792129d0335f506James Dong    mChunkSamples.clear();
236520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
236620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
23673b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const {
2368c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    return mTrackDurationUs;
236920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
237020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2371d599cd4573b5a2d5914c5040e0565ef866749b77James Dongint64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
2372d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    return mEstimatedTrackSizeBytes;
2373d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
2374d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
2375690f546b0ee548dbfe997df36418e5302ec2d786James Dongstatus_t MPEG4Writer::Track::checkCodecSpecificData() const {
2376690f546b0ee548dbfe997df36418e5302ec2d786James Dong    const char *mime;
2377690f546b0ee548dbfe997df36418e5302ec2d786James Dong    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
2378690f546b0ee548dbfe997df36418e5302ec2d786James Dong    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) ||
2379690f546b0ee548dbfe997df36418e5302ec2d786James Dong        !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
2380690f546b0ee548dbfe997df36418e5302ec2d786James Dong        !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2381690f546b0ee548dbfe997df36418e5302ec2d786James Dong        if (!mCodecSpecificData ||
2382690f546b0ee548dbfe997df36418e5302ec2d786James Dong            mCodecSpecificDataSize <= 0) {
2383a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong            LOGE("Missing codec specific data");
2384690f546b0ee548dbfe997df36418e5302ec2d786James Dong            return ERROR_MALFORMED;
2385690f546b0ee548dbfe997df36418e5302ec2d786James Dong        }
2386690f546b0ee548dbfe997df36418e5302ec2d786James Dong    } else {
2387690f546b0ee548dbfe997df36418e5302ec2d786James Dong        if (mCodecSpecificData ||
2388690f546b0ee548dbfe997df36418e5302ec2d786James Dong            mCodecSpecificDataSize > 0) {
2389a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong            LOGE("Unexepected codec specific data found");
2390690f546b0ee548dbfe997df36418e5302ec2d786James Dong            return ERROR_MALFORMED;
2391690f546b0ee548dbfe997df36418e5302ec2d786James Dong        }
2392690f546b0ee548dbfe997df36418e5302ec2d786James Dong    }
2393690f546b0ee548dbfe997df36418e5302ec2d786James Dong    return OK;
2394690f546b0ee548dbfe997df36418e5302ec2d786James Dong}
2395690f546b0ee548dbfe997df36418e5302ec2d786James Dong
2396b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) {
239720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
23988f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    LOGV("%s track time scale: %d",
23991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mIsAudio? "Audio": "Video", mTimeScale);
24008f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
240120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    time_t now = time(NULL);
2402b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("trak");
2403b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeTkhdBox(now);
2404b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("mdia");
2405b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            writeMdhdBox(now);
2406b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            writeHdlrBox();
2407b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->beginBox("minf");
2408b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                if (mIsAudio) {
2409b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                    writeSmhdBox();
2410b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                } else {
2411b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                    writeVmhdBox();
2412b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                }
2413b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                writeDinfBox();
2414b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                writeStblBox(use32BitOffset);
2415b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->endBox();  // minf
2416b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->endBox();  // mdia
2417b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // trak
2418b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2419b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2420b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStblBox(bool use32BitOffset) {
2421b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stbl");
2422b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stsd");
2423b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);               // version=0, flags=0
2424b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1);               // entry count
2425b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mIsAudio) {
2426b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeAudioFourCCBox();
2427b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2428b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeVideoFourCCBox();
2429b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2430b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stsd
2431b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeSttsBox();
2432b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!mIsAudio) {
2433b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeStssBox();
2434b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2435b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeStszBox();
2436b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeStscBox();
2437b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeStcoBox(use32BitOffset);
2438b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stbl
2439b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2440b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2441b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVideoFourCCBox() {
2442b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    const char *mime;
2443b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    bool success = mMeta->findCString(kKeyMIMEType, &mime);
2444b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2445b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2446b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("mp4v");
2447b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2448b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("s263");
2449b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2450b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("avc1");
2451b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2452b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        LOGE("Unknown mime type '%s'.", mime);
2453b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(!"should not be here, unknown mime type.");
2454b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2455b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2456b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2457b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2458b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(1);           // data ref index
2459b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // predefined
2460b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2461b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // predefined
2462b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // predefined
2463b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // predefined
2464b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2465b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t width, height;
2466b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    success = mMeta->findInt32(kKeyWidth, &width);
2467b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    success = success && mMeta->findInt32(kKeyHeight, &height);
2468b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2469b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2470b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(width);
2471b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(height);
2472b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x480000);    // horiz resolution
2473b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x480000);    // vert resolution
2474b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2475b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(1);           // frame count
2476b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write("                                ", 32);
2477b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x18);        // depth
2478b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(-1);          // predefined
2479b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2480b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(23 + mCodecSpecificDataSize < 128);
2481b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2482b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2483b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeMp4vEsdsBox();
2484b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2485b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeD263Box();
2486b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2487b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeAvccBox();
2488b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2489b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2490b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writePaspBox();
2491b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // mp4v, s263 or avc1
2492b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2493b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2494b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAudioFourCCBox() {
2495b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    const char *mime;
2496b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    bool success = mMeta->findCString(kKeyMIMEType, &mime);
2497b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2498b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    const char *fourcc = NULL;
2499b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
2500b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fourcc = "samr";
2501b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2502b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fourcc = "sawb";
2503b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2504b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fourcc = "mp4a";
2505b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2506b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        LOGE("Unknown mime type '%s'.", mime);
2507b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(!"should not be here, unknown mime type.");
2508b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2509b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2510b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox(fourcc);        // audio format
2511b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2512b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2513b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x1);         // data ref index
2514b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2515b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2516b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t nChannels;
2517b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels));
2518b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(nChannels);   // channel count
2519b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(16);          // sample size
2520b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // predefined
2521b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2522b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2523b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t samplerate;
2524b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    success = mMeta->findInt32(kKeySampleRate, &samplerate);
2525b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2526b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(samplerate << 16);
2527b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2528b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeMp4aEsdsBox();
2529b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) ||
2530b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong               !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2531b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeDamrBox();
2532b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2533b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2534b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2535b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2536b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4aEsdsBox() {
2537b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("esds");
2538b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificData);
2539b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificDataSize > 0);
2540b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2541b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Make sure all sizes encode to a single byte.
2542b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificDataSize + 23 < 128);
2543b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2544b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);     // version=0, flags=0
2545b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x03);   // ES_DescrTag
2546b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(23 + mCodecSpecificDataSize);
2547b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x0000);// ES_ID
2548b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x00);
2549b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2550b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x04);   // DecoderConfigDescrTag
2551b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(15 + mCodecSpecificDataSize);
2552b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x40);   // objectTypeIndication ISO/IEC 14492-2
2553b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x15);   // streamType AudioStream
2554b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2555b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x03);  // XXX
2556b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x00);   // buffer size 24-bit
2557b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(96000); // max bit rate
2558b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(96000); // avg bit rate
2559b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2560b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x05);   // DecoderSpecificInfoTag
2561b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(mCodecSpecificDataSize);
2562b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2563b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2564b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    static const uint8_t kData2[] = {
2565b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x06,  // SLConfigDescriptorTag
2566b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x01,
2567b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x02
2568b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    };
2569b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(kData2, sizeof(kData2));
2570b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2571b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // esds
2572b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2573b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2574b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4vEsdsBox() {
2575b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificData);
2576b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificDataSize > 0);
2577b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("esds");
2578b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2579b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);    // version=0, flags=0
2580b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2581b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x03);  // ES_DescrTag
2582b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(23 + mCodecSpecificDataSize);
2583b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x0000);  // ES_ID
2584b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x1f);
2585b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2586b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x04);  // DecoderConfigDescrTag
2587b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(15 + mCodecSpecificDataSize);
2588b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x20);  // objectTypeIndication ISO/IEC 14492-2
2589b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x11);  // streamType VisualStream
2590b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2591b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    static const uint8_t kData[] = {
2592b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x01, 0x77, 0x00,
2593b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x00, 0x03, 0xe8, 0x00,
2594b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x00, 0x03, 0xe8, 0x00
2595b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    };
2596b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(kData, sizeof(kData));
2597b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2598b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
2599b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2600b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(mCodecSpecificDataSize);
2601b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2602b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2603b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    static const uint8_t kData2[] = {
2604b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x06,  // SLConfigDescriptorTag
2605b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x01,
2606b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x02
2607b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    };
2608b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(kData2, sizeof(kData2));
2609b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2610b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // esds
2611b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2612b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2613b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeTkhdBox(time_t now) {
2614b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("tkhd");
2615b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Flags = 7 to indicate that the track is enabled, and
2616b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // part of the presentation
2617b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x07);          // version=0, flags=7
2618b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // creation time
2619b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // modification time
2620b5212db69734962f55e1493d3e696794172ced51James Dong    mOwner->writeInt32(mTrackId + 1);  // track id starts with 1
2621b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
26228f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t trakDurationUs = getDurationUs();
2623b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t mvhdTimeScale = mOwner->getTimeScale();
2624b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t tkhdDuration =
2625b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        (trakDurationUs * mvhdTimeScale + 5E5) / 1E6;
2626b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(tkhdDuration);  // in mvhd timescale
2627b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2628b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2629b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // layer
2630b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // alternate group
2631b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(mIsAudio ? 0x100 : 0);  // volume
2632b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // reserved
2633b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2634b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeCompositionMatrix(mRotation);       // matrix
263520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2636b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mIsAudio) {
2637b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(0);
2638b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(0);
2639b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2640b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        int32_t width, height;
2641b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        bool success = mMeta->findInt32(kKeyWidth, &width);
2642b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        success = success && mMeta->findInt32(kKeyHeight, &height);
2643b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(success);
2644b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2645b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(width << 16);   // 32-bit fixed-point value
2646b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(height << 16);  // 32-bit fixed-point value
2647b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2648b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // tkhd
2649b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2650b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2651b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVmhdBox() {
2652b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("vmhd");
2653b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x01);        // version=0, flags=1
2654b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // graphics mode
2655b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // opcolor
2656b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);
2657b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);
2658b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2659b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2660b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2661b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeSmhdBox() {
2662b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("smhd");
2663b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // version=0, flags=0
2664b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // balance
2665b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2666b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2667b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2668b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2669b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeHdlrBox() {
2670b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("hdlr");
2671b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // version=0, flags=0
2672b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // component type: should be mhlr
2673b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeFourcc(mIsAudio ? "soun" : "vide");  // component subtype
2674b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2675b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2676b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2677b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Removing "r" for the name string just makes the string 4 byte aligned
2678b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle");  // name
2679b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2680b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2681b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2682b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMdhdBox(time_t now) {
2683b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int64_t trakDurationUs = getDurationUs();
2684b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("mdhd");
2685b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // version=0, flags=0
2686b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // creation time
2687b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // modification time
2688b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mTimeScale);    // media timescale
2689b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6;
2690b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mdhdDuration);  // use media timescale
2691b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Language follows the three letter standard ISO-639-2/T
2692b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // 'e', 'n', 'g' for "English", for instance.
2693b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Each character is packed as the difference between its ASCII value and 0x60.
2694b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // For "English", these are 00101, 01110, 00111.
2695b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // XXX: Where is the padding bit located: 0x15C7?
2696b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // language code
2697b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // predefined
2698b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2699b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2700b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2701b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDamrBox() {
2702b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // 3gpp2 Spec AMRSampleEntry fields
2703b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("damr");
2704b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeCString("   ");  // vendor: 4 bytes
2705b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);         // decoder version
2706b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x83FF);   // mode set: all enabled
2707b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);         // mode change period
2708b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(1);         // frames per sample
2709b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2710b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2711b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2712b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeUrlBox() {
2713b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // The table index here refers to the sample description index
2714b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // in the sample table entries.
2715b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("url ");
2716b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1);  // version=0, flags=1 (self-contained)
2717b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // url
2718b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2719b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2720b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDrefBox() {
2721b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("dref");
2722b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2723b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1);  // entry count (either url or urn)
2724b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeUrlBox();
2725b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // dref
2726b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2727b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2728b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDinfBox() {
2729b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("dinf");
2730b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeDrefBox();
2731b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // dinf
2732b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2733b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2734b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAvccBox() {
2735b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificData);
2736b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificDataSize >= 5);
2737b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2738b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Patch avcc's lengthSize field to match the number
2739b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // of bytes we use to indicate the size of a nal unit.
2740b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    uint8_t *ptr = (uint8_t *)mCodecSpecificData;
2741b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    ptr[4] = (ptr[4] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1);
2742b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("avcC");
2743b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2744b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // avcC
2745b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2746b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2747b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeD263Box() {
2748b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("d263");
2749b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // vendor
2750b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);   // decoder version
2751b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(10);  // level: 10
2752b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);   // profile: 0
2753b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // d263
2754b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2755b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2756b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong// This is useful if the pixel is not square
2757b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writePaspBox() {
2758b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("pasp");
2759b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1 << 16);  // hspacing
2760b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1 << 16);  // vspacing
2761b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // pasp
2762b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2763b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2764b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeSttsBox() {
2765b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stts");
2766b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2767b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mNumSttsTableEntries);
276870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
2769a472613aec322e25891abf5c77bf3f7e3c244920James Dong    // Compensate for small start time difference from different media tracks
2770a472613aec322e25891abf5c77bf3f7e3c244920James Dong    int64_t trackStartTimeOffsetUs = 0;
2771b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
2772b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mStartTimestampUs != moovStartTimeUs) {
2773b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(mStartTimestampUs > moovStartTimeUs);
2774b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
2775b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2776b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int64_t prevTimestampUs = trackStartTimeOffsetUs;
2777b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
2778b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mSttsTableEntries.end(); ++it) {
2779b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(it->sampleCount);
2780a472613aec322e25891abf5c77bf3f7e3c244920James Dong
2781b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        // Make sure that we are calculating the sample duration the exactly
2782b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        // same way as we made decision on how to create stts entries.
2783b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        int64_t currTimestampUs = prevTimestampUs + it->sampleDurationUs;
2784b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        int32_t dur = ((currTimestampUs * mTimeScale + 500000LL) / 1000000LL -
2785b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            (prevTimestampUs * mTimeScale + 500000LL) / 1000000LL);
2786b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        prevTimestampUs += (it->sampleCount * it->sampleDurationUs);
278720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2788b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(dur);
2789b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2790b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stts
2791b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
279220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2793b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStssBox() {
2794b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stss");
2795b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2796b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mNumStssTableEntries);  // number of sync frames
2797b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<int32_t>::iterator it = mStssTableEntries.begin();
2798b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mStssTableEntries.end(); ++it) {
2799b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(*it);
2800b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2801b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stss
2802b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
280325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
2804b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStszBox() {
2805b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stsz");
2806b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2807b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mSamplesHaveSameSize) {
2808b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        List<size_t>::iterator it = mSampleSizes.begin();
2809b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(*it);  // default sample size
2810b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2811b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(0);
2812b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2813b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mNumSamples);
2814b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!mSamplesHaveSameSize) {
2815b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        for (List<size_t>::iterator it = mSampleSizes.begin();
2816b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            it != mSampleSizes.end(); ++it) {
2817b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->writeInt32(*it);
2818b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        }
2819b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2820b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stsz
2821b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
282220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2823b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStscBox() {
2824b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stsc");
2825b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2826b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mNumStscTableEntries);
2827b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<StscTableEntry>::iterator it = mStscTableEntries.begin();
2828b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mStscTableEntries.end(); ++it) {
2829b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(it->firstChunk);
2830b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(it->samplesPerChunk);
2831b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(it->sampleDescriptionId);
2832b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2833b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stsc
2834b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
283520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2836b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) {
2837b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox(use32BitOffset? "stco": "co64");
2838b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2839b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mNumStcoTableEntries);
2840b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<off64_t>::iterator it = mChunkOffsets.begin();
2841b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mChunkOffsets.end(); ++it) {
2842b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        if (use32BitOffset) {
2843b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->writeInt32(static_cast<int32_t>(*it));
2844b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        } else {
2845b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->writeInt64((*it));
2846b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        }
2847b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2848b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stco or co64
284920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
285020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
285107b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeUdtaBox() {
285207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    beginBox("udta");
285307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeGeoDataBox();
285407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    endBox();
285507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
285607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
285707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong/*
285807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * Geodata is stored according to ISO-6709 standard.
285907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */
286007b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeGeoDataBox() {
286107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    beginBox("\xA9xyz");
286207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    /*
286307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong     * For historical reasons, any user data start
286407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong     * with "\0xA9", must be followed by its assoicated
286507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong     * language code.
2866432ec3768cc4a3b1b01afedc456689d75c89ee2bJames Dong     * 0x0012: text string length
2867432ec3768cc4a3b1b01afedc456689d75c89ee2bJames Dong     * 0x15c7: lang (locale) code: en
286807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong     */
286907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeInt32(0x001215c7);
287007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeLatitude(mLatitudex10000);
287107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeLongitude(mLongitudex10000);
287207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeInt8(0x2F);
287307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    endBox();
287407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
287507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
287620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}  // namespace android
2877