MPEG4Writer.cpp revision b5212db69734962f55e1493d3e696794172ced51
120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber/*
220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Copyright (C) 2009 The Android Open Source Project
320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber *
420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * you may not use this file except in compliance with the License.
620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * You may obtain a copy of the License at
720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber *
820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber *
1020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * Unless required by applicable law or agreed to in writing, software
1120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
1220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * See the License for the specific language governing permissions and
1420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber * limitations under the License.
1520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber */
1620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
17050b28a593350047845a45a14cc5026221ac1620James Dong//#define LOG_NDEBUG 0
18050b28a593350047845a45a14cc5026221ac1620James Dong#define LOG_TAG "MPEG4Writer"
19050b28a593350047845a45a14cc5026221ac1620James Dong#include <utils/Log.h>
20050b28a593350047845a45a14cc5026221ac1620James Dong
2120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <arpa/inet.h>
2220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <pthread.h>
24a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong#include <sys/prctl.h>
25a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong#include <sys/resource.h>
2620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MPEG4Writer.h>
2820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaBuffer.h>
2920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MetaData.h>
300c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber#include <media/stagefright/MediaDebug.h>
3118291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber#include <media/stagefright/MediaDefs.h>
3203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#include <media/stagefright/MediaErrors.h>
3320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaSource.h>
3420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/Utils.h>
35d599cd4573b5a2d5914c5040e0565ef866749b77James Dong#include <media/mediarecorder.h>
36674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <sys/types.h>
37674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <sys/stat.h>
38674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <fcntl.h>
39674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong#include <unistd.h>
4020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
4119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber#include "include/ESDS.h"
4219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
4320111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubernamespace android {
4420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
451f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongstatic const int64_t kMax32BitFileSize = 0x007fffffffLL;
463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypeSeqParamSet = 0x07;
473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypePicParamSet = 0x08;
4870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dongstatic const int64_t kInitialDelayTimeUs     = 700000LL;
495b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong
505b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong// Using longer adjustment period to suppress fluctuations in
515b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong// the audio encoding paths
525b6a01e65aa4129a9226667536d1bc1dad5980d8James Dongstatic const int64_t kVideoMediaTimeAdjustPeriodTimeUs = 600000000LL;  // 10 minutes
533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
5420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberclass MPEG4Writer::Track {
5520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberpublic:
56bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId);
578f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
5820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    ~Track();
5920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    status_t start(MetaData *params);
6137187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t stop();
6237187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t pause();
6325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool reachedEOS();
6420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
653b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber    int64_t getDurationUs() const;
66d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    int64_t getEstimatedTrackSizeBytes() const;
67b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeTrackHeader(bool use32BitOffset = true);
681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    void bufferChunk(int64_t timestampUs);
691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool isAvc() const { return mIsAvc; }
701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool isAudio() const { return mIsAudio; }
711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool isMPEG4() const { return mIsMPEG4; }
72c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    void addChunkOffset(off64_t offset);
7370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    int32_t getTrackId() const { return mTrackId; }
74dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    status_t dump(int fd, const Vector<String16>& args) const;
7520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
7620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberprivate:
7720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    MPEG4Writer *mOwner;
7820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    sp<MetaData> mMeta;
79693d271e62a3726689ff68f4505ba49228eb94b2Andreas Huber    sp<MediaSource> mSource;
8020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    volatile bool mDone;
81a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    volatile bool mPaused;
82a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    volatile bool mResumed;
83eaae38445a340c4857c1c5569475879a728e63b7James Dong    volatile bool mStarted;
841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool mIsAvc;
851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool mIsAudio;
861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool mIsMPEG4;
87bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    int32_t mTrackId;
88c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    int64_t mTrackDurationUs;
8943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    int64_t mMaxChunkDurationUs;
90e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
91e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    // For realtime applications, we need to adjust the media clock
92e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    // for video track based on the audio media clock
93e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    bool mIsRealTimeRecording;
94e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    int64_t mMaxTimeStampUs;
95d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    int64_t mEstimatedTrackSizeBytes;
961f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    int64_t mMdatSizeBytes;
978f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int32_t mTimeScale;
9820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
9920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_t mThread;
10020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
101ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    // mNumSamples is used to track how many samples in mSampleSizes List.
102ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    // This is to reduce the cost associated with mSampleSizes.size() call,
103ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    // since it is O(n). Ideally, the fix should be in List class.
104ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    size_t              mNumSamples;
1058644c14618d30d9e57a69df40ed939986ebf02c4James Dong    List<size_t>        mSampleSizes;
106be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    bool                mSamplesHaveSameSize;
107be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
10813aec890216948b0c364f8f92792129d0335f506James Dong    List<MediaBuffer *> mChunkSamples;
1091f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1101f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    size_t              mNumStcoTableEntries;
111c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    List<off64_t>         mChunkOffsets;
11213aec890216948b0c364f8f92792129d0335f506James Dong
1131f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    size_t              mNumStscTableEntries;
11413aec890216948b0c364f8f92792129d0335f506James Dong    struct StscTableEntry {
11513aec890216948b0c364f8f92792129d0335f506James Dong
11613aec890216948b0c364f8f92792129d0335f506James Dong        StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id)
11713aec890216948b0c364f8f92792129d0335f506James Dong            : firstChunk(chunk),
11813aec890216948b0c364f8f92792129d0335f506James Dong              samplesPerChunk(samples),
11913aec890216948b0c364f8f92792129d0335f506James Dong              sampleDescriptionId(id) {}
12013aec890216948b0c364f8f92792129d0335f506James Dong
12113aec890216948b0c364f8f92792129d0335f506James Dong        uint32_t firstChunk;
12213aec890216948b0c364f8f92792129d0335f506James Dong        uint32_t samplesPerChunk;
12313aec890216948b0c364f8f92792129d0335f506James Dong        uint32_t sampleDescriptionId;
12413aec890216948b0c364f8f92792129d0335f506James Dong    };
12513aec890216948b0c364f8f92792129d0335f506James Dong    List<StscTableEntry> mStscTableEntries;
12620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1271f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    size_t        mNumStssTableEntries;
128050b28a593350047845a45a14cc5026221ac1620James Dong    List<int32_t> mStssTableEntries;
129050b28a593350047845a45a14cc5026221ac1620James Dong
1301f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    size_t        mNumSttsTableEntries;
131be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    struct SttsTableEntry {
132be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
1338f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        SttsTableEntry(uint32_t count, uint32_t durationUs)
1348f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            : sampleCount(count), sampleDurationUs(durationUs) {}
135be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
136be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        uint32_t sampleCount;
1378f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        uint32_t sampleDurationUs;
138be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    };
139be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    List<SttsTableEntry> mSttsTableEntries;
140be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
1413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Sequence parameter set or picture parameter set
1423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    struct AVCParamSet {
1433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        AVCParamSet(uint16_t length, const uint8_t *data)
1443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            : mLength(length), mData(data) {}
1453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
1463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t mLength;
1473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *mData;
1483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    };
1493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    List<AVCParamSet> mSeqParamSets;
1503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    List<AVCParamSet> mPicParamSets;
1513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mProfileIdc;
1523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mProfileCompatible;
1533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mLevelIdc;
1543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    void *mCodecSpecificData;
15620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    size_t mCodecSpecificDataSize;
157548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber    bool mGotAllCodecSpecificData;
15893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    bool mTrackingProgressStatus;
15920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
16025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool mReachedEOS;
1613c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    int64_t mStartTimestampUs;
16270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    int64_t mStartTimeRealUs;
16370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    int64_t mFirstSampleTimeRealUs;
16493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t mPreviousTrackTimeUs;
16593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t mTrackEveryTimeDurationUs;
16625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
167872a481558350634a3fd5cb67939de288af00ecbJames Dong    // Has the media time adjustment for video started?
168872a481558350634a3fd5cb67939de288af00ecbJames Dong    bool    mIsMediaTimeAdjustmentOn;
169872a481558350634a3fd5cb67939de288af00ecbJames Dong    // The time stamp when previous media time adjustment period starts
170872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t mPrevMediaTimeAdjustTimestampUs;
171872a481558350634a3fd5cb67939de288af00ecbJames Dong    // Number of vidoe frames whose time stamp may be adjusted
172872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t mMediaTimeAdjustNumFrames;
173872a481558350634a3fd5cb67939de288af00ecbJames Dong    // The sample number when previous meida time adjustmnet period starts
174872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t mPrevMediaTimeAdjustSample;
175872a481558350634a3fd5cb67939de288af00ecbJames Dong    // The total accumulated drift time within a period of
176872a481558350634a3fd5cb67939de288af00ecbJames Dong    // kVideoMediaTimeAdjustPeriodTimeUs.
177872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t mTotalDriftTimeToAdjustUs;
178872a481558350634a3fd5cb67939de288af00ecbJames Dong    // The total accumalated drift time since the start of the recording
179872a481558350634a3fd5cb67939de288af00ecbJames Dong    // excluding the current time adjustment period
180872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t mPrevTotalAccumDriftTimeUs;
181872a481558350634a3fd5cb67939de288af00ecbJames Dong
182872a481558350634a3fd5cb67939de288af00ecbJames Dong    // Update the audio track's drift information.
183872a481558350634a3fd5cb67939de288af00ecbJames Dong    void updateDriftTime(const sp<MetaData>& meta);
184872a481558350634a3fd5cb67939de288af00ecbJames Dong
185872a481558350634a3fd5cb67939de288af00ecbJames Dong    // Adjust the time stamp of the video track according to
186872a481558350634a3fd5cb67939de288af00ecbJames Dong    // the drift time information from the audio track.
187872a481558350634a3fd5cb67939de288af00ecbJames Dong    void adjustMediaTime(int64_t *timestampUs);
188872a481558350634a3fd5cb67939de288af00ecbJames Dong
18920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    static void *ThreadWrapper(void *me);
19037187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t threadEntry();
19120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *parseParamSet(
1933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length, int type, size_t *paramSetLen);
1943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
195b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    status_t makeAVCCodecSpecificData(const uint8_t *data, size_t size);
196b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    status_t copyAVCCodecSpecificData(const uint8_t *data, size_t size);
197b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    status_t parseAVCCodecSpecificData(const uint8_t *data, size_t size);
198215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong
199215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    // Track authoring progress status
200faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    void trackProgressStatus(int64_t timeUs, status_t err = OK);
20193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    void initTrackingProgressStatus(MetaData *params);
20203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
20319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    void getCodecSpecificDataFromInputFormatIfPossible();
20419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
205c059860c73678a202bfa33062723e8f82fb779d9James Dong    // Determine the track time scale
206c059860c73678a202bfa33062723e8f82fb779d9James Dong    // If it is an audio track, try to use the sampling rate as
207c059860c73678a202bfa33062723e8f82fb779d9James Dong    // the time scale; however, if user chooses the overwrite
208c059860c73678a202bfa33062723e8f82fb779d9James Dong    // value, the user-supplied time scale will be used.
209c059860c73678a202bfa33062723e8f82fb779d9James Dong    void setTimeScale();
210c059860c73678a202bfa33062723e8f82fb779d9James Dong
211690f546b0ee548dbfe997df36418e5302ec2d786James Dong    // Simple validation on the codec specific data
212690f546b0ee548dbfe997df36418e5302ec2d786James Dong    status_t checkCodecSpecificData() const;
21313f6284305e4b27395a23db7882d670bdb1bcae1James Dong    int32_t mRotation;
214690f546b0ee548dbfe997df36418e5302ec2d786James Dong
2151f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void updateTrackSizeEstimate();
2161f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void addOneStscTableEntry(size_t chunkId, size_t sampleId);
2171f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void addOneStssTableEntry(size_t sampleId);
2181f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void addOneSttsTableEntry(size_t sampleCount, int64_t durationUs);
21943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    void sendTrackSummary(bool hasMultipleTracks);
2201f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
221b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Write the boxes
222b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStcoBox(bool use32BitOffset);
223b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStscBox();
224b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStszBox();
225b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStssBox();
226b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeSttsBox();
227b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeD263Box();
228b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writePaspBox();
229b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeAvccBox();
230b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeUrlBox();
231b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeDrefBox();
232b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeDinfBox();
233b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeDamrBox();
234b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeMdhdBox(time_t now);
235b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeSmhdBox();
236b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeVmhdBox();
237b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeHdlrBox();
238b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeTkhdBox(time_t now);
239b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeMp4aEsdsBox();
240b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeMp4vEsdsBox();
241b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeAudioFourCCBox();
242b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeVideoFourCCBox();
243b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStblBox(bool use32BitOffset);
244b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
24520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track(const Track &);
24620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track &operator=(const Track &);
24720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber};
24820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
24920111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::MPEG4Writer(const char *filename)
250674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    : mFd(-1),
251674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong      mInitCheck(NO_INIT),
252b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong      mUse4ByteNalLength(true),
2531acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong      mUse32BitOffset(true),
254a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong      mIsFileSizeLimitExplicitlyRequested(false),
255a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
256a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mStarted(false),
25720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mOffset(0),
25813aec890216948b0c364f8f92792129d0335f506James Dong      mMdatOffset(0),
2597837c17063a4c50bc856ba59418516fdab731de7James Dong      mEstimatedMoovBoxSize(0),
260f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong      mInterleaveDurationUs(1000000) {
261674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong
26203f6f4e7e2ce09357cbc05bb546cd8a6e54b5baeJames Dong    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR);
263674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mFd >= 0) {
264674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        mInitCheck = OK;
265674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    }
26620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
26720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
26830ab66297501757d745b9ae10da61adcd891f497Andreas HuberMPEG4Writer::MPEG4Writer(int fd)
269674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    : mFd(dup(fd)),
270674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong      mInitCheck(mFd < 0? NO_INIT: OK),
271b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong      mUse4ByteNalLength(true),
2721acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong      mUse32BitOffset(true),
273a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong      mIsFileSizeLimitExplicitlyRequested(false),
274a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
275a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mStarted(false),
27630ab66297501757d745b9ae10da61adcd891f497Andreas Huber      mOffset(0),
27713aec890216948b0c364f8f92792129d0335f506James Dong      mMdatOffset(0),
2787837c17063a4c50bc856ba59418516fdab731de7James Dong      mEstimatedMoovBoxSize(0),
279f01528f435e6b1f02d118fcd8305a148c27a89f1James Dong      mInterleaveDurationUs(1000000) {
28030ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
28130ab66297501757d745b9ae10da61adcd891f497Andreas Huber
28220111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() {
28320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    stop();
28420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2851f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    while (!mTracks.empty()) {
2861f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        List<Track *>::iterator it = mTracks.begin();
28720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        delete *it;
2881f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        (*it) = NULL;
2891f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        mTracks.erase(it);
29020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
29120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mTracks.clear();
29220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
29320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
294dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::dump(
295dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        int fd, const Vector<String16>& args) {
296dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    const size_t SIZE = 256;
297dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    char buffer[SIZE];
298dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    String8 result;
299dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "   MPEG4Writer %p\n", this);
300dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
301dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "     mStarted: %s\n", mStarted? "true": "false");
302dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
303dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    ::write(fd, result.string(), result.size());
304dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    for (List<Track *>::iterator it = mTracks.begin();
305dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong         it != mTracks.end(); ++it) {
306dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        (*it)->dump(fd, args);
307dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    }
308dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    return OK;
309dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong}
310dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong
311dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::Track::dump(
312dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        int fd, const Vector<String16>& args) const {
313dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    const size_t SIZE = 256;
314dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    char buffer[SIZE];
315dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    String8 result;
316dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "     %s track\n", mIsAudio? "Audio": "Video");
317dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
318dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "       reached EOS: %s\n",
319dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong            mReachedEOS? "true": "false");
320dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
321dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    ::write(fd, result.string(), result.size());
322dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    return OK;
323dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong}
324dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong
3252dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
326bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    Mutex::Autolock l(mLock);
327bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    if (mStarted) {
328bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        LOGE("Attempt to add source AFTER recording is started");
329bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        return UNKNOWN_ERROR;
330bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    }
331bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    Track *track = new Track(this, source, mTracks.size());
33220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mTracks.push_back(track);
3332dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
3342dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    return OK;
33520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
33620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
33793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::startTracks(MetaData *params) {
338a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    for (List<Track *>::iterator it = mTracks.begin();
339a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong         it != mTracks.end(); ++it) {
34093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        status_t err = (*it)->start(params);
341a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
342a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (err != OK) {
343a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            for (List<Track *>::iterator it2 = mTracks.begin();
344a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong                 it2 != it; ++it2) {
345a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong                (*it2)->stop();
346a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            }
347a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
348a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            return err;
349a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
350a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
351a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    return OK;
352a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
353a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
3542dec2b5be2056c6d9428897dc672185872d30d17James Dongint64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) {
3552dec2b5be2056c6d9428897dc672185872d30d17James Dong    // This implementation is highly experimental/heurisitic.
3562dec2b5be2056c6d9428897dc672185872d30d17James Dong    //
3572dec2b5be2056c6d9428897dc672185872d30d17James Dong    // Statistical analysis shows that metadata usually accounts
3582dec2b5be2056c6d9428897dc672185872d30d17James Dong    // for a small portion of the total file size, usually < 0.6%.
3592dec2b5be2056c6d9428897dc672185872d30d17James Dong
36078a1a286f736888ae7af8860b2c424af0d978848James Dong    // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2,
3612dec2b5be2056c6d9428897dc672185872d30d17James Dong    // where 1MB is the common file size limit for MMS application.
36278a1a286f736888ae7af8860b2c424af0d978848James Dong    // The default MAX _MOOV_BOX_SIZE value is based on about 3
3632dec2b5be2056c6d9428897dc672185872d30d17James Dong    // minute video recording with a bit rate about 3 Mbps, because
3642dec2b5be2056c6d9428897dc672185872d30d17James Dong    // statistics also show that most of the video captured are going
3652dec2b5be2056c6d9428897dc672185872d30d17James Dong    // to be less than 3 minutes.
3662dec2b5be2056c6d9428897dc672185872d30d17James Dong
3672dec2b5be2056c6d9428897dc672185872d30d17James Dong    // If the estimation is wrong, we will pay the price of wasting
3682dec2b5be2056c6d9428897dc672185872d30d17James Dong    // some reserved space. This should not happen so often statistically.
3692dec2b5be2056c6d9428897dc672185872d30d17James Dong    static const int32_t factor = mUse32BitOffset? 1: 2;
37078a1a286f736888ae7af8860b2c424af0d978848James Dong    static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024;  // 3 KB
3712dec2b5be2056c6d9428897dc672185872d30d17James Dong    static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000);
3722dec2b5be2056c6d9428897dc672185872d30d17James Dong    int64_t size = MIN_MOOV_BOX_SIZE;
3732dec2b5be2056c6d9428897dc672185872d30d17James Dong
37478a1a286f736888ae7af8860b2c424af0d978848James Dong    // Max file size limit is set
375a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
37678a1a286f736888ae7af8860b2c424af0d978848James Dong        size = mMaxFileSizeLimitBytes * 6 / 1000;
37778a1a286f736888ae7af8860b2c424af0d978848James Dong    }
37878a1a286f736888ae7af8860b2c424af0d978848James Dong
37978a1a286f736888ae7af8860b2c424af0d978848James Dong    // Max file duration limit is set
38078a1a286f736888ae7af8860b2c424af0d978848James Dong    if (mMaxFileDurationLimitUs != 0) {
38178a1a286f736888ae7af8860b2c424af0d978848James Dong        if (bitRate > 0) {
38278a1a286f736888ae7af8860b2c424af0d978848James Dong            int64_t size2 =
38378a1a286f736888ae7af8860b2c424af0d978848James Dong                ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000);
38478a1a286f736888ae7af8860b2c424af0d978848James Dong            if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
38578a1a286f736888ae7af8860b2c424af0d978848James Dong                // When both file size and duration limits are set,
38678a1a286f736888ae7af8860b2c424af0d978848James Dong                // we use the smaller limit of the two.
38778a1a286f736888ae7af8860b2c424af0d978848James Dong                if (size > size2) {
38878a1a286f736888ae7af8860b2c424af0d978848James Dong                    size = size2;
38978a1a286f736888ae7af8860b2c424af0d978848James Dong                }
39078a1a286f736888ae7af8860b2c424af0d978848James Dong            } else {
39178a1a286f736888ae7af8860b2c424af0d978848James Dong                // Only max file duration limit is set
39278a1a286f736888ae7af8860b2c424af0d978848James Dong                size = size2;
39378a1a286f736888ae7af8860b2c424af0d978848James Dong            }
3942dec2b5be2056c6d9428897dc672185872d30d17James Dong        }
3952dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
39678a1a286f736888ae7af8860b2c424af0d978848James Dong
3972dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (size < MIN_MOOV_BOX_SIZE) {
3982dec2b5be2056c6d9428897dc672185872d30d17James Dong        size = MIN_MOOV_BOX_SIZE;
3992dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
4002dec2b5be2056c6d9428897dc672185872d30d17James Dong
4012dec2b5be2056c6d9428897dc672185872d30d17James Dong    // Any long duration recording will be probably end up with
4022dec2b5be2056c6d9428897dc672185872d30d17James Dong    // non-streamable mp4 file.
4032dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (size > MAX_MOOV_BOX_SIZE) {
4042dec2b5be2056c6d9428897dc672185872d30d17James Dong        size = MAX_MOOV_BOX_SIZE;
4052dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
4062dec2b5be2056c6d9428897dc672185872d30d17James Dong
407a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    LOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated"
4082dec2b5be2056c6d9428897dc672185872d30d17James Dong         " moov size %lld bytes",
4092dec2b5be2056c6d9428897dc672185872d30d17James Dong         mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size);
4102dec2b5be2056c6d9428897dc672185872d30d17James Dong    return factor * size;
4112dec2b5be2056c6d9428897dc672185872d30d17James Dong}
4122dec2b5be2056c6d9428897dc672185872d30d17James Dong
4132dec2b5be2056c6d9428897dc672185872d30d17James Dongstatus_t MPEG4Writer::start(MetaData *param) {
414674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mInitCheck != OK) {
41525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        return UNKNOWN_ERROR;
41620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
41720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
418a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    /*
419a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * Check mMaxFileSizeLimitBytes at the beginning
420a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * since mMaxFileSizeLimitBytes may be implicitly
421a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * changed later for 32-bit file offset even if
422a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * user does not ask to set it explicitly.
423a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     */
424a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    if (mMaxFileSizeLimitBytes != 0) {
425a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong        mIsFileSizeLimitExplicitlyRequested = true;
426a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    }
427a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong
4282dec2b5be2056c6d9428897dc672185872d30d17James Dong    int32_t use64BitOffset;
4292dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (param &&
4302dec2b5be2056c6d9428897dc672185872d30d17James Dong        param->findInt32(kKey64BitFileOffset, &use64BitOffset) &&
4312dec2b5be2056c6d9428897dc672185872d30d17James Dong        use64BitOffset) {
4322dec2b5be2056c6d9428897dc672185872d30d17James Dong        mUse32BitOffset = false;
4332dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
4342dec2b5be2056c6d9428897dc672185872d30d17James Dong
4351f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    if (mUse32BitOffset) {
4361f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        // Implicit 32 bit file size limit
4371f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        if (mMaxFileSizeLimitBytes == 0) {
4381f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            mMaxFileSizeLimitBytes = kMax32BitFileSize;
4391f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        }
4401f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
4411f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        // If file size is set to be larger than the 32 bit file
4421f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        // size limit, treat it as an error.
4431f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        if (mMaxFileSizeLimitBytes > kMax32BitFileSize) {
444872a481558350634a3fd5cb67939de288af00ecbJames Dong            LOGW("32-bit file size limit (%lld bytes) too big. "
445d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong                 "It is changed to %lld bytes",
446d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong                mMaxFileSizeLimitBytes, kMax32BitFileSize);
447d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong            mMaxFileSizeLimitBytes = kMax32BitFileSize;
4481f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        }
4491f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    }
4501f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
451b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    int32_t use2ByteNalLength;
452b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    if (param &&
453b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) &&
454b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        use2ByteNalLength) {
455b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        mUse4ByteNalLength = false;
4562dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
4572dec2b5be2056c6d9428897dc672185872d30d17James Dong
458065d1aff96818df54456053f1574aec8a234d0deJames Dong    mStartTimestampUs = -1;
45993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
460a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (mStarted) {
461a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mPaused) {
462a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            mPaused = false;
46393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            return startTracks(param);
464a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
465a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return OK;
466a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
467a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
4688f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    if (!param ||
4698f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        !param->findInt32(kKeyTimeScale, &mTimeScale)) {
4708f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        mTimeScale = 1000;
4718f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    }
4728f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    CHECK(mTimeScale > 0);
4738f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    LOGV("movie time scale: %d", mTimeScale);
4748f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
4757837c17063a4c50bc856ba59418516fdab731de7James Dong    mStreamableFile = true;
4767837c17063a4c50bc856ba59418516fdab731de7James Dong    mWriteMoovBoxToMemory = false;
4777837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBuffer = NULL;
4787837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBufferOffset = 0;
4797837c17063a4c50bc856ba59418516fdab731de7James Dong
480b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeFtypBox(param);
48120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
4827837c17063a4c50bc856ba59418516fdab731de7James Dong    mFreeBoxOffset = mOffset;
48320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
4847837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mEstimatedMoovBoxSize == 0) {
4852dec2b5be2056c6d9428897dc672185872d30d17James Dong        int32_t bitRate = -1;
4862dec2b5be2056c6d9428897dc672185872d30d17James Dong        if (param) {
4872dec2b5be2056c6d9428897dc672185872d30d17James Dong            param->findInt32(kKeyBitRate, &bitRate);
4882dec2b5be2056c6d9428897dc672185872d30d17James Dong        }
4892dec2b5be2056c6d9428897dc672185872d30d17James Dong        mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate);
4907837c17063a4c50bc856ba59418516fdab731de7James Dong    }
4917837c17063a4c50bc856ba59418516fdab731de7James Dong    CHECK(mEstimatedMoovBoxSize >= 8);
492c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    lseek64(mFd, mFreeBoxOffset, SEEK_SET);
4937837c17063a4c50bc856ba59418516fdab731de7James Dong    writeInt32(mEstimatedMoovBoxSize);
4947837c17063a4c50bc856ba59418516fdab731de7James Dong    write("free", 4);
4957837c17063a4c50bc856ba59418516fdab731de7James Dong
4967837c17063a4c50bc856ba59418516fdab731de7James Dong    mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize;
4977837c17063a4c50bc856ba59418516fdab731de7James Dong    mOffset = mMdatOffset;
498c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    lseek64(mFd, mMdatOffset, SEEK_SET);
4991acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    if (mUse32BitOffset) {
5001acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        write("????mdat", 8);
5011acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    } else {
5021acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        write("\x00\x00\x00\x01mdat????????", 16);
5031acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    }
5041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
5051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    status_t err = startWriterThread();
5061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (err != OK) {
5071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        return err;
5081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
5091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
5101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    err = startTracks(param);
511a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (err != OK) {
512a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return err;
51320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
5141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
515a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mStarted = true;
51625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return OK;
51720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
51820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
5191f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongbool MPEG4Writer::use32BitFileOffset() const {
5201f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    return mUse32BitOffset;
5211f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
5221f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
52337187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::pause() {
524674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mInitCheck != OK) {
52537187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
526a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
527a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mPaused = true;
52837187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = OK;
529a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    for (List<Track *>::iterator it = mTracks.begin();
530a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong         it != mTracks.end(); ++it) {
53137187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = (*it)->pause();
53237187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (status != OK) {
53337187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
53437187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
535a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
53637187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
537a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
538a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
5391c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::stopWriterThread() {
540cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong    LOGD("Stopping writer thread");
5411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
5421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    {
5431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        Mutex::Autolock autolock(mLock);
5441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
5451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mDone = true;
5461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mChunkReadyCondition.signal();
5471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
5481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
5491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    void *dummy;
5501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_join(mThread, &dummy);
551cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong    LOGD("Writer thread stopped");
5521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
5531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
55413f6284305e4b27395a23db7882d670bdb1bcae1James Dong/*
55513f6284305e4b27395a23db7882d670bdb1bcae1James Dong * MP4 file standard defines a composition matrix:
55613f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | a  b  u |
55713f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | c  d  v |
55813f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | x  y  w |
55913f6284305e4b27395a23db7882d670bdb1bcae1James Dong *
56013f6284305e4b27395a23db7882d670bdb1bcae1James Dong * the element in the matrix is stored in the following
56113f6284305e4b27395a23db7882d670bdb1bcae1James Dong * order: {a, b, u, c, d, v, x, y, w},
56213f6284305e4b27395a23db7882d670bdb1bcae1James Dong * where a, b, c, d, x, and y is in 16.16 format, while
56313f6284305e4b27395a23db7882d670bdb1bcae1James Dong * u, v and w is in 2.30 format.
56413f6284305e4b27395a23db7882d670bdb1bcae1James Dong */
56513f6284305e4b27395a23db7882d670bdb1bcae1James Dongvoid MPEG4Writer::writeCompositionMatrix(int degrees) {
56613f6284305e4b27395a23db7882d670bdb1bcae1James Dong    LOGV("writeCompositionMatrix");
56713f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t a = 0x00010000;
56813f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t b = 0;
56913f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t c = 0;
57013f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t d = 0x00010000;
57113f6284305e4b27395a23db7882d670bdb1bcae1James Dong    switch (degrees) {
57213f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 0:
57313f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
57413f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 90:
57513f6284305e4b27395a23db7882d670bdb1bcae1James Dong            a = 0;
57613f6284305e4b27395a23db7882d670bdb1bcae1James Dong            b = 0x00010000;
57713f6284305e4b27395a23db7882d670bdb1bcae1James Dong            c = 0xFFFF0000;
57813f6284305e4b27395a23db7882d670bdb1bcae1James Dong            d = 0;
57913f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
58013f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 180:
58113f6284305e4b27395a23db7882d670bdb1bcae1James Dong            a = 0xFFFF0000;
58213f6284305e4b27395a23db7882d670bdb1bcae1James Dong            d = 0xFFFF0000;
58313f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
58413f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 270:
58513f6284305e4b27395a23db7882d670bdb1bcae1James Dong            a = 0;
58613f6284305e4b27395a23db7882d670bdb1bcae1James Dong            b = 0xFFFF0000;
58713f6284305e4b27395a23db7882d670bdb1bcae1James Dong            c = 0x00010000;
58813f6284305e4b27395a23db7882d670bdb1bcae1James Dong            d = 0;
58913f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
59013f6284305e4b27395a23db7882d670bdb1bcae1James Dong        default:
59113f6284305e4b27395a23db7882d670bdb1bcae1James Dong            CHECK(!"Should never reach this unknown rotation");
59213f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
59313f6284305e4b27395a23db7882d670bdb1bcae1James Dong    }
59413f6284305e4b27395a23db7882d670bdb1bcae1James Dong
59513f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(a);           // a
59613f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(b);           // b
59713f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // u
59813f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(c);           // c
59913f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(d);           // d
60013f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // v
60113f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // x
60213f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // y
60313f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0x40000000);  // w
60413f6284305e4b27395a23db7882d670bdb1bcae1James Dong}
60513f6284305e4b27395a23db7882d670bdb1bcae1James Dong
60613f6284305e4b27395a23db7882d670bdb1bcae1James Dong
60737187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::stop() {
608674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mInitCheck != OK) {
60937187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
61020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
61120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
61237187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = OK;
6138f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t maxDurationUs = 0;
61465b3d76025c71d755b0fb3b6ead90255f25417edJames Dong    int64_t minDurationUs = 0x7fffffffffffffffLL;
61520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    for (List<Track *>::iterator it = mTracks.begin();
61620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber         it != mTracks.end(); ++it) {
61737187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = (*it)->stop();
61837187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (err == OK && status != OK) {
61937187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
62037187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
62120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6228f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        int64_t durationUs = (*it)->getDurationUs();
6238f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        if (durationUs > maxDurationUs) {
6248f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            maxDurationUs = durationUs;
62520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
62665b3d76025c71d755b0fb3b6ead90255f25417edJames Dong        if (durationUs < minDurationUs) {
62765b3d76025c71d755b0fb3b6ead90255f25417edJames Dong            minDurationUs = durationUs;
62865b3d76025c71d755b0fb3b6ead90255f25417edJames Dong        }
62965b3d76025c71d755b0fb3b6ead90255f25417edJames Dong    }
63065b3d76025c71d755b0fb3b6ead90255f25417edJames Dong
63165b3d76025c71d755b0fb3b6ead90255f25417edJames Dong    if (mTracks.size() > 1) {
63265b3d76025c71d755b0fb3b6ead90255f25417edJames Dong        LOGD("Duration from tracks range is [%lld, %lld] us",
63365b3d76025c71d755b0fb3b6ead90255f25417edJames Dong            minDurationUs, maxDurationUs);
63420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
63520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    stopWriterThread();
6377837c17063a4c50bc856ba59418516fdab731de7James Dong
63837187916a486504acaf83bea30147eb5fbf46ae5James Dong    // Do not write out movie header on error.
63937187916a486504acaf83bea30147eb5fbf46ae5James Dong    if (err != OK) {
640674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        close(mFd);
641674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        mFd = -1;
642674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        mInitCheck = NO_INIT;
64337187916a486504acaf83bea30147eb5fbf46ae5James Dong        mStarted = false;
64437187916a486504acaf83bea30147eb5fbf46ae5James Dong        return err;
64537187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
64637187916a486504acaf83bea30147eb5fbf46ae5James Dong
64720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    // Fix up the size of the 'mdat' chunk.
6481acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    if (mUse32BitOffset) {
649c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mMdatOffset, SEEK_SET);
6501acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset));
651c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &size, 4);
6521acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    } else {
653c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mMdatOffset + 8, SEEK_SET);
6541acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        int64_t size = mOffset - mMdatOffset;
6551acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        size = hton64(size);
656c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &size, 8);
6571acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    }
658c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    lseek64(mFd, mOffset, SEEK_SET);
65920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
660c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    const off64_t moovOffset = mOffset;
6617837c17063a4c50bc856ba59418516fdab731de7James Dong    mWriteMoovBoxToMemory = true;
6627837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
6637837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBufferOffset = 0;
6647837c17063a4c50bc856ba59418516fdab731de7James Dong    CHECK(mMoovBoxBuffer != NULL);
665b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeMoovBox(maxDurationUs);
66620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6677837c17063a4c50bc856ba59418516fdab731de7James Dong    mWriteMoovBoxToMemory = false;
6687837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mStreamableFile) {
6697837c17063a4c50bc856ba59418516fdab731de7James Dong        CHECK(mMoovBoxBufferOffset + 8 <= mEstimatedMoovBoxSize);
6707837c17063a4c50bc856ba59418516fdab731de7James Dong
6717837c17063a4c50bc856ba59418516fdab731de7James Dong        // Moov box
672c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mFreeBoxOffset, SEEK_SET);
6737837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset = mFreeBoxOffset;
674674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset);
6757837c17063a4c50bc856ba59418516fdab731de7James Dong
6767837c17063a4c50bc856ba59418516fdab731de7James Dong        // Free box
677c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mOffset, SEEK_SET);
6787837c17063a4c50bc856ba59418516fdab731de7James Dong        writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset);
6797837c17063a4c50bc856ba59418516fdab731de7James Dong        write("free", 4);
6807837c17063a4c50bc856ba59418516fdab731de7James Dong
6817837c17063a4c50bc856ba59418516fdab731de7James Dong        // Free temp memory
6827837c17063a4c50bc856ba59418516fdab731de7James Dong        free(mMoovBoxBuffer);
6837837c17063a4c50bc856ba59418516fdab731de7James Dong        mMoovBoxBuffer = NULL;
6847837c17063a4c50bc856ba59418516fdab731de7James Dong        mMoovBoxBufferOffset = 0;
6852dec2b5be2056c6d9428897dc672185872d30d17James Dong    } else {
6862dec2b5be2056c6d9428897dc672185872d30d17James Dong        LOGI("The mp4 file will not be streamable.");
6877837c17063a4c50bc856ba59418516fdab731de7James Dong    }
6887837c17063a4c50bc856ba59418516fdab731de7James Dong
6890c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(mBoxes.empty());
69020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
691674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    close(mFd);
692674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    mFd = -1;
693674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    mInitCheck = NO_INIT;
694a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mStarted = false;
69570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
69637187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
69720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
69820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
699b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::writeMvhdBox(int64_t durationUs) {
700b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    time_t now = time(NULL);
701b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    beginBox("mvhd");
702b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // version=0, flags=0
703b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(now);           // creation time
704b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(now);           // modification time
705b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(mTimeScale);    // mvhd timescale
706b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t duration = (durationUs * mTimeScale + 5E5) / 1E6;
707b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(duration);
708b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0x10000);       // rate: 1.0
709b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt16(0x100);         // volume
710b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt16(0);             // reserved
711b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // reserved
712b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // reserved
713b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeCompositionMatrix(0); // matrix
714b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
715b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
716b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
717b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
718b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
719b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
720b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(mTracks.size() + 1);  // nextTrackID
721b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    endBox();  // mvhd
722b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
723b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
724b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::writeMoovBox(int64_t durationUs) {
725b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    beginBox("moov");
726b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeMvhdBox(durationUs);
727b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t id = 1;
728b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<Track *>::iterator it = mTracks.begin();
729b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mTracks.end(); ++it, ++id) {
730b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        (*it)->writeTrackHeader(mUse32BitOffset);
731b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
732b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    endBox();  // moov
733b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
734b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
7354650ff0e86f9e815e3152a806a06c700418d071dJames Dongvoid MPEG4Writer::writeFtypBox(const MetaData *param) {
736b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    beginBox("ftyp");
737b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
738b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t fileType;
739b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (param && param->findInt32(kKeyFileType, &fileType) &&
740b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fileType != OUTPUT_FORMAT_MPEG_4) {
741b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeFourcc("3gp4");
742b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
743b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeFourcc("isom");
744b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
745b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
746b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);
747b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeFourcc("isom");
748b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeFourcc("3gp4");
749b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    endBox();
750b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
751b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
75270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dongvoid MPEG4Writer::sendSessionSummary() {
75370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
75470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong         it != mChunkInfos.end(); ++it) {
75570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        int trackNum = it->mTrack->getTrackId() << 28;
75670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
75770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                trackNum | MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS,
75870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                it->mMaxInterChunkDurUs);
75970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    }
76070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong}
76170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
76213aec890216948b0c364f8f92792129d0335f506James Dongstatus_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) {
76313aec890216948b0c364f8f92792129d0335f506James Dong    mInterleaveDurationUs = durationUs;
76413aec890216948b0c364f8f92792129d0335f506James Dong    return OK;
76513aec890216948b0c364f8f92792129d0335f506James Dong}
76613aec890216948b0c364f8f92792129d0335f506James Dong
76713aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::lock() {
76813aec890216948b0c364f8f92792129d0335f506James Dong    mLock.lock();
76913aec890216948b0c364f8f92792129d0335f506James Dong}
77013aec890216948b0c364f8f92792129d0335f506James Dong
77113aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::unlock() {
77213aec890216948b0c364f8f92792129d0335f506James Dong    mLock.unlock();
77313aec890216948b0c364f8f92792129d0335f506James Dong}
77420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
775c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addSample_l(MediaBuffer *buffer) {
776c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t old_offset = mOffset;
77720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
778c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    ::write(mFd,
779c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong          (const uint8_t *)buffer->data() + buffer->range_offset(),
780c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong          buffer->range_length());
78120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
78220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mOffset += buffer->range_length();
78320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
78420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    return old_offset;
78520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
78620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
78703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) {
78803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (buffer->range_length() < 4) {
78903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return;
79003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
79103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
79203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    const uint8_t *ptr =
79303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        (const uint8_t *)buffer->data() + buffer->range_offset();
79403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
79503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
79603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        buffer->set_range(
79703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                buffer->range_offset() + 4, buffer->range_length() - 4);
79803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
79903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber}
80003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
801c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
802c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t old_offset = mOffset;
80330ab66297501757d745b9ae10da61adcd891f497Andreas Huber
80430ab66297501757d745b9ae10da61adcd891f497Andreas Huber    size_t length = buffer->range_length();
80503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
806b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    if (mUse4ByteNalLength) {
807b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        uint8_t x = length >> 24;
808c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
809b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = (length >> 16) & 0xff;
810c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
811b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = (length >> 8) & 0xff;
812c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
813b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = length & 0xff;
814c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
815c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong
816c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd,
817c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong              (const uint8_t *)buffer->data() + buffer->range_offset(),
818c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong              length);
819b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong
820b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        mOffset += length + 4;
821b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    } else {
822b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        CHECK(length < 65536);
82330ab66297501757d745b9ae10da61adcd891f497Andreas Huber
824b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        uint8_t x = length >> 8;
825c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
826b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = length & 0xff;
827c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
828c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length);
829b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        mOffset += length + 2;
830b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    }
83130ab66297501757d745b9ae10da61adcd891f497Andreas Huber
83230ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return old_offset;
83330ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
83430ab66297501757d745b9ae10da61adcd891f497Andreas Huber
8357837c17063a4c50bc856ba59418516fdab731de7James Dongsize_t MPEG4Writer::write(
836674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        const void *ptr, size_t size, size_t nmemb) {
8377837c17063a4c50bc856ba59418516fdab731de7James Dong
8387837c17063a4c50bc856ba59418516fdab731de7James Dong    const size_t bytes = size * nmemb;
8397837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mWriteMoovBoxToMemory) {
840674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        // This happens only when we write the moov box at the end of
841674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        // recording, not for each output video/audio frame we receive.
842c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        off64_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes;
8431acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        if (moovBoxSize > mEstimatedMoovBoxSize) {
844c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong            for (List<off64_t>::iterator it = mBoxes.begin();
8457837c17063a4c50bc856ba59418516fdab731de7James Dong                 it != mBoxes.end(); ++it) {
8467837c17063a4c50bc856ba59418516fdab731de7James Dong                (*it) += mOffset;
8477837c17063a4c50bc856ba59418516fdab731de7James Dong            }
848674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong            lseek64(mFd, mOffset, SEEK_SET);
849674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong            ::write(mFd, mMoovBoxBuffer, mMoovBoxBufferOffset);
850674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong            ::write(mFd, ptr, size * nmemb);
8517837c17063a4c50bc856ba59418516fdab731de7James Dong            mOffset += (bytes + mMoovBoxBufferOffset);
8527837c17063a4c50bc856ba59418516fdab731de7James Dong            free(mMoovBoxBuffer);
8537837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBuffer = NULL;
8547837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBufferOffset = 0;
8557837c17063a4c50bc856ba59418516fdab731de7James Dong            mWriteMoovBoxToMemory = false;
8567837c17063a4c50bc856ba59418516fdab731de7James Dong            mStreamableFile = false;
8577837c17063a4c50bc856ba59418516fdab731de7James Dong        } else {
8587837c17063a4c50bc856ba59418516fdab731de7James Dong            memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes);
8597837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBufferOffset += bytes;
8607837c17063a4c50bc856ba59418516fdab731de7James Dong        }
8617837c17063a4c50bc856ba59418516fdab731de7James Dong    } else {
862674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        ::write(mFd, ptr, size * nmemb);
8637837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset += bytes;
8647837c17063a4c50bc856ba59418516fdab731de7James Dong    }
8657837c17063a4c50bc856ba59418516fdab731de7James Dong    return bytes;
8667837c17063a4c50bc856ba59418516fdab731de7James Dong}
8677837c17063a4c50bc856ba59418516fdab731de7James Dong
86820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) {
8690c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK_EQ(strlen(fourcc), 4);
87020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
8717837c17063a4c50bc856ba59418516fdab731de7James Dong    mBoxes.push_back(mWriteMoovBoxToMemory?
8727837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBufferOffset: mOffset);
87320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
87420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    writeInt32(0);
87520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    writeFourcc(fourcc);
87620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
87720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
87820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() {
8790c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(!mBoxes.empty());
88020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
881c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t offset = *--mBoxes.end();
88220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mBoxes.erase(--mBoxes.end());
88320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
8847837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mWriteMoovBoxToMemory) {
8857837c17063a4c50bc856ba59418516fdab731de7James Dong       int32_t x = htonl(mMoovBoxBufferOffset - offset);
8867837c17063a4c50bc856ba59418516fdab731de7James Dong       memcpy(mMoovBoxBuffer + offset, &x, 4);
8877837c17063a4c50bc856ba59418516fdab731de7James Dong    } else {
888c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, offset, SEEK_SET);
8897837c17063a4c50bc856ba59418516fdab731de7James Dong        writeInt32(mOffset - offset);
8907837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset -= 4;
891c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mOffset, SEEK_SET);
8927837c17063a4c50bc856ba59418516fdab731de7James Dong    }
89320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
89420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
89520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) {
896674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 1);
89720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
89820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
89920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) {
90020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = htons(x);
901674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 2);
90220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
90320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
90420111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) {
90520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = htonl(x);
906674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 4);
90720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
90820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
90920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) {
91020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = hton64(x);
911674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 8);
91220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
91320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
91420111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) {
91520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    size_t n = strlen(s);
916674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(s, 1, n + 1);
91720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
91820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
91920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) {
9200c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK_EQ(strlen(s), 4);
921674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(s, 1, 4);
92220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
92320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
92420111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) {
925674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(data, 1, size);
92620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
92720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
92878a1a286f736888ae7af8860b2c424af0d978848James Dongbool MPEG4Writer::isFileStreamable() const {
92978a1a286f736888ae7af8860b2c424af0d978848James Dong    return mStreamableFile;
93078a1a286f736888ae7af8860b2c424af0d978848James Dong}
93178a1a286f736888ae7af8860b2c424af0d978848James Dong
932d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileSizeLimit() {
933d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    // No limit
934d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    if (mMaxFileSizeLimitBytes == 0) {
935d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        return false;
936d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
937d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
938956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize);
939d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    for (List<Track *>::iterator it = mTracks.begin();
940d599cd4573b5a2d5914c5040e0565ef866749b77James Dong         it != mTracks.end(); ++it) {
941d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
942d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
9431f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
944acd234bba9f048971d66890009eeff9a8db94be3James Dong    // Be conservative in the estimate: do not exceed 95% of
945acd234bba9f048971d66890009eeff9a8db94be3James Dong    // the target file limit. For small target file size limit, though,
946acd234bba9f048971d66890009eeff9a8db94be3James Dong    // this will not help.
947acd234bba9f048971d66890009eeff9a8db94be3James Dong    return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100);
948d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
949d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
950d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileDurationLimit() {
951d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    // No limit
952d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    if (mMaxFileDurationLimitUs == 0) {
953d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        return false;
954d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
955d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
956d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    for (List<Track *>::iterator it = mTracks.begin();
957d599cd4573b5a2d5914c5040e0565ef866749b77James Dong         it != mTracks.end(); ++it) {
958d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) {
959d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            return true;
960d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
961d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
962d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    return false;
963d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
964d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
96525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() {
96625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool allDone = true;
96725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    for (List<Track *>::iterator it = mTracks.begin();
96825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber         it != mTracks.end(); ++it) {
96925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        if (!(*it)->reachedEOS()) {
97025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber            allDone = false;
97125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber            break;
97225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        }
97325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    }
97425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
97525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return allDone;
97625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber}
97725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
978f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongvoid MPEG4Writer::setStartTimestampUs(int64_t timeUs) {
979f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    LOGI("setStartTimestampUs: %lld", timeUs);
980f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    CHECK(timeUs >= 0);
9813c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    Mutex::Autolock autoLock(mLock);
982065d1aff96818df54456053f1574aec8a234d0deJames Dong    if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) {
983f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong        mStartTimestampUs = timeUs;
984f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong        LOGI("Earliest track starting time: %lld", mStartTimestampUs);
9853c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    }
9863c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong}
9873c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong
988f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongint64_t MPEG4Writer::getStartTimestampUs() {
9893c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    Mutex::Autolock autoLock(mLock);
9903c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    return mStartTimestampUs;
9913c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong}
9923c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong
99358ae9c530247668f8af36e30d228c716c226b3d4James Dongsize_t MPEG4Writer::numTracks() {
99458ae9c530247668f8af36e30d228c716c226b3d4James Dong    Mutex::Autolock autolock(mLock);
99558ae9c530247668f8af36e30d228c716c226b3d4James Dong    return mTracks.size();
99658ae9c530247668f8af36e30d228c716c226b3d4James Dong}
99758ae9c530247668f8af36e30d228c716c226b3d4James Dong
99820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber////////////////////////////////////////////////////////////////////////////////
99920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
100020111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track(
1001bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId)
100220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    : mOwner(owner),
100325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber      mMeta(source->getFormat()),
100420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mSource(source),
100520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mDone(false),
1006a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
1007a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mResumed(false),
1008eaae38445a340c4857c1c5569475879a728e63b7James Dong      mStarted(false),
1009bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong      mTrackId(trackId),
1010c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong      mTrackDurationUs(0),
1011956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      mEstimatedTrackSizeBytes(0),
1012be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong      mSamplesHaveSameSize(true),
101320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mCodecSpecificData(NULL),
101425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber      mCodecSpecificDataSize(0),
1015548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber      mGotAllCodecSpecificData(false),
101613f6284305e4b27395a23db7882d670bdb1bcae1James Dong      mReachedEOS(false),
101713f6284305e4b27395a23db7882d670bdb1bcae1James Dong      mRotation(0) {
101819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    getCodecSpecificDataFromInputFormatIfPossible();
10198f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
10201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    const char *mime;
10211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mMeta->findCString(kKeyMIMEType, &mime);
10221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
10231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsAudio = !strncasecmp(mime, "audio/", 6);
10241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
10251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong               !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
10261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1027c059860c73678a202bfa33062723e8f82fb779d9James Dong    setTimeScale();
1028c059860c73678a202bfa33062723e8f82fb779d9James Dong}
1029c059860c73678a202bfa33062723e8f82fb779d9James Dong
10301f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::updateTrackSizeEstimate() {
10311f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
10321f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    int64_t stcoBoxSizeBytes = mOwner->use32BitFileOffset()
10331f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                                ? mNumStcoTableEntries * 4
10341f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                                : mNumStcoTableEntries * 8;
10351f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
10361f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mNumSamples * 4);
10371f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
103878a1a286f736888ae7af8860b2c424af0d978848James Dong    mEstimatedTrackSizeBytes = mMdatSizeBytes;  // media data size
103978a1a286f736888ae7af8860b2c424af0d978848James Dong    if (!mOwner->isFileStreamable()) {
104078a1a286f736888ae7af8860b2c424af0d978848James Dong        // Reserved free space is not large enough to hold
104178a1a286f736888ae7af8860b2c424af0d978848James Dong        // all meta data and thus wasted.
104278a1a286f736888ae7af8860b2c424af0d978848James Dong        mEstimatedTrackSizeBytes += mNumStscTableEntries * 12 +  // stsc box size
104378a1a286f736888ae7af8860b2c424af0d978848James Dong                                    mNumStssTableEntries * 4 +   // stss box size
104478a1a286f736888ae7af8860b2c424af0d978848James Dong                                    mNumSttsTableEntries * 8 +   // stts box size
104578a1a286f736888ae7af8860b2c424af0d978848James Dong                                    stcoBoxSizeBytes +           // stco box size
104678a1a286f736888ae7af8860b2c424af0d978848James Dong                                    stszBoxSizeBytes;            // stsz box size
104778a1a286f736888ae7af8860b2c424af0d978848James Dong    }
10481f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
10491f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
10501f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStscTableEntry(
10511f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        size_t chunkId, size_t sampleId) {
10521f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
10531f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        StscTableEntry stscEntry(chunkId, sampleId, 1);
10541f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        mStscTableEntries.push_back(stscEntry);
10551f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        ++mNumStscTableEntries;
10561f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
10571f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
10581f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) {
10591f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mStssTableEntries.push_back(sampleId);
10601f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    ++mNumStssTableEntries;
10611f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
10621f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
10631f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneSttsTableEntry(
10641f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        size_t sampleCount, int64_t durationUs) {
10651f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
10661f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    SttsTableEntry sttsEntry(sampleCount, durationUs);
10671f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mSttsTableEntries.push_back(sttsEntry);
10681f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    ++mNumSttsTableEntries;
10691f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
10701f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1071c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongvoid MPEG4Writer::Track::addChunkOffset(off64_t offset) {
10721f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    ++mNumStcoTableEntries;
10731f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mChunkOffsets.push_back(offset);
10741f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
10751f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1076c059860c73678a202bfa33062723e8f82fb779d9James Dongvoid MPEG4Writer::Track::setTimeScale() {
1077c059860c73678a202bfa33062723e8f82fb779d9James Dong    LOGV("setTimeScale");
1078c059860c73678a202bfa33062723e8f82fb779d9James Dong    // Default time scale
1079c059860c73678a202bfa33062723e8f82fb779d9James Dong    mTimeScale = 90000;
1080c059860c73678a202bfa33062723e8f82fb779d9James Dong
1081c059860c73678a202bfa33062723e8f82fb779d9James Dong    if (mIsAudio) {
1082c059860c73678a202bfa33062723e8f82fb779d9James Dong        // Use the sampling rate as the default time scale for audio track.
1083c059860c73678a202bfa33062723e8f82fb779d9James Dong        int32_t sampleRate;
1084c059860c73678a202bfa33062723e8f82fb779d9James Dong        bool success = mMeta->findInt32(kKeySampleRate, &sampleRate);
1085c059860c73678a202bfa33062723e8f82fb779d9James Dong        CHECK(success);
1086c059860c73678a202bfa33062723e8f82fb779d9James Dong        mTimeScale = sampleRate;
1087c059860c73678a202bfa33062723e8f82fb779d9James Dong    }
1088c059860c73678a202bfa33062723e8f82fb779d9James Dong
1089c059860c73678a202bfa33062723e8f82fb779d9James Dong    // If someone would like to overwrite the timescale, use user-supplied value.
1090c059860c73678a202bfa33062723e8f82fb779d9James Dong    int32_t timeScale;
1091c059860c73678a202bfa33062723e8f82fb779d9James Dong    if (mMeta->findInt32(kKeyTimeScale, &timeScale)) {
1092c059860c73678a202bfa33062723e8f82fb779d9James Dong        mTimeScale = timeScale;
1093c059860c73678a202bfa33062723e8f82fb779d9James Dong    }
1094c059860c73678a202bfa33062723e8f82fb779d9James Dong
10958f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    CHECK(mTimeScale > 0);
109619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber}
109719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
109819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Hubervoid MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
109919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    const char *mime;
110019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
110119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
110219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
110319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        uint32_t type;
110419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        const void *data;
110519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        size_t size;
110619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        if (mMeta->findData(kKeyAVCC, &type, &data, &size)) {
110719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mCodecSpecificData = malloc(size);
110819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mCodecSpecificDataSize = size;
110919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            memcpy(mCodecSpecificData, data, size);
111019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mGotAllCodecSpecificData = true;
111119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        }
111219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
111319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
111419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        uint32_t type;
111519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        const void *data;
111619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        size_t size;
111719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
111819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            ESDS esds(data, size);
111919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            if (esds.getCodecSpecificInfo(&data, &size) == OK) {
112019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mCodecSpecificData = malloc(size);
112119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mCodecSpecificDataSize = size;
112219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                memcpy(mCodecSpecificData, data, size);
112319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mGotAllCodecSpecificData = true;
112419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            }
112519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        }
112619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    }
112720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
112820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
112920111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() {
113020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    stop();
113120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
113220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mCodecSpecificData != NULL) {
113320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        free(mCodecSpecificData);
113420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mCodecSpecificData = NULL;
113520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
113620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
113720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
113893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongvoid MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) {
113993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    LOGV("initTrackingProgressStatus");
114093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mPreviousTrackTimeUs = -1;
114193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mTrackingProgressStatus = false;
114293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mTrackEveryTimeDurationUs = 0;
114393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    {
114493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        int64_t timeUs;
114593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) {
114693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            LOGV("Receive request to track progress status for every %lld us", timeUs);
114793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            mTrackEveryTimeDurationUs = timeUs;
114893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            mTrackingProgressStatus = true;
114993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        }
115093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    }
115193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong}
115293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
11531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong// static
11541c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid *MPEG4Writer::ThreadWrapper(void *me) {
11551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("ThreadWrapper: %p", me);
11561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    MPEG4Writer *writer = static_cast<MPEG4Writer *>(me);
11571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    writer->threadFunc();
11581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    return NULL;
11591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
11601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
11611c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::bufferChunk(const Chunk& chunk) {
11621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("bufferChunk: %p", chunk.mTrack);
11631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Mutex::Autolock autolock(mLock);
11641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    CHECK_EQ(mDone, false);
11651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
11661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
11671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
11681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
11691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (chunk.mTrack == it->mTrack) {  // Found owner
11701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            it->mChunks.push_back(chunk);
11711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            mChunkReadyCondition.signal();
11721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            return;
11731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
11741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
11751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
11761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    CHECK("Received a chunk for a unknown track" == 0);
11771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
11781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1179fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeChunkToFile(Chunk* chunk) {
1180fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    LOGV("writeChunkToFile: %lld from %s track",
1181fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        chunk.mTimestampUs, chunk.mTrack->isAudio()? "audio": "video");
1182fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1183fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    int32_t isFirstSample = true;
1184fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    while (!chunk->mSamples.empty()) {
1185fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        List<MediaBuffer *>::iterator it = chunk->mSamples.begin();
1186fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1187fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        off64_t offset = chunk->mTrack->isAvc()
1188fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong                                ? addLengthPrefixedSample_l(*it)
1189fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong                                : addSample_l(*it);
1190fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1191fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        if (isFirstSample) {
1192fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            chunk->mTrack->addChunkOffset(offset);
1193fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            isFirstSample = false;
11941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
11951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
11961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        (*it)->release();
11971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        (*it) = NULL;
1198fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        chunk->mSamples.erase(it);
11991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1200fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    chunk->mSamples.clear();
12011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
12021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1203fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeAllChunks() {
1204fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    LOGV("writeAllChunks");
12051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    size_t outstandingChunks = 0;
120670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    Chunk chunk;
120770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    while (findChunkToWrite(&chunk)) {
120870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        ++outstandingChunks;
12091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
121070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
121170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    sendSessionSummary();
121270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
12131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mChunkInfos.clear();
12141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGD("%d chunks are written in the last batch", outstandingChunks);
12151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
12161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1217fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongbool MPEG4Writer::findChunkToWrite(Chunk *chunk) {
1218fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    LOGV("findChunkToWrite");
12191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
12201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL;
12211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Track *track = NULL;
12221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
12231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
12241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (!it->mChunks.empty()) {
12251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            List<Chunk>::iterator chunkIt = it->mChunks.begin();
12261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            if (chunkIt->mTimeStampUs < minTimestampUs) {
12271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                minTimestampUs = chunkIt->mTimeStampUs;
12281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                track = it->mTrack;
12291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            }
12301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
12311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
12321c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
12331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (track == NULL) {
12341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        LOGV("Nothing to be written after all");
1235fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        return false;
12361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
12371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
12381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (mIsFirstChunk) {
12391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mIsFirstChunk = false;
12401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1241fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
12421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
12431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
12441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (it->mTrack == track) {
1245fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            *chunk = *(it->mChunks.begin());
1246fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            it->mChunks.erase(it->mChunks.begin());
1247fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            CHECK_EQ(chunk->mTrack, track);
124870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
124970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            int64_t interChunkTimeUs =
125070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                chunk->mTimeStampUs - it->mPrevChunkTimestampUs;
125170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            if (interChunkTimeUs > it->mPrevChunkTimestampUs) {
125270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                it->mMaxInterChunkDurUs = interChunkTimeUs;
125370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            }
125470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
1255fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            return true;
12561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
12571c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1258fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1259fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    return false;
12601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
12611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
12621c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::threadFunc() {
12631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("threadFunc");
12641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1265a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0);
1266fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1267fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    Mutex::Autolock autoLock(mLock);
12681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    while (!mDone) {
1269fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        Chunk chunk;
1270fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        bool chunkFound = false;
1271fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1272fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) {
12731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            mChunkReadyCondition.wait(mLock);
12741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
12751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1276fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        // Actual write without holding the lock in order to
1277fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        // reduce the blocking time for media track threads.
1278fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        if (chunkFound) {
1279fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            mLock.unlock();
1280fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            writeChunkToFile(&chunk);
1281fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            mLock.lock();
1282fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        }
12831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1284fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1285fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    writeAllChunks();
12861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
12871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
12881c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::startWriterThread() {
12891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("startWriterThread");
12901c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
12911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mDone = false;
12921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsFirstChunk = true;
1293e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    mDriftTimeUs = 0;
12941c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<Track *>::iterator it = mTracks.begin();
12951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mTracks.end(); ++it) {
12961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        ChunkInfo info;
12971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        info.mTrack = *it;
129870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        info.mPrevChunkTimestampUs = 0;
129970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        info.mMaxInterChunkDurUs = 0;
13001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mChunkInfos.push_back(info);
13011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
13021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
13031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_t attr;
13041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_init(&attr);
13051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
13061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_create(&mThread, &attr, ThreadWrapper, this);
13071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_destroy(&attr);
13081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    return OK;
13091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
13101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
13111f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
131293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::Track::start(MetaData *params) {
1313a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (!mDone && mPaused) {
1314a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        mPaused = false;
1315a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        mResumed = true;
1316a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return OK;
1317a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
131825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
131993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t startTimeUs;
132019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) {
132119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        startTimeUs = 0;
132219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    }
132370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    mStartTimeRealUs = startTimeUs;
132419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
132513f6284305e4b27395a23db7882d670bdb1bcae1James Dong    int32_t rotationDegrees;
132613f6284305e4b27395a23db7882d670bdb1bcae1James Dong    if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) {
132713f6284305e4b27395a23db7882d670bdb1bcae1James Dong        mRotation = rotationDegrees;
132813f6284305e4b27395a23db7882d670bdb1bcae1James Dong    }
132913f6284305e4b27395a23db7882d670bdb1bcae1James Dong
13305b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong    mIsRealTimeRecording = true;
1331e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    {
1332e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        int32_t isNotRealTime;
1333e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) {
1334e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            mIsRealTimeRecording = (isNotRealTime == 0);
1335e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        }
1336e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    }
1337e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
133893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    initTrackingProgressStatus(params);
133993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
1340f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    sp<MetaData> meta = new MetaData;
1341a472613aec322e25891abf5c77bf3f7e3c244920James Dong    if (mIsRealTimeRecording && mOwner->numTracks() > 1) {
1342a472613aec322e25891abf5c77bf3f7e3c244920James Dong        /*
1343a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * This extra delay of accepting incoming audio/video signals
1344a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * helps to align a/v start time at the beginning of a recording
1345a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * session, and it also helps eliminate the "recording" sound for
1346a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * camcorder applications.
1347a472613aec322e25891abf5c77bf3f7e3c244920James Dong         *
1348a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * Ideally, this platform-specific value should be defined
1349a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * in media_profiles.xml file
1350a472613aec322e25891abf5c77bf3f7e3c244920James Dong         */
135170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        startTimeUs += kInitialDelayTimeUs;
1352a472613aec322e25891abf5c77bf3f7e3c244920James Dong    }
1353a472613aec322e25891abf5c77bf3f7e3c244920James Dong
1354f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    meta->setInt64(kKeyTime, startTimeUs);
1355a472613aec322e25891abf5c77bf3f7e3c244920James Dong
1356f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    status_t err = mSource->start(meta.get());
135725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    if (err != OK) {
135825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        mDone = mReachedEOS = true;
135925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        return err;
136025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    }
136120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
136220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_t attr;
136320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_init(&attr);
136420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
136520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
136620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mDone = false;
1367eaae38445a340c4857c1c5569475879a728e63b7James Dong    mStarted = true;
1368c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    mTrackDurationUs = 0;
136925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    mReachedEOS = false;
1370956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    mEstimatedTrackSizeBytes = 0;
13711f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mNumStcoTableEntries = 0;
13721f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mNumStssTableEntries = 0;
13731f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mNumStscTableEntries = 0;
13741f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mNumSttsTableEntries = 0;
13751f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mMdatSizeBytes = 0;
1376872a481558350634a3fd5cb67939de288af00ecbJames Dong    mIsMediaTimeAdjustmentOn = false;
1377872a481558350634a3fd5cb67939de288af00ecbJames Dong    mPrevMediaTimeAdjustTimestampUs = 0;
1378872a481558350634a3fd5cb67939de288af00ecbJames Dong    mMediaTimeAdjustNumFrames = 0;
1379872a481558350634a3fd5cb67939de288af00ecbJames Dong    mPrevMediaTimeAdjustSample = 0;
1380872a481558350634a3fd5cb67939de288af00ecbJames Dong    mTotalDriftTimeToAdjustUs = 0;
1381872a481558350634a3fd5cb67939de288af00ecbJames Dong    mPrevTotalAccumDriftTimeUs = 0;
138243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mMaxChunkDurationUs = 0;
138320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
138425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    pthread_create(&mThread, &attr, ThreadWrapper, this);
138520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_destroy(&attr);
138625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
138725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return OK;
138820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
138920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
139037187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::pause() {
1391a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mPaused = true;
139237187916a486504acaf83bea30147eb5fbf46ae5James Dong    return OK;
1393a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
1394a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
139537187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::stop() {
1396cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong    LOGD("Stopping %s track", mIsAudio? "Audio": "Video");
1397eaae38445a340c4857c1c5569475879a728e63b7James Dong    if (!mStarted) {
1398eaae38445a340c4857c1c5569475879a728e63b7James Dong        LOGE("Stop() called but track is not started");
1399eaae38445a340c4857c1c5569475879a728e63b7James Dong        return ERROR_END_OF_STREAM;
1400eaae38445a340c4857c1c5569475879a728e63b7James Dong    }
1401eaae38445a340c4857c1c5569475879a728e63b7James Dong
140220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mDone) {
140337187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
140420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
140520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mDone = true;
140620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
140720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    void *dummy;
140820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_join(mThread, &dummy);
140920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
141037187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = (status_t) dummy;
141137187916a486504acaf83bea30147eb5fbf46ae5James Dong
1412cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong    LOGD("Stopping %s track source", mIsAudio? "Audio": "Video");
141337187916a486504acaf83bea30147eb5fbf46ae5James Dong    {
141437187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = mSource->stop();
141537187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (err == OK && status != OK && status != ERROR_END_OF_STREAM) {
141637187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
141737187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
141837187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
141937187916a486504acaf83bea30147eb5fbf46ae5James Dong
1420cb09c03450bb09304ad5afd2d223254bf2e6e38cJames Dong    LOGD("%s track stopped", mIsAudio? "Audio": "Video");
142137187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
142220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
142320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
142425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() {
142525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return mReachedEOS;
142625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber}
142725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
142820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static
142920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) {
143020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track *track = static_cast<Track *>(me);
143120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
143237187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = track->threadEntry();
143337187916a486504acaf83bea30147eb5fbf46ae5James Dong    return (void *) err;
143420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
143520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
14363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic void getNalUnitType(uint8_t byte, uint8_t* type) {
14373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("getNalUnitType: %d", byte);
14383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // nal_unit_type: 5-bit unsigned integer
14403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    *type = (byte & 0x1F);
14413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
14423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t *findNextStartCode(
14443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length) {
14453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("findNextStartCode: %p %d", data, length);
14473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t bytesLeft = length;
14493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    while (bytesLeft > 4  &&
14503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) {
14513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        --bytesLeft;
14523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
14533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (bytesLeft <= 4) {
14543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        bytesLeft = 0; // Last parameter set
14553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
14563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return &data[length - bytesLeft];
14573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
14583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongconst uint8_t *MPEG4Writer::Track::parseParamSet(
14603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length, int type, size_t *paramSetLen) {
14613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("parseParamSet");
14633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    CHECK(type == kNalUnitTypeSeqParamSet ||
14643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong          type == kNalUnitTypePicParamSet);
14653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *nextStartCode = findNextStartCode(data, length);
14673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    *paramSetLen = nextStartCode - data;
14683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (*paramSetLen == 0) {
14693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        LOGE("Param set is malformed, since its length is 0");
14703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return NULL;
14713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
14723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    AVCParamSet paramSet(*paramSetLen, data);
14743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (type == kNalUnitTypeSeqParamSet) {
14753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (*paramSetLen < 4) {
14763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Seq parameter set malformed");
14773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return NULL;
14783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
14793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (mSeqParamSets.empty()) {
14803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileIdc = data[1];
14813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileCompatible = data[2];
14823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mLevelIdc = data[3];
14833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else {
14843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (mProfileIdc != data[1] ||
14853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                mProfileCompatible != data[2] ||
14863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                mLevelIdc != data[3]) {
14873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                LOGE("Inconsistent profile/level found in seq parameter sets");
14883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return NULL;
14893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
14903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
14913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mSeqParamSets.push_back(paramSet);
14923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    } else {
14933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mPicParamSets.push_back(paramSet);
14943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
14953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return nextStartCode;
14963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
14973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
14983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::copyAVCCodecSpecificData(
14993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t size) {
15003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("copyAVCCodecSpecificData");
15013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 2 bytes for each of the parameter set length field
15033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // plus the 7 bytes for the header
15043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (size < 4 + 7) {
15053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        LOGE("Codec specific data length too short: %d", size);
15063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return ERROR_MALFORMED;
15073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
15083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize = size;
15103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificData = malloc(size);
15113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    memcpy(mCodecSpecificData, data, size);
15123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return OK;
15133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
15143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::parseAVCCodecSpecificData(
15163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t size) {
15173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    LOGV("parseAVCCodecSpecificData");
15193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Data starts with a start code.
15203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // SPS and PPS are separated with start codes.
15213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Also, SPS must come before PPS
15223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t type = kNalUnitTypeSeqParamSet;
15233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    bool gotSps = false;
15243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    bool gotPps = false;
15253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *tmp = data;
15263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *nextStartCode = data;
15273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t bytesLeft = size;
15283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t paramSetLen = 0;
15293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize = 0;
15303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) {
15313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        getNalUnitType(*(tmp + 4), &type);
15323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (type == kNalUnitTypeSeqParamSet) {
15333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (gotPps) {
15343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                LOGE("SPS must come before PPS");
15353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return ERROR_MALFORMED;
15363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
15373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotSps) {
15383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                gotSps = true;
15393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
15403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
15413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else if (type == kNalUnitTypePicParamSet) {
15423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotSps) {
15433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                LOGE("SPS must come before PPS");
15443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return ERROR_MALFORMED;
15453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
15463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotPps) {
15473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                gotPps = true;
15483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
15493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
15503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else {
15513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Only SPS and PPS Nal units are expected");
15523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
15533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
15543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nextStartCode == NULL) {
15563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
15573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
15583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Move on to find the next parameter set
15603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        bytesLeft -= nextStartCode - tmp;
15613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        tmp = nextStartCode;
15623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mCodecSpecificDataSize += (2 + paramSetLen);
15633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
15643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
15663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the number of seq parameter sets
15673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        size_t nSeqParamSets = mSeqParamSets.size();
15683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nSeqParamSets == 0) {
15693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Cound not find sequence parameter set");
15703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
15713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
15723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nSeqParamSets > 0x1F) {
15743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Too many seq parameter sets (%d) found", nSeqParamSets);
15753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
15763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
15773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
15783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
15803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the number of pic parameter sets
15813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        size_t nPicParamSets = mPicParamSets.size();
15823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nPicParamSets == 0) {
15833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Cound not find picture parameter set");
15843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
15853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
15863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nPicParamSets > 0xFF) {
15873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Too many pic parameter sets (%d) found", nPicParamSets);
15883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
15893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
15903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
15913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
15933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the profiles
15943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // These profiles requires additional parameter set extensions
15953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (mProfileIdc == 100 || mProfileIdc == 110 ||
15963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileIdc == 122 || mProfileIdc == 144) {
15973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            LOGE("Sorry, no support for profile_idc: %d!", mProfileIdc);
15983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return BAD_VALUE;
15993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
16003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
16013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return OK;
16033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
1604548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
160503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData(
160603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        const uint8_t *data, size_t size) {
1607548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
160803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (mCodecSpecificData != NULL) {
1609548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber        LOGE("Already have codec specific data");
161003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
161103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
161203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
16133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (size < 4) {
16143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        LOGE("Codec specific data length too short: %d", size);
161503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
161603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
161703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
16183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Data is in the form of AVCCodecSpecificData
16193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (memcmp("\x00\x00\x00\x01", data, 4)) {
16203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return copyAVCCodecSpecificData(data, size);
162103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
162203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
16233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (parseAVCCodecSpecificData(data, size) != OK) {
162403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
162503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
162603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
16273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // ISO 14496-15: AVC file format
16283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize += 7;  // 7 more bytes in the header
162903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    mCodecSpecificData = malloc(mCodecSpecificDataSize);
163003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    uint8_t *header = (uint8_t *)mCodecSpecificData;
16313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[0] = 1;                     // version
16323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[1] = mProfileIdc;           // profile indication
16333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[2] = mProfileCompatible;    // profile compatibility
16343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[3] = mLevelIdc;
163503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
16363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne
1637b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    if (mOwner->useNalLengthFour()) {
1638b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        header[4] = 0xfc | 3;  // length size == 4 bytes
1639b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    } else {
1640b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        header[4] = 0xfc | 1;  // length size == 2 bytes
1641b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    }
164203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
16433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 3-bit '111' followed by 5-bit numSequenceParameterSets
16443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    int nSequenceParamSets = mSeqParamSets.size();
16453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[5] = 0xe0 | nSequenceParamSets;
16463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header += 6;
16473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    for (List<AVCParamSet>::iterator it = mSeqParamSets.begin();
16483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong         it != mSeqParamSets.end(); ++it) {
16493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // 16-bit sequence parameter set length
16503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t seqParamSetLength = it->mLength;
16513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[0] = seqParamSetLength >> 8;
16523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[1] = seqParamSetLength & 0xff;
16533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // SPS NAL unit (sequence parameter length bytes)
16553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        memcpy(&header[2], it->mData, seqParamSetLength);
16563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header += (2 + seqParamSetLength);
16573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
16583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 8-bit nPictureParameterSets
16603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    int nPictureParamSets = mPicParamSets.size();
16613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[0] = nPictureParamSets;
16623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header += 1;
16633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    for (List<AVCParamSet>::iterator it = mPicParamSets.begin();
16643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong         it != mPicParamSets.end(); ++it) {
16653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // 16-bit picture parameter set length
16663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t picParamSetLength = it->mLength;
16673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[0] = picParamSetLength >> 8;
16683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[1] = picParamSetLength & 0xff;
16693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // PPS Nal unit (picture parameter set length bytes)
16713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        memcpy(&header[2], it->mData, picParamSetLength);
16723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header += (2 + picParamSetLength);
16733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
167403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
167503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    return OK;
167603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber}
167703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
1678872a481558350634a3fd5cb67939de288af00ecbJames Dong/*
1679872a481558350634a3fd5cb67939de288af00ecbJames Dong* The video track's media time adjustment for real-time applications
1680872a481558350634a3fd5cb67939de288af00ecbJames Dong* is described as follows:
1681872a481558350634a3fd5cb67939de288af00ecbJames Dong*
1682872a481558350634a3fd5cb67939de288af00ecbJames Dong* First, the media time adjustment is done for every period of
1683872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs. kVideoMediaTimeAdjustPeriodTimeUs
1684872a481558350634a3fd5cb67939de288af00ecbJames Dong* is currently a fixed value chosen heuristically. The value of
1685872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs should not be very large or very small
1686872a481558350634a3fd5cb67939de288af00ecbJames Dong* for two considerations: on one hand, a relatively large value
1687872a481558350634a3fd5cb67939de288af00ecbJames Dong* helps reduce large fluctuation of drift time in the audio encoding
1688872a481558350634a3fd5cb67939de288af00ecbJames Dong* path; while on the other hand, a relatively small value helps keep
1689872a481558350634a3fd5cb67939de288af00ecbJames Dong* restoring synchronization in audio/video more frequently. Note for the
1690872a481558350634a3fd5cb67939de288af00ecbJames Dong* very first period of kVideoMediaTimeAdjustPeriodTimeUs, there is
1691872a481558350634a3fd5cb67939de288af00ecbJames Dong* no media time adjustment for the video track.
1692872a481558350634a3fd5cb67939de288af00ecbJames Dong*
1693872a481558350634a3fd5cb67939de288af00ecbJames Dong* Second, the total accumulated audio track time drift found
1694872a481558350634a3fd5cb67939de288af00ecbJames Dong* in a period of kVideoMediaTimeAdjustPeriodTimeUs is distributed
1695872a481558350634a3fd5cb67939de288af00ecbJames Dong* over a stream of incoming video frames. The number of video frames
1696872a481558350634a3fd5cb67939de288af00ecbJames Dong* affected is determined based on the number of recorded video frames
1697872a481558350634a3fd5cb67939de288af00ecbJames Dong* within the past kVideoMediaTimeAdjustPeriodTimeUs period.
1698872a481558350634a3fd5cb67939de288af00ecbJames Dong* We choose to distribute the drift time over only a portion
1699872a481558350634a3fd5cb67939de288af00ecbJames Dong* (rather than all) of the total number of recorded video frames
1700872a481558350634a3fd5cb67939de288af00ecbJames Dong* in order to make sure that the video track media time adjustment is
1701872a481558350634a3fd5cb67939de288af00ecbJames Dong* completed for the current period before the next video track media
1702872a481558350634a3fd5cb67939de288af00ecbJames Dong* time adjustment period starts. Currently, the portion chosen is a
1703872a481558350634a3fd5cb67939de288af00ecbJames Dong* half (0.5).
1704872a481558350634a3fd5cb67939de288af00ecbJames Dong*
1705872a481558350634a3fd5cb67939de288af00ecbJames Dong* Last, various additional checks are performed to ensure that
1706872a481558350634a3fd5cb67939de288af00ecbJames Dong* the actual audio encoding path does not have too much drift.
1707872a481558350634a3fd5cb67939de288af00ecbJames Dong* In particular, 1) we want to limit the average incremental time
1708872a481558350634a3fd5cb67939de288af00ecbJames Dong* adjustment for each video frame to be less than a threshold
1709872a481558350634a3fd5cb67939de288af00ecbJames Dong* for a single period of kVideoMediaTimeAdjustPeriodTimeUs.
1710872a481558350634a3fd5cb67939de288af00ecbJames Dong* Currently, the threshold is set to 5 ms. If the average incremental
1711872a481558350634a3fd5cb67939de288af00ecbJames Dong* media time adjustment for a video frame is larger than the
1712872a481558350634a3fd5cb67939de288af00ecbJames Dong* threshold, the audio encoding path has too much time drift.
1713872a481558350634a3fd5cb67939de288af00ecbJames Dong* 2) We also want to limit the total time drift in the audio
1714872a481558350634a3fd5cb67939de288af00ecbJames Dong* encoding path to be less than a threshold for a period of
1715872a481558350634a3fd5cb67939de288af00ecbJames Dong* kVideoMediaTimeAdjustPeriodTimeUs. Currently, the threshold
1716872a481558350634a3fd5cb67939de288af00ecbJames Dong* is 0.5% of kVideoMediaTimeAdjustPeriodTimeUs. If the time drift of
1717872a481558350634a3fd5cb67939de288af00ecbJames Dong* the audio encoding path is larger than the threshold, the audio
1718872a481558350634a3fd5cb67939de288af00ecbJames Dong* encoding path has too much time drift. We treat the large time
1719872a481558350634a3fd5cb67939de288af00ecbJames Dong* drift of the audio encoding path as errors, since there is no
1720872a481558350634a3fd5cb67939de288af00ecbJames Dong* way to keep audio/video in synchronization for real-time
1721872a481558350634a3fd5cb67939de288af00ecbJames Dong* applications if the time drift is too large unless we drop some
1722872a481558350634a3fd5cb67939de288af00ecbJames Dong* video frames, which has its own problems that we don't want
1723872a481558350634a3fd5cb67939de288af00ecbJames Dong* to get into for the time being.
1724872a481558350634a3fd5cb67939de288af00ecbJames Dong*/
1725872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::adjustMediaTime(int64_t *timestampUs) {
1726872a481558350634a3fd5cb67939de288af00ecbJames Dong    if (*timestampUs - mPrevMediaTimeAdjustTimestampUs >=
1727872a481558350634a3fd5cb67939de288af00ecbJames Dong        kVideoMediaTimeAdjustPeriodTimeUs) {
1728872a481558350634a3fd5cb67939de288af00ecbJames Dong
1729872a481558350634a3fd5cb67939de288af00ecbJames Dong        LOGV("New media time adjustment period at %lld us", *timestampUs);
1730872a481558350634a3fd5cb67939de288af00ecbJames Dong        mIsMediaTimeAdjustmentOn = true;
1731872a481558350634a3fd5cb67939de288af00ecbJames Dong        mMediaTimeAdjustNumFrames =
1732872a481558350634a3fd5cb67939de288af00ecbJames Dong                (mNumSamples - mPrevMediaTimeAdjustSample) >> 1;
1733872a481558350634a3fd5cb67939de288af00ecbJames Dong
1734872a481558350634a3fd5cb67939de288af00ecbJames Dong        mPrevMediaTimeAdjustTimestampUs = *timestampUs;
1735872a481558350634a3fd5cb67939de288af00ecbJames Dong        mPrevMediaTimeAdjustSample = mNumSamples;
1736872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t totalAccumDriftTimeUs = mOwner->getDriftTimeUs();
1737872a481558350634a3fd5cb67939de288af00ecbJames Dong        mTotalDriftTimeToAdjustUs =
1738872a481558350634a3fd5cb67939de288af00ecbJames Dong                totalAccumDriftTimeUs - mPrevTotalAccumDriftTimeUs;
1739872a481558350634a3fd5cb67939de288af00ecbJames Dong
1740872a481558350634a3fd5cb67939de288af00ecbJames Dong        mPrevTotalAccumDriftTimeUs = totalAccumDriftTimeUs;
1741872a481558350634a3fd5cb67939de288af00ecbJames Dong
1742872a481558350634a3fd5cb67939de288af00ecbJames Dong        // Check on incremental adjusted time per frame
1743872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t adjustTimePerFrameUs =
1744872a481558350634a3fd5cb67939de288af00ecbJames Dong                mTotalDriftTimeToAdjustUs / mMediaTimeAdjustNumFrames;
1745872a481558350634a3fd5cb67939de288af00ecbJames Dong
1746872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (adjustTimePerFrameUs < 0) {
1747872a481558350634a3fd5cb67939de288af00ecbJames Dong            adjustTimePerFrameUs = -adjustTimePerFrameUs;
1748872a481558350634a3fd5cb67939de288af00ecbJames Dong        }
1749872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (adjustTimePerFrameUs >= 5000) {
1750872a481558350634a3fd5cb67939de288af00ecbJames Dong            LOGE("Adjusted time per video frame is %lld us",
1751872a481558350634a3fd5cb67939de288af00ecbJames Dong                adjustTimePerFrameUs);
1752872a481558350634a3fd5cb67939de288af00ecbJames Dong            CHECK(!"Video frame time adjustment is too large!");
1753872a481558350634a3fd5cb67939de288af00ecbJames Dong        }
1754872a481558350634a3fd5cb67939de288af00ecbJames Dong
1755872a481558350634a3fd5cb67939de288af00ecbJames Dong        // Check on total accumulated time drift within a period of
1756872a481558350634a3fd5cb67939de288af00ecbJames Dong        // kVideoMediaTimeAdjustPeriodTimeUs.
1757872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t driftPercentage = (mTotalDriftTimeToAdjustUs * 1000)
1758872a481558350634a3fd5cb67939de288af00ecbJames Dong                / kVideoMediaTimeAdjustPeriodTimeUs;
1759872a481558350634a3fd5cb67939de288af00ecbJames Dong
1760872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (driftPercentage < 0) {
1761872a481558350634a3fd5cb67939de288af00ecbJames Dong            driftPercentage = -driftPercentage;
1762872a481558350634a3fd5cb67939de288af00ecbJames Dong        }
1763872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (driftPercentage > 5) {
1764872a481558350634a3fd5cb67939de288af00ecbJames Dong            LOGE("Audio track has time drift %lld us over %lld us",
1765872a481558350634a3fd5cb67939de288af00ecbJames Dong                mTotalDriftTimeToAdjustUs,
1766872a481558350634a3fd5cb67939de288af00ecbJames Dong                kVideoMediaTimeAdjustPeriodTimeUs);
1767872a481558350634a3fd5cb67939de288af00ecbJames Dong
1768872a481558350634a3fd5cb67939de288af00ecbJames Dong            CHECK(!"The audio track media time drifts too much!");
1769872a481558350634a3fd5cb67939de288af00ecbJames Dong        }
1770872a481558350634a3fd5cb67939de288af00ecbJames Dong
1771872a481558350634a3fd5cb67939de288af00ecbJames Dong    }
1772872a481558350634a3fd5cb67939de288af00ecbJames Dong
1773872a481558350634a3fd5cb67939de288af00ecbJames Dong    if (mIsMediaTimeAdjustmentOn) {
1774872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (mNumSamples - mPrevMediaTimeAdjustSample <=
1775872a481558350634a3fd5cb67939de288af00ecbJames Dong            mMediaTimeAdjustNumFrames) {
1776872a481558350634a3fd5cb67939de288af00ecbJames Dong
1777872a481558350634a3fd5cb67939de288af00ecbJames Dong            // Do media time incremental adjustment
1778872a481558350634a3fd5cb67939de288af00ecbJames Dong            int64_t incrementalAdjustTimeUs =
1779872a481558350634a3fd5cb67939de288af00ecbJames Dong                        (mTotalDriftTimeToAdjustUs *
1780872a481558350634a3fd5cb67939de288af00ecbJames Dong                            (mNumSamples - mPrevMediaTimeAdjustSample))
1781872a481558350634a3fd5cb67939de288af00ecbJames Dong                                / mMediaTimeAdjustNumFrames;
1782872a481558350634a3fd5cb67939de288af00ecbJames Dong
1783872a481558350634a3fd5cb67939de288af00ecbJames Dong            *timestampUs +=
1784872a481558350634a3fd5cb67939de288af00ecbJames Dong                (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs);
1785872a481558350634a3fd5cb67939de288af00ecbJames Dong
1786872a481558350634a3fd5cb67939de288af00ecbJames Dong            LOGV("Incremental video frame media time adjustment: %lld us",
1787872a481558350634a3fd5cb67939de288af00ecbJames Dong                (incrementalAdjustTimeUs + mPrevTotalAccumDriftTimeUs));
1788872a481558350634a3fd5cb67939de288af00ecbJames Dong        } else {
1789872a481558350634a3fd5cb67939de288af00ecbJames Dong            // Within the remaining adjustment period,
1790872a481558350634a3fd5cb67939de288af00ecbJames Dong            // no incremental adjustment is needed.
1791872a481558350634a3fd5cb67939de288af00ecbJames Dong            *timestampUs +=
1792872a481558350634a3fd5cb67939de288af00ecbJames Dong                (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs);
1793872a481558350634a3fd5cb67939de288af00ecbJames Dong
1794872a481558350634a3fd5cb67939de288af00ecbJames Dong            LOGV("Fixed video frame media time adjustment: %lld us",
1795872a481558350634a3fd5cb67939de288af00ecbJames Dong                (mTotalDriftTimeToAdjustUs + mPrevTotalAccumDriftTimeUs));
1796872a481558350634a3fd5cb67939de288af00ecbJames Dong        }
1797872a481558350634a3fd5cb67939de288af00ecbJames Dong    }
1798872a481558350634a3fd5cb67939de288af00ecbJames Dong}
1799872a481558350634a3fd5cb67939de288af00ecbJames Dong
1800872a481558350634a3fd5cb67939de288af00ecbJames Dong/*
1801872a481558350634a3fd5cb67939de288af00ecbJames Dong * Updates the drift time from the audio track so that
1802872a481558350634a3fd5cb67939de288af00ecbJames Dong * the video track can get the updated drift time information
1803872a481558350634a3fd5cb67939de288af00ecbJames Dong * from the file writer. The fluctuation of the drift time of the audio
1804872a481558350634a3fd5cb67939de288af00ecbJames Dong * encoding path is smoothed out with a simple filter by giving a larger
1805872a481558350634a3fd5cb67939de288af00ecbJames Dong * weight to more recently drift time. The filter coefficients, 0.5 and 0.5,
1806872a481558350634a3fd5cb67939de288af00ecbJames Dong * are heuristically determined.
1807872a481558350634a3fd5cb67939de288af00ecbJames Dong */
1808872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) {
1809872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t driftTimeUs = 0;
1810872a481558350634a3fd5cb67939de288af00ecbJames Dong    if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) {
1811872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t prevDriftTimeUs = mOwner->getDriftTimeUs();
1812872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1;
1813872a481558350634a3fd5cb67939de288af00ecbJames Dong        mOwner->setDriftTimeUs(timeUs);
1814872a481558350634a3fd5cb67939de288af00ecbJames Dong    }
1815872a481558350634a3fd5cb67939de288af00ecbJames Dong}
1816872a481558350634a3fd5cb67939de288af00ecbJames Dong
181737187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::threadEntry() {
181830ab66297501757d745b9ae10da61adcd891f497Andreas Huber    int32_t count = 0;
181913aec890216948b0c364f8f92792129d0335f506James Dong    const int64_t interleaveDurationUs = mOwner->interleaveDuration();
182043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    const bool hasMultipleTracks = (mOwner->numTracks() > 1);
182113aec890216948b0c364f8f92792129d0335f506James Dong    int64_t chunkTimestampUs = 0;
182213aec890216948b0c364f8f92792129d0335f506James Dong    int32_t nChunks = 0;
182313aec890216948b0c364f8f92792129d0335f506James Dong    int32_t nZeroLengthFrames = 0;
18248f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t lastTimestampUs = 0;  // Previous sample time stamp in ms
18258f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t lastDurationUs = 0;   // Between the previous two samples in ms
1826c059860c73678a202bfa33062723e8f82fb779d9James Dong    int64_t currDurationTicks = 0;  // Timescale based ticks
1827c059860c73678a202bfa33062723e8f82fb779d9James Dong    int64_t lastDurationTicks = 0;  // Timescale based ticks
18288f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int32_t sampleCount = 1;      // Sample count in the current stts table entry
1829be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    uint32_t previousSampleSize = 0;  // Size of the previous sample
1830a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    int64_t previousPausedDurationUs = 0;
18311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    int64_t timestampUs;
1832e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
1833a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    if (mIsAudio) {
1834a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong        prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
1835a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    } else {
1836a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong        prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0);
1837a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    }
1838985f838934510983d8a887461e98dca60a6e858fJames Dong    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
1839985f838934510983d8a887461e98dca60a6e858fJames Dong
1840d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong    sp<MetaData> meta_data;
184120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1842ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    mNumSamples = 0;
184393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    status_t err = OK;
184420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    MediaBuffer *buffer;
184593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    while (!mDone && (err = mSource->read(&buffer)) == OK) {
184620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        if (buffer->range_length() == 0) {
184720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            buffer->release();
184820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            buffer = NULL;
184913aec890216948b0c364f8f92792129d0335f506James Dong            ++nZeroLengthFrames;
185020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            continue;
185120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
185220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1853a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // If the codec specific data has not been received yet, delay pause.
1854a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // After the codec specific data is received, discard what we received
1855a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // when the track is to be paused.
1856a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mPaused && !mResumed) {
1857a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            buffer->release();
1858a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            buffer = NULL;
1859a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            continue;
1860a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
1861a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
186230ab66297501757d745b9ae10da61adcd891f497Andreas Huber        ++count;
186330ab66297501757d745b9ae10da61adcd891f497Andreas Huber
186403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        int32_t isCodecConfig;
186503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
186603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                && isCodecConfig) {
1867548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            CHECK(!mGotAllCodecSpecificData);
1868548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
18691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            if (mIsAvc) {
187003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                status_t err = makeAVCCodecSpecificData(
187103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        (const uint8_t *)buffer->data()
187203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                            + buffer->range_offset(),
187303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        buffer->range_length());
1874be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                CHECK_EQ(OK, err);
18751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            } else if (mIsMPEG4) {
187603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                mCodecSpecificDataSize = buffer->range_length();
187703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                mCodecSpecificData = malloc(mCodecSpecificDataSize);
187803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                memcpy(mCodecSpecificData,
187903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        (const uint8_t *)buffer->data()
188003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                            + buffer->range_offset(),
188103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                       buffer->range_length());
188230ab66297501757d745b9ae10da61adcd891f497Andreas Huber            }
188330ab66297501757d745b9ae10da61adcd891f497Andreas Huber
188430ab66297501757d745b9ae10da61adcd891f497Andreas Huber            buffer->release();
188530ab66297501757d745b9ae10da61adcd891f497Andreas Huber            buffer = NULL;
188630ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1887548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            mGotAllCodecSpecificData = true;
188830ab66297501757d745b9ae10da61adcd891f497Andreas Huber            continue;
1889a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
1890a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
1891d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        // Make a deep copy of the MediaBuffer and Metadata and release
1892d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        // the original as soon as we can
1893d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        MediaBuffer *copy = new MediaBuffer(buffer->range_length());
1894d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(),
1895d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong                buffer->range_length());
1896d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        copy->set_range(0, buffer->range_length());
1897d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        meta_data = new MetaData(*buffer->meta_data().get());
1898d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        buffer->release();
1899d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        buffer = NULL;
1900d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
19011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (mIsAvc) StripStartcode(copy);
1902e136c3bb38e88315bf8797a464ebf2c788296b22James Dong
1903b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        size_t sampleSize = copy->range_length();
1904b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        if (mIsAvc) {
1905b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong            if (mOwner->useNalLengthFour()) {
1906b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong                sampleSize += 4;
1907b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong            } else {
1908b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong                sampleSize += 2;
1909b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong            }
1910b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        }
1911050b28a593350047845a45a14cc5026221ac1620James Dong
1912d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        // Max file size or duration handling
19131f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        mMdatSizeBytes += sampleSize;
19141f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        updateTrackSizeEstimate();
19151f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1916d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if (mOwner->exceedsFileSizeLimit()) {
1917d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
1918d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            break;
1919d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
1920d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if (mOwner->exceedsFileDurationLimit()) {
1921d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
1922d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            break;
1923d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
1924d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
1925050b28a593350047845a45a14cc5026221ac1620James Dong
1926d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        int32_t isSync = false;
1927d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        meta_data->findInt32(kKeyIsSyncFrame, &isSync);
1928d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
19298428af5381e835cc783b7ecb0d71cb60961c99c2James Dong        /*
19308428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * The original timestamp found in the data buffer will be modified as below:
19318428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         *
19328428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * There is a playback offset into this track if the track's start time
19338428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * is not the same as the movie start time, which will be recorded in edst
19348428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * box of the output file. The playback offset is to make sure that the
19358428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * starting time of the audio/video tracks are synchronized. Although the
19368428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * track's media timestamp may be subject to various modifications
19378428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * as outlined below, the track's playback offset time remains unchanged
19388428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * once the first data buffer of the track is received.
19398428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         *
19408428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * The media time stamp will be calculated by subtracting the playback offset
19418428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * (and potential pause durations) from the original timestamp in the buffer.
19428428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         *
19438428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * If this track is a video track for a real-time recording application with
19448428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * both audio and video tracks, its media timestamp will subject to further
19458428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * modification based on the media clock of the audio track. This modification
19468428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * is needed for the purpose of maintaining good audio/video synchronization.
19478428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         *
19488428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * If the recording session is paused and resumed multiple times, the track
19498428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * media timestamp will be modified as if the  recording session had never been
19508428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * paused at all during playback of the recorded output file. In other words,
19518428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         * the output file will have no memory of pause/resume durations.
19528428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         *
19538428af5381e835cc783b7ecb0d71cb60961c99c2James Dong         */
1954d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
19558428af5381e835cc783b7ecb0d71cb60961c99c2James Dong        LOGV("%s timestampUs: %lld", mIsAudio? "Audio": "Video", timestampUs);
1956d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
1957d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong////////////////////////////////////////////////////////////////////////////////
195870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        if (mNumSamples == 0) {
195970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            mFirstSampleTimeRealUs = systemTime() / 1000;
1960f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong            mStartTimestampUs = timestampUs;
1961f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong            mOwner->setStartTimestampUs(mStartTimestampUs);
19628428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            previousPausedDurationUs = mStartTimestampUs;
19633c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong        }
196448c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber
1965a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mResumed) {
19668428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
19678428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            CHECK(durExcludingEarlierPausesUs >= 0);
19688428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
19698428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            CHECK(pausedDurationUs >= lastDurationUs);
19708428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            previousPausedDurationUs += pausedDurationUs - lastDurationUs;
1971a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            mResumed = false;
1972a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
1973a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
1974a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        timestampUs -= previousPausedDurationUs;
19758428af5381e835cc783b7ecb0d71cb60961c99c2James Dong        CHECK(timestampUs >= 0);
1976872a481558350634a3fd5cb67939de288af00ecbJames Dong
1977872a481558350634a3fd5cb67939de288af00ecbJames Dong        // Media time adjustment for real-time applications
1978872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (mIsRealTimeRecording) {
1979872a481558350634a3fd5cb67939de288af00ecbJames Dong            if (mIsAudio) {
1980872a481558350634a3fd5cb67939de288af00ecbJames Dong                updateDriftTime(meta_data);
1981872a481558350634a3fd5cb67939de288af00ecbJames Dong            } else {
1982872a481558350634a3fd5cb67939de288af00ecbJames Dong                adjustMediaTime(&timestampUs);
1983e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            }
1984e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        }
1985872a481558350634a3fd5cb67939de288af00ecbJames Dong
1986e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        CHECK(timestampUs >= 0);
1987e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        if (mNumSamples > 1) {
1988e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            if (timestampUs <= lastTimestampUs) {
19894f86a980fee1880dca61b828599fa6d76755a485James Dong                LOGW("Frame arrives too late!");
19904f86a980fee1880dca61b828599fa6d76755a485James Dong                // Don't drop the late frame, since dropping a frame may cause
19914f86a980fee1880dca61b828599fa6d76755a485James Dong                // problems later during playback
19924f86a980fee1880dca61b828599fa6d76755a485James Dong
19934f86a980fee1880dca61b828599fa6d76755a485James Dong                // The idea here is to avoid having two or more samples with the
19944f86a980fee1880dca61b828599fa6d76755a485James Dong                // same timestamp in the output file.
19954f86a980fee1880dca61b828599fa6d76755a485James Dong                if (mTimeScale >= 1000000LL) {
199640e9940fadf22daa64c1e766fa8a855c7b149c17James Dong                    timestampUs = lastTimestampUs + 1;
19974f86a980fee1880dca61b828599fa6d76755a485James Dong                } else {
199840e9940fadf22daa64c1e766fa8a855c7b149c17James Dong                    timestampUs = lastTimestampUs + (1000000LL + (mTimeScale >> 1)) / mTimeScale;
19994f86a980fee1880dca61b828599fa6d76755a485James Dong                }
2000e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            }
2001e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        }
2002e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
20038428af5381e835cc783b7ecb0d71cb60961c99c2James Dong        LOGV("%s media time stamp: %lld and previous paused duration %lld",
20048428af5381e835cc783b7ecb0d71cb60961c99c2James Dong                mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs);
2005c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong        if (timestampUs > mTrackDurationUs) {
2006c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong            mTrackDurationUs = timestampUs;
20073b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber        }
20083b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber
20098644c14618d30d9e57a69df40ed939986ebf02c4James Dong        mSampleSizes.push_back(sampleSize);
2010ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong        ++mNumSamples;
2011ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong        if (mNumSamples > 2) {
2012c059860c73678a202bfa33062723e8f82fb779d9James Dong            // We need to use the time scale based ticks, rather than the
2013c059860c73678a202bfa33062723e8f82fb779d9James Dong            // timestamp itself to determine whether we have to use a new
2014c059860c73678a202bfa33062723e8f82fb779d9James Dong            // stts entry, since we may have rounding errors.
2015c059860c73678a202bfa33062723e8f82fb779d9James Dong            // The calculation is intended to reduce the accumulated
2016c059860c73678a202bfa33062723e8f82fb779d9James Dong            // rounding errors.
2017c059860c73678a202bfa33062723e8f82fb779d9James Dong            currDurationTicks =
2018c059860c73678a202bfa33062723e8f82fb779d9James Dong                     ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
2019c059860c73678a202bfa33062723e8f82fb779d9James Dong                     (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
2020c059860c73678a202bfa33062723e8f82fb779d9James Dong
2021a472613aec322e25891abf5c77bf3f7e3c244920James Dong            // Force the first sample to have its own stts entry so that
2022a472613aec322e25891abf5c77bf3f7e3c244920James Dong            // we can adjust its value later to maintain the A/V sync.
2023a472613aec322e25891abf5c77bf3f7e3c244920James Dong            if (mNumSamples == 3 || currDurationTicks != lastDurationTicks) {
2024a472613aec322e25891abf5c77bf3f7e3c244920James Dong                LOGV("%s lastDurationUs: %lld us, currDurationTicks: %lld us",
2025a472613aec322e25891abf5c77bf3f7e3c244920James Dong                        mIsAudio? "Audio": "Video", lastDurationUs, currDurationTicks);
20261f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                addOneSttsTableEntry(sampleCount, lastDurationUs);
2027be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                sampleCount = 1;
2028be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            } else {
2029be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                ++sampleCount;
2030be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            }
2031be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        }
2032be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        if (mSamplesHaveSameSize) {
2033ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong            if (mNumSamples >= 2 && previousSampleSize != sampleSize) {
2034be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                mSamplesHaveSameSize = false;
2035be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            }
20368644c14618d30d9e57a69df40ed939986ebf02c4James Dong            previousSampleSize = sampleSize;
2037be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        }
2038a472613aec322e25891abf5c77bf3f7e3c244920James Dong        LOGV("%s timestampUs/lastTimestampUs: %lld/%lld",
2039a472613aec322e25891abf5c77bf3f7e3c244920James Dong                mIsAudio? "Audio": "Video", timestampUs, lastTimestampUs);
20408644c14618d30d9e57a69df40ed939986ebf02c4James Dong        lastDurationUs = timestampUs - lastTimestampUs;
2041c059860c73678a202bfa33062723e8f82fb779d9James Dong        lastDurationTicks = currDurationTicks;
20428644c14618d30d9e57a69df40ed939986ebf02c4James Dong        lastTimestampUs = timestampUs;
204320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2044d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        if (isSync != 0) {
20451f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            addOneStssTableEntry(mNumSamples);
2046d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        }
2047d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
204893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        if (mTrackingProgressStatus) {
204993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            if (mPreviousTrackTimeUs <= 0) {
205093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong                mPreviousTrackTimeUs = mStartTimestampUs;
205193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            }
2052faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong            trackProgressStatus(timestampUs);
205393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        }
205443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong        if (!hasMultipleTracks) {
2055c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong            off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy)
205658ae9c530247668f8af36e30d228c716c226b3d4James Dong                                 : mOwner->addSample_l(copy);
205758ae9c530247668f8af36e30d228c716c226b3d4James Dong            if (mChunkOffsets.empty()) {
20581f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                addChunkOffset(offset);
205958ae9c530247668f8af36e30d228c716c226b3d4James Dong            }
206058ae9c530247668f8af36e30d228c716c226b3d4James Dong            copy->release();
206158ae9c530247668f8af36e30d228c716c226b3d4James Dong            copy = NULL;
206258ae9c530247668f8af36e30d228c716c226b3d4James Dong            continue;
206358ae9c530247668f8af36e30d228c716c226b3d4James Dong        }
206413aec890216948b0c364f8f92792129d0335f506James Dong
206513aec890216948b0c364f8f92792129d0335f506James Dong        mChunkSamples.push_back(copy);
206613aec890216948b0c364f8f92792129d0335f506James Dong        if (interleaveDurationUs == 0) {
20671f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            addOneStscTableEntry(++nChunks, 1);
20681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            bufferChunk(timestampUs);
206913aec890216948b0c364f8f92792129d0335f506James Dong        } else {
207013aec890216948b0c364f8f92792129d0335f506James Dong            if (chunkTimestampUs == 0) {
207113aec890216948b0c364f8f92792129d0335f506James Dong                chunkTimestampUs = timestampUs;
207213aec890216948b0c364f8f92792129d0335f506James Dong            } else {
207343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                int64_t chunkDurationUs = timestampUs - chunkTimestampUs;
207443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                if (chunkDurationUs > interleaveDurationUs) {
207543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    if (chunkDurationUs > mMaxChunkDurationUs) {
207643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                        mMaxChunkDurationUs = chunkDurationUs;
207743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    }
207813aec890216948b0c364f8f92792129d0335f506James Dong                    ++nChunks;
207913aec890216948b0c364f8f92792129d0335f506James Dong                    if (nChunks == 1 ||  // First chunk
208013aec890216948b0c364f8f92792129d0335f506James Dong                        (--(mStscTableEntries.end()))->samplesPerChunk !=
208113aec890216948b0c364f8f92792129d0335f506James Dong                         mChunkSamples.size()) {
20821f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                        addOneStscTableEntry(nChunks, mChunkSamples.size());
208313aec890216948b0c364f8f92792129d0335f506James Dong                    }
20841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                    bufferChunk(timestampUs);
208513aec890216948b0c364f8f92792129d0335f506James Dong                    chunkTimestampUs = timestampUs;
208613aec890216948b0c364f8f92792129d0335f506James Dong                }
208713aec890216948b0c364f8f92792129d0335f506James Dong            }
208813aec890216948b0c364f8f92792129d0335f506James Dong        }
208913aec890216948b0c364f8f92792129d0335f506James Dong
209020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
209125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
2092a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong    if (mSampleSizes.empty() ||                      // no samples written
2093a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong        (!mIsAudio && mNumStssTableEntries == 0) ||  // no sync frames for video
2094a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong        (OK != checkCodecSpecificData())) {          // no codec specific data
2095690f546b0ee548dbfe997df36418e5302ec2d786James Dong        err = ERROR_MALFORMED;
2096f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong    }
2097bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    mOwner->trackProgressStatus(mTrackId, -1, err);
2098be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
209913aec890216948b0c364f8f92792129d0335f506James Dong    // Last chunk
210043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    if (!hasMultipleTracks) {
21011f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        addOneStscTableEntry(1, mNumSamples);
210258ae9c530247668f8af36e30d228c716c226b3d4James Dong    } else if (!mChunkSamples.empty()) {
21031f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        addOneStscTableEntry(++nChunks, mChunkSamples.size());
21041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        bufferChunk(timestampUs);
210513aec890216948b0c364f8f92792129d0335f506James Dong    }
210613aec890216948b0c364f8f92792129d0335f506James Dong
2107be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // We don't really know how long the last frame lasts, since
2108be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // there is no frame time after it, just repeat the previous
2109be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // frame's duration.
2110ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    if (mNumSamples == 1) {
21118f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        lastDurationUs = 0;  // A single sample's duration
2112be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    } else {
2113be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        ++sampleCount;  // Count for the last sample
2114be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    }
2115a472613aec322e25891abf5c77bf3f7e3c244920James Dong
2116a472613aec322e25891abf5c77bf3f7e3c244920James Dong    if (mNumSamples <= 2) {
2117a472613aec322e25891abf5c77bf3f7e3c244920James Dong        addOneSttsTableEntry(1, lastDurationUs);
2118a472613aec322e25891abf5c77bf3f7e3c244920James Dong        if (sampleCount - 1 > 0) {
2119a472613aec322e25891abf5c77bf3f7e3c244920James Dong            addOneSttsTableEntry(sampleCount - 1, lastDurationUs);
2120a472613aec322e25891abf5c77bf3f7e3c244920James Dong        }
2121a472613aec322e25891abf5c77bf3f7e3c244920James Dong    } else {
2122a472613aec322e25891abf5c77bf3f7e3c244920James Dong        addOneSttsTableEntry(sampleCount, lastDurationUs);
2123a472613aec322e25891abf5c77bf3f7e3c244920James Dong    }
2124a472613aec322e25891abf5c77bf3f7e3c244920James Dong
2125c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    mTrackDurationUs += lastDurationUs;
212625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    mReachedEOS = true;
212743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
212843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    sendTrackSummary(hasMultipleTracks);
212943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
21301f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s",
21311f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            count, nZeroLengthFrames, mNumSamples, mIsAudio? "audio": "video");
2132872a481558350634a3fd5cb67939de288af00ecbJames Dong    if (mIsAudio) {
2133872a481558350634a3fd5cb67939de288af00ecbJames Dong        LOGI("Audio track drift time: %lld us", mOwner->getDriftTimeUs());
2134872a481558350634a3fd5cb67939de288af00ecbJames Dong    }
2135365a963142093a1cd8efdcea76b5f65096a5b115James Dong
213637187916a486504acaf83bea30147eb5fbf46ae5James Dong    if (err == ERROR_END_OF_STREAM) {
213737187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
213837187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
213937187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
2140365a963142093a1cd8efdcea76b5f65096a5b115James Dong}
2141365a963142093a1cd8efdcea76b5f65096a5b115James Dong
214243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dongvoid MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) {
214343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    int trackNum = (mTrackId << 28);
214443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
214543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
214643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_TYPE,
214743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    mIsAudio? 0: 1);
214843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
214943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
215043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_DURATION_MS,
215143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    mTrackDurationUs / 1000);
215243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
215343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
215443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES,
215543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    mNumSamples);
215643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
215770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    // The system delay time excluding the requested initial delay that
215870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    // is used to eliminate the recording sound.
215970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    int64_t initialDelayUs =
216070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        mFirstSampleTimeRealUs - mStartTimeRealUs - kInitialDelayTimeUs;
216170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
216270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS,
216370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    (initialDelayUs) / 1000);
216470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
216543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    if (hasMultipleTracks) {
216643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong        mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
216743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS,
216843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    mMaxChunkDurationUs / 1000);
216970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
217070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
217170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        if (mStartTimestampUs != moovStartTimeUs) {
217270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            int64_t startTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
217370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
217470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS,
217570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    startTimeOffsetUs / 1000);
217670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        }
217743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    }
217843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong}
217943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
2180faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) {
2181faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    LOGV("trackProgressStatus: %lld us", timeUs);
2182215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    if (mTrackEveryTimeDurationUs > 0 &&
2183215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong        timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) {
218493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        LOGV("Fire time tracking progress status at %lld us", timeUs);
2185bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err);
218693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        mPreviousTrackTimeUs = timeUs;
218793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    }
218893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong}
218993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
2190faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::trackProgressStatus(
2191bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        size_t trackId, int64_t timeUs, status_t err) {
2192faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    Mutex::Autolock lock(mLock);
2193bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    int32_t trackNum = (trackId << 28);
2194faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
2195faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    // Error notification
2196faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    // Do not consider ERROR_END_OF_STREAM an error
2197faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    if (err != OK && err != ERROR_END_OF_STREAM) {
2198bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_ERROR,
2199bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong               trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL,
2200faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               err);
2201faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        return;
2202faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    }
2203faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
2204faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    if (timeUs == -1) {
2205faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        // Send completion notification
2206bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2207bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong               trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS,
2208faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               err);
2209faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    } else {
2210faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        // Send progress status
2211bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2212bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong               trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME,
2213faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               timeUs / 1000);
2214faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    }
2215faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong}
2216faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
2217d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dongvoid MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) {
2218d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong    LOGV("setDriftTimeUs: %lld us", driftTimeUs);
2219e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    Mutex::Autolock autolock(mLock);
2220d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong    mDriftTimeUs = driftTimeUs;
2221e259531ce59ab1f31de5a23124b22536f6a5a767James Dong}
2222e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
2223e259531ce59ab1f31de5a23124b22536f6a5a767James Dongint64_t MPEG4Writer::getDriftTimeUs() {
2224e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    LOGV("getDriftTimeUs: %lld us", mDriftTimeUs);
2225e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    Mutex::Autolock autolock(mLock);
2226e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    return mDriftTimeUs;
2227e259531ce59ab1f31de5a23124b22536f6a5a767James Dong}
2228e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
2229b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dongbool MPEG4Writer::useNalLengthFour() {
2230b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    return mUse4ByteNalLength;
2231b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong}
2232b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong
22331c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
22341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    LOGV("bufferChunk");
22351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
22361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Chunk chunk(this, timestampUs, mChunkSamples);
22371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mOwner->bufferChunk(chunk);
223813aec890216948b0c364f8f92792129d0335f506James Dong    mChunkSamples.clear();
223920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
224020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
22413b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const {
2242c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    return mTrackDurationUs;
224320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
224420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2245d599cd4573b5a2d5914c5040e0565ef866749b77James Dongint64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
2246d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    return mEstimatedTrackSizeBytes;
2247d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
2248d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
2249690f546b0ee548dbfe997df36418e5302ec2d786James Dongstatus_t MPEG4Writer::Track::checkCodecSpecificData() const {
2250690f546b0ee548dbfe997df36418e5302ec2d786James Dong    const char *mime;
2251690f546b0ee548dbfe997df36418e5302ec2d786James Dong    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
2252690f546b0ee548dbfe997df36418e5302ec2d786James Dong    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) ||
2253690f546b0ee548dbfe997df36418e5302ec2d786James Dong        !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
2254690f546b0ee548dbfe997df36418e5302ec2d786James Dong        !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2255690f546b0ee548dbfe997df36418e5302ec2d786James Dong        if (!mCodecSpecificData ||
2256690f546b0ee548dbfe997df36418e5302ec2d786James Dong            mCodecSpecificDataSize <= 0) {
2257a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong            LOGE("Missing codec specific data");
2258690f546b0ee548dbfe997df36418e5302ec2d786James Dong            return ERROR_MALFORMED;
2259690f546b0ee548dbfe997df36418e5302ec2d786James Dong        }
2260690f546b0ee548dbfe997df36418e5302ec2d786James Dong    } else {
2261690f546b0ee548dbfe997df36418e5302ec2d786James Dong        if (mCodecSpecificData ||
2262690f546b0ee548dbfe997df36418e5302ec2d786James Dong            mCodecSpecificDataSize > 0) {
2263a1abc1a76741914c7bc43f1df9e32744f023ab75James Dong            LOGE("Unexepected codec specific data found");
2264690f546b0ee548dbfe997df36418e5302ec2d786James Dong            return ERROR_MALFORMED;
2265690f546b0ee548dbfe997df36418e5302ec2d786James Dong        }
2266690f546b0ee548dbfe997df36418e5302ec2d786James Dong    }
2267690f546b0ee548dbfe997df36418e5302ec2d786James Dong    return OK;
2268690f546b0ee548dbfe997df36418e5302ec2d786James Dong}
2269690f546b0ee548dbfe997df36418e5302ec2d786James Dong
2270b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) {
227120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
22728f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    LOGV("%s track time scale: %d",
22731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mIsAudio? "Audio": "Video", mTimeScale);
22748f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
227520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    time_t now = time(NULL);
2276b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("trak");
2277b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeTkhdBox(now);
2278b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("mdia");
2279b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            writeMdhdBox(now);
2280b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            writeHdlrBox();
2281b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->beginBox("minf");
2282b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                if (mIsAudio) {
2283b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                    writeSmhdBox();
2284b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                } else {
2285b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                    writeVmhdBox();
2286b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                }
2287b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                writeDinfBox();
2288b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                writeStblBox(use32BitOffset);
2289b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->endBox();  // minf
2290b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->endBox();  // mdia
2291b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // trak
2292b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2293b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2294b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStblBox(bool use32BitOffset) {
2295b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stbl");
2296b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stsd");
2297b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);               // version=0, flags=0
2298b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1);               // entry count
2299b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mIsAudio) {
2300b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeAudioFourCCBox();
2301b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2302b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeVideoFourCCBox();
2303b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2304b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stsd
2305b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeSttsBox();
2306b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!mIsAudio) {
2307b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeStssBox();
2308b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2309b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeStszBox();
2310b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeStscBox();
2311b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeStcoBox(use32BitOffset);
2312b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stbl
2313b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2314b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2315b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVideoFourCCBox() {
2316b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    const char *mime;
2317b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    bool success = mMeta->findCString(kKeyMIMEType, &mime);
2318b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2319b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2320b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("mp4v");
2321b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2322b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("s263");
2323b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2324b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("avc1");
2325b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2326b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        LOGE("Unknown mime type '%s'.", mime);
2327b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(!"should not be here, unknown mime type.");
2328b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2329b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2330b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2331b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2332b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(1);           // data ref index
2333b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // predefined
2334b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2335b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // predefined
2336b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // predefined
2337b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // predefined
2338b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2339b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t width, height;
2340b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    success = mMeta->findInt32(kKeyWidth, &width);
2341b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    success = success && mMeta->findInt32(kKeyHeight, &height);
2342b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2343b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2344b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(width);
2345b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(height);
2346b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x480000);    // horiz resolution
2347b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x480000);    // vert resolution
2348b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2349b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(1);           // frame count
2350b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write("                                ", 32);
2351b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x18);        // depth
2352b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(-1);          // predefined
2353b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2354b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(23 + mCodecSpecificDataSize < 128);
2355b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2356b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2357b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeMp4vEsdsBox();
2358b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2359b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeD263Box();
2360b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2361b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeAvccBox();
2362b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2363b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2364b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writePaspBox();
2365b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // mp4v, s263 or avc1
2366b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2367b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2368b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAudioFourCCBox() {
2369b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    const char *mime;
2370b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    bool success = mMeta->findCString(kKeyMIMEType, &mime);
2371b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2372b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    const char *fourcc = NULL;
2373b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
2374b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fourcc = "samr";
2375b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2376b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fourcc = "sawb";
2377b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2378b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fourcc = "mp4a";
2379b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2380b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        LOGE("Unknown mime type '%s'.", mime);
2381b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(!"should not be here, unknown mime type.");
2382b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2383b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2384b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox(fourcc);        // audio format
2385b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2386b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2387b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x1);         // data ref index
2388b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2389b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2390b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t nChannels;
2391b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels));
2392b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(nChannels);   // channel count
2393b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(16);          // sample size
2394b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // predefined
2395b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2396b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2397b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t samplerate;
2398b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    success = mMeta->findInt32(kKeySampleRate, &samplerate);
2399b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2400b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(samplerate << 16);
2401b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2402b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeMp4aEsdsBox();
2403b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) ||
2404b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong               !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2405b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeDamrBox();
2406b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2407b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2408b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2409b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2410b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4aEsdsBox() {
2411b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("esds");
2412b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificData);
2413b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificDataSize > 0);
2414b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2415b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Make sure all sizes encode to a single byte.
2416b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificDataSize + 23 < 128);
2417b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2418b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);     // version=0, flags=0
2419b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x03);   // ES_DescrTag
2420b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(23 + mCodecSpecificDataSize);
2421b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x0000);// ES_ID
2422b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x00);
2423b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2424b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x04);   // DecoderConfigDescrTag
2425b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(15 + mCodecSpecificDataSize);
2426b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x40);   // objectTypeIndication ISO/IEC 14492-2
2427b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x15);   // streamType AudioStream
2428b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2429b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x03);  // XXX
2430b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x00);   // buffer size 24-bit
2431b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(96000); // max bit rate
2432b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(96000); // avg bit rate
2433b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2434b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x05);   // DecoderSpecificInfoTag
2435b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(mCodecSpecificDataSize);
2436b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2437b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2438b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    static const uint8_t kData2[] = {
2439b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x06,  // SLConfigDescriptorTag
2440b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x01,
2441b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x02
2442b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    };
2443b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(kData2, sizeof(kData2));
2444b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2445b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // esds
2446b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2447b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2448b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4vEsdsBox() {
2449b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificData);
2450b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificDataSize > 0);
2451b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("esds");
2452b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2453b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);    // version=0, flags=0
2454b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2455b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x03);  // ES_DescrTag
2456b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(23 + mCodecSpecificDataSize);
2457b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x0000);  // ES_ID
2458b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x1f);
2459b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2460b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x04);  // DecoderConfigDescrTag
2461b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(15 + mCodecSpecificDataSize);
2462b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x20);  // objectTypeIndication ISO/IEC 14492-2
2463b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x11);  // streamType VisualStream
2464b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2465b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    static const uint8_t kData[] = {
2466b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x01, 0x77, 0x00,
2467b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x00, 0x03, 0xe8, 0x00,
2468b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x00, 0x03, 0xe8, 0x00
2469b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    };
2470b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(kData, sizeof(kData));
2471b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2472b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
2473b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2474b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(mCodecSpecificDataSize);
2475b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2476b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2477b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    static const uint8_t kData2[] = {
2478b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x06,  // SLConfigDescriptorTag
2479b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x01,
2480b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x02
2481b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    };
2482b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(kData2, sizeof(kData2));
2483b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2484b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // esds
2485b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2486b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2487b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeTkhdBox(time_t now) {
2488b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("tkhd");
2489b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Flags = 7 to indicate that the track is enabled, and
2490b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // part of the presentation
2491b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x07);          // version=0, flags=7
2492b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // creation time
2493b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // modification time
2494b5212db69734962f55e1493d3e696794172ced51James Dong    mOwner->writeInt32(mTrackId + 1);  // track id starts with 1
2495b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
24968f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t trakDurationUs = getDurationUs();
2497b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t mvhdTimeScale = mOwner->getTimeScale();
2498b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t tkhdDuration =
2499b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        (trakDurationUs * mvhdTimeScale + 5E5) / 1E6;
2500b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(tkhdDuration);  // in mvhd timescale
2501b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2502b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2503b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // layer
2504b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // alternate group
2505b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(mIsAudio ? 0x100 : 0);  // volume
2506b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // reserved
2507b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2508b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeCompositionMatrix(mRotation);       // matrix
250920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2510b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mIsAudio) {
2511b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(0);
2512b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(0);
2513b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2514b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        int32_t width, height;
2515b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        bool success = mMeta->findInt32(kKeyWidth, &width);
2516b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        success = success && mMeta->findInt32(kKeyHeight, &height);
2517b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(success);
2518b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2519b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(width << 16);   // 32-bit fixed-point value
2520b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(height << 16);  // 32-bit fixed-point value
2521b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2522b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // tkhd
2523b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2524b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2525b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVmhdBox() {
2526b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("vmhd");
2527b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x01);        // version=0, flags=1
2528b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // graphics mode
2529b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // opcolor
2530b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);
2531b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);
2532b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2533b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2534b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2535b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeSmhdBox() {
2536b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("smhd");
2537b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // version=0, flags=0
2538b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // balance
2539b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2540b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2541b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2542b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2543b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeHdlrBox() {
2544b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("hdlr");
2545b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // version=0, flags=0
2546b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // component type: should be mhlr
2547b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeFourcc(mIsAudio ? "soun" : "vide");  // component subtype
2548b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2549b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2550b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2551b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Removing "r" for the name string just makes the string 4 byte aligned
2552b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle");  // name
2553b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2554b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2555b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2556b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMdhdBox(time_t now) {
2557b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int64_t trakDurationUs = getDurationUs();
2558b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("mdhd");
2559b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // version=0, flags=0
2560b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // creation time
2561b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // modification time
2562b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mTimeScale);    // media timescale
2563b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6;
2564b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mdhdDuration);  // use media timescale
2565b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Language follows the three letter standard ISO-639-2/T
2566b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // 'e', 'n', 'g' for "English", for instance.
2567b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Each character is packed as the difference between its ASCII value and 0x60.
2568b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // For "English", these are 00101, 01110, 00111.
2569b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // XXX: Where is the padding bit located: 0x15C7?
2570b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // language code
2571b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // predefined
2572b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2573b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2574b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2575b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDamrBox() {
2576b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // 3gpp2 Spec AMRSampleEntry fields
2577b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("damr");
2578b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeCString("   ");  // vendor: 4 bytes
2579b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);         // decoder version
2580b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x83FF);   // mode set: all enabled
2581b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);         // mode change period
2582b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(1);         // frames per sample
2583b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2584b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2585b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2586b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeUrlBox() {
2587b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // The table index here refers to the sample description index
2588b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // in the sample table entries.
2589b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("url ");
2590b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1);  // version=0, flags=1 (self-contained)
2591b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // url
2592b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2593b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2594b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDrefBox() {
2595b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("dref");
2596b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2597b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1);  // entry count (either url or urn)
2598b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeUrlBox();
2599b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // dref
2600b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2601b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2602b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDinfBox() {
2603b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("dinf");
2604b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeDrefBox();
2605b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // dinf
2606b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2607b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2608b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAvccBox() {
2609b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificData);
2610b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificDataSize >= 5);
2611b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2612b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Patch avcc's lengthSize field to match the number
2613b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // of bytes we use to indicate the size of a nal unit.
2614b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    uint8_t *ptr = (uint8_t *)mCodecSpecificData;
2615b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    ptr[4] = (ptr[4] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1);
2616b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("avcC");
2617b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2618b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // avcC
2619b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2620b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2621b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeD263Box() {
2622b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("d263");
2623b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // vendor
2624b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);   // decoder version
2625b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(10);  // level: 10
2626b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);   // profile: 0
2627b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // d263
2628b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2629b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2630b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong// This is useful if the pixel is not square
2631b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writePaspBox() {
2632b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("pasp");
2633b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1 << 16);  // hspacing
2634b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1 << 16);  // vspacing
2635b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // pasp
2636b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2637b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2638b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeSttsBox() {
2639b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stts");
2640b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2641b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mNumSttsTableEntries);
264270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
2643a472613aec322e25891abf5c77bf3f7e3c244920James Dong    // Compensate for small start time difference from different media tracks
2644a472613aec322e25891abf5c77bf3f7e3c244920James Dong    int64_t trackStartTimeOffsetUs = 0;
2645b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
2646b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mStartTimestampUs != moovStartTimeUs) {
2647b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(mStartTimestampUs > moovStartTimeUs);
2648b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
2649b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2650b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int64_t prevTimestampUs = trackStartTimeOffsetUs;
2651b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
2652b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mSttsTableEntries.end(); ++it) {
2653b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(it->sampleCount);
2654a472613aec322e25891abf5c77bf3f7e3c244920James Dong
2655b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        // Make sure that we are calculating the sample duration the exactly
2656b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        // same way as we made decision on how to create stts entries.
2657b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        int64_t currTimestampUs = prevTimestampUs + it->sampleDurationUs;
2658b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        int32_t dur = ((currTimestampUs * mTimeScale + 500000LL) / 1000000LL -
2659b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            (prevTimestampUs * mTimeScale + 500000LL) / 1000000LL);
2660b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        prevTimestampUs += (it->sampleCount * it->sampleDurationUs);
266120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2662b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(dur);
2663b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2664b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stts
2665b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
266620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2667b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStssBox() {
2668b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stss");
2669b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2670b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mNumStssTableEntries);  // number of sync frames
2671b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<int32_t>::iterator it = mStssTableEntries.begin();
2672b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mStssTableEntries.end(); ++it) {
2673b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(*it);
2674b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2675b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stss
2676b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
267725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
2678b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStszBox() {
2679b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stsz");
2680b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2681b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mSamplesHaveSameSize) {
2682b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        List<size_t>::iterator it = mSampleSizes.begin();
2683b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(*it);  // default sample size
2684b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2685b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(0);
2686b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2687b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mNumSamples);
2688b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!mSamplesHaveSameSize) {
2689b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        for (List<size_t>::iterator it = mSampleSizes.begin();
2690b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            it != mSampleSizes.end(); ++it) {
2691b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->writeInt32(*it);
2692b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        }
2693b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2694b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stsz
2695b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
269620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2697b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStscBox() {
2698b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stsc");
2699b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2700b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mNumStscTableEntries);
2701b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<StscTableEntry>::iterator it = mStscTableEntries.begin();
2702b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mStscTableEntries.end(); ++it) {
2703b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(it->firstChunk);
2704b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(it->samplesPerChunk);
2705b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(it->sampleDescriptionId);
2706b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2707b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stsc
2708b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
270920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2710b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) {
2711b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox(use32BitOffset? "stco": "co64");
2712b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2713b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mNumStcoTableEntries);
2714b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<off64_t>::iterator it = mChunkOffsets.begin();
2715b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mChunkOffsets.end(); ++it) {
2716b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        if (use32BitOffset) {
2717b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->writeInt32(static_cast<int32_t>(*it));
2718b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        } else {
2719b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->writeInt64((*it));
2720b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        }
2721b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2722b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stco or co64
272320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
272420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
272520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}  // namespace android
2726