MPEG4Writer.cpp revision 8c460498c028888c533ab442be12b6d4b669b965
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>
2520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong#include <media/stagefright/foundation/ADebug.h>
2720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MPEG4Writer.h>
2820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaBuffer.h>
2920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MetaData.h>
3018291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber#include <media/stagefright/MediaDefs.h>
3103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber#include <media/stagefright/MediaErrors.h>
3220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/MediaSource.h>
3320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber#include <media/stagefright/Utils.h>
34d599cd4573b5a2d5914c5040e0565ef866749b77James Dong#include <media/mediarecorder.h>
3507ec01904613a0bac32caaa8444b4690998faed7James Dong#include <cutils/properties.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
5020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberclass MPEG4Writer::Track {
5120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberpublic:
52bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId);
538f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
5420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    ~Track();
5520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
5693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    status_t start(MetaData *params);
5737187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t stop();
5837187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t pause();
5925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool reachedEOS();
6020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
613b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber    int64_t getDurationUs() const;
62d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    int64_t getEstimatedTrackSizeBytes() const;
63b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeTrackHeader(bool use32BitOffset = true);
641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    void bufferChunk(int64_t timestampUs);
651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool isAvc() const { return mIsAvc; }
661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool isAudio() const { return mIsAudio; }
671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool isMPEG4() const { return mIsMPEG4; }
68c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    void addChunkOffset(off64_t offset);
6970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    int32_t getTrackId() const { return mTrackId; }
70dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    status_t dump(int fd, const Vector<String16>& args) const;
7120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
7220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberprivate:
73000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    enum {
74000e18370baae60ffd9f25b509501dd8c26deabfJames Dong        kMaxCttsOffsetTimeUs = 1000000LL,  // 1 second
758c460498c028888c533ab442be12b6d4b669b965James Dong        kSampleArraySize = 1000,
76000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    };
77000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
7820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    MPEG4Writer *mOwner;
7920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    sp<MetaData> mMeta;
80693d271e62a3726689ff68f4505ba49228eb94b2Andreas Huber    sp<MediaSource> mSource;
8120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    volatile bool mDone;
82a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    volatile bool mPaused;
83a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    volatile bool mResumed;
84eaae38445a340c4857c1c5569475879a728e63b7James Dong    volatile bool mStarted;
851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool mIsAvc;
861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool mIsAudio;
871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool mIsMPEG4;
88bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    int32_t mTrackId;
89c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    int64_t mTrackDurationUs;
9043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    int64_t mMaxChunkDurationUs;
91e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
92e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    bool mIsRealTimeRecording;
93e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    int64_t mMaxTimeStampUs;
94d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    int64_t mEstimatedTrackSizeBytes;
951f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    int64_t mMdatSizeBytes;
968f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int32_t mTimeScale;
9720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
9820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_t mThread;
9920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1008c460498c028888c533ab442be12b6d4b669b965James Dong    /*
1018c460498c028888c533ab442be12b6d4b669b965James Dong     * mNumSamples is used to track the total number of samples in
1028c460498c028888c533ab442be12b6d4b669b965James Dong     * mSampleSizes List.
1038c460498c028888c533ab442be12b6d4b669b965James Dong     *
1048c460498c028888c533ab442be12b6d4b669b965James Dong     * A linked list of fixed sized array is used here to reduce the time
1058c460498c028888c533ab442be12b6d4b669b965James Dong     * to write out stsz box.
1068c460498c028888c533ab442be12b6d4b669b965James Dong     */
1078c460498c028888c533ab442be12b6d4b669b965James Dong    uint32_t            mNumSamples;
1088c460498c028888c533ab442be12b6d4b669b965James Dong    uint32_t*           mCurrentSampleSizeArr;
1098c460498c028888c533ab442be12b6d4b669b965James Dong    List<uint32_t *>    mSampleSizes;
110be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    bool                mSamplesHaveSameSize;
111be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
11213aec890216948b0c364f8f92792129d0335f506James Dong    List<MediaBuffer *> mChunkSamples;
1131f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1141f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    size_t              mNumStcoTableEntries;
115c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    List<off64_t>         mChunkOffsets;
11613aec890216948b0c364f8f92792129d0335f506James Dong
1171f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    size_t              mNumStscTableEntries;
11813aec890216948b0c364f8f92792129d0335f506James Dong    struct StscTableEntry {
11913aec890216948b0c364f8f92792129d0335f506James Dong
12013aec890216948b0c364f8f92792129d0335f506James Dong        StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id)
12113aec890216948b0c364f8f92792129d0335f506James Dong            : firstChunk(chunk),
12213aec890216948b0c364f8f92792129d0335f506James Dong              samplesPerChunk(samples),
12313aec890216948b0c364f8f92792129d0335f506James Dong              sampleDescriptionId(id) {}
12413aec890216948b0c364f8f92792129d0335f506James Dong
12513aec890216948b0c364f8f92792129d0335f506James Dong        uint32_t firstChunk;
12613aec890216948b0c364f8f92792129d0335f506James Dong        uint32_t samplesPerChunk;
12713aec890216948b0c364f8f92792129d0335f506James Dong        uint32_t sampleDescriptionId;
12813aec890216948b0c364f8f92792129d0335f506James Dong    };
12913aec890216948b0c364f8f92792129d0335f506James Dong    List<StscTableEntry> mStscTableEntries;
13020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1311f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    size_t        mNumStssTableEntries;
132050b28a593350047845a45a14cc5026221ac1620James Dong    List<int32_t> mStssTableEntries;
133050b28a593350047845a45a14cc5026221ac1620James Dong
134be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    struct SttsTableEntry {
135be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
13679761ab096f57c3027fad9556c2bc436672d614eJames Dong        SttsTableEntry(uint32_t count, uint32_t duration)
13779761ab096f57c3027fad9556c2bc436672d614eJames Dong            : sampleCount(count), sampleDuration(duration) {}
138be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
139be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        uint32_t sampleCount;
14079761ab096f57c3027fad9556c2bc436672d614eJames Dong        uint32_t sampleDuration;  // time scale based
141be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    };
142965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    size_t        mNumSttsTableEntries;
143be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    List<SttsTableEntry> mSttsTableEntries;
144be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
145965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    struct CttsTableEntry {
146965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        CttsTableEntry(uint32_t count, int32_t timescaledDur)
147965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong            : sampleCount(count), sampleDuration(timescaledDur) {}
148965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
149965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        uint32_t sampleCount;
15043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        uint32_t sampleDuration;  // time scale based
151965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    };
152965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    size_t        mNumCttsTableEntries;
153965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    List<CttsTableEntry> mCttsTableEntries;
154000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    int64_t mMinCttsOffsetTimeUs;
155000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    int64_t mMaxCttsOffsetTimeUs;
156965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
1573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Sequence parameter set or picture parameter set
1583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    struct AVCParamSet {
1593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        AVCParamSet(uint16_t length, const uint8_t *data)
1603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            : mLength(length), mData(data) {}
1613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
1623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t mLength;
1633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *mData;
1643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    };
1653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    List<AVCParamSet> mSeqParamSets;
1663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    List<AVCParamSet> mPicParamSets;
1673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mProfileIdc;
1683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mProfileCompatible;
1693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mLevelIdc;
1703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
17120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    void *mCodecSpecificData;
17220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    size_t mCodecSpecificDataSize;
173548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber    bool mGotAllCodecSpecificData;
17493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    bool mTrackingProgressStatus;
17520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
17625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool mReachedEOS;
1773c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    int64_t mStartTimestampUs;
17870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    int64_t mStartTimeRealUs;
17970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    int64_t mFirstSampleTimeRealUs;
18093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t mPreviousTrackTimeUs;
18193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t mTrackEveryTimeDurationUs;
18225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
183872a481558350634a3fd5cb67939de288af00ecbJames Dong    // Update the audio track's drift information.
184872a481558350634a3fd5cb67939de288af00ecbJames Dong    void updateDriftTime(const sp<MetaData>& meta);
185872a481558350634a3fd5cb67939de288af00ecbJames Dong
186000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    int32_t getStartTimeOffsetScaledTime() const;
187000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
18820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    static void *ThreadWrapper(void *me);
18937187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t threadEntry();
19020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *parseParamSet(
1923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length, int type, size_t *paramSetLen);
1933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
194b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    status_t makeAVCCodecSpecificData(const uint8_t *data, size_t size);
195b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    status_t copyAVCCodecSpecificData(const uint8_t *data, size_t size);
196b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    status_t parseAVCCodecSpecificData(const uint8_t *data, size_t size);
197215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong
198215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    // Track authoring progress status
199faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    void trackProgressStatus(int64_t timeUs, status_t err = OK);
20093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    void initTrackingProgressStatus(MetaData *params);
20103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
20219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    void getCodecSpecificDataFromInputFormatIfPossible();
20319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
204c059860c73678a202bfa33062723e8f82fb779d9James Dong    // Determine the track time scale
205c059860c73678a202bfa33062723e8f82fb779d9James Dong    // If it is an audio track, try to use the sampling rate as
206c059860c73678a202bfa33062723e8f82fb779d9James Dong    // the time scale; however, if user chooses the overwrite
207c059860c73678a202bfa33062723e8f82fb779d9James Dong    // value, the user-supplied time scale will be used.
208c059860c73678a202bfa33062723e8f82fb779d9James Dong    void setTimeScale();
209c059860c73678a202bfa33062723e8f82fb779d9James Dong
210690f546b0ee548dbfe997df36418e5302ec2d786James Dong    // Simple validation on the codec specific data
211690f546b0ee548dbfe997df36418e5302ec2d786James Dong    status_t checkCodecSpecificData() const;
21213f6284305e4b27395a23db7882d670bdb1bcae1James Dong    int32_t mRotation;
213690f546b0ee548dbfe997df36418e5302ec2d786James Dong
2141f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void updateTrackSizeEstimate();
2151f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void addOneStscTableEntry(size_t chunkId, size_t sampleId);
2161f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void addOneStssTableEntry(size_t sampleId);
21779761ab096f57c3027fad9556c2bc436672d614eJames Dong
21879761ab096f57c3027fad9556c2bc436672d614eJames Dong    // Duration is time scale based
21979761ab096f57c3027fad9556c2bc436672d614eJames Dong    void addOneSttsTableEntry(size_t sampleCount, int32_t timescaledDur);
220965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    void addOneCttsTableEntry(size_t sampleCount, int32_t timescaledDur);
22145c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong
22245c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    bool isTrackMalFormed() const;
22343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    void sendTrackSummary(bool hasMultipleTracks);
2241f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
225b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Write the boxes
226b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStcoBox(bool use32BitOffset);
227b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStscBox();
228b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStszBox();
229b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStssBox();
230b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeSttsBox();
231965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    void writeCttsBox();
232b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeD263Box();
233b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writePaspBox();
234b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeAvccBox();
235b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeUrlBox();
236b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeDrefBox();
237b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeDinfBox();
238b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeDamrBox();
239b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeMdhdBox(time_t now);
240b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeSmhdBox();
241b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeVmhdBox();
242b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeHdlrBox();
243b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeTkhdBox(time_t now);
244b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeMp4aEsdsBox();
245b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeMp4vEsdsBox();
246b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeAudioFourCCBox();
247b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeVideoFourCCBox();
248b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStblBox(bool use32BitOffset);
249b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
25020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track(const Track &);
25120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track &operator=(const Track &);
25220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber};
25320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
25420111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::MPEG4Writer(const char *filename)
255674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    : mFd(-1),
256674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong      mInitCheck(NO_INIT),
257b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong      mUse4ByteNalLength(true),
2581acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong      mUse32BitOffset(true),
259a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong      mIsFileSizeLimitExplicitlyRequested(false),
260a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
261a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mStarted(false),
262411ba422e3635d534928ffd81abf54f4f291c739James Dong      mWriterThreadStarted(false),
26320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mOffset(0),
26413aec890216948b0c364f8f92792129d0335f506James Dong      mMdatOffset(0),
2657837c17063a4c50bc856ba59418516fdab731de7James Dong      mEstimatedMoovBoxSize(0),
26607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mInterleaveDurationUs(1000000),
26707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mLatitudex10000(0),
26807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mLongitudex10000(0),
26986b7f47aa7482424cf8fd248f1315311919be3b0James Dong      mAreGeoTagsAvailable(false),
27086b7f47aa7482424cf8fd248f1315311919be3b0James Dong      mStartTimeOffsetMs(-1) {
271674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong
27203f6f4e7e2ce09357cbc05bb546cd8a6e54b5baeJames Dong    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR);
273674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mFd >= 0) {
274674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        mInitCheck = OK;
275674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    }
27620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
27720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
27830ab66297501757d745b9ae10da61adcd891f497Andreas HuberMPEG4Writer::MPEG4Writer(int fd)
279674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    : mFd(dup(fd)),
280674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong      mInitCheck(mFd < 0? NO_INIT: OK),
281b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong      mUse4ByteNalLength(true),
2821acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong      mUse32BitOffset(true),
283a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong      mIsFileSizeLimitExplicitlyRequested(false),
284a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
285a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mStarted(false),
286411ba422e3635d534928ffd81abf54f4f291c739James Dong      mWriterThreadStarted(false),
28730ab66297501757d745b9ae10da61adcd891f497Andreas Huber      mOffset(0),
28813aec890216948b0c364f8f92792129d0335f506James Dong      mMdatOffset(0),
2897837c17063a4c50bc856ba59418516fdab731de7James Dong      mEstimatedMoovBoxSize(0),
29007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mInterleaveDurationUs(1000000),
29107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mLatitudex10000(0),
29207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mLongitudex10000(0),
29386b7f47aa7482424cf8fd248f1315311919be3b0James Dong      mAreGeoTagsAvailable(false),
29486b7f47aa7482424cf8fd248f1315311919be3b0James Dong      mStartTimeOffsetMs(-1) {
29530ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
29630ab66297501757d745b9ae10da61adcd891f497Andreas Huber
29720111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() {
2988bcc65c753085fe3328592cceda0cf0e8f8b0a45James Dong    reset();
29920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
3001f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    while (!mTracks.empty()) {
3011f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        List<Track *>::iterator it = mTracks.begin();
30220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        delete *it;
3031f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        (*it) = NULL;
3041f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        mTracks.erase(it);
30520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
30620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mTracks.clear();
30720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
30820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
309dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::dump(
310dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        int fd, const Vector<String16>& args) {
311dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    const size_t SIZE = 256;
312dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    char buffer[SIZE];
313dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    String8 result;
314dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "   MPEG4Writer %p\n", this);
315dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
316dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "     mStarted: %s\n", mStarted? "true": "false");
317dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
318dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    ::write(fd, result.string(), result.size());
319dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    for (List<Track *>::iterator it = mTracks.begin();
320dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong         it != mTracks.end(); ++it) {
321dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        (*it)->dump(fd, args);
322dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    }
323dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    return OK;
324dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong}
325dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong
326dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::Track::dump(
327dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        int fd, const Vector<String16>& args) const {
328dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    const size_t SIZE = 256;
329dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    char buffer[SIZE];
330dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    String8 result;
331dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "     %s track\n", mIsAudio? "Audio": "Video");
332dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
333dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "       reached EOS: %s\n",
334dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong            mReachedEOS? "true": "false");
335dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
336dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    ::write(fd, result.string(), result.size());
337dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    return OK;
338dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong}
339dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong
3402dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
341bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    Mutex::Autolock l(mLock);
342bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    if (mStarted) {
34329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Attempt to add source AFTER recording is started");
344bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        return UNKNOWN_ERROR;
345bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    }
346bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    Track *track = new Track(this, source, mTracks.size());
34720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mTracks.push_back(track);
3482dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
3492dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    return OK;
35020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
35120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
35293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::startTracks(MetaData *params) {
353a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    for (List<Track *>::iterator it = mTracks.begin();
354a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong         it != mTracks.end(); ++it) {
35593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        status_t err = (*it)->start(params);
356a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
357a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (err != OK) {
358a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            for (List<Track *>::iterator it2 = mTracks.begin();
359a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong                 it2 != it; ++it2) {
360a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong                (*it2)->stop();
361a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            }
362a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
363a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            return err;
364a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
365a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
366a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    return OK;
367a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
368a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
3692dec2b5be2056c6d9428897dc672185872d30d17James Dongint64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) {
3702dec2b5be2056c6d9428897dc672185872d30d17James Dong    // This implementation is highly experimental/heurisitic.
3712dec2b5be2056c6d9428897dc672185872d30d17James Dong    //
3722dec2b5be2056c6d9428897dc672185872d30d17James Dong    // Statistical analysis shows that metadata usually accounts
3732dec2b5be2056c6d9428897dc672185872d30d17James Dong    // for a small portion of the total file size, usually < 0.6%.
3742dec2b5be2056c6d9428897dc672185872d30d17James Dong
37578a1a286f736888ae7af8860b2c424af0d978848James Dong    // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2,
3762dec2b5be2056c6d9428897dc672185872d30d17James Dong    // where 1MB is the common file size limit for MMS application.
37778a1a286f736888ae7af8860b2c424af0d978848James Dong    // The default MAX _MOOV_BOX_SIZE value is based on about 3
3782dec2b5be2056c6d9428897dc672185872d30d17James Dong    // minute video recording with a bit rate about 3 Mbps, because
3792dec2b5be2056c6d9428897dc672185872d30d17James Dong    // statistics also show that most of the video captured are going
3802dec2b5be2056c6d9428897dc672185872d30d17James Dong    // to be less than 3 minutes.
3812dec2b5be2056c6d9428897dc672185872d30d17James Dong
3822dec2b5be2056c6d9428897dc672185872d30d17James Dong    // If the estimation is wrong, we will pay the price of wasting
3832dec2b5be2056c6d9428897dc672185872d30d17James Dong    // some reserved space. This should not happen so often statistically.
3842dec2b5be2056c6d9428897dc672185872d30d17James Dong    static const int32_t factor = mUse32BitOffset? 1: 2;
38578a1a286f736888ae7af8860b2c424af0d978848James Dong    static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024;  // 3 KB
3862dec2b5be2056c6d9428897dc672185872d30d17James Dong    static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000);
3872dec2b5be2056c6d9428897dc672185872d30d17James Dong    int64_t size = MIN_MOOV_BOX_SIZE;
3882dec2b5be2056c6d9428897dc672185872d30d17James Dong
38978a1a286f736888ae7af8860b2c424af0d978848James Dong    // Max file size limit is set
390a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
39178a1a286f736888ae7af8860b2c424af0d978848James Dong        size = mMaxFileSizeLimitBytes * 6 / 1000;
39278a1a286f736888ae7af8860b2c424af0d978848James Dong    }
39378a1a286f736888ae7af8860b2c424af0d978848James Dong
39478a1a286f736888ae7af8860b2c424af0d978848James Dong    // Max file duration limit is set
39578a1a286f736888ae7af8860b2c424af0d978848James Dong    if (mMaxFileDurationLimitUs != 0) {
39678a1a286f736888ae7af8860b2c424af0d978848James Dong        if (bitRate > 0) {
39778a1a286f736888ae7af8860b2c424af0d978848James Dong            int64_t size2 =
39878a1a286f736888ae7af8860b2c424af0d978848James Dong                ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000);
39978a1a286f736888ae7af8860b2c424af0d978848James Dong            if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
40078a1a286f736888ae7af8860b2c424af0d978848James Dong                // When both file size and duration limits are set,
40178a1a286f736888ae7af8860b2c424af0d978848James Dong                // we use the smaller limit of the two.
40278a1a286f736888ae7af8860b2c424af0d978848James Dong                if (size > size2) {
40378a1a286f736888ae7af8860b2c424af0d978848James Dong                    size = size2;
40478a1a286f736888ae7af8860b2c424af0d978848James Dong                }
40578a1a286f736888ae7af8860b2c424af0d978848James Dong            } else {
40678a1a286f736888ae7af8860b2c424af0d978848James Dong                // Only max file duration limit is set
40778a1a286f736888ae7af8860b2c424af0d978848James Dong                size = size2;
40878a1a286f736888ae7af8860b2c424af0d978848James Dong            }
4092dec2b5be2056c6d9428897dc672185872d30d17James Dong        }
4102dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
41178a1a286f736888ae7af8860b2c424af0d978848James Dong
4122dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (size < MIN_MOOV_BOX_SIZE) {
4132dec2b5be2056c6d9428897dc672185872d30d17James Dong        size = MIN_MOOV_BOX_SIZE;
4142dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
4152dec2b5be2056c6d9428897dc672185872d30d17James Dong
4162dec2b5be2056c6d9428897dc672185872d30d17James Dong    // Any long duration recording will be probably end up with
4172dec2b5be2056c6d9428897dc672185872d30d17James Dong    // non-streamable mp4 file.
4182dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (size > MAX_MOOV_BOX_SIZE) {
4192dec2b5be2056c6d9428897dc672185872d30d17James Dong        size = MAX_MOOV_BOX_SIZE;
4202dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
4212dec2b5be2056c6d9428897dc672185872d30d17James Dong
422df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block    ALOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated"
4232dec2b5be2056c6d9428897dc672185872d30d17James Dong         " moov size %lld bytes",
4242dec2b5be2056c6d9428897dc672185872d30d17James Dong         mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size);
4252dec2b5be2056c6d9428897dc672185872d30d17James Dong    return factor * size;
4262dec2b5be2056c6d9428897dc672185872d30d17James Dong}
4272dec2b5be2056c6d9428897dc672185872d30d17James Dong
4282dec2b5be2056c6d9428897dc672185872d30d17James Dongstatus_t MPEG4Writer::start(MetaData *param) {
429674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mInitCheck != OK) {
43025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        return UNKNOWN_ERROR;
43120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
43220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
433a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    /*
434a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * Check mMaxFileSizeLimitBytes at the beginning
435a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * since mMaxFileSizeLimitBytes may be implicitly
436a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * changed later for 32-bit file offset even if
437a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * user does not ask to set it explicitly.
438a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     */
439a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    if (mMaxFileSizeLimitBytes != 0) {
440a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong        mIsFileSizeLimitExplicitlyRequested = true;
441a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    }
442a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong
4432dec2b5be2056c6d9428897dc672185872d30d17James Dong    int32_t use64BitOffset;
4442dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (param &&
4452dec2b5be2056c6d9428897dc672185872d30d17James Dong        param->findInt32(kKey64BitFileOffset, &use64BitOffset) &&
4462dec2b5be2056c6d9428897dc672185872d30d17James Dong        use64BitOffset) {
4472dec2b5be2056c6d9428897dc672185872d30d17James Dong        mUse32BitOffset = false;
4482dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
4492dec2b5be2056c6d9428897dc672185872d30d17James Dong
4501f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    if (mUse32BitOffset) {
4511f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        // Implicit 32 bit file size limit
4521f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        if (mMaxFileSizeLimitBytes == 0) {
4531f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            mMaxFileSizeLimitBytes = kMax32BitFileSize;
4541f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        }
4551f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
4561f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        // If file size is set to be larger than the 32 bit file
4571f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        // size limit, treat it as an error.
4581f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        if (mMaxFileSizeLimitBytes > kMax32BitFileSize) {
4595ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block            ALOGW("32-bit file size limit (%lld bytes) too big. "
460d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong                 "It is changed to %lld bytes",
461d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong                mMaxFileSizeLimitBytes, kMax32BitFileSize);
462d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong            mMaxFileSizeLimitBytes = kMax32BitFileSize;
4631f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        }
4641f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    }
4651f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
466b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    int32_t use2ByteNalLength;
467b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    if (param &&
468b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) &&
469b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        use2ByteNalLength) {
470b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        mUse4ByteNalLength = false;
4712dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
4722dec2b5be2056c6d9428897dc672185872d30d17James Dong
473065d1aff96818df54456053f1574aec8a234d0deJames Dong    mStartTimestampUs = -1;
47493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
475a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (mStarted) {
476a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mPaused) {
477a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            mPaused = false;
47893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            return startTracks(param);
479a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
480a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return OK;
481a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
482a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
4838f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    if (!param ||
4848f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        !param->findInt32(kKeyTimeScale, &mTimeScale)) {
4858f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        mTimeScale = 1000;
4868f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    }
48743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GT(mTimeScale, 0);
4883856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("movie time scale: %d", mTimeScale);
4898f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
4907837c17063a4c50bc856ba59418516fdab731de7James Dong    mStreamableFile = true;
4917837c17063a4c50bc856ba59418516fdab731de7James Dong    mWriteMoovBoxToMemory = false;
4927837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBuffer = NULL;
4937837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBufferOffset = 0;
4947837c17063a4c50bc856ba59418516fdab731de7James Dong
495b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeFtypBox(param);
49620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
4977837c17063a4c50bc856ba59418516fdab731de7James Dong    mFreeBoxOffset = mOffset;
49820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
4997837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mEstimatedMoovBoxSize == 0) {
5002dec2b5be2056c6d9428897dc672185872d30d17James Dong        int32_t bitRate = -1;
5012dec2b5be2056c6d9428897dc672185872d30d17James Dong        if (param) {
5022dec2b5be2056c6d9428897dc672185872d30d17James Dong            param->findInt32(kKeyBitRate, &bitRate);
5032dec2b5be2056c6d9428897dc672185872d30d17James Dong        }
5042dec2b5be2056c6d9428897dc672185872d30d17James Dong        mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate);
5057837c17063a4c50bc856ba59418516fdab731de7James Dong    }
50643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GE(mEstimatedMoovBoxSize, 8);
507c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    lseek64(mFd, mFreeBoxOffset, SEEK_SET);
5087837c17063a4c50bc856ba59418516fdab731de7James Dong    writeInt32(mEstimatedMoovBoxSize);
5097837c17063a4c50bc856ba59418516fdab731de7James Dong    write("free", 4);
5107837c17063a4c50bc856ba59418516fdab731de7James Dong
5117837c17063a4c50bc856ba59418516fdab731de7James Dong    mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize;
5127837c17063a4c50bc856ba59418516fdab731de7James Dong    mOffset = mMdatOffset;
513c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    lseek64(mFd, mMdatOffset, SEEK_SET);
5141acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    if (mUse32BitOffset) {
5151acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        write("????mdat", 8);
5161acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    } else {
5171acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        write("\x00\x00\x00\x01mdat????????", 16);
5181acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    }
5191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
5201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    status_t err = startWriterThread();
5211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (err != OK) {
5221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        return err;
5231c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
5241c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
5251c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    err = startTracks(param);
526a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (err != OK) {
527a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return err;
52820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
5291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
530a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mStarted = true;
53125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return OK;
53220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
53320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
5341f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongbool MPEG4Writer::use32BitFileOffset() const {
5351f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    return mUse32BitOffset;
5361f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
5371f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
53837187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::pause() {
539674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mInitCheck != OK) {
54037187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
541a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
542a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mPaused = true;
54337187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = OK;
544a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    for (List<Track *>::iterator it = mTracks.begin();
545a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong         it != mTracks.end(); ++it) {
54637187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = (*it)->pause();
54737187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (status != OK) {
54837187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
54937187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
550a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
55137187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
552a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
553a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
5541c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::stopWriterThread() {
555b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("Stopping writer thread");
556411ba422e3635d534928ffd81abf54f4f291c739James Dong    if (!mWriterThreadStarted) {
557411ba422e3635d534928ffd81abf54f4f291c739James Dong        return;
558411ba422e3635d534928ffd81abf54f4f291c739James Dong    }
5591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
5601c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    {
5611c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        Mutex::Autolock autolock(mLock);
5621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
5631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mDone = true;
5641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mChunkReadyCondition.signal();
5651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
5661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
5671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    void *dummy;
5681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_join(mThread, &dummy);
569411ba422e3635d534928ffd81abf54f4f291c739James Dong    mWriterThreadStarted = false;
570b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("Writer thread stopped");
5711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
5721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
57313f6284305e4b27395a23db7882d670bdb1bcae1James Dong/*
57413f6284305e4b27395a23db7882d670bdb1bcae1James Dong * MP4 file standard defines a composition matrix:
57513f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | a  b  u |
57613f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | c  d  v |
57713f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | x  y  w |
57813f6284305e4b27395a23db7882d670bdb1bcae1James Dong *
57913f6284305e4b27395a23db7882d670bdb1bcae1James Dong * the element in the matrix is stored in the following
58013f6284305e4b27395a23db7882d670bdb1bcae1James Dong * order: {a, b, u, c, d, v, x, y, w},
58113f6284305e4b27395a23db7882d670bdb1bcae1James Dong * where a, b, c, d, x, and y is in 16.16 format, while
58213f6284305e4b27395a23db7882d670bdb1bcae1James Dong * u, v and w is in 2.30 format.
58313f6284305e4b27395a23db7882d670bdb1bcae1James Dong */
58413f6284305e4b27395a23db7882d670bdb1bcae1James Dongvoid MPEG4Writer::writeCompositionMatrix(int degrees) {
5853856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("writeCompositionMatrix");
58613f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t a = 0x00010000;
58713f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t b = 0;
58813f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t c = 0;
58913f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t d = 0x00010000;
59013f6284305e4b27395a23db7882d670bdb1bcae1James Dong    switch (degrees) {
59113f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 0:
59213f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
59313f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 90:
59413f6284305e4b27395a23db7882d670bdb1bcae1James Dong            a = 0;
59513f6284305e4b27395a23db7882d670bdb1bcae1James Dong            b = 0x00010000;
59613f6284305e4b27395a23db7882d670bdb1bcae1James Dong            c = 0xFFFF0000;
59713f6284305e4b27395a23db7882d670bdb1bcae1James Dong            d = 0;
59813f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
59913f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 180:
60013f6284305e4b27395a23db7882d670bdb1bcae1James Dong            a = 0xFFFF0000;
60113f6284305e4b27395a23db7882d670bdb1bcae1James Dong            d = 0xFFFF0000;
60213f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
60313f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 270:
60413f6284305e4b27395a23db7882d670bdb1bcae1James Dong            a = 0;
60513f6284305e4b27395a23db7882d670bdb1bcae1James Dong            b = 0xFFFF0000;
60613f6284305e4b27395a23db7882d670bdb1bcae1James Dong            c = 0x00010000;
60713f6284305e4b27395a23db7882d670bdb1bcae1James Dong            d = 0;
60813f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
60913f6284305e4b27395a23db7882d670bdb1bcae1James Dong        default:
61013f6284305e4b27395a23db7882d670bdb1bcae1James Dong            CHECK(!"Should never reach this unknown rotation");
61113f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
61213f6284305e4b27395a23db7882d670bdb1bcae1James Dong    }
61313f6284305e4b27395a23db7882d670bdb1bcae1James Dong
61413f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(a);           // a
61513f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(b);           // b
61613f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // u
61713f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(c);           // c
61813f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(d);           // d
61913f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // v
62013f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // x
62113f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // y
62213f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0x40000000);  // w
62313f6284305e4b27395a23db7882d670bdb1bcae1James Dong}
62413f6284305e4b27395a23db7882d670bdb1bcae1James Dong
625411ba422e3635d534928ffd81abf54f4f291c739James Dongvoid MPEG4Writer::release() {
626411ba422e3635d534928ffd81abf54f4f291c739James Dong    close(mFd);
627411ba422e3635d534928ffd81abf54f4f291c739James Dong    mFd = -1;
628411ba422e3635d534928ffd81abf54f4f291c739James Dong    mInitCheck = NO_INIT;
629411ba422e3635d534928ffd81abf54f4f291c739James Dong    mStarted = false;
630411ba422e3635d534928ffd81abf54f4f291c739James Dong}
63113f6284305e4b27395a23db7882d670bdb1bcae1James Dong
6328bcc65c753085fe3328592cceda0cf0e8f8b0a45James Dongstatus_t MPEG4Writer::reset() {
633674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mInitCheck != OK) {
63437187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
635411ba422e3635d534928ffd81abf54f4f291c739James Dong    } else {
636411ba422e3635d534928ffd81abf54f4f291c739James Dong        if (!mWriterThreadStarted ||
637411ba422e3635d534928ffd81abf54f4f291c739James Dong            !mStarted) {
638411ba422e3635d534928ffd81abf54f4f291c739James Dong            if (mWriterThreadStarted) {
639411ba422e3635d534928ffd81abf54f4f291c739James Dong                stopWriterThread();
640411ba422e3635d534928ffd81abf54f4f291c739James Dong            }
641411ba422e3635d534928ffd81abf54f4f291c739James Dong            release();
642411ba422e3635d534928ffd81abf54f4f291c739James Dong            return OK;
643411ba422e3635d534928ffd81abf54f4f291c739James Dong        }
64420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
64520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
64637187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = OK;
6478f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t maxDurationUs = 0;
64865b3d76025c71d755b0fb3b6ead90255f25417edJames Dong    int64_t minDurationUs = 0x7fffffffffffffffLL;
64920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    for (List<Track *>::iterator it = mTracks.begin();
65020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber         it != mTracks.end(); ++it) {
65137187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = (*it)->stop();
65237187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (err == OK && status != OK) {
65337187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
65437187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
65520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6568f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        int64_t durationUs = (*it)->getDurationUs();
6578f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        if (durationUs > maxDurationUs) {
6588f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            maxDurationUs = durationUs;
65920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
66065b3d76025c71d755b0fb3b6ead90255f25417edJames Dong        if (durationUs < minDurationUs) {
66165b3d76025c71d755b0fb3b6ead90255f25417edJames Dong            minDurationUs = durationUs;
66265b3d76025c71d755b0fb3b6ead90255f25417edJames Dong        }
66365b3d76025c71d755b0fb3b6ead90255f25417edJames Dong    }
66465b3d76025c71d755b0fb3b6ead90255f25417edJames Dong
66565b3d76025c71d755b0fb3b6ead90255f25417edJames Dong    if (mTracks.size() > 1) {
666b8a805261bf0282e992d3608035e47d05a898710Steve Block        ALOGD("Duration from tracks range is [%lld, %lld] us",
66765b3d76025c71d755b0fb3b6ead90255f25417edJames Dong            minDurationUs, maxDurationUs);
66820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
66920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    stopWriterThread();
6717837c17063a4c50bc856ba59418516fdab731de7James Dong
67237187916a486504acaf83bea30147eb5fbf46ae5James Dong    // Do not write out movie header on error.
67337187916a486504acaf83bea30147eb5fbf46ae5James Dong    if (err != OK) {
674411ba422e3635d534928ffd81abf54f4f291c739James Dong        release();
67537187916a486504acaf83bea30147eb5fbf46ae5James Dong        return err;
67637187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
67737187916a486504acaf83bea30147eb5fbf46ae5James Dong
67820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    // Fix up the size of the 'mdat' chunk.
6791acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    if (mUse32BitOffset) {
680c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mMdatOffset, SEEK_SET);
6811acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset));
682c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &size, 4);
6831acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    } else {
684c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mMdatOffset + 8, SEEK_SET);
6851acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        int64_t size = mOffset - mMdatOffset;
6861acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        size = hton64(size);
687c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &size, 8);
6881acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    }
689c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    lseek64(mFd, mOffset, SEEK_SET);
69020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
691c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    const off64_t moovOffset = mOffset;
6927837c17063a4c50bc856ba59418516fdab731de7James Dong    mWriteMoovBoxToMemory = true;
6937837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
6947837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBufferOffset = 0;
6957837c17063a4c50bc856ba59418516fdab731de7James Dong    CHECK(mMoovBoxBuffer != NULL);
696b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeMoovBox(maxDurationUs);
69720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6987837c17063a4c50bc856ba59418516fdab731de7James Dong    mWriteMoovBoxToMemory = false;
6997837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mStreamableFile) {
70043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        CHECK_LE(mMoovBoxBufferOffset + 8, mEstimatedMoovBoxSize);
7017837c17063a4c50bc856ba59418516fdab731de7James Dong
7027837c17063a4c50bc856ba59418516fdab731de7James Dong        // Moov box
703c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mFreeBoxOffset, SEEK_SET);
7047837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset = mFreeBoxOffset;
705674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset);
7067837c17063a4c50bc856ba59418516fdab731de7James Dong
7077837c17063a4c50bc856ba59418516fdab731de7James Dong        // Free box
708c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mOffset, SEEK_SET);
7097837c17063a4c50bc856ba59418516fdab731de7James Dong        writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset);
7107837c17063a4c50bc856ba59418516fdab731de7James Dong        write("free", 4);
7117837c17063a4c50bc856ba59418516fdab731de7James Dong
7127837c17063a4c50bc856ba59418516fdab731de7James Dong        // Free temp memory
7137837c17063a4c50bc856ba59418516fdab731de7James Dong        free(mMoovBoxBuffer);
7147837c17063a4c50bc856ba59418516fdab731de7James Dong        mMoovBoxBuffer = NULL;
7157837c17063a4c50bc856ba59418516fdab731de7James Dong        mMoovBoxBufferOffset = 0;
7162dec2b5be2056c6d9428897dc672185872d30d17James Dong    } else {
717df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block        ALOGI("The mp4 file will not be streamable.");
7187837c17063a4c50bc856ba59418516fdab731de7James Dong    }
7197837c17063a4c50bc856ba59418516fdab731de7James Dong
7200c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(mBoxes.empty());
72120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
722411ba422e3635d534928ffd81abf54f4f291c739James Dong    release();
72337187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
72420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
72520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
726b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::writeMvhdBox(int64_t durationUs) {
727b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    time_t now = time(NULL);
728b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    beginBox("mvhd");
729b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // version=0, flags=0
730b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(now);           // creation time
731b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(now);           // modification time
732b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(mTimeScale);    // mvhd timescale
733b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t duration = (durationUs * mTimeScale + 5E5) / 1E6;
734b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(duration);
735b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0x10000);       // rate: 1.0
736b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt16(0x100);         // volume
737b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt16(0);             // reserved
738b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // reserved
739b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // reserved
740b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeCompositionMatrix(0); // matrix
741b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
742b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
743b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
744b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
745b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
746b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
747b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(mTracks.size() + 1);  // nextTrackID
748b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    endBox();  // mvhd
749b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
750b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
751b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::writeMoovBox(int64_t durationUs) {
752b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    beginBox("moov");
753b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeMvhdBox(durationUs);
75407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (mAreGeoTagsAvailable) {
75507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        writeUdtaBox();
75607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
757b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t id = 1;
758b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<Track *>::iterator it = mTracks.begin();
759b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mTracks.end(); ++it, ++id) {
760b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        (*it)->writeTrackHeader(mUse32BitOffset);
761b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
762b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    endBox();  // moov
763b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
764b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
7652cf9c5073ca3342ee52673ad68763fadd2c2be79James Dongvoid MPEG4Writer::writeFtypBox(MetaData *param) {
766b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    beginBox("ftyp");
767b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
768b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t fileType;
769b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (param && param->findInt32(kKeyFileType, &fileType) &&
770b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fileType != OUTPUT_FORMAT_MPEG_4) {
771b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeFourcc("3gp4");
772b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
773b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeFourcc("isom");
774b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
775b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
776b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);
777b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeFourcc("isom");
778b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeFourcc("3gp4");
779b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    endBox();
780b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
781b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
78207ec01904613a0bac32caaa8444b4690998faed7James Dongstatic bool isTestModeEnabled() {
78307ec01904613a0bac32caaa8444b4690998faed7James Dong#if (PROPERTY_VALUE_MAX < 5)
78407ec01904613a0bac32caaa8444b4690998faed7James Dong#error "PROPERTY_VALUE_MAX must be at least 5"
78507ec01904613a0bac32caaa8444b4690998faed7James Dong#endif
78607ec01904613a0bac32caaa8444b4690998faed7James Dong
78707ec01904613a0bac32caaa8444b4690998faed7James Dong    // Test mode is enabled only if rw.media.record.test system
78807ec01904613a0bac32caaa8444b4690998faed7James Dong    // property is enabled.
78907ec01904613a0bac32caaa8444b4690998faed7James Dong    char value[PROPERTY_VALUE_MAX];
79007ec01904613a0bac32caaa8444b4690998faed7James Dong    if (property_get("rw.media.record.test", value, NULL) &&
79107ec01904613a0bac32caaa8444b4690998faed7James Dong        (!strcasecmp(value, "true") || !strcasecmp(value, "1"))) {
79207ec01904613a0bac32caaa8444b4690998faed7James Dong        return true;
79307ec01904613a0bac32caaa8444b4690998faed7James Dong    }
79407ec01904613a0bac32caaa8444b4690998faed7James Dong    return false;
79507ec01904613a0bac32caaa8444b4690998faed7James Dong}
79607ec01904613a0bac32caaa8444b4690998faed7James Dong
79770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dongvoid MPEG4Writer::sendSessionSummary() {
79807ec01904613a0bac32caaa8444b4690998faed7James Dong    // Send session summary only if test mode is enabled
79907ec01904613a0bac32caaa8444b4690998faed7James Dong    if (!isTestModeEnabled()) {
80007ec01904613a0bac32caaa8444b4690998faed7James Dong        return;
80107ec01904613a0bac32caaa8444b4690998faed7James Dong    }
80207ec01904613a0bac32caaa8444b4690998faed7James Dong
80370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
80470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong         it != mChunkInfos.end(); ++it) {
80570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        int trackNum = it->mTrack->getTrackId() << 28;
80670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
80770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                trackNum | MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS,
80870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                it->mMaxInterChunkDurUs);
80970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    }
81070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong}
81170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
81213aec890216948b0c364f8f92792129d0335f506James Dongstatus_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) {
81313aec890216948b0c364f8f92792129d0335f506James Dong    mInterleaveDurationUs = durationUs;
81413aec890216948b0c364f8f92792129d0335f506James Dong    return OK;
81513aec890216948b0c364f8f92792129d0335f506James Dong}
81613aec890216948b0c364f8f92792129d0335f506James Dong
81713aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::lock() {
81813aec890216948b0c364f8f92792129d0335f506James Dong    mLock.lock();
81913aec890216948b0c364f8f92792129d0335f506James Dong}
82013aec890216948b0c364f8f92792129d0335f506James Dong
82113aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::unlock() {
82213aec890216948b0c364f8f92792129d0335f506James Dong    mLock.unlock();
82313aec890216948b0c364f8f92792129d0335f506James Dong}
82420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
825c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addSample_l(MediaBuffer *buffer) {
826c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t old_offset = mOffset;
82720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
828c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    ::write(mFd,
829c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong          (const uint8_t *)buffer->data() + buffer->range_offset(),
830c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong          buffer->range_length());
83120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
83220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mOffset += buffer->range_length();
83320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
83420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    return old_offset;
83520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
83620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
83703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) {
83803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (buffer->range_length() < 4) {
83903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return;
84003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
84103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
84203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    const uint8_t *ptr =
84303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        (const uint8_t *)buffer->data() + buffer->range_offset();
84403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
84503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
84603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        buffer->set_range(
84703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                buffer->range_offset() + 4, buffer->range_length() - 4);
84803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
84903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber}
85003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
851c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
852c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t old_offset = mOffset;
85330ab66297501757d745b9ae10da61adcd891f497Andreas Huber
85430ab66297501757d745b9ae10da61adcd891f497Andreas Huber    size_t length = buffer->range_length();
85503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
856b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    if (mUse4ByteNalLength) {
857b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        uint8_t x = length >> 24;
858c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
859b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = (length >> 16) & 0xff;
860c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
861b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = (length >> 8) & 0xff;
862c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
863b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = length & 0xff;
864c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
865c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong
866c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd,
867c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong              (const uint8_t *)buffer->data() + buffer->range_offset(),
868c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong              length);
869b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong
870b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        mOffset += length + 4;
871b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    } else {
87243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        CHECK_LT(length, 65536);
87330ab66297501757d745b9ae10da61adcd891f497Andreas Huber
874b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        uint8_t x = length >> 8;
875c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
876b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = length & 0xff;
877c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
878c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length);
879b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        mOffset += length + 2;
880b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    }
88130ab66297501757d745b9ae10da61adcd891f497Andreas Huber
88230ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return old_offset;
88330ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
88430ab66297501757d745b9ae10da61adcd891f497Andreas Huber
8857837c17063a4c50bc856ba59418516fdab731de7James Dongsize_t MPEG4Writer::write(
886674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        const void *ptr, size_t size, size_t nmemb) {
8877837c17063a4c50bc856ba59418516fdab731de7James Dong
8887837c17063a4c50bc856ba59418516fdab731de7James Dong    const size_t bytes = size * nmemb;
8897837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mWriteMoovBoxToMemory) {
890674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        // This happens only when we write the moov box at the end of
891674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        // recording, not for each output video/audio frame we receive.
892c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        off64_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes;
8931acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        if (moovBoxSize > mEstimatedMoovBoxSize) {
894c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong            for (List<off64_t>::iterator it = mBoxes.begin();
8957837c17063a4c50bc856ba59418516fdab731de7James Dong                 it != mBoxes.end(); ++it) {
8967837c17063a4c50bc856ba59418516fdab731de7James Dong                (*it) += mOffset;
8977837c17063a4c50bc856ba59418516fdab731de7James Dong            }
898674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong            lseek64(mFd, mOffset, SEEK_SET);
899674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong            ::write(mFd, mMoovBoxBuffer, mMoovBoxBufferOffset);
900674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong            ::write(mFd, ptr, size * nmemb);
9017837c17063a4c50bc856ba59418516fdab731de7James Dong            mOffset += (bytes + mMoovBoxBufferOffset);
9027837c17063a4c50bc856ba59418516fdab731de7James Dong            free(mMoovBoxBuffer);
9037837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBuffer = NULL;
9047837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBufferOffset = 0;
9057837c17063a4c50bc856ba59418516fdab731de7James Dong            mWriteMoovBoxToMemory = false;
9067837c17063a4c50bc856ba59418516fdab731de7James Dong            mStreamableFile = false;
9077837c17063a4c50bc856ba59418516fdab731de7James Dong        } else {
9087837c17063a4c50bc856ba59418516fdab731de7James Dong            memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes);
9097837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBufferOffset += bytes;
9107837c17063a4c50bc856ba59418516fdab731de7James Dong        }
9117837c17063a4c50bc856ba59418516fdab731de7James Dong    } else {
912674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        ::write(mFd, ptr, size * nmemb);
9137837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset += bytes;
9147837c17063a4c50bc856ba59418516fdab731de7James Dong    }
9157837c17063a4c50bc856ba59418516fdab731de7James Dong    return bytes;
9167837c17063a4c50bc856ba59418516fdab731de7James Dong}
9177837c17063a4c50bc856ba59418516fdab731de7James Dong
91820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) {
9190c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK_EQ(strlen(fourcc), 4);
92020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
9217837c17063a4c50bc856ba59418516fdab731de7James Dong    mBoxes.push_back(mWriteMoovBoxToMemory?
9227837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBufferOffset: mOffset);
92320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
92420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    writeInt32(0);
92520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    writeFourcc(fourcc);
92620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
92720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
92820111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() {
9290c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(!mBoxes.empty());
93020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
931c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t offset = *--mBoxes.end();
93220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mBoxes.erase(--mBoxes.end());
93320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
9347837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mWriteMoovBoxToMemory) {
9357837c17063a4c50bc856ba59418516fdab731de7James Dong       int32_t x = htonl(mMoovBoxBufferOffset - offset);
9367837c17063a4c50bc856ba59418516fdab731de7James Dong       memcpy(mMoovBoxBuffer + offset, &x, 4);
9377837c17063a4c50bc856ba59418516fdab731de7James Dong    } else {
938c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, offset, SEEK_SET);
9397837c17063a4c50bc856ba59418516fdab731de7James Dong        writeInt32(mOffset - offset);
9407837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset -= 4;
941c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mOffset, SEEK_SET);
9427837c17063a4c50bc856ba59418516fdab731de7James Dong    }
94320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
94420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
94520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) {
946674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 1);
94720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
94820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
94920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) {
95020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = htons(x);
951674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 2);
95220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
95320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
95420111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) {
95520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = htonl(x);
956674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 4);
95720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
95820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
95920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) {
96020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = hton64(x);
961674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 8);
96220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
96320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
96420111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) {
96520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    size_t n = strlen(s);
966674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(s, 1, n + 1);
96720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
96820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
96920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) {
9700c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK_EQ(strlen(s), 4);
971674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(s, 1, 4);
97220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
97320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
97407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
97507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong// Written in +/-DD.DDDD format
97607b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeLatitude(int degreex10000) {
97707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    bool isNegative = (degreex10000 < 0);
97807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    char sign = isNegative? '-': '+';
97907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
98007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Handle the whole part
98107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    char str[9];
98207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    int wholePart = degreex10000 / 10000;
98307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (wholePart == 0) {
98407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        snprintf(str, 5, "%c%.2d.", sign, wholePart);
98507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    } else {
98607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        snprintf(str, 5, "%+.2d.", wholePart);
98707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
98807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
98907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Handle the fractional part
99007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    int fractionalPart = degreex10000 - (wholePart * 10000);
99107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (fractionalPart < 0) {
99207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        fractionalPart = -fractionalPart;
99307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
99407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    snprintf(&str[4], 5, "%.4d", fractionalPart);
99507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
99607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Do not write the null terminator
99707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    write(str, 1, 8);
99807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
99907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
100007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong// Written in +/- DDD.DDDD format
100107b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeLongitude(int degreex10000) {
100207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    bool isNegative = (degreex10000 < 0);
100307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    char sign = isNegative? '-': '+';
100407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
100507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Handle the whole part
100607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    char str[10];
100707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    int wholePart = degreex10000 / 10000;
100807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (wholePart == 0) {
100907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        snprintf(str, 6, "%c%.3d.", sign, wholePart);
101007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    } else {
101107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        snprintf(str, 6, "%+.3d.", wholePart);
101207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
101307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
101407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Handle the fractional part
101507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    int fractionalPart = degreex10000 - (wholePart * 10000);
101607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (fractionalPart < 0) {
101707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        fractionalPart = -fractionalPart;
101807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
101907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    snprintf(&str[5], 5, "%.4d", fractionalPart);
102007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
102107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Do not write the null terminator
102207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    write(str, 1, 9);
102307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
102407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
102507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong/*
102607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * Geodata is stored according to ISO-6709 standard.
102707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * latitudex10000 is latitude in degrees times 10000, and
102807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * longitudex10000 is longitude in degrees times 10000.
102907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * The range for the latitude is in [-90, +90], and
103007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * The range for the longitude is in [-180, +180]
103107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */
103207b1bb529a1ae76c46a71b01338c166f9490629dJames Dongstatus_t MPEG4Writer::setGeoData(int latitudex10000, int longitudex10000) {
103307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Is latitude or longitude out of range?
103407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (latitudex10000 < -900000 || latitudex10000 > 900000 ||
103507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        longitudex10000 < -1800000 || longitudex10000 > 1800000) {
103607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        return BAD_VALUE;
103707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
103807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
103907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    mLatitudex10000 = latitudex10000;
104007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    mLongitudex10000 = longitudex10000;
104107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    mAreGeoTagsAvailable = true;
104207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    return OK;
104307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
104407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
104520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) {
1046674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(data, 1, size);
104720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
104820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
104978a1a286f736888ae7af8860b2c424af0d978848James Dongbool MPEG4Writer::isFileStreamable() const {
105078a1a286f736888ae7af8860b2c424af0d978848James Dong    return mStreamableFile;
105178a1a286f736888ae7af8860b2c424af0d978848James Dong}
105278a1a286f736888ae7af8860b2c424af0d978848James Dong
1053d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileSizeLimit() {
1054d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    // No limit
1055d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    if (mMaxFileSizeLimitBytes == 0) {
1056d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        return false;
1057d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
1058d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
1059956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize);
1060d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    for (List<Track *>::iterator it = mTracks.begin();
1061d599cd4573b5a2d5914c5040e0565ef866749b77James Dong         it != mTracks.end(); ++it) {
1062d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
1063d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
10641f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1065acd234bba9f048971d66890009eeff9a8db94be3James Dong    // Be conservative in the estimate: do not exceed 95% of
1066acd234bba9f048971d66890009eeff9a8db94be3James Dong    // the target file limit. For small target file size limit, though,
1067acd234bba9f048971d66890009eeff9a8db94be3James Dong    // this will not help.
1068acd234bba9f048971d66890009eeff9a8db94be3James Dong    return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100);
1069d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
1070d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
1071d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileDurationLimit() {
1072d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    // No limit
1073d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    if (mMaxFileDurationLimitUs == 0) {
1074d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        return false;
1075d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
1076d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
1077d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    for (List<Track *>::iterator it = mTracks.begin();
1078d599cd4573b5a2d5914c5040e0565ef866749b77James Dong         it != mTracks.end(); ++it) {
1079d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) {
1080d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            return true;
1081d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
1082d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
1083d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    return false;
1084d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
1085d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
108625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() {
108725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool allDone = true;
108825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    for (List<Track *>::iterator it = mTracks.begin();
108925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber         it != mTracks.end(); ++it) {
109025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        if (!(*it)->reachedEOS()) {
109125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber            allDone = false;
109225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber            break;
109325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        }
109425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    }
109525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
109625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return allDone;
109725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber}
109825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
1099f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongvoid MPEG4Writer::setStartTimestampUs(int64_t timeUs) {
1100df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block    ALOGI("setStartTimestampUs: %lld", timeUs);
110143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GE(timeUs, 0ll);
11023c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    Mutex::Autolock autoLock(mLock);
1103065d1aff96818df54456053f1574aec8a234d0deJames Dong    if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) {
1104f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong        mStartTimestampUs = timeUs;
1105df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block        ALOGI("Earliest track starting time: %lld", mStartTimestampUs);
11063c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    }
11073c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong}
11083c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong
1109f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongint64_t MPEG4Writer::getStartTimestampUs() {
11103c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    Mutex::Autolock autoLock(mLock);
11113c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    return mStartTimestampUs;
11123c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong}
11133c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong
111458ae9c530247668f8af36e30d228c716c226b3d4James Dongsize_t MPEG4Writer::numTracks() {
111558ae9c530247668f8af36e30d228c716c226b3d4James Dong    Mutex::Autolock autolock(mLock);
111658ae9c530247668f8af36e30d228c716c226b3d4James Dong    return mTracks.size();
111758ae9c530247668f8af36e30d228c716c226b3d4James Dong}
111858ae9c530247668f8af36e30d228c716c226b3d4James Dong
111920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber////////////////////////////////////////////////////////////////////////////////
112020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
112120111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track(
1122bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId)
112320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    : mOwner(owner),
112425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber      mMeta(source->getFormat()),
112520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mSource(source),
112620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mDone(false),
1127a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
1128a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mResumed(false),
1129eaae38445a340c4857c1c5569475879a728e63b7James Dong      mStarted(false),
1130bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong      mTrackId(trackId),
1131c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong      mTrackDurationUs(0),
1132956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      mEstimatedTrackSizeBytes(0),
1133be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong      mSamplesHaveSameSize(true),
113420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mCodecSpecificData(NULL),
113525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber      mCodecSpecificDataSize(0),
1136548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber      mGotAllCodecSpecificData(false),
113713f6284305e4b27395a23db7882d670bdb1bcae1James Dong      mReachedEOS(false),
113813f6284305e4b27395a23db7882d670bdb1bcae1James Dong      mRotation(0) {
113919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    getCodecSpecificDataFromInputFormatIfPossible();
11408f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
11411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    const char *mime;
11421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mMeta->findCString(kKeyMIMEType, &mime);
11431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
11441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsAudio = !strncasecmp(mime, "audio/", 6);
11451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
11461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong               !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
11471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1148c059860c73678a202bfa33062723e8f82fb779d9James Dong    setTimeScale();
1149c059860c73678a202bfa33062723e8f82fb779d9James Dong}
1150c059860c73678a202bfa33062723e8f82fb779d9James Dong
11511f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::updateTrackSizeEstimate() {
11521f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
11531f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    int64_t stcoBoxSizeBytes = mOwner->use32BitFileOffset()
11541f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                                ? mNumStcoTableEntries * 4
11551f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                                : mNumStcoTableEntries * 8;
11561f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
11571f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mNumSamples * 4);
11581f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
115978a1a286f736888ae7af8860b2c424af0d978848James Dong    mEstimatedTrackSizeBytes = mMdatSizeBytes;  // media data size
116078a1a286f736888ae7af8860b2c424af0d978848James Dong    if (!mOwner->isFileStreamable()) {
116178a1a286f736888ae7af8860b2c424af0d978848James Dong        // Reserved free space is not large enough to hold
116278a1a286f736888ae7af8860b2c424af0d978848James Dong        // all meta data and thus wasted.
116378a1a286f736888ae7af8860b2c424af0d978848James Dong        mEstimatedTrackSizeBytes += mNumStscTableEntries * 12 +  // stsc box size
116478a1a286f736888ae7af8860b2c424af0d978848James Dong                                    mNumStssTableEntries * 4 +   // stss box size
116578a1a286f736888ae7af8860b2c424af0d978848James Dong                                    mNumSttsTableEntries * 8 +   // stts box size
1166965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong                                    mNumCttsTableEntries * 8 +   // ctts box size
116778a1a286f736888ae7af8860b2c424af0d978848James Dong                                    stcoBoxSizeBytes +           // stco box size
116878a1a286f736888ae7af8860b2c424af0d978848James Dong                                    stszBoxSizeBytes;            // stsz box size
116978a1a286f736888ae7af8860b2c424af0d978848James Dong    }
11701f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
11711f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
11721f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStscTableEntry(
11731f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        size_t chunkId, size_t sampleId) {
11741f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
11751f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        StscTableEntry stscEntry(chunkId, sampleId, 1);
11761f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        mStscTableEntries.push_back(stscEntry);
11771f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        ++mNumStscTableEntries;
11781f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
11791f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
11801f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) {
11811f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mStssTableEntries.push_back(sampleId);
11821f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    ++mNumStssTableEntries;
11831f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
11841f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
11851f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneSttsTableEntry(
118679761ab096f57c3027fad9556c2bc436672d614eJames Dong        size_t sampleCount, int32_t duration) {
11871f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
11885a217fba010e801c255503602bda4b86ac5a6ac9James Dong    if (duration == 0) {
11895ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block        ALOGW("0-duration samples found: %d", sampleCount);
11905a217fba010e801c255503602bda4b86ac5a6ac9James Dong    }
119179761ab096f57c3027fad9556c2bc436672d614eJames Dong    SttsTableEntry sttsEntry(sampleCount, duration);
11921f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mSttsTableEntries.push_back(sttsEntry);
11931f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    ++mNumSttsTableEntries;
11941f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
11951f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1196965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dongvoid MPEG4Writer::Track::addOneCttsTableEntry(
1197965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        size_t sampleCount, int32_t duration) {
1198965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
1199965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    if (mIsAudio) {
1200965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        return;
1201965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    }
1202965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    CttsTableEntry cttsEntry(sampleCount, duration);
1203965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    mCttsTableEntries.push_back(cttsEntry);
1204965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    ++mNumCttsTableEntries;
1205965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong}
1206965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
1207c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongvoid MPEG4Writer::Track::addChunkOffset(off64_t offset) {
12081f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    ++mNumStcoTableEntries;
12091f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mChunkOffsets.push_back(offset);
12101f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
12111f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1212c059860c73678a202bfa33062723e8f82fb779d9James Dongvoid MPEG4Writer::Track::setTimeScale() {
12133856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("setTimeScale");
1214c059860c73678a202bfa33062723e8f82fb779d9James Dong    // Default time scale
1215c059860c73678a202bfa33062723e8f82fb779d9James Dong    mTimeScale = 90000;
1216c059860c73678a202bfa33062723e8f82fb779d9James Dong
1217c059860c73678a202bfa33062723e8f82fb779d9James Dong    if (mIsAudio) {
1218c059860c73678a202bfa33062723e8f82fb779d9James Dong        // Use the sampling rate as the default time scale for audio track.
1219c059860c73678a202bfa33062723e8f82fb779d9James Dong        int32_t sampleRate;
1220c059860c73678a202bfa33062723e8f82fb779d9James Dong        bool success = mMeta->findInt32(kKeySampleRate, &sampleRate);
1221c059860c73678a202bfa33062723e8f82fb779d9James Dong        CHECK(success);
1222c059860c73678a202bfa33062723e8f82fb779d9James Dong        mTimeScale = sampleRate;
1223c059860c73678a202bfa33062723e8f82fb779d9James Dong    }
1224c059860c73678a202bfa33062723e8f82fb779d9James Dong
1225c059860c73678a202bfa33062723e8f82fb779d9James Dong    // If someone would like to overwrite the timescale, use user-supplied value.
1226c059860c73678a202bfa33062723e8f82fb779d9James Dong    int32_t timeScale;
1227c059860c73678a202bfa33062723e8f82fb779d9James Dong    if (mMeta->findInt32(kKeyTimeScale, &timeScale)) {
1228c059860c73678a202bfa33062723e8f82fb779d9James Dong        mTimeScale = timeScale;
1229c059860c73678a202bfa33062723e8f82fb779d9James Dong    }
1230c059860c73678a202bfa33062723e8f82fb779d9James Dong
123143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GT(mTimeScale, 0);
123219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber}
123319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
123419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Hubervoid MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
123519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    const char *mime;
123619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
123719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
123819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
123919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        uint32_t type;
124019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        const void *data;
124119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        size_t size;
124219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        if (mMeta->findData(kKeyAVCC, &type, &data, &size)) {
124319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mCodecSpecificData = malloc(size);
124419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mCodecSpecificDataSize = size;
124519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            memcpy(mCodecSpecificData, data, size);
124619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mGotAllCodecSpecificData = true;
124719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        }
124819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
124919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
125019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        uint32_t type;
125119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        const void *data;
125219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        size_t size;
125319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
125419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            ESDS esds(data, size);
125519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            if (esds.getCodecSpecificInfo(&data, &size) == OK) {
125619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mCodecSpecificData = malloc(size);
125719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mCodecSpecificDataSize = size;
125819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                memcpy(mCodecSpecificData, data, size);
125919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mGotAllCodecSpecificData = true;
126019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            }
126119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        }
126219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    }
126320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
126420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
126520111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() {
126620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    stop();
126720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
126820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mCodecSpecificData != NULL) {
126920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        free(mCodecSpecificData);
127020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mCodecSpecificData = NULL;
127120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
12728c460498c028888c533ab442be12b6d4b669b965James Dong
12738c460498c028888c533ab442be12b6d4b669b965James Dong    while (!mSampleSizes.empty()) {
12748c460498c028888c533ab442be12b6d4b669b965James Dong        List<uint32_t *>::iterator it = mSampleSizes.begin();
12758c460498c028888c533ab442be12b6d4b669b965James Dong        delete[] (*it);
12768c460498c028888c533ab442be12b6d4b669b965James Dong        mSampleSizes.erase(it);
12778c460498c028888c533ab442be12b6d4b669b965James Dong    }
127820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
127920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
128093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongvoid MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) {
12813856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("initTrackingProgressStatus");
128293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mPreviousTrackTimeUs = -1;
128393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mTrackingProgressStatus = false;
128493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mTrackEveryTimeDurationUs = 0;
128593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    {
128693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        int64_t timeUs;
128793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) {
12883856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            ALOGV("Receive request to track progress status for every %lld us", timeUs);
128993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            mTrackEveryTimeDurationUs = timeUs;
129093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            mTrackingProgressStatus = true;
129193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        }
129293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    }
129393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong}
129493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
12951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong// static
12961c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid *MPEG4Writer::ThreadWrapper(void *me) {
12973856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("ThreadWrapper: %p", me);
12981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    MPEG4Writer *writer = static_cast<MPEG4Writer *>(me);
12991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    writer->threadFunc();
13001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    return NULL;
13011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
13021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
13031c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::bufferChunk(const Chunk& chunk) {
13043856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("bufferChunk: %p", chunk.mTrack);
13051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Mutex::Autolock autolock(mLock);
13061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    CHECK_EQ(mDone, false);
13071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
13081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
13091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
13101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
13111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (chunk.mTrack == it->mTrack) {  // Found owner
13121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            it->mChunks.push_back(chunk);
13131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            mChunkReadyCondition.signal();
13141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            return;
13151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
13161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
13171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
131843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK(!"Received a chunk for a unknown track");
13191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
13201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1321fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeChunkToFile(Chunk* chunk) {
13223856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("writeChunkToFile: %lld from %s track",
13235410afcbb0af5d29d9f710a1c2978c500f9792dcPannag Sanketi        chunk->mTimeStampUs, chunk->mTrack->isAudio()? "audio": "video");
1324fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1325fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    int32_t isFirstSample = true;
1326fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    while (!chunk->mSamples.empty()) {
1327fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        List<MediaBuffer *>::iterator it = chunk->mSamples.begin();
1328fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1329fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        off64_t offset = chunk->mTrack->isAvc()
1330fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong                                ? addLengthPrefixedSample_l(*it)
1331fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong                                : addSample_l(*it);
1332fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1333fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        if (isFirstSample) {
1334fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            chunk->mTrack->addChunkOffset(offset);
1335fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            isFirstSample = false;
13361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
13371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
13381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        (*it)->release();
13391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        (*it) = NULL;
1340fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        chunk->mSamples.erase(it);
13411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1342fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    chunk->mSamples.clear();
13431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
13441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1345fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeAllChunks() {
13463856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("writeAllChunks");
13471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    size_t outstandingChunks = 0;
134870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    Chunk chunk;
134970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    while (findChunkToWrite(&chunk)) {
1350e9f6d0579603372fd2547e6c5ba6e114c6f8cba7James Dong        writeChunkToFile(&chunk);
135170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        ++outstandingChunks;
13521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
135370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
135470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    sendSessionSummary();
135570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
13561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mChunkInfos.clear();
1357b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("%d chunks are written in the last batch", outstandingChunks);
13581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
13591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1360fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongbool MPEG4Writer::findChunkToWrite(Chunk *chunk) {
13613856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("findChunkToWrite");
13621c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
13631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL;
13641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Track *track = NULL;
13651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
13661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
13671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (!it->mChunks.empty()) {
13681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            List<Chunk>::iterator chunkIt = it->mChunks.begin();
13691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            if (chunkIt->mTimeStampUs < minTimestampUs) {
13701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                minTimestampUs = chunkIt->mTimeStampUs;
13711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                track = it->mTrack;
13721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            }
13731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
13741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
13751c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
13761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (track == NULL) {
13773856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("Nothing to be written after all");
1378fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        return false;
13791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
13801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
13811c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (mIsFirstChunk) {
13821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mIsFirstChunk = false;
13831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1384fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
13851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
13861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
13871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (it->mTrack == track) {
1388fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            *chunk = *(it->mChunks.begin());
1389fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            it->mChunks.erase(it->mChunks.begin());
1390fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            CHECK_EQ(chunk->mTrack, track);
139170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
139270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            int64_t interChunkTimeUs =
139370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                chunk->mTimeStampUs - it->mPrevChunkTimestampUs;
139470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            if (interChunkTimeUs > it->mPrevChunkTimestampUs) {
139570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                it->mMaxInterChunkDurUs = interChunkTimeUs;
139670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            }
139770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
1398fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            return true;
13991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
14001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1401fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1402fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    return false;
14031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
14041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
14051c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::threadFunc() {
14063856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("threadFunc");
14071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1408a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0);
1409fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1410fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    Mutex::Autolock autoLock(mLock);
14111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    while (!mDone) {
1412fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        Chunk chunk;
1413fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        bool chunkFound = false;
1414fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1415fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) {
14161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            mChunkReadyCondition.wait(mLock);
14171c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
14181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1419fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        // Actual write without holding the lock in order to
1420fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        // reduce the blocking time for media track threads.
1421fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        if (chunkFound) {
1422fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            mLock.unlock();
1423fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            writeChunkToFile(&chunk);
1424fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            mLock.lock();
1425fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        }
14261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1427fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1428fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    writeAllChunks();
14291c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
14301c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
14311c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::startWriterThread() {
14323856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("startWriterThread");
14331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
14341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mDone = false;
14351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsFirstChunk = true;
1436e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    mDriftTimeUs = 0;
14371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<Track *>::iterator it = mTracks.begin();
14381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mTracks.end(); ++it) {
14391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        ChunkInfo info;
14401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        info.mTrack = *it;
144170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        info.mPrevChunkTimestampUs = 0;
144270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        info.mMaxInterChunkDurUs = 0;
14431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mChunkInfos.push_back(info);
14441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
14451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
14461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_t attr;
14471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_init(&attr);
14481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
14491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_create(&mThread, &attr, ThreadWrapper, this);
14501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_destroy(&attr);
1451411ba422e3635d534928ffd81abf54f4f291c739James Dong    mWriterThreadStarted = true;
14521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    return OK;
14531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
14541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
14551f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
145693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::Track::start(MetaData *params) {
1457a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (!mDone && mPaused) {
1458a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        mPaused = false;
1459a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        mResumed = true;
1460a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return OK;
1461a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
146225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
146393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t startTimeUs;
146419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) {
146519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        startTimeUs = 0;
146619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    }
146770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    mStartTimeRealUs = startTimeUs;
146819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
146913f6284305e4b27395a23db7882d670bdb1bcae1James Dong    int32_t rotationDegrees;
147013f6284305e4b27395a23db7882d670bdb1bcae1James Dong    if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) {
147113f6284305e4b27395a23db7882d670bdb1bcae1James Dong        mRotation = rotationDegrees;
147213f6284305e4b27395a23db7882d670bdb1bcae1James Dong    }
147313f6284305e4b27395a23db7882d670bdb1bcae1James Dong
14745b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong    mIsRealTimeRecording = true;
1475e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    {
1476e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        int32_t isNotRealTime;
1477e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        if (params && params->findInt32(kKeyNotRealTime, &isNotRealTime)) {
1478e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            mIsRealTimeRecording = (isNotRealTime == 0);
1479e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        }
1480e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    }
1481e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
148293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    initTrackingProgressStatus(params);
148393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
1484f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    sp<MetaData> meta = new MetaData;
1485a472613aec322e25891abf5c77bf3f7e3c244920James Dong    if (mIsRealTimeRecording && mOwner->numTracks() > 1) {
1486a472613aec322e25891abf5c77bf3f7e3c244920James Dong        /*
1487a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * This extra delay of accepting incoming audio/video signals
1488a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * helps to align a/v start time at the beginning of a recording
1489a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * session, and it also helps eliminate the "recording" sound for
1490a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * camcorder applications.
1491a472613aec322e25891abf5c77bf3f7e3c244920James Dong         *
149286b7f47aa7482424cf8fd248f1315311919be3b0James Dong         * If client does not set the start time offset, we fall back to
149386b7f47aa7482424cf8fd248f1315311919be3b0James Dong         * use the default initial delay value.
1494a472613aec322e25891abf5c77bf3f7e3c244920James Dong         */
149586b7f47aa7482424cf8fd248f1315311919be3b0James Dong        int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL;
149686b7f47aa7482424cf8fd248f1315311919be3b0James Dong        if (startTimeOffsetUs < 0) {  // Start time offset was not set
149786b7f47aa7482424cf8fd248f1315311919be3b0James Dong            startTimeOffsetUs = kInitialDelayTimeUs;
149886b7f47aa7482424cf8fd248f1315311919be3b0James Dong        }
149986b7f47aa7482424cf8fd248f1315311919be3b0James Dong        startTimeUs += startTimeOffsetUs;
1500df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block        ALOGI("Start time offset: %lld us", startTimeOffsetUs);
1501a472613aec322e25891abf5c77bf3f7e3c244920James Dong    }
1502a472613aec322e25891abf5c77bf3f7e3c244920James Dong
1503f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    meta->setInt64(kKeyTime, startTimeUs);
1504a472613aec322e25891abf5c77bf3f7e3c244920James Dong
1505f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    status_t err = mSource->start(meta.get());
150625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    if (err != OK) {
150725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        mDone = mReachedEOS = true;
150825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        return err;
150925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    }
151020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
151120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_t attr;
151220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_init(&attr);
151320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
151420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
151520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mDone = false;
1516eaae38445a340c4857c1c5569475879a728e63b7James Dong    mStarted = true;
1517c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    mTrackDurationUs = 0;
151825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    mReachedEOS = false;
1519956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    mEstimatedTrackSizeBytes = 0;
15201f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mNumStcoTableEntries = 0;
15211f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mNumStssTableEntries = 0;
15221f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mNumStscTableEntries = 0;
15231f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mNumSttsTableEntries = 0;
1524965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    mNumCttsTableEntries = 0;
15251f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mMdatSizeBytes = 0;
1526f2ab12d0dcef27fd52dcae53221e9c51a369fef6James Dong
152743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mMaxChunkDurationUs = 0;
152820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
152925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    pthread_create(&mThread, &attr, ThreadWrapper, this);
153020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_destroy(&attr);
153125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
153225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return OK;
153320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
153420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
153537187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::pause() {
1536a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mPaused = true;
153737187916a486504acaf83bea30147eb5fbf46ae5James Dong    return OK;
1538a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
1539a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
154037187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::stop() {
1541b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("Stopping %s track", mIsAudio? "Audio": "Video");
1542eaae38445a340c4857c1c5569475879a728e63b7James Dong    if (!mStarted) {
154329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Stop() called but track is not started");
1544eaae38445a340c4857c1c5569475879a728e63b7James Dong        return ERROR_END_OF_STREAM;
1545eaae38445a340c4857c1c5569475879a728e63b7James Dong    }
1546eaae38445a340c4857c1c5569475879a728e63b7James Dong
154720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mDone) {
154837187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
154920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
155020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mDone = true;
155120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
155220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    void *dummy;
155320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_join(mThread, &dummy);
155420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
155537187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = (status_t) dummy;
155637187916a486504acaf83bea30147eb5fbf46ae5James Dong
1557b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("Stopping %s track source", mIsAudio? "Audio": "Video");
155837187916a486504acaf83bea30147eb5fbf46ae5James Dong    {
155937187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = mSource->stop();
156037187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (err == OK && status != OK && status != ERROR_END_OF_STREAM) {
156137187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
156237187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
156337187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
156437187916a486504acaf83bea30147eb5fbf46ae5James Dong
1565b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("%s track stopped", mIsAudio? "Audio": "Video");
156637187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
156720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
156820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
156925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() {
157025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return mReachedEOS;
157125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber}
157225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
157320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static
157420111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) {
157520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track *track = static_cast<Track *>(me);
157620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
157737187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = track->threadEntry();
157837187916a486504acaf83bea30147eb5fbf46ae5James Dong    return (void *) err;
157920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
158020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
15813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic void getNalUnitType(uint8_t byte, uint8_t* type) {
15823856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("getNalUnitType: %d", byte);
15833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // nal_unit_type: 5-bit unsigned integer
15853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    *type = (byte & 0x1F);
15863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
15873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15883266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t *findNextStartCode(
15893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length) {
15903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15913856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("findNextStartCode: %p %d", data, length);
15923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
15933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t bytesLeft = length;
15943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    while (bytesLeft > 4  &&
15953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) {
15963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        --bytesLeft;
15973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
15983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (bytesLeft <= 4) {
15993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        bytesLeft = 0; // Last parameter set
16003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
16013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return &data[length - bytesLeft];
16023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
16033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongconst uint8_t *MPEG4Writer::Track::parseParamSet(
16053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length, int type, size_t *paramSetLen) {
16063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16073856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("parseParamSet");
16083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    CHECK(type == kNalUnitTypeSeqParamSet ||
16093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong          type == kNalUnitTypePicParamSet);
16103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *nextStartCode = findNextStartCode(data, length);
16123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    *paramSetLen = nextStartCode - data;
16133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (*paramSetLen == 0) {
161429357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Param set is malformed, since its length is 0");
16153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return NULL;
16163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
16173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    AVCParamSet paramSet(*paramSetLen, data);
16193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (type == kNalUnitTypeSeqParamSet) {
16203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (*paramSetLen < 4) {
162129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Seq parameter set malformed");
16223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return NULL;
16233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
16243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (mSeqParamSets.empty()) {
16253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileIdc = data[1];
16263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileCompatible = data[2];
16273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mLevelIdc = data[3];
16283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else {
16293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (mProfileIdc != data[1] ||
16303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                mProfileCompatible != data[2] ||
16313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                mLevelIdc != data[3]) {
163229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("Inconsistent profile/level found in seq parameter sets");
16333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return NULL;
16343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
16353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
16363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mSeqParamSets.push_back(paramSet);
16373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    } else {
16383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mPicParamSets.push_back(paramSet);
16393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
16403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return nextStartCode;
16413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
16423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::copyAVCCodecSpecificData(
16443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t size) {
16453856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("copyAVCCodecSpecificData");
16463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 2 bytes for each of the parameter set length field
16483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // plus the 7 bytes for the header
16493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (size < 4 + 7) {
165029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Codec specific data length too short: %d", size);
16513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return ERROR_MALFORMED;
16523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
16533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize = size;
16553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificData = malloc(size);
16563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    memcpy(mCodecSpecificData, data, size);
16573266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return OK;
16583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
16593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::parseAVCCodecSpecificData(
16613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t size) {
16623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
16633856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("parseAVCCodecSpecificData");
16643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Data starts with a start code.
16653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // SPS and PPS are separated with start codes.
16663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Also, SPS must come before PPS
16673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t type = kNalUnitTypeSeqParamSet;
16683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    bool gotSps = false;
16693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    bool gotPps = false;
16703266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *tmp = data;
16713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *nextStartCode = data;
16723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t bytesLeft = size;
16733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t paramSetLen = 0;
16743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize = 0;
16753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) {
16763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        getNalUnitType(*(tmp + 4), &type);
16773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (type == kNalUnitTypeSeqParamSet) {
16783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (gotPps) {
167929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("SPS must come before PPS");
16803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return ERROR_MALFORMED;
16813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
16823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotSps) {
16833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                gotSps = true;
16843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
16853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
16863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else if (type == kNalUnitTypePicParamSet) {
16873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotSps) {
168829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("SPS must come before PPS");
16893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return ERROR_MALFORMED;
16903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
16913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotPps) {
16923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                gotPps = true;
16933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
16943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
16953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else {
169629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Only SPS and PPS Nal units are expected");
16973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
16983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
16993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
17003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nextStartCode == NULL) {
17013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
17023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
17033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
17043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Move on to find the next parameter set
17053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        bytesLeft -= nextStartCode - tmp;
17063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        tmp = nextStartCode;
17073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mCodecSpecificDataSize += (2 + paramSetLen);
17083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
17093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
17103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
17113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the number of seq parameter sets
17123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        size_t nSeqParamSets = mSeqParamSets.size();
17133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nSeqParamSets == 0) {
171429357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Cound not find sequence parameter set");
17153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
17163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
17173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
17183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nSeqParamSets > 0x1F) {
171929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Too many seq parameter sets (%d) found", nSeqParamSets);
17203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
17213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
17223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
17233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
17243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
17253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the number of pic parameter sets
17263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        size_t nPicParamSets = mPicParamSets.size();
17273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nPicParamSets == 0) {
172829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Cound not find picture parameter set");
17293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
17303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
17313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nPicParamSets > 0xFF) {
173229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Too many pic parameter sets (%d) found", nPicParamSets);
17333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
17343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
17353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
17361374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket// FIXME:
17371374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket// Add chromat_format_idc, bit depth values, etc for AVC/h264 high profile and above
17381374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket// and remove #if 0
17391374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket#if 0
17403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
17413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the profiles
17423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // These profiles requires additional parameter set extensions
17433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (mProfileIdc == 100 || mProfileIdc == 110 ||
17443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileIdc == 122 || mProfileIdc == 144) {
174529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Sorry, no support for profile_idc: %d!", mProfileIdc);
17463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return BAD_VALUE;
17473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
17483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
17491374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket#endif
17503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return OK;
17513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
1752548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
175303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData(
175403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        const uint8_t *data, size_t size) {
1755548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
175603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (mCodecSpecificData != NULL) {
175729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Already have codec specific data");
175803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
175903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
176003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
17613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (size < 4) {
176229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Codec specific data length too short: %d", size);
176303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
176403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
176503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
17663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Data is in the form of AVCCodecSpecificData
17673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (memcmp("\x00\x00\x00\x01", data, 4)) {
17683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return copyAVCCodecSpecificData(data, size);
176903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
177003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
17713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (parseAVCCodecSpecificData(data, size) != OK) {
177203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
177303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
177403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
17753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // ISO 14496-15: AVC file format
17763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize += 7;  // 7 more bytes in the header
177703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    mCodecSpecificData = malloc(mCodecSpecificDataSize);
177803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    uint8_t *header = (uint8_t *)mCodecSpecificData;
17793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[0] = 1;                     // version
17803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[1] = mProfileIdc;           // profile indication
17813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[2] = mProfileCompatible;    // profile compatibility
17823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[3] = mLevelIdc;
178303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
17843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne
1785b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    if (mOwner->useNalLengthFour()) {
1786b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        header[4] = 0xfc | 3;  // length size == 4 bytes
1787b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    } else {
1788b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        header[4] = 0xfc | 1;  // length size == 2 bytes
1789b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    }
179003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
17913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 3-bit '111' followed by 5-bit numSequenceParameterSets
17923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    int nSequenceParamSets = mSeqParamSets.size();
17933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[5] = 0xe0 | nSequenceParamSets;
17943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header += 6;
17953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    for (List<AVCParamSet>::iterator it = mSeqParamSets.begin();
17963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong         it != mSeqParamSets.end(); ++it) {
17973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // 16-bit sequence parameter set length
17983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t seqParamSetLength = it->mLength;
17993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[0] = seqParamSetLength >> 8;
18003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[1] = seqParamSetLength & 0xff;
18013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // SPS NAL unit (sequence parameter length bytes)
18033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        memcpy(&header[2], it->mData, seqParamSetLength);
18043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header += (2 + seqParamSetLength);
18053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
18063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 8-bit nPictureParameterSets
18083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    int nPictureParamSets = mPicParamSets.size();
18093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[0] = nPictureParamSets;
18103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header += 1;
18113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    for (List<AVCParamSet>::iterator it = mPicParamSets.begin();
18123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong         it != mPicParamSets.end(); ++it) {
18133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // 16-bit picture parameter set length
18143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t picParamSetLength = it->mLength;
18153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[0] = picParamSetLength >> 8;
18163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[1] = picParamSetLength & 0xff;
18173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // PPS Nal unit (picture parameter set length bytes)
18193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        memcpy(&header[2], it->mData, picParamSetLength);
18203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header += (2 + picParamSetLength);
18213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
182203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
182303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    return OK;
182403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber}
182503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
1826872a481558350634a3fd5cb67939de288af00ecbJames Dong/*
1827872a481558350634a3fd5cb67939de288af00ecbJames Dong * Updates the drift time from the audio track so that
1828872a481558350634a3fd5cb67939de288af00ecbJames Dong * the video track can get the updated drift time information
1829872a481558350634a3fd5cb67939de288af00ecbJames Dong * from the file writer. The fluctuation of the drift time of the audio
1830872a481558350634a3fd5cb67939de288af00ecbJames Dong * encoding path is smoothed out with a simple filter by giving a larger
1831872a481558350634a3fd5cb67939de288af00ecbJames Dong * weight to more recently drift time. The filter coefficients, 0.5 and 0.5,
1832872a481558350634a3fd5cb67939de288af00ecbJames Dong * are heuristically determined.
1833872a481558350634a3fd5cb67939de288af00ecbJames Dong */
1834872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) {
1835872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t driftTimeUs = 0;
1836872a481558350634a3fd5cb67939de288af00ecbJames Dong    if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) {
1837872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t prevDriftTimeUs = mOwner->getDriftTimeUs();
1838872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1;
1839872a481558350634a3fd5cb67939de288af00ecbJames Dong        mOwner->setDriftTimeUs(timeUs);
1840872a481558350634a3fd5cb67939de288af00ecbJames Dong    }
1841872a481558350634a3fd5cb67939de288af00ecbJames Dong}
1842872a481558350634a3fd5cb67939de288af00ecbJames Dong
184337187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::threadEntry() {
184430ab66297501757d745b9ae10da61adcd891f497Andreas Huber    int32_t count = 0;
184513aec890216948b0c364f8f92792129d0335f506James Dong    const int64_t interleaveDurationUs = mOwner->interleaveDuration();
184643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    const bool hasMultipleTracks = (mOwner->numTracks() > 1);
184713aec890216948b0c364f8f92792129d0335f506James Dong    int64_t chunkTimestampUs = 0;
184813aec890216948b0c364f8f92792129d0335f506James Dong    int32_t nChunks = 0;
184913aec890216948b0c364f8f92792129d0335f506James Dong    int32_t nZeroLengthFrames = 0;
1850965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    int64_t lastTimestampUs = 0;      // Previous sample time stamp
1851965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    int64_t lastDurationUs = 0;       // Between the previous two samples
1852965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    int64_t currDurationTicks = 0;    // Timescale based ticks
1853965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    int64_t lastDurationTicks = 0;    // Timescale based ticks
1854965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    int32_t sampleCount = 1;          // Sample count in the current stts table entry
1855000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    uint32_t previousSampleSize = 0;  // Size of the previous sample
1856a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    int64_t previousPausedDurationUs = 0;
1857965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    int64_t timestampUs = 0;
1858000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    int64_t cttsOffsetTimeUs = 0;
1859000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    int64_t currCttsOffsetTimeTicks = 0;   // Timescale based ticks
1860000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    int64_t lastCttsOffsetTimeTicks = -1;  // Timescale based ticks
186143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    int32_t cttsSampleCount = 0;           // Sample count in the current ctts table entry
1862e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
1863a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    if (mIsAudio) {
1864a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong        prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
1865a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    } else {
1866a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong        prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0);
1867a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    }
186886106f8b0641444c97a39e9788eeef55ab2a2ac6Glenn Kasten    androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
1869985f838934510983d8a887461e98dca60a6e858fJames Dong
1870d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong    sp<MetaData> meta_data;
187120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1872ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    mNumSamples = 0;
187393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    status_t err = OK;
187420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    MediaBuffer *buffer;
187593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    while (!mDone && (err = mSource->read(&buffer)) == OK) {
187620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        if (buffer->range_length() == 0) {
187720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            buffer->release();
187820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            buffer = NULL;
187913aec890216948b0c364f8f92792129d0335f506James Dong            ++nZeroLengthFrames;
188020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            continue;
188120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
188220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1883a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // If the codec specific data has not been received yet, delay pause.
1884a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // After the codec specific data is received, discard what we received
1885a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // when the track is to be paused.
1886a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mPaused && !mResumed) {
1887a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            buffer->release();
1888a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            buffer = NULL;
1889a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            continue;
1890a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
1891a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
189230ab66297501757d745b9ae10da61adcd891f497Andreas Huber        ++count;
189330ab66297501757d745b9ae10da61adcd891f497Andreas Huber
189403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        int32_t isCodecConfig;
189503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
189603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                && isCodecConfig) {
1897548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            CHECK(!mGotAllCodecSpecificData);
1898548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
18991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            if (mIsAvc) {
190003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                status_t err = makeAVCCodecSpecificData(
190103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        (const uint8_t *)buffer->data()
190203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                            + buffer->range_offset(),
190303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        buffer->range_length());
190443089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                CHECK_EQ((status_t)OK, err);
19051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            } else if (mIsMPEG4) {
190603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                mCodecSpecificDataSize = buffer->range_length();
190703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                mCodecSpecificData = malloc(mCodecSpecificDataSize);
190803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                memcpy(mCodecSpecificData,
190903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        (const uint8_t *)buffer->data()
191003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                            + buffer->range_offset(),
191103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                       buffer->range_length());
191230ab66297501757d745b9ae10da61adcd891f497Andreas Huber            }
191330ab66297501757d745b9ae10da61adcd891f497Andreas Huber
191430ab66297501757d745b9ae10da61adcd891f497Andreas Huber            buffer->release();
191530ab66297501757d745b9ae10da61adcd891f497Andreas Huber            buffer = NULL;
191630ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1917548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            mGotAllCodecSpecificData = true;
191830ab66297501757d745b9ae10da61adcd891f497Andreas Huber            continue;
1919a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
1920a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
1921d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        // Make a deep copy of the MediaBuffer and Metadata and release
1922d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        // the original as soon as we can
1923d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        MediaBuffer *copy = new MediaBuffer(buffer->range_length());
1924d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(),
1925d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong                buffer->range_length());
1926d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        copy->set_range(0, buffer->range_length());
1927d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        meta_data = new MetaData(*buffer->meta_data().get());
1928d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        buffer->release();
1929d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        buffer = NULL;
1930d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
19311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (mIsAvc) StripStartcode(copy);
1932e136c3bb38e88315bf8797a464ebf2c788296b22James Dong
1933b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        size_t sampleSize = copy->range_length();
1934b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        if (mIsAvc) {
1935b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong            if (mOwner->useNalLengthFour()) {
1936b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong                sampleSize += 4;
1937b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong            } else {
1938b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong                sampleSize += 2;
1939b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong            }
1940b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        }
1941050b28a593350047845a45a14cc5026221ac1620James Dong
1942d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        // Max file size or duration handling
19431f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        mMdatSizeBytes += sampleSize;
19441f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        updateTrackSizeEstimate();
19451f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1946d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if (mOwner->exceedsFileSizeLimit()) {
1947d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
1948d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            break;
1949d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
1950d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if (mOwner->exceedsFileDurationLimit()) {
1951d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
1952d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            break;
1953d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
1954d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
1955050b28a593350047845a45a14cc5026221ac1620James Dong
1956d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        int32_t isSync = false;
1957d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        meta_data->findInt32(kKeyIsSyncFrame, &isSync);
1958d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
1959d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
1960d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong////////////////////////////////////////////////////////////////////////////////
196170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        if (mNumSamples == 0) {
196270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            mFirstSampleTimeRealUs = systemTime() / 1000;
1963f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong            mStartTimestampUs = timestampUs;
1964f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong            mOwner->setStartTimestampUs(mStartTimestampUs);
19658428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            previousPausedDurationUs = mStartTimestampUs;
19663c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong        }
196748c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber
1968a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mResumed) {
19698428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
197043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            CHECK_GE(durExcludingEarlierPausesUs, 0ll);
19718428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
197243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            CHECK_GE(pausedDurationUs, lastDurationUs);
19738428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            previousPausedDurationUs += pausedDurationUs - lastDurationUs;
1974a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            mResumed = false;
1975a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
1976a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
1977a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        timestampUs -= previousPausedDurationUs;
197843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        CHECK_GE(timestampUs, 0ll);
1979000e18370baae60ffd9f25b509501dd8c26deabfJames Dong        if (!mIsAudio) {
1980965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong            /*
1981965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong             * Composition time: timestampUs
1982965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong             * Decoding time: decodingTimeUs
1983000e18370baae60ffd9f25b509501dd8c26deabfJames Dong             * Composition time offset = composition time - decoding time
1984965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong             */
1985965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong            int64_t decodingTimeUs;
1986965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong            CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs));
1987965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong            decodingTimeUs -= previousPausedDurationUs;
1988000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            cttsOffsetTimeUs =
1989000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                    timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
199043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            CHECK_GE(cttsOffsetTimeUs, 0ll);
1991965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong            timestampUs = decodingTimeUs;
1992000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            ALOGV("decoding time: %lld and ctts offset time: %lld",
1993000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                timestampUs, cttsOffsetTimeUs);
1994000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
1995000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            // Update ctts box table if necessary
1996000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            currCttsOffsetTimeTicks =
1997000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                    (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL;
199843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            CHECK_LE(currCttsOffsetTimeTicks, 0x0FFFFFFFFLL);
199943089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            if (mNumSamples == 0) {
200043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                // Force the first ctts table entry to have one single entry
200143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                // so that we can do adjustment for the initial track start
200243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                // time offset easily in writeCttsBox().
200343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
200443089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                addOneCttsTableEntry(1, currCttsOffsetTimeTicks);
200543089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                cttsSampleCount = 0;      // No sample in ctts box is pending
200643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            } else {
200743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                if (currCttsOffsetTimeTicks != lastCttsOffsetTimeTicks) {
200843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                    addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
200943089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                    lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
201043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                    cttsSampleCount = 1;  // One sample in ctts box is pending
201143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                } else {
201243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                    ++cttsSampleCount;
201343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                }
201443089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            }
2015000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
2016000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            // Update ctts time offset range
2017000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            if (mNumSamples == 0) {
2018000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2019000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2020000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            } else {
2021000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                if (currCttsOffsetTimeTicks > mMaxCttsOffsetTimeUs) {
2022000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                    mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2023000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTimeUs) {
2024000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                    mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2025000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                }
2026000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            }
2027000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
2028965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        }
2029872a481558350634a3fd5cb67939de288af00ecbJames Dong
2030872a481558350634a3fd5cb67939de288af00ecbJames Dong        if (mIsRealTimeRecording) {
2031872a481558350634a3fd5cb67939de288af00ecbJames Dong            if (mIsAudio) {
2032872a481558350634a3fd5cb67939de288af00ecbJames Dong                updateDriftTime(meta_data);
2033e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            }
2034e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        }
2035872a481558350634a3fd5cb67939de288af00ecbJames Dong
203643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        CHECK_GE(timestampUs, 0ll);
20373856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("%s media time stamp: %lld and previous paused duration %lld",
20388428af5381e835cc783b7ecb0d71cb60961c99c2James Dong                mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs);
2039c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong        if (timestampUs > mTrackDurationUs) {
2040c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong            mTrackDurationUs = timestampUs;
20413b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber        }
20423b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber
20435a217fba010e801c255503602bda4b86ac5a6ac9James Dong        // We need to use the time scale based ticks, rather than the
20445a217fba010e801c255503602bda4b86ac5a6ac9James Dong        // timestamp itself to determine whether we have to use a new
20455a217fba010e801c255503602bda4b86ac5a6ac9James Dong        // stts entry, since we may have rounding errors.
20465a217fba010e801c255503602bda4b86ac5a6ac9James Dong        // The calculation is intended to reduce the accumulated
20475a217fba010e801c255503602bda4b86ac5a6ac9James Dong        // rounding errors.
20485a217fba010e801c255503602bda4b86ac5a6ac9James Dong        currDurationTicks =
20495a217fba010e801c255503602bda4b86ac5a6ac9James Dong            ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
20505a217fba010e801c255503602bda4b86ac5a6ac9James Dong                (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
205143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        CHECK_GE(currDurationTicks, 0ll);
20525a217fba010e801c255503602bda4b86ac5a6ac9James Dong
20538c460498c028888c533ab442be12b6d4b669b965James Dong        if ((mNumSamples % kSampleArraySize) == 0) {
20548c460498c028888c533ab442be12b6d4b669b965James Dong            uint32_t *arr = new uint32_t[kSampleArraySize];
20558c460498c028888c533ab442be12b6d4b669b965James Dong            CHECK(arr != NULL);
20568c460498c028888c533ab442be12b6d4b669b965James Dong            mSampleSizes.push_back(arr);
20578c460498c028888c533ab442be12b6d4b669b965James Dong            mCurrentSampleSizeArr = arr;
20588c460498c028888c533ab442be12b6d4b669b965James Dong        }
20598c460498c028888c533ab442be12b6d4b669b965James Dong
20608c460498c028888c533ab442be12b6d4b669b965James Dong        mCurrentSampleSizeArr[mNumSamples % kSampleArraySize] = htonl(sampleSize);
2061ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong        ++mNumSamples;
2062ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong        if (mNumSamples > 2) {
2063c059860c73678a202bfa33062723e8f82fb779d9James Dong
2064a472613aec322e25891abf5c77bf3f7e3c244920James Dong            // Force the first sample to have its own stts entry so that
2065a472613aec322e25891abf5c77bf3f7e3c244920James Dong            // we can adjust its value later to maintain the A/V sync.
2066a472613aec322e25891abf5c77bf3f7e3c244920James Dong            if (mNumSamples == 3 || currDurationTicks != lastDurationTicks) {
206779761ab096f57c3027fad9556c2bc436672d614eJames Dong                addOneSttsTableEntry(sampleCount, lastDurationTicks);
2068be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                sampleCount = 1;
2069be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            } else {
2070be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                ++sampleCount;
2071be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            }
2072965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
2073be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        }
2074be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        if (mSamplesHaveSameSize) {
2075ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong            if (mNumSamples >= 2 && previousSampleSize != sampleSize) {
2076be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                mSamplesHaveSameSize = false;
2077be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            }
20788644c14618d30d9e57a69df40ed939986ebf02c4James Dong            previousSampleSize = sampleSize;
2079be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        }
20803856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("%s timestampUs/lastTimestampUs: %lld/%lld",
2081a472613aec322e25891abf5c77bf3f7e3c244920James Dong                mIsAudio? "Audio": "Video", timestampUs, lastTimestampUs);
20828644c14618d30d9e57a69df40ed939986ebf02c4James Dong        lastDurationUs = timestampUs - lastTimestampUs;
2083c059860c73678a202bfa33062723e8f82fb779d9James Dong        lastDurationTicks = currDurationTicks;
20848644c14618d30d9e57a69df40ed939986ebf02c4James Dong        lastTimestampUs = timestampUs;
208520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2086d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        if (isSync != 0) {
20871f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            addOneStssTableEntry(mNumSamples);
2088d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        }
2089d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
209093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        if (mTrackingProgressStatus) {
209193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            if (mPreviousTrackTimeUs <= 0) {
209293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong                mPreviousTrackTimeUs = mStartTimestampUs;
209393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            }
2094faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong            trackProgressStatus(timestampUs);
209593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        }
209643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong        if (!hasMultipleTracks) {
2097c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong            off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy)
209858ae9c530247668f8af36e30d228c716c226b3d4James Dong                                 : mOwner->addSample_l(copy);
209958ae9c530247668f8af36e30d228c716c226b3d4James Dong            if (mChunkOffsets.empty()) {
21001f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                addChunkOffset(offset);
210158ae9c530247668f8af36e30d228c716c226b3d4James Dong            }
210258ae9c530247668f8af36e30d228c716c226b3d4James Dong            copy->release();
210358ae9c530247668f8af36e30d228c716c226b3d4James Dong            copy = NULL;
210458ae9c530247668f8af36e30d228c716c226b3d4James Dong            continue;
210558ae9c530247668f8af36e30d228c716c226b3d4James Dong        }
210613aec890216948b0c364f8f92792129d0335f506James Dong
210713aec890216948b0c364f8f92792129d0335f506James Dong        mChunkSamples.push_back(copy);
210813aec890216948b0c364f8f92792129d0335f506James Dong        if (interleaveDurationUs == 0) {
21091f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            addOneStscTableEntry(++nChunks, 1);
21101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            bufferChunk(timestampUs);
211113aec890216948b0c364f8f92792129d0335f506James Dong        } else {
211213aec890216948b0c364f8f92792129d0335f506James Dong            if (chunkTimestampUs == 0) {
211313aec890216948b0c364f8f92792129d0335f506James Dong                chunkTimestampUs = timestampUs;
211413aec890216948b0c364f8f92792129d0335f506James Dong            } else {
211543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                int64_t chunkDurationUs = timestampUs - chunkTimestampUs;
211643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                if (chunkDurationUs > interleaveDurationUs) {
211743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    if (chunkDurationUs > mMaxChunkDurationUs) {
211843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                        mMaxChunkDurationUs = chunkDurationUs;
211943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    }
212013aec890216948b0c364f8f92792129d0335f506James Dong                    ++nChunks;
212113aec890216948b0c364f8f92792129d0335f506James Dong                    if (nChunks == 1 ||  // First chunk
212213aec890216948b0c364f8f92792129d0335f506James Dong                        (--(mStscTableEntries.end()))->samplesPerChunk !=
212313aec890216948b0c364f8f92792129d0335f506James Dong                         mChunkSamples.size()) {
21241f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                        addOneStscTableEntry(nChunks, mChunkSamples.size());
212513aec890216948b0c364f8f92792129d0335f506James Dong                    }
21261c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                    bufferChunk(timestampUs);
212713aec890216948b0c364f8f92792129d0335f506James Dong                    chunkTimestampUs = timestampUs;
212813aec890216948b0c364f8f92792129d0335f506James Dong                }
212913aec890216948b0c364f8f92792129d0335f506James Dong            }
213013aec890216948b0c364f8f92792129d0335f506James Dong        }
213113aec890216948b0c364f8f92792129d0335f506James Dong
213220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
213325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
213445c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    if (isTrackMalFormed()) {
2135690f546b0ee548dbfe997df36418e5302ec2d786James Dong        err = ERROR_MALFORMED;
2136f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong    }
213745c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong
2138bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    mOwner->trackProgressStatus(mTrackId, -1, err);
2139be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
214013aec890216948b0c364f8f92792129d0335f506James Dong    // Last chunk
214143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    if (!hasMultipleTracks) {
21421f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        addOneStscTableEntry(1, mNumSamples);
214358ae9c530247668f8af36e30d228c716c226b3d4James Dong    } else if (!mChunkSamples.empty()) {
21441f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        addOneStscTableEntry(++nChunks, mChunkSamples.size());
21451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        bufferChunk(timestampUs);
214613aec890216948b0c364f8f92792129d0335f506James Dong    }
214713aec890216948b0c364f8f92792129d0335f506James Dong
2148be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // We don't really know how long the last frame lasts, since
2149be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // there is no frame time after it, just repeat the previous
2150be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // frame's duration.
2151ff4a7fa411401910e6e5ac88aeb6e0080a8cc8b1James Dong    if (mNumSamples == 1) {
21528f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        lastDurationUs = 0;  // A single sample's duration
215379761ab096f57c3027fad9556c2bc436672d614eJames Dong        lastDurationTicks = 0;
2154be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    } else {
2155be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        ++sampleCount;  // Count for the last sample
2156be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    }
2157a472613aec322e25891abf5c77bf3f7e3c244920James Dong
2158a472613aec322e25891abf5c77bf3f7e3c244920James Dong    if (mNumSamples <= 2) {
215979761ab096f57c3027fad9556c2bc436672d614eJames Dong        addOneSttsTableEntry(1, lastDurationTicks);
2160a472613aec322e25891abf5c77bf3f7e3c244920James Dong        if (sampleCount - 1 > 0) {
216179761ab096f57c3027fad9556c2bc436672d614eJames Dong            addOneSttsTableEntry(sampleCount - 1, lastDurationTicks);
2162a472613aec322e25891abf5c77bf3f7e3c244920James Dong        }
2163a472613aec322e25891abf5c77bf3f7e3c244920James Dong    } else {
216479761ab096f57c3027fad9556c2bc436672d614eJames Dong        addOneSttsTableEntry(sampleCount, lastDurationTicks);
2165a472613aec322e25891abf5c77bf3f7e3c244920James Dong    }
2166a472613aec322e25891abf5c77bf3f7e3c244920James Dong
216743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    // The last ctts box may not have been written yet, and this
216843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    // is to make sure that we write out the last ctts box.
216943089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) {
217043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        if (cttsSampleCount > 0) {
217143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
217243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        }
217343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    }
217443089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong
2175c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    mTrackDurationUs += lastDurationUs;
217625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    mReachedEOS = true;
217743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
217843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    sendTrackSummary(hasMultipleTracks);
217943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
2180df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block    ALOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s",
21811f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            count, nZeroLengthFrames, mNumSamples, mIsAudio? "audio": "video");
2182872a481558350634a3fd5cb67939de288af00ecbJames Dong    if (mIsAudio) {
2183df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block        ALOGI("Audio track drift time: %lld us", mOwner->getDriftTimeUs());
2184872a481558350634a3fd5cb67939de288af00ecbJames Dong    }
2185365a963142093a1cd8efdcea76b5f65096a5b115James Dong
218637187916a486504acaf83bea30147eb5fbf46ae5James Dong    if (err == ERROR_END_OF_STREAM) {
218737187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
218837187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
218937187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
2190365a963142093a1cd8efdcea76b5f65096a5b115James Dong}
2191365a963142093a1cd8efdcea76b5f65096a5b115James Dong
219245c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dongbool MPEG4Writer::Track::isTrackMalFormed() const {
219345c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    if (mSampleSizes.empty()) {                      // no samples written
219429357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("The number of recorded samples is 0");
219545c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong        return true;
219645c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    }
219745c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong
219845c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    if (!mIsAudio && mNumStssTableEntries == 0) {  // no sync frames for video
219929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("There are no sync frames for video track");
220045c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong        return true;
220145c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    }
220245c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong
220345c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    if (OK != checkCodecSpecificData()) {         // no codec specific data
220445c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong        return true;
220545c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    }
220645c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong
220745c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    return false;
220845c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong}
220945c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong
221043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dongvoid MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) {
221107ec01904613a0bac32caaa8444b4690998faed7James Dong
221207ec01904613a0bac32caaa8444b4690998faed7James Dong    // Send track summary only if test mode is enabled.
221307ec01904613a0bac32caaa8444b4690998faed7James Dong    if (!isTestModeEnabled()) {
221407ec01904613a0bac32caaa8444b4690998faed7James Dong        return;
221507ec01904613a0bac32caaa8444b4690998faed7James Dong    }
221607ec01904613a0bac32caaa8444b4690998faed7James Dong
221743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    int trackNum = (mTrackId << 28);
221843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
221943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
222043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_TYPE,
222143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    mIsAudio? 0: 1);
222243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
222343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
222443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_DURATION_MS,
222543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    mTrackDurationUs / 1000);
222643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
222743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
222843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES,
222943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    mNumSamples);
223043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
223186b7f47aa7482424cf8fd248f1315311919be3b0James Dong    {
223286b7f47aa7482424cf8fd248f1315311919be3b0James Dong        // The system delay time excluding the requested initial delay that
223386b7f47aa7482424cf8fd248f1315311919be3b0James Dong        // is used to eliminate the recording sound.
223486b7f47aa7482424cf8fd248f1315311919be3b0James Dong        int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL;
223586b7f47aa7482424cf8fd248f1315311919be3b0James Dong        if (startTimeOffsetUs < 0) {  // Start time offset was not set
223686b7f47aa7482424cf8fd248f1315311919be3b0James Dong            startTimeOffsetUs = kInitialDelayTimeUs;
223786b7f47aa7482424cf8fd248f1315311919be3b0James Dong        }
223886b7f47aa7482424cf8fd248f1315311919be3b0James Dong        int64_t initialDelayUs =
223986b7f47aa7482424cf8fd248f1315311919be3b0James Dong            mFirstSampleTimeRealUs - mStartTimeRealUs - startTimeOffsetUs;
224086b7f47aa7482424cf8fd248f1315311919be3b0James Dong
224186b7f47aa7482424cf8fd248f1315311919be3b0James Dong        mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
224270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS,
224370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    (initialDelayUs) / 1000);
224486b7f47aa7482424cf8fd248f1315311919be3b0James Dong    }
224570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
224607ec01904613a0bac32caaa8444b4690998faed7James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
224707ec01904613a0bac32caaa8444b4690998faed7James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES,
224807ec01904613a0bac32caaa8444b4690998faed7James Dong                    mMdatSizeBytes / 1024);
224907ec01904613a0bac32caaa8444b4690998faed7James Dong
225043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    if (hasMultipleTracks) {
225143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong        mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
225243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS,
225343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    mMaxChunkDurationUs / 1000);
225470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
225570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
225670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        if (mStartTimestampUs != moovStartTimeUs) {
225770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            int64_t startTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
225870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
225970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS,
226070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    startTimeOffsetUs / 1000);
226170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        }
226243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    }
226343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong}
226443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
2265faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) {
22663856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("trackProgressStatus: %lld us", timeUs);
2267215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    if (mTrackEveryTimeDurationUs > 0 &&
2268215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong        timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) {
22693856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("Fire time tracking progress status at %lld us", timeUs);
2270bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err);
227193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        mPreviousTrackTimeUs = timeUs;
227293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    }
227393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong}
227493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
2275faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::trackProgressStatus(
2276bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        size_t trackId, int64_t timeUs, status_t err) {
2277faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    Mutex::Autolock lock(mLock);
2278bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    int32_t trackNum = (trackId << 28);
2279faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
2280faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    // Error notification
2281faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    // Do not consider ERROR_END_OF_STREAM an error
2282faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    if (err != OK && err != ERROR_END_OF_STREAM) {
2283bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_ERROR,
2284bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong               trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL,
2285faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               err);
2286faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        return;
2287faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    }
2288faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
2289faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    if (timeUs == -1) {
2290faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        // Send completion notification
2291bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2292bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong               trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS,
2293faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               err);
2294faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    } else {
2295faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        // Send progress status
2296bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2297bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong               trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME,
2298faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               timeUs / 1000);
2299faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    }
2300faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong}
2301faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
2302d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dongvoid MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) {
23033856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("setDriftTimeUs: %lld us", driftTimeUs);
2304e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    Mutex::Autolock autolock(mLock);
2305d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong    mDriftTimeUs = driftTimeUs;
2306e259531ce59ab1f31de5a23124b22536f6a5a767James Dong}
2307e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
2308e259531ce59ab1f31de5a23124b22536f6a5a767James Dongint64_t MPEG4Writer::getDriftTimeUs() {
23093856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("getDriftTimeUs: %lld us", mDriftTimeUs);
2310e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    Mutex::Autolock autolock(mLock);
2311e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    return mDriftTimeUs;
2312e259531ce59ab1f31de5a23124b22536f6a5a767James Dong}
2313e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
2314b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dongbool MPEG4Writer::useNalLengthFour() {
2315b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    return mUse4ByteNalLength;
2316b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong}
2317b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong
23181c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
23193856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("bufferChunk");
23201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
23211c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Chunk chunk(this, timestampUs, mChunkSamples);
23221c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mOwner->bufferChunk(chunk);
232313aec890216948b0c364f8f92792129d0335f506James Dong    mChunkSamples.clear();
232420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
232520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
23263b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const {
2327c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    return mTrackDurationUs;
232820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
232920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2330d599cd4573b5a2d5914c5040e0565ef866749b77James Dongint64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
2331d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    return mEstimatedTrackSizeBytes;
2332d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
2333d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
2334690f546b0ee548dbfe997df36418e5302ec2d786James Dongstatus_t MPEG4Writer::Track::checkCodecSpecificData() const {
2335690f546b0ee548dbfe997df36418e5302ec2d786James Dong    const char *mime;
2336690f546b0ee548dbfe997df36418e5302ec2d786James Dong    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
2337690f546b0ee548dbfe997df36418e5302ec2d786James Dong    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) ||
2338690f546b0ee548dbfe997df36418e5302ec2d786James Dong        !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
2339690f546b0ee548dbfe997df36418e5302ec2d786James Dong        !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2340690f546b0ee548dbfe997df36418e5302ec2d786James Dong        if (!mCodecSpecificData ||
2341690f546b0ee548dbfe997df36418e5302ec2d786James Dong            mCodecSpecificDataSize <= 0) {
234229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Missing codec specific data");
2343690f546b0ee548dbfe997df36418e5302ec2d786James Dong            return ERROR_MALFORMED;
2344690f546b0ee548dbfe997df36418e5302ec2d786James Dong        }
2345690f546b0ee548dbfe997df36418e5302ec2d786James Dong    } else {
2346690f546b0ee548dbfe997df36418e5302ec2d786James Dong        if (mCodecSpecificData ||
2347690f546b0ee548dbfe997df36418e5302ec2d786James Dong            mCodecSpecificDataSize > 0) {
234829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Unexepected codec specific data found");
2349690f546b0ee548dbfe997df36418e5302ec2d786James Dong            return ERROR_MALFORMED;
2350690f546b0ee548dbfe997df36418e5302ec2d786James Dong        }
2351690f546b0ee548dbfe997df36418e5302ec2d786James Dong    }
2352690f546b0ee548dbfe997df36418e5302ec2d786James Dong    return OK;
2353690f546b0ee548dbfe997df36418e5302ec2d786James Dong}
2354690f546b0ee548dbfe997df36418e5302ec2d786James Dong
2355b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) {
235620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
23573856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("%s track time scale: %d",
23581c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mIsAudio? "Audio": "Video", mTimeScale);
23598f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
236020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    time_t now = time(NULL);
2361b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("trak");
2362b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeTkhdBox(now);
2363b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("mdia");
2364b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            writeMdhdBox(now);
2365b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            writeHdlrBox();
2366b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->beginBox("minf");
2367b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                if (mIsAudio) {
2368b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                    writeSmhdBox();
2369b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                } else {
2370b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                    writeVmhdBox();
2371b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                }
2372b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                writeDinfBox();
2373b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                writeStblBox(use32BitOffset);
2374b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->endBox();  // minf
2375b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->endBox();  // mdia
2376b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // trak
2377b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2378b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2379b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStblBox(bool use32BitOffset) {
2380b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stbl");
2381b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stsd");
2382b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);               // version=0, flags=0
2383b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1);               // entry count
2384b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mIsAudio) {
2385b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeAudioFourCCBox();
2386b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2387b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeVideoFourCCBox();
2388b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2389b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stsd
2390b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeSttsBox();
2391965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    writeCttsBox();
2392b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!mIsAudio) {
2393b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeStssBox();
2394b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2395b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeStszBox();
2396b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeStscBox();
2397b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeStcoBox(use32BitOffset);
2398b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stbl
2399b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2400b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2401b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVideoFourCCBox() {
2402b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    const char *mime;
2403b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    bool success = mMeta->findCString(kKeyMIMEType, &mime);
2404b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2405b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2406b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("mp4v");
2407b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2408b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("s263");
2409b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2410b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("avc1");
2411b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
241229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Unknown mime type '%s'.", mime);
2413b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(!"should not be here, unknown mime type.");
2414b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2415b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2416b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2417b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2418b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(1);           // data ref index
2419b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // predefined
2420b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2421b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // predefined
2422b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // predefined
2423b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // predefined
2424b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2425b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t width, height;
2426b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    success = mMeta->findInt32(kKeyWidth, &width);
2427b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    success = success && mMeta->findInt32(kKeyHeight, &height);
2428b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2429b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2430b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(width);
2431b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(height);
2432b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x480000);    // horiz resolution
2433b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x480000);    // vert resolution
2434b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2435b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(1);           // frame count
2436b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write("                                ", 32);
2437b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x18);        // depth
2438b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(-1);          // predefined
2439b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
244043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_LT(23 + mCodecSpecificDataSize, 128);
2441b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2442b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2443b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeMp4vEsdsBox();
2444b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2445b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeD263Box();
2446b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2447b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeAvccBox();
2448b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2449b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2450b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writePaspBox();
2451b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // mp4v, s263 or avc1
2452b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2453b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2454b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAudioFourCCBox() {
2455b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    const char *mime;
2456b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    bool success = mMeta->findCString(kKeyMIMEType, &mime);
2457b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2458b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    const char *fourcc = NULL;
2459b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
2460b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fourcc = "samr";
2461b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2462b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fourcc = "sawb";
2463b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2464b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fourcc = "mp4a";
2465b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
246629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Unknown mime type '%s'.", mime);
2467b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(!"should not be here, unknown mime type.");
2468b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2469b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2470b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox(fourcc);        // audio format
2471b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2472b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2473b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x1);         // data ref index
2474b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2475b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2476b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t nChannels;
2477b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels));
2478b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(nChannels);   // channel count
2479b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(16);          // sample size
2480b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // predefined
2481b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2482b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2483b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t samplerate;
2484b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    success = mMeta->findInt32(kKeySampleRate, &samplerate);
2485b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2486b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(samplerate << 16);
2487b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2488b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeMp4aEsdsBox();
2489b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) ||
2490b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong               !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2491b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeDamrBox();
2492b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2493b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2494b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2495b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2496b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4aEsdsBox() {
2497b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("esds");
2498b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificData);
249943089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GT(mCodecSpecificDataSize, 0);
2500b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2501b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Make sure all sizes encode to a single byte.
250243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_LT(mCodecSpecificDataSize + 23, 128);
2503b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2504b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);     // version=0, flags=0
2505b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x03);   // ES_DescrTag
2506b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(23 + mCodecSpecificDataSize);
2507b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x0000);// ES_ID
2508b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x00);
2509b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2510b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x04);   // DecoderConfigDescrTag
2511b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(15 + mCodecSpecificDataSize);
2512b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x40);   // objectTypeIndication ISO/IEC 14492-2
2513b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x15);   // streamType AudioStream
2514b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2515b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x03);  // XXX
2516b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x00);   // buffer size 24-bit
2517b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(96000); // max bit rate
2518b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(96000); // avg bit rate
2519b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2520b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x05);   // DecoderSpecificInfoTag
2521b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(mCodecSpecificDataSize);
2522b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2523b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2524b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    static const uint8_t kData2[] = {
2525b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x06,  // SLConfigDescriptorTag
2526b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x01,
2527b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x02
2528b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    };
2529b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(kData2, sizeof(kData2));
2530b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2531b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // esds
2532b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2533b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2534b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4vEsdsBox() {
2535b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificData);
253643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GT(mCodecSpecificDataSize, 0);
2537b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("esds");
2538b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2539b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);    // version=0, flags=0
2540b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2541b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x03);  // ES_DescrTag
2542b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(23 + mCodecSpecificDataSize);
2543b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x0000);  // ES_ID
2544b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x1f);
2545b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2546b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x04);  // DecoderConfigDescrTag
2547b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(15 + mCodecSpecificDataSize);
2548b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x20);  // objectTypeIndication ISO/IEC 14492-2
2549b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x11);  // streamType VisualStream
2550b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2551b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    static const uint8_t kData[] = {
2552b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x01, 0x77, 0x00,
2553b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x00, 0x03, 0xe8, 0x00,
2554b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x00, 0x03, 0xe8, 0x00
2555b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    };
2556b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(kData, sizeof(kData));
2557b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2558b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
2559b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2560b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(mCodecSpecificDataSize);
2561b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2562b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2563b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    static const uint8_t kData2[] = {
2564b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x06,  // SLConfigDescriptorTag
2565b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x01,
2566b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x02
2567b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    };
2568b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(kData2, sizeof(kData2));
2569b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2570b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // esds
2571b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2572b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2573b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeTkhdBox(time_t now) {
2574b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("tkhd");
2575b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Flags = 7 to indicate that the track is enabled, and
2576b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // part of the presentation
2577b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x07);          // version=0, flags=7
2578b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // creation time
2579b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // modification time
2580b5212db69734962f55e1493d3e696794172ced51James Dong    mOwner->writeInt32(mTrackId + 1);  // track id starts with 1
2581b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
25828f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t trakDurationUs = getDurationUs();
2583b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t mvhdTimeScale = mOwner->getTimeScale();
2584b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t tkhdDuration =
2585b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        (trakDurationUs * mvhdTimeScale + 5E5) / 1E6;
2586b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(tkhdDuration);  // in mvhd timescale
2587b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2588b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2589b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // layer
2590b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // alternate group
2591b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(mIsAudio ? 0x100 : 0);  // volume
2592b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // reserved
2593b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2594b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeCompositionMatrix(mRotation);       // matrix
259520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2596b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mIsAudio) {
2597b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(0);
2598b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(0);
2599b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2600b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        int32_t width, height;
2601b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        bool success = mMeta->findInt32(kKeyWidth, &width);
2602b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        success = success && mMeta->findInt32(kKeyHeight, &height);
2603b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(success);
2604b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2605b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(width << 16);   // 32-bit fixed-point value
2606b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(height << 16);  // 32-bit fixed-point value
2607b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2608b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // tkhd
2609b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2610b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2611b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVmhdBox() {
2612b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("vmhd");
2613b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x01);        // version=0, flags=1
2614b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // graphics mode
2615b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // opcolor
2616b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);
2617b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);
2618b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2619b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2620b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2621b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeSmhdBox() {
2622b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("smhd");
2623b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // version=0, flags=0
2624b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // balance
2625b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2626b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2627b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2628b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2629b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeHdlrBox() {
2630b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("hdlr");
2631b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // version=0, flags=0
2632b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // component type: should be mhlr
2633b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeFourcc(mIsAudio ? "soun" : "vide");  // component subtype
2634b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2635b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2636b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2637b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Removing "r" for the name string just makes the string 4 byte aligned
2638b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle");  // name
2639b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2640b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2641b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2642b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMdhdBox(time_t now) {
2643b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int64_t trakDurationUs = getDurationUs();
2644b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("mdhd");
2645b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // version=0, flags=0
2646b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // creation time
2647b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // modification time
2648b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mTimeScale);    // media timescale
2649b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6;
2650b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mdhdDuration);  // use media timescale
2651b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Language follows the three letter standard ISO-639-2/T
2652b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // 'e', 'n', 'g' for "English", for instance.
2653b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Each character is packed as the difference between its ASCII value and 0x60.
2654b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // For "English", these are 00101, 01110, 00111.
2655b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // XXX: Where is the padding bit located: 0x15C7?
2656b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // language code
2657b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // predefined
2658b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2659b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2660b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2661b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDamrBox() {
2662b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // 3gpp2 Spec AMRSampleEntry fields
2663b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("damr");
2664b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeCString("   ");  // vendor: 4 bytes
2665b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);         // decoder version
2666b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x83FF);   // mode set: all enabled
2667b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);         // mode change period
2668b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(1);         // frames per sample
2669b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2670b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2671b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2672b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeUrlBox() {
2673b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // The table index here refers to the sample description index
2674b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // in the sample table entries.
2675b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("url ");
2676b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1);  // version=0, flags=1 (self-contained)
2677b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // url
2678b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2679b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2680b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDrefBox() {
2681b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("dref");
2682b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2683b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1);  // entry count (either url or urn)
2684b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeUrlBox();
2685b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // dref
2686b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2687b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2688b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDinfBox() {
2689b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("dinf");
2690b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeDrefBox();
2691b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // dinf
2692b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2693b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2694b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAvccBox() {
2695b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificData);
269643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GE(mCodecSpecificDataSize, 5);
2697b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2698b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Patch avcc's lengthSize field to match the number
2699b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // of bytes we use to indicate the size of a nal unit.
2700b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    uint8_t *ptr = (uint8_t *)mCodecSpecificData;
2701b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    ptr[4] = (ptr[4] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1);
2702b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("avcC");
2703b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2704b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // avcC
2705b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2706b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2707b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeD263Box() {
2708b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("d263");
2709b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // vendor
2710b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);   // decoder version
2711b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(10);  // level: 10
2712b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);   // profile: 0
2713b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // d263
2714b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2715b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2716b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong// This is useful if the pixel is not square
2717b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writePaspBox() {
2718b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("pasp");
2719b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1 << 16);  // hspacing
2720b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1 << 16);  // vspacing
2721b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // pasp
2722b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2723b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2724000e18370baae60ffd9f25b509501dd8c26deabfJames Dongint32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const {
2725a472613aec322e25891abf5c77bf3f7e3c244920James Dong    int64_t trackStartTimeOffsetUs = 0;
2726b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
2727b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mStartTimestampUs != moovStartTimeUs) {
272843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        CHECK_GT(mStartTimestampUs, moovStartTimeUs);
2729b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
2730b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2731000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    return (trackStartTimeOffsetUs *  mTimeScale + 500000LL) / 1000000LL;
2732000e18370baae60ffd9f25b509501dd8c26deabfJames Dong}
2733000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
2734000e18370baae60ffd9f25b509501dd8c26deabfJames Dongvoid MPEG4Writer::Track::writeSttsBox() {
2735000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    mOwner->beginBox("stts");
2736000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2737000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    mOwner->writeInt32(mNumSttsTableEntries);
2738000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
2739000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    // Compensate for small start time difference from different media tracks
274079761ab096f57c3027fad9556c2bc436672d614eJames Dong    List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
274179761ab096f57c3027fad9556c2bc436672d614eJames Dong    CHECK(it != mSttsTableEntries.end() && it->sampleCount == 1);
274279761ab096f57c3027fad9556c2bc436672d614eJames Dong    mOwner->writeInt32(it->sampleCount);
2743000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    mOwner->writeInt32(getStartTimeOffsetScaledTime() + it->sampleDuration);
2744a472613aec322e25891abf5c77bf3f7e3c244920James Dong
2745965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    int64_t totalCount = 1;
274679761ab096f57c3027fad9556c2bc436672d614eJames Dong    while (++it != mSttsTableEntries.end()) {
274779761ab096f57c3027fad9556c2bc436672d614eJames Dong        mOwner->writeInt32(it->sampleCount);
274879761ab096f57c3027fad9556c2bc436672d614eJames Dong        mOwner->writeInt32(it->sampleDuration);
2749965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        totalCount += it->sampleCount;
2750b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
275143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_EQ(totalCount, mNumSamples);
2752b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stts
2753b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
275420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2755965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dongvoid MPEG4Writer::Track::writeCttsBox() {
2756965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    if (mIsAudio) {  // ctts is not for audio
2757965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        return;
2758965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    }
2759965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
2760000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    // There is no B frame at all
2761000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    if (mMinCttsOffsetTimeUs == mMaxCttsOffsetTimeUs) {
2762000e18370baae60ffd9f25b509501dd8c26deabfJames Dong        return;
2763000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    }
2764000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
2765965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    // Do not write ctts box when there is no need to have it.
2766965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    if ((mNumCttsTableEntries == 1 &&
2767965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        mCttsTableEntries.begin()->sampleDuration == 0) ||
2768965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        mNumCttsTableEntries == 0) {
2769965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        return;
2770965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    }
2771965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
2772000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    ALOGD("ctts box has %d entries with range [%lld, %lld]",
2773000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            mNumCttsTableEntries, mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs);
2774965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
2775965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    mOwner->beginBox("ctts");
2776000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    // Version 1 allows to use negative offset time value, but
2777000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    // we are sticking to version 0 for now.
2778000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2779965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    mOwner->writeInt32(mNumCttsTableEntries);
2780965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
2781000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    // Compensate for small start time difference from different media tracks
2782000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    List<CttsTableEntry>::iterator it = mCttsTableEntries.begin();
2783000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    CHECK(it != mCttsTableEntries.end() && it->sampleCount == 1);
2784000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    mOwner->writeInt32(it->sampleCount);
2785000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    mOwner->writeInt32(getStartTimeOffsetScaledTime() +
2786000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            it->sampleDuration - mMinCttsOffsetTimeUs);
2787000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
2788000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    int64_t totalCount = 1;
2789000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    while (++it != mCttsTableEntries.end()) {
2790965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        mOwner->writeInt32(it->sampleCount);
2791000e18370baae60ffd9f25b509501dd8c26deabfJames Dong        mOwner->writeInt32(it->sampleDuration - mMinCttsOffsetTimeUs);
2792965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        totalCount += it->sampleCount;
2793965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    }
279443089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_EQ(totalCount, mNumSamples);
2795965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    mOwner->endBox();  // ctts
2796965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong}
2797965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
2798b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStssBox() {
2799b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stss");
2800b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2801b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mNumStssTableEntries);  // number of sync frames
2802b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<int32_t>::iterator it = mStssTableEntries.begin();
2803b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mStssTableEntries.end(); ++it) {
2804b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(*it);
2805b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2806b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stss
2807b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
280825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
2809b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStszBox() {
28108c460498c028888c533ab442be12b6d4b669b965James Dong    ALOGD("writeStszBox for %s track", isAudio()? "Audio": "Video");
2811b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stsz");
2812b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2813b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mSamplesHaveSameSize) {
28148c460498c028888c533ab442be12b6d4b669b965James Dong        List<uint32_t *>::iterator it = mSampleSizes.begin();
28158c460498c028888c533ab442be12b6d4b669b965James Dong        mOwner->writeInt32((*it)[0]);  // default sample size
2816b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2817b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(0);
2818b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2819b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mNumSamples);
28208c460498c028888c533ab442be12b6d4b669b965James Dong    uint32_t nSamples = mNumSamples;
2821b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!mSamplesHaveSameSize) {
28228c460498c028888c533ab442be12b6d4b669b965James Dong        for (List<uint32_t *>::iterator it = mSampleSizes.begin();
2823b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            it != mSampleSizes.end(); ++it) {
28248c460498c028888c533ab442be12b6d4b669b965James Dong            if (nSamples >= kSampleArraySize) {
28258c460498c028888c533ab442be12b6d4b669b965James Dong                mOwner->write(*it, 4, kSampleArraySize);
28268c460498c028888c533ab442be12b6d4b669b965James Dong                nSamples -= kSampleArraySize;
28278c460498c028888c533ab442be12b6d4b669b965James Dong            } else {
28288c460498c028888c533ab442be12b6d4b669b965James Dong                mOwner->write(*it, 4, nSamples);
28298c460498c028888c533ab442be12b6d4b669b965James Dong                break;
28308c460498c028888c533ab442be12b6d4b669b965James Dong            }
2831b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        }
2832b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2833b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stsz
28348c460498c028888c533ab442be12b6d4b669b965James Dong    ALOGD("writeStszBox: X");
2835b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
283620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2837b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStscBox() {
2838b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stsc");
2839b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2840b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mNumStscTableEntries);
2841b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<StscTableEntry>::iterator it = mStscTableEntries.begin();
2842b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mStscTableEntries.end(); ++it) {
2843b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(it->firstChunk);
2844b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(it->samplesPerChunk);
2845b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(it->sampleDescriptionId);
2846b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2847b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stsc
2848b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
284920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2850b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) {
2851b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox(use32BitOffset? "stco": "co64");
2852b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2853b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mNumStcoTableEntries);
2854b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<off64_t>::iterator it = mChunkOffsets.begin();
2855b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mChunkOffsets.end(); ++it) {
2856b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        if (use32BitOffset) {
2857b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->writeInt32(static_cast<int32_t>(*it));
2858b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        } else {
2859b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->writeInt64((*it));
2860b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        }
2861b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2862b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stco or co64
286320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
286420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
286507b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeUdtaBox() {
286607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    beginBox("udta");
286707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeGeoDataBox();
286807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    endBox();
286907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
287007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
287107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong/*
287207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * Geodata is stored according to ISO-6709 standard.
287307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */
287407b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeGeoDataBox() {
287507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    beginBox("\xA9xyz");
287607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    /*
287707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong     * For historical reasons, any user data start
287807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong     * with "\0xA9", must be followed by its assoicated
287907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong     * language code.
2880432ec3768cc4a3b1b01afedc456689d75c89ee2bJames Dong     * 0x0012: text string length
2881432ec3768cc4a3b1b01afedc456689d75c89ee2bJames Dong     * 0x15c7: lang (locale) code: en
288207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong     */
288307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeInt32(0x001215c7);
288407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeLatitude(mLatitudex10000);
288507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeLongitude(mLongitudex10000);
288607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeInt8(0x2F);
288707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    endBox();
288807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
288907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
289020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}  // namespace android
2891