MPEG4Writer.cpp revision 8284de3be2ac07d8774b15e6565df5aba084db04
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
4577e8ae9967a078770416619e99ddb5b010def312James Dongstatic const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024;
461f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongstatic const int64_t kMax32BitFileSize = 0x007fffffffLL;
473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypeSeqParamSet = 0x07;
483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t kNalUnitTypePicParamSet = 0x08;
4970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dongstatic const int64_t kInitialDelayTimeUs     = 700000LL;
505b6a01e65aa4129a9226667536d1bc1dad5980d8James Dong
5120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberclass MPEG4Writer::Track {
5220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberpublic:
53bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId);
548f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
5520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    ~Track();
5620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
5793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    status_t start(MetaData *params);
5837187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t stop();
5937187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t pause();
6025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool reachedEOS();
6120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
623b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber    int64_t getDurationUs() const;
63d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    int64_t getEstimatedTrackSizeBytes() const;
64b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeTrackHeader(bool use32BitOffset = true);
651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    void bufferChunk(int64_t timestampUs);
661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool isAvc() const { return mIsAvc; }
671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool isAudio() const { return mIsAudio; }
681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool isMPEG4() const { return mIsMPEG4; }
69c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    void addChunkOffset(off64_t offset);
7070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    int32_t getTrackId() const { return mTrackId; }
71dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    status_t dump(int fd, const Vector<String16>& args) const;
7220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
7320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huberprivate:
74000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    enum {
75000e18370baae60ffd9f25b509501dd8c26deabfJames Dong        kMaxCttsOffsetTimeUs = 1000000LL,  // 1 second
768c460498c028888c533ab442be12b6d4b669b965James Dong        kSampleArraySize = 1000,
77000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    };
78000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
79c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    // A helper class to handle faster write box with table entries
80c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    template<class TYPE>
81c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    struct ListTableEntries {
82c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        ListTableEntries(uint32_t elementCapacity, uint32_t entryCapacity)
83c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            : mElementCapacity(elementCapacity),
84c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            mEntryCapacity(entryCapacity),
85c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            mTotalNumTableEntries(0),
86c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            mNumValuesInCurrEntry(0),
87c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            mCurrTableEntriesElement(NULL) {
88c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            CHECK_GT(mElementCapacity, 0);
89c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            CHECK_GT(mEntryCapacity, 0);
90c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        }
91c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
92c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        // Free the allocated memory.
93c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        ~ListTableEntries() {
94c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            while (!mTableEntryList.empty()) {
95c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                typename List<TYPE *>::iterator it = mTableEntryList.begin();
96c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                delete[] (*it);
97c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                mTableEntryList.erase(it);
98c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            }
99c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        }
100c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
101c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        // Replace the value at the given position by the given value.
102c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        // There must be an existing value at the given position.
103c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        // @arg value must be in network byte order
104c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        // @arg pos location the value must be in.
105c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        void set(const TYPE& value, uint32_t pos) {
10625f0d7ba1987de61c75f8c68b19de48e0ad9736cJames Dong            CHECK_LT(pos, mTotalNumTableEntries * mEntryCapacity);
107c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
108c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            typename List<TYPE *>::iterator it = mTableEntryList.begin();
109c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            uint32_t iterations = (pos / (mElementCapacity * mEntryCapacity));
110c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            while (it != mTableEntryList.end() && iterations > 0) {
111c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                ++it;
112c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                --iterations;
113c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            }
114c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            CHECK(it != mTableEntryList.end());
115c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            CHECK_EQ(iterations, 0);
116c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
117c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            (*it)[(pos % (mElementCapacity * mEntryCapacity))] = value;
118c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        }
119c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
120c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        // Get the value at the given position by the given value.
121c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        // @arg value the retrieved value at the position in network byte order.
122c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        // @arg pos location the value must be in.
123c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        // @return true if a value is found.
124c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        bool get(TYPE& value, uint32_t pos) const {
12525f0d7ba1987de61c75f8c68b19de48e0ad9736cJames Dong            if (pos >= mTotalNumTableEntries * mEntryCapacity) {
126c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                return false;
127c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            }
128c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
129c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            typename List<TYPE *>::iterator it = mTableEntryList.begin();
130c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            uint32_t iterations = (pos / (mElementCapacity * mEntryCapacity));
131c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            while (it != mTableEntryList.end() && iterations > 0) {
132c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                ++it;
133c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                --iterations;
134c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            }
135c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            CHECK(it != mTableEntryList.end());
136c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            CHECK_EQ(iterations, 0);
137c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
138c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            value = (*it)[(pos % (mElementCapacity * mEntryCapacity))];
139c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            return true;
140c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        }
141c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
142c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        // Store a single value.
143c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        // @arg value must be in network byte order.
144c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        void add(const TYPE& value) {
145c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            CHECK_LT(mNumValuesInCurrEntry, mElementCapacity);
146c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            uint32_t nEntries = mTotalNumTableEntries % mElementCapacity;
147c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            uint32_t nValues  = mNumValuesInCurrEntry % mEntryCapacity;
148c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            if (nEntries == 0 && nValues == 0) {
149c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                mCurrTableEntriesElement = new TYPE[mEntryCapacity * mElementCapacity];
150c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                CHECK(mCurrTableEntriesElement != NULL);
151c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                mTableEntryList.push_back(mCurrTableEntriesElement);
152c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            }
153c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
154c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            uint32_t pos = nEntries * mEntryCapacity + nValues;
155c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            mCurrTableEntriesElement[pos] = value;
156c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
157c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            ++mNumValuesInCurrEntry;
158c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            if ((mNumValuesInCurrEntry % mEntryCapacity) == 0) {
159c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                ++mTotalNumTableEntries;
160c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                mNumValuesInCurrEntry = 0;
161c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            }
162c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        }
163c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
164c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        // Write out the table entries:
165c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        // 1. the number of entries goes first
166c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        // 2. followed by the values in the table enties in order
167c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        // @arg writer the writer to actual write to the storage
168c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        void write(MPEG4Writer *writer) const {
169c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            CHECK_EQ(mNumValuesInCurrEntry % mEntryCapacity, 0);
170c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            uint32_t nEntries = mTotalNumTableEntries;
171c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            writer->writeInt32(nEntries);
172c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            for (typename List<TYPE *>::iterator it = mTableEntryList.begin();
173c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                it != mTableEntryList.end(); ++it) {
174c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                CHECK_GT(nEntries, 0);
175c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                if (nEntries >= mElementCapacity) {
176c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                    writer->write(*it, sizeof(TYPE) * mEntryCapacity, mElementCapacity);
177c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                    nEntries -= mElementCapacity;
178c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                } else {
179c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                    writer->write(*it, sizeof(TYPE) * mEntryCapacity, nEntries);
180c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                    break;
181c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                }
182c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            }
183c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        }
184c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
185c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        // Return the number of entries in the table.
186c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        uint32_t count() const { return mTotalNumTableEntries; }
187c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
188c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    private:
189c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        uint32_t         mElementCapacity;  // # entries in an element
190c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        uint32_t         mEntryCapacity;    // # of values in each entry
191c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        uint32_t         mTotalNumTableEntries;
192c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        uint32_t         mNumValuesInCurrEntry;  // up to mEntryCapacity
193c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        TYPE             *mCurrTableEntriesElement;
194c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        mutable List<TYPE *>     mTableEntryList;
195c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
196c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        DISALLOW_EVIL_CONSTRUCTORS(ListTableEntries);
197c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    };
198c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
199c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
200c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
20120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    MPEG4Writer *mOwner;
20220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    sp<MetaData> mMeta;
203693d271e62a3726689ff68f4505ba49228eb94b2Andreas Huber    sp<MediaSource> mSource;
20420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    volatile bool mDone;
205a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    volatile bool mPaused;
206a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    volatile bool mResumed;
207eaae38445a340c4857c1c5569475879a728e63b7James Dong    volatile bool mStarted;
2081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool mIsAvc;
2091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool mIsAudio;
2101c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    bool mIsMPEG4;
211bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    int32_t mTrackId;
212c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    int64_t mTrackDurationUs;
21343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    int64_t mMaxChunkDurationUs;
214e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
215d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    int64_t mEstimatedTrackSizeBytes;
2161f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    int64_t mMdatSizeBytes;
2178f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int32_t mTimeScale;
21820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
21920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_t mThread;
22020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
221be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
22213aec890216948b0c364f8f92792129d0335f506James Dong    List<MediaBuffer *> mChunkSamples;
2231f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
224c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    bool                mSamplesHaveSameSize;
225c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    ListTableEntries<uint32_t> *mStszTableEntries;
226be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
227c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    ListTableEntries<uint32_t> *mStcoTableEntries;
228c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    ListTableEntries<off64_t> *mCo64TableEntries;
229c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    ListTableEntries<uint32_t> *mStscTableEntries;
230c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    ListTableEntries<uint32_t> *mStssTableEntries;
231c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    ListTableEntries<uint32_t> *mSttsTableEntries;
232c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    ListTableEntries<uint32_t> *mCttsTableEntries;
233965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
234000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    int64_t mMinCttsOffsetTimeUs;
235000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    int64_t mMaxCttsOffsetTimeUs;
236965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
2373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Sequence parameter set or picture parameter set
2383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    struct AVCParamSet {
2393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        AVCParamSet(uint16_t length, const uint8_t *data)
2403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            : mLength(length), mData(data) {}
2413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
2423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t mLength;
2433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *mData;
2443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    };
2453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    List<AVCParamSet> mSeqParamSets;
2463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    List<AVCParamSet> mPicParamSets;
2473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mProfileIdc;
2483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mProfileCompatible;
2493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t mLevelIdc;
2503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
25120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    void *mCodecSpecificData;
25220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    size_t mCodecSpecificDataSize;
253548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber    bool mGotAllCodecSpecificData;
25493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    bool mTrackingProgressStatus;
25520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
25625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool mReachedEOS;
2573c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    int64_t mStartTimestampUs;
25870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    int64_t mStartTimeRealUs;
25970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    int64_t mFirstSampleTimeRealUs;
26093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t mPreviousTrackTimeUs;
26193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t mTrackEveryTimeDurationUs;
26225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
263872a481558350634a3fd5cb67939de288af00ecbJames Dong    // Update the audio track's drift information.
264872a481558350634a3fd5cb67939de288af00ecbJames Dong    void updateDriftTime(const sp<MetaData>& meta);
265872a481558350634a3fd5cb67939de288af00ecbJames Dong
266000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    int32_t getStartTimeOffsetScaledTime() const;
267000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
26820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    static void *ThreadWrapper(void *me);
26937187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t threadEntry();
27020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *parseParamSet(
2723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length, int type, size_t *paramSetLen);
2733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
274b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    status_t makeAVCCodecSpecificData(const uint8_t *data, size_t size);
275b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    status_t copyAVCCodecSpecificData(const uint8_t *data, size_t size);
276b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    status_t parseAVCCodecSpecificData(const uint8_t *data, size_t size);
277215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong
278215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    // Track authoring progress status
279faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    void trackProgressStatus(int64_t timeUs, status_t err = OK);
28093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    void initTrackingProgressStatus(MetaData *params);
28103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
28219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    void getCodecSpecificDataFromInputFormatIfPossible();
28319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
284c059860c73678a202bfa33062723e8f82fb779d9James Dong    // Determine the track time scale
285c059860c73678a202bfa33062723e8f82fb779d9James Dong    // If it is an audio track, try to use the sampling rate as
286c059860c73678a202bfa33062723e8f82fb779d9James Dong    // the time scale; however, if user chooses the overwrite
287c059860c73678a202bfa33062723e8f82fb779d9James Dong    // value, the user-supplied time scale will be used.
288c059860c73678a202bfa33062723e8f82fb779d9James Dong    void setTimeScale();
289c059860c73678a202bfa33062723e8f82fb779d9James Dong
290690f546b0ee548dbfe997df36418e5302ec2d786James Dong    // Simple validation on the codec specific data
291690f546b0ee548dbfe997df36418e5302ec2d786James Dong    status_t checkCodecSpecificData() const;
29213f6284305e4b27395a23db7882d670bdb1bcae1James Dong    int32_t mRotation;
293690f546b0ee548dbfe997df36418e5302ec2d786James Dong
2941f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void updateTrackSizeEstimate();
2951f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void addOneStscTableEntry(size_t chunkId, size_t sampleId);
2961f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    void addOneStssTableEntry(size_t sampleId);
29779761ab096f57c3027fad9556c2bc436672d614eJames Dong
29879761ab096f57c3027fad9556c2bc436672d614eJames Dong    // Duration is time scale based
29979761ab096f57c3027fad9556c2bc436672d614eJames Dong    void addOneSttsTableEntry(size_t sampleCount, int32_t timescaledDur);
300965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    void addOneCttsTableEntry(size_t sampleCount, int32_t timescaledDur);
30145c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong
30245c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    bool isTrackMalFormed() const;
30343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    void sendTrackSummary(bool hasMultipleTracks);
3041f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
305b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Write the boxes
306b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStcoBox(bool use32BitOffset);
307b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStscBox();
308b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStszBox();
309b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStssBox();
310b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeSttsBox();
311965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    void writeCttsBox();
312b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeD263Box();
313b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writePaspBox();
314b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeAvccBox();
315b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeUrlBox();
316b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeDrefBox();
317b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeDinfBox();
318b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeDamrBox();
319efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson    void writeMdhdBox(uint32_t now);
320b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeSmhdBox();
321b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeVmhdBox();
322b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeHdlrBox();
323efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson    void writeTkhdBox(uint32_t now);
324b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeMp4aEsdsBox();
325b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeMp4vEsdsBox();
326b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeAudioFourCCBox();
327b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeVideoFourCCBox();
328b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    void writeStblBox(bool use32BitOffset);
329b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
33020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track(const Track &);
33120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track &operator=(const Track &);
33220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber};
33320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
33420111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::MPEG4Writer(const char *filename)
335674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    : mFd(-1),
336674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong      mInitCheck(NO_INIT),
337de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui      mIsRealTimeRecording(true),
338b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong      mUse4ByteNalLength(true),
3391acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong      mUse32BitOffset(true),
340a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong      mIsFileSizeLimitExplicitlyRequested(false),
341a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
342a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mStarted(false),
343411ba422e3635d534928ffd81abf54f4f291c739James Dong      mWriterThreadStarted(false),
34420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mOffset(0),
34513aec890216948b0c364f8f92792129d0335f506James Dong      mMdatOffset(0),
3467837c17063a4c50bc856ba59418516fdab731de7James Dong      mEstimatedMoovBoxSize(0),
34707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mInterleaveDurationUs(1000000),
34807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mLatitudex10000(0),
34907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mLongitudex10000(0),
35086b7f47aa7482424cf8fd248f1315311919be3b0James Dong      mAreGeoTagsAvailable(false),
35186b7f47aa7482424cf8fd248f1315311919be3b0James Dong      mStartTimeOffsetMs(-1) {
352674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong
353af8e8aa1ada2948972555592570ec9ad90cbf372Nick Kralevich    mFd = open(filename, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
354674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mFd >= 0) {
355674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        mInitCheck = OK;
356674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    }
35720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
35820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
35930ab66297501757d745b9ae10da61adcd891f497Andreas HuberMPEG4Writer::MPEG4Writer(int fd)
360674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    : mFd(dup(fd)),
361674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong      mInitCheck(mFd < 0? NO_INIT: OK),
362de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui      mIsRealTimeRecording(true),
363b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong      mUse4ByteNalLength(true),
3641acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong      mUse32BitOffset(true),
365a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong      mIsFileSizeLimitExplicitlyRequested(false),
366a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
367a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mStarted(false),
368411ba422e3635d534928ffd81abf54f4f291c739James Dong      mWriterThreadStarted(false),
36930ab66297501757d745b9ae10da61adcd891f497Andreas Huber      mOffset(0),
37013aec890216948b0c364f8f92792129d0335f506James Dong      mMdatOffset(0),
3717837c17063a4c50bc856ba59418516fdab731de7James Dong      mEstimatedMoovBoxSize(0),
37207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mInterleaveDurationUs(1000000),
37307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mLatitudex10000(0),
37407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong      mLongitudex10000(0),
37586b7f47aa7482424cf8fd248f1315311919be3b0James Dong      mAreGeoTagsAvailable(false),
37686b7f47aa7482424cf8fd248f1315311919be3b0James Dong      mStartTimeOffsetMs(-1) {
37730ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
37830ab66297501757d745b9ae10da61adcd891f497Andreas Huber
37920111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::~MPEG4Writer() {
3808bcc65c753085fe3328592cceda0cf0e8f8b0a45James Dong    reset();
38120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
3821f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    while (!mTracks.empty()) {
3831f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        List<Track *>::iterator it = mTracks.begin();
38420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        delete *it;
3851f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        (*it) = NULL;
3861f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        mTracks.erase(it);
38720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
38820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mTracks.clear();
38920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
39020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
391dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::dump(
392dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        int fd, const Vector<String16>& args) {
393dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    const size_t SIZE = 256;
394dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    char buffer[SIZE];
395dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    String8 result;
396dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "   MPEG4Writer %p\n", this);
397dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
398dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "     mStarted: %s\n", mStarted? "true": "false");
399dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
400dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    ::write(fd, result.string(), result.size());
401dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    for (List<Track *>::iterator it = mTracks.begin();
402dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong         it != mTracks.end(); ++it) {
403dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        (*it)->dump(fd, args);
404dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    }
405dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    return OK;
406dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong}
407dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong
408dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dongstatus_t MPEG4Writer::Track::dump(
409dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong        int fd, const Vector<String16>& args) const {
410dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    const size_t SIZE = 256;
411dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    char buffer[SIZE];
412dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    String8 result;
413dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "     %s track\n", mIsAudio? "Audio": "Video");
414dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
415dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    snprintf(buffer, SIZE, "       reached EOS: %s\n",
416dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong            mReachedEOS? "true": "false");
417dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    result.append(buffer);
418c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    snprintf(buffer, SIZE, "       frames encoded : %d\n", mStszTableEntries->count());
41913210f3346462a86ce9fe3af72a0c200dba84e27James Dong    result.append(buffer);
42013210f3346462a86ce9fe3af72a0c200dba84e27James Dong    snprintf(buffer, SIZE, "       duration encoded : %lld us\n", mTrackDurationUs);
42113210f3346462a86ce9fe3af72a0c200dba84e27James Dong    result.append(buffer);
422dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    ::write(fd, result.string(), result.size());
423dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong    return OK;
424dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong}
425dedf414d3fe2e79ee0aad0f1c82ca16ebd886ff6James Dong
4262dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huberstatus_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
427bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    Mutex::Autolock l(mLock);
428bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    if (mStarted) {
42929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Attempt to add source AFTER recording is started");
430bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        return UNKNOWN_ERROR;
431bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    }
432acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong
433acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    // At most 2 tracks can be supported.
434acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    if (mTracks.size() >= 2) {
435acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong        ALOGE("Too many tracks (%d) to add", mTracks.size());
436acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong        return ERROR_UNSUPPORTED;
437acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    }
438acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong
439acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    CHECK(source.get() != NULL);
440acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong
441acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    // A track of type other than video or audio is not supported.
442acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    const char *mime;
443acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    source->getFormat()->findCString(kKeyMIMEType, &mime);
444acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    bool isAudio = !strncasecmp(mime, "audio/", 6);
445acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    bool isVideo = !strncasecmp(mime, "video/", 6);
446acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    if (!isAudio && !isVideo) {
447acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong        ALOGE("Track (%s) other than video or audio is not supported",
448acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong            mime);
449acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong        return ERROR_UNSUPPORTED;
450acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    }
451acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong
452acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    // At this point, we know the track to be added is either
453acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    // video or audio. Thus, we only need to check whether it
454acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    // is an audio track or not (if it is not, then it must be
455acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    // a video track).
456acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong
457acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    // No more than one video or one audio track is supported.
458acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    for (List<Track*>::iterator it = mTracks.begin();
459acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong         it != mTracks.end(); ++it) {
460acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong        if ((*it)->isAudio() == isAudio) {
461acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong            ALOGE("%s track already exists", isAudio? "Audio": "Video");
462acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong            return ERROR_UNSUPPORTED;
463acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong        }
464acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    }
465acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong
466acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    // This is the first track of either audio or video.
467acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    // Go ahead to add the track.
468219f195159f93d627af2b243732e3f9020511a46James Dong    Track *track = new Track(this, source, 1 + mTracks.size());
46920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mTracks.push_back(track);
4702dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber
4712dce41ad26cb3e9e15c9e456a84bcf5309548ca0Andreas Huber    return OK;
47220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
47320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
47493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::startTracks(MetaData *params) {
475acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    if (mTracks.empty()) {
476acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong        ALOGE("No source added");
477acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong        return INVALID_OPERATION;
478acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong    }
479acc47642e0f5d962f6289e6ba687fabf68f8312bJames Dong
480a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    for (List<Track *>::iterator it = mTracks.begin();
481a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong         it != mTracks.end(); ++it) {
48293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        status_t err = (*it)->start(params);
483a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
484a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (err != OK) {
485a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            for (List<Track *>::iterator it2 = mTracks.begin();
486a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong                 it2 != it; ++it2) {
487a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong                (*it2)->stop();
488a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            }
489a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
490a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            return err;
491a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
492a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
493a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    return OK;
494a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
495a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
4962dec2b5be2056c6d9428897dc672185872d30d17James Dongint64_t MPEG4Writer::estimateMoovBoxSize(int32_t bitRate) {
4972dec2b5be2056c6d9428897dc672185872d30d17James Dong    // This implementation is highly experimental/heurisitic.
4982dec2b5be2056c6d9428897dc672185872d30d17James Dong    //
4992dec2b5be2056c6d9428897dc672185872d30d17James Dong    // Statistical analysis shows that metadata usually accounts
5002dec2b5be2056c6d9428897dc672185872d30d17James Dong    // for a small portion of the total file size, usually < 0.6%.
5012dec2b5be2056c6d9428897dc672185872d30d17James Dong
50278a1a286f736888ae7af8860b2c424af0d978848James Dong    // The default MIN_MOOV_BOX_SIZE is set to 0.6% x 1MB / 2,
5032dec2b5be2056c6d9428897dc672185872d30d17James Dong    // where 1MB is the common file size limit for MMS application.
50478a1a286f736888ae7af8860b2c424af0d978848James Dong    // The default MAX _MOOV_BOX_SIZE value is based on about 3
5052dec2b5be2056c6d9428897dc672185872d30d17James Dong    // minute video recording with a bit rate about 3 Mbps, because
5062dec2b5be2056c6d9428897dc672185872d30d17James Dong    // statistics also show that most of the video captured are going
5072dec2b5be2056c6d9428897dc672185872d30d17James Dong    // to be less than 3 minutes.
5082dec2b5be2056c6d9428897dc672185872d30d17James Dong
5092dec2b5be2056c6d9428897dc672185872d30d17James Dong    // If the estimation is wrong, we will pay the price of wasting
5102dec2b5be2056c6d9428897dc672185872d30d17James Dong    // some reserved space. This should not happen so often statistically.
5112dec2b5be2056c6d9428897dc672185872d30d17James Dong    static const int32_t factor = mUse32BitOffset? 1: 2;
51278a1a286f736888ae7af8860b2c424af0d978848James Dong    static const int64_t MIN_MOOV_BOX_SIZE = 3 * 1024;  // 3 KB
5132dec2b5be2056c6d9428897dc672185872d30d17James Dong    static const int64_t MAX_MOOV_BOX_SIZE = (180 * 3000000 * 6LL / 8000);
5142dec2b5be2056c6d9428897dc672185872d30d17James Dong    int64_t size = MIN_MOOV_BOX_SIZE;
5152dec2b5be2056c6d9428897dc672185872d30d17James Dong
51678a1a286f736888ae7af8860b2c424af0d978848James Dong    // Max file size limit is set
517a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
51878a1a286f736888ae7af8860b2c424af0d978848James Dong        size = mMaxFileSizeLimitBytes * 6 / 1000;
51978a1a286f736888ae7af8860b2c424af0d978848James Dong    }
52078a1a286f736888ae7af8860b2c424af0d978848James Dong
52178a1a286f736888ae7af8860b2c424af0d978848James Dong    // Max file duration limit is set
52278a1a286f736888ae7af8860b2c424af0d978848James Dong    if (mMaxFileDurationLimitUs != 0) {
52378a1a286f736888ae7af8860b2c424af0d978848James Dong        if (bitRate > 0) {
52478a1a286f736888ae7af8860b2c424af0d978848James Dong            int64_t size2 =
52578a1a286f736888ae7af8860b2c424af0d978848James Dong                ((mMaxFileDurationLimitUs * bitRate * 6) / 1000 / 8000000);
52678a1a286f736888ae7af8860b2c424af0d978848James Dong            if (mMaxFileSizeLimitBytes != 0 && mIsFileSizeLimitExplicitlyRequested) {
52778a1a286f736888ae7af8860b2c424af0d978848James Dong                // When both file size and duration limits are set,
52878a1a286f736888ae7af8860b2c424af0d978848James Dong                // we use the smaller limit of the two.
52978a1a286f736888ae7af8860b2c424af0d978848James Dong                if (size > size2) {
53078a1a286f736888ae7af8860b2c424af0d978848James Dong                    size = size2;
53178a1a286f736888ae7af8860b2c424af0d978848James Dong                }
53278a1a286f736888ae7af8860b2c424af0d978848James Dong            } else {
53378a1a286f736888ae7af8860b2c424af0d978848James Dong                // Only max file duration limit is set
53478a1a286f736888ae7af8860b2c424af0d978848James Dong                size = size2;
53578a1a286f736888ae7af8860b2c424af0d978848James Dong            }
5362dec2b5be2056c6d9428897dc672185872d30d17James Dong        }
5372dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
53878a1a286f736888ae7af8860b2c424af0d978848James Dong
5392dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (size < MIN_MOOV_BOX_SIZE) {
5402dec2b5be2056c6d9428897dc672185872d30d17James Dong        size = MIN_MOOV_BOX_SIZE;
5412dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
5422dec2b5be2056c6d9428897dc672185872d30d17James Dong
5432dec2b5be2056c6d9428897dc672185872d30d17James Dong    // Any long duration recording will be probably end up with
5442dec2b5be2056c6d9428897dc672185872d30d17James Dong    // non-streamable mp4 file.
5452dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (size > MAX_MOOV_BOX_SIZE) {
5462dec2b5be2056c6d9428897dc672185872d30d17James Dong        size = MAX_MOOV_BOX_SIZE;
5472dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
5482dec2b5be2056c6d9428897dc672185872d30d17James Dong
549df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block    ALOGI("limits: %lld/%lld bytes/us, bit rate: %d bps and the estimated"
5502dec2b5be2056c6d9428897dc672185872d30d17James Dong         " moov size %lld bytes",
5512dec2b5be2056c6d9428897dc672185872d30d17James Dong         mMaxFileSizeLimitBytes, mMaxFileDurationLimitUs, bitRate, size);
5522dec2b5be2056c6d9428897dc672185872d30d17James Dong    return factor * size;
5532dec2b5be2056c6d9428897dc672185872d30d17James Dong}
5542dec2b5be2056c6d9428897dc672185872d30d17James Dong
5552dec2b5be2056c6d9428897dc672185872d30d17James Dongstatus_t MPEG4Writer::start(MetaData *param) {
556674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mInitCheck != OK) {
55725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        return UNKNOWN_ERROR;
55820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
55920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
560a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    /*
561a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * Check mMaxFileSizeLimitBytes at the beginning
562a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * since mMaxFileSizeLimitBytes may be implicitly
563a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * changed later for 32-bit file offset even if
564a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     * user does not ask to set it explicitly.
565a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong     */
566a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    if (mMaxFileSizeLimitBytes != 0) {
567a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong        mIsFileSizeLimitExplicitlyRequested = true;
568a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong    }
569a007e8229fb2be4866c483f9cd6c4af238a2da5eJames Dong
5702dec2b5be2056c6d9428897dc672185872d30d17James Dong    int32_t use64BitOffset;
5712dec2b5be2056c6d9428897dc672185872d30d17James Dong    if (param &&
5722dec2b5be2056c6d9428897dc672185872d30d17James Dong        param->findInt32(kKey64BitFileOffset, &use64BitOffset) &&
5732dec2b5be2056c6d9428897dc672185872d30d17James Dong        use64BitOffset) {
5742dec2b5be2056c6d9428897dc672185872d30d17James Dong        mUse32BitOffset = false;
5752dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
5762dec2b5be2056c6d9428897dc672185872d30d17James Dong
5771f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    if (mUse32BitOffset) {
5781f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        // Implicit 32 bit file size limit
5791f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        if (mMaxFileSizeLimitBytes == 0) {
5801f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            mMaxFileSizeLimitBytes = kMax32BitFileSize;
5811f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        }
5821f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
5831f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        // If file size is set to be larger than the 32 bit file
5841f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        // size limit, treat it as an error.
5851f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        if (mMaxFileSizeLimitBytes > kMax32BitFileSize) {
5865ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block            ALOGW("32-bit file size limit (%lld bytes) too big. "
587d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong                 "It is changed to %lld bytes",
588d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong                mMaxFileSizeLimitBytes, kMax32BitFileSize);
589d2518e0c0a5bffd30b0dccb04fe7bf5b77c354b1James Dong            mMaxFileSizeLimitBytes = kMax32BitFileSize;
5901f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        }
5911f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    }
5921f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
593b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    int32_t use2ByteNalLength;
594b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    if (param &&
595b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) &&
596b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        use2ByteNalLength) {
597b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        mUse4ByteNalLength = false;
5982dec2b5be2056c6d9428897dc672185872d30d17James Dong    }
5992dec2b5be2056c6d9428897dc672185872d30d17James Dong
600de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui    int32_t isRealTimeRecording;
601de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui    if (param && param->findInt32(kKeyRealTimeRecording, &isRealTimeRecording)) {
602de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui        mIsRealTimeRecording = isRealTimeRecording;
603de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui    }
604de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui
605065d1aff96818df54456053f1574aec8a234d0deJames Dong    mStartTimestampUs = -1;
60693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
607a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (mStarted) {
608a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mPaused) {
609a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            mPaused = false;
61093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            return startTracks(param);
611a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
612a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return OK;
613a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
614a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
6158f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    if (!param ||
6168f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        !param->findInt32(kKeyTimeScale, &mTimeScale)) {
6178f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        mTimeScale = 1000;
6188f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    }
61943089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GT(mTimeScale, 0);
6203856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("movie time scale: %d", mTimeScale);
6218f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
62277e8ae9967a078770416619e99ddb5b010def312James Dong    /*
62377e8ae9967a078770416619e99ddb5b010def312James Dong     * When the requested file size limit is small, the priority
62477e8ae9967a078770416619e99ddb5b010def312James Dong     * is to meet the file size limit requirement, rather than
6257b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * to make the file streamable. mStreamableFile does not tell
6267b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * whether the actual recorded file is streamable or not.
62777e8ae9967a078770416619e99ddb5b010def312James Dong     */
62877e8ae9967a078770416619e99ddb5b010def312James Dong    mStreamableFile =
62977e8ae9967a078770416619e99ddb5b010def312James Dong        (mMaxFileSizeLimitBytes != 0 &&
63077e8ae9967a078770416619e99ddb5b010def312James Dong         mMaxFileSizeLimitBytes >= kMinStreamableFileSizeInBytes);
63177e8ae9967a078770416619e99ddb5b010def312James Dong
6327b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    /*
6337b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * mWriteMoovBoxToMemory is true if the amount of data in moov box is
6347b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * smaller than the reserved free space at the beginning of a file, AND
6357b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * when the content of moov box is constructed. Note that video/audio
6367b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * frame data is always written to the file but not in the memory.
6377b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     *
6387b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * Before stop()/reset() is called, mWriteMoovBoxToMemory is always
6397b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * false. When reset() is called at the end of a recording session,
6407b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * Moov box needs to be constructed.
6417b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     *
6427b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * 1) Right before a moov box is constructed, mWriteMoovBoxToMemory
6437b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * to set to mStreamableFile so that if
6447b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * the file is intended to be streamable, it is set to true;
6457b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * otherwise, it is set to false. When the value is set to false,
6467b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * all the content of the moov box is written immediately to
6477b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * the end of the file. When the value is set to true, all the
6487b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * content of the moov box is written to an in-memory cache,
6497b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * mMoovBoxBuffer, util the following condition happens. Note
6507b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * that the size of the in-memory cache is the same as the
6517b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * reserved free space at the beginning of the file.
6527b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     *
6537b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * 2) While the data of the moov box is written to an in-memory
6547b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * cache, the data size is checked against the reserved space.
6557b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * If the data size surpasses the reserved space, subsequent moov
6567b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * data could no longer be hold in the in-memory cache. This also
6577b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * indicates that the reserved space was too small. At this point,
6587b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * _all_ moov data must be written to the end of the file.
6597b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * mWriteMoovBoxToMemory must be set to false to direct the write
6607b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * to the file.
6617b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     *
6627b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * 3) If the data size in moov box is smaller than the reserved
6637b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * space after moov box is completely constructed, the in-memory
6647b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * cache copy of the moov box is written to the reserved free
6657b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * space. Thus, immediately after the moov is completedly
6667b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     * constructed, mWriteMoovBoxToMemory is always set to false.
6677b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong     */
6687b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    mWriteMoovBoxToMemory = false;
6697837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBuffer = NULL;
6707837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBufferOffset = 0;
6717837c17063a4c50bc856ba59418516fdab731de7James Dong
672b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeFtypBox(param);
67320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6747837c17063a4c50bc856ba59418516fdab731de7James Dong    mFreeBoxOffset = mOffset;
67520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
6767837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mEstimatedMoovBoxSize == 0) {
6772dec2b5be2056c6d9428897dc672185872d30d17James Dong        int32_t bitRate = -1;
6782dec2b5be2056c6d9428897dc672185872d30d17James Dong        if (param) {
6792dec2b5be2056c6d9428897dc672185872d30d17James Dong            param->findInt32(kKeyBitRate, &bitRate);
6802dec2b5be2056c6d9428897dc672185872d30d17James Dong        }
6812dec2b5be2056c6d9428897dc672185872d30d17James Dong        mEstimatedMoovBoxSize = estimateMoovBoxSize(bitRate);
6827837c17063a4c50bc856ba59418516fdab731de7James Dong    }
68343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GE(mEstimatedMoovBoxSize, 8);
68477e8ae9967a078770416619e99ddb5b010def312James Dong    if (mStreamableFile) {
68577e8ae9967a078770416619e99ddb5b010def312James Dong        // Reserve a 'free' box only for streamable file
68677e8ae9967a078770416619e99ddb5b010def312James Dong        lseek64(mFd, mFreeBoxOffset, SEEK_SET);
68777e8ae9967a078770416619e99ddb5b010def312James Dong        writeInt32(mEstimatedMoovBoxSize);
68877e8ae9967a078770416619e99ddb5b010def312James Dong        write("free", 4);
68977e8ae9967a078770416619e99ddb5b010def312James Dong        mMdatOffset = mFreeBoxOffset + mEstimatedMoovBoxSize;
69077e8ae9967a078770416619e99ddb5b010def312James Dong    } else {
69177e8ae9967a078770416619e99ddb5b010def312James Dong        mMdatOffset = mOffset;
69277e8ae9967a078770416619e99ddb5b010def312James Dong    }
6937837c17063a4c50bc856ba59418516fdab731de7James Dong
6947837c17063a4c50bc856ba59418516fdab731de7James Dong    mOffset = mMdatOffset;
695c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    lseek64(mFd, mMdatOffset, SEEK_SET);
6961acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    if (mUse32BitOffset) {
6971acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        write("????mdat", 8);
6981acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    } else {
6991acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        write("\x00\x00\x00\x01mdat????????", 16);
7001acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    }
7011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
7021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    status_t err = startWriterThread();
7031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (err != OK) {
7041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        return err;
7051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
7061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
7071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    err = startTracks(param);
708a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (err != OK) {
709a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return err;
71020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
7111c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
712a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mStarted = true;
71325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return OK;
71420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
71520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
7161f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongbool MPEG4Writer::use32BitFileOffset() const {
7171f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    return mUse32BitOffset;
7181f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
7191f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
72037187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::pause() {
721674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mInitCheck != OK) {
72237187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
723a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
724a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mPaused = true;
72537187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = OK;
726a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    for (List<Track *>::iterator it = mTracks.begin();
727a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong         it != mTracks.end(); ++it) {
72837187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = (*it)->pause();
72937187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (status != OK) {
73037187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
73137187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
732a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
73337187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
734a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
735a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
7361c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::stopWriterThread() {
737b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("Stopping writer thread");
738411ba422e3635d534928ffd81abf54f4f291c739James Dong    if (!mWriterThreadStarted) {
739411ba422e3635d534928ffd81abf54f4f291c739James Dong        return;
740411ba422e3635d534928ffd81abf54f4f291c739James Dong    }
7411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
7421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    {
7431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        Mutex::Autolock autolock(mLock);
7441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
7451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mDone = true;
7461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mChunkReadyCondition.signal();
7471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
7481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
7491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    void *dummy;
7501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_join(mThread, &dummy);
751411ba422e3635d534928ffd81abf54f4f291c739James Dong    mWriterThreadStarted = false;
752b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("Writer thread stopped");
7531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
7541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
75513f6284305e4b27395a23db7882d670bdb1bcae1James Dong/*
75613f6284305e4b27395a23db7882d670bdb1bcae1James Dong * MP4 file standard defines a composition matrix:
75713f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | a  b  u |
75813f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | c  d  v |
75913f6284305e4b27395a23db7882d670bdb1bcae1James Dong * | x  y  w |
76013f6284305e4b27395a23db7882d670bdb1bcae1James Dong *
76113f6284305e4b27395a23db7882d670bdb1bcae1James Dong * the element in the matrix is stored in the following
76213f6284305e4b27395a23db7882d670bdb1bcae1James Dong * order: {a, b, u, c, d, v, x, y, w},
76313f6284305e4b27395a23db7882d670bdb1bcae1James Dong * where a, b, c, d, x, and y is in 16.16 format, while
76413f6284305e4b27395a23db7882d670bdb1bcae1James Dong * u, v and w is in 2.30 format.
76513f6284305e4b27395a23db7882d670bdb1bcae1James Dong */
76613f6284305e4b27395a23db7882d670bdb1bcae1James Dongvoid MPEG4Writer::writeCompositionMatrix(int degrees) {
7673856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("writeCompositionMatrix");
76813f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t a = 0x00010000;
76913f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t b = 0;
77013f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t c = 0;
77113f6284305e4b27395a23db7882d670bdb1bcae1James Dong    uint32_t d = 0x00010000;
77213f6284305e4b27395a23db7882d670bdb1bcae1James Dong    switch (degrees) {
77313f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 0:
77413f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
77513f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 90:
77613f6284305e4b27395a23db7882d670bdb1bcae1James Dong            a = 0;
77713f6284305e4b27395a23db7882d670bdb1bcae1James Dong            b = 0x00010000;
77813f6284305e4b27395a23db7882d670bdb1bcae1James Dong            c = 0xFFFF0000;
77913f6284305e4b27395a23db7882d670bdb1bcae1James Dong            d = 0;
78013f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
78113f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 180:
78213f6284305e4b27395a23db7882d670bdb1bcae1James Dong            a = 0xFFFF0000;
78313f6284305e4b27395a23db7882d670bdb1bcae1James Dong            d = 0xFFFF0000;
78413f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
78513f6284305e4b27395a23db7882d670bdb1bcae1James Dong        case 270:
78613f6284305e4b27395a23db7882d670bdb1bcae1James Dong            a = 0;
78713f6284305e4b27395a23db7882d670bdb1bcae1James Dong            b = 0xFFFF0000;
78813f6284305e4b27395a23db7882d670bdb1bcae1James Dong            c = 0x00010000;
78913f6284305e4b27395a23db7882d670bdb1bcae1James Dong            d = 0;
79013f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
79113f6284305e4b27395a23db7882d670bdb1bcae1James Dong        default:
79213f6284305e4b27395a23db7882d670bdb1bcae1James Dong            CHECK(!"Should never reach this unknown rotation");
79313f6284305e4b27395a23db7882d670bdb1bcae1James Dong            break;
79413f6284305e4b27395a23db7882d670bdb1bcae1James Dong    }
79513f6284305e4b27395a23db7882d670bdb1bcae1James Dong
79613f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(a);           // a
79713f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(b);           // b
79813f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // u
79913f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(c);           // c
80013f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(d);           // d
80113f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // v
80213f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // x
80313f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0);           // y
80413f6284305e4b27395a23db7882d670bdb1bcae1James Dong    writeInt32(0x40000000);  // w
80513f6284305e4b27395a23db7882d670bdb1bcae1James Dong}
80613f6284305e4b27395a23db7882d670bdb1bcae1James Dong
807411ba422e3635d534928ffd81abf54f4f291c739James Dongvoid MPEG4Writer::release() {
808411ba422e3635d534928ffd81abf54f4f291c739James Dong    close(mFd);
809411ba422e3635d534928ffd81abf54f4f291c739James Dong    mFd = -1;
810411ba422e3635d534928ffd81abf54f4f291c739James Dong    mInitCheck = NO_INIT;
811411ba422e3635d534928ffd81abf54f4f291c739James Dong    mStarted = false;
812411ba422e3635d534928ffd81abf54f4f291c739James Dong}
81313f6284305e4b27395a23db7882d670bdb1bcae1James Dong
8148bcc65c753085fe3328592cceda0cf0e8f8b0a45James Dongstatus_t MPEG4Writer::reset() {
815674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    if (mInitCheck != OK) {
81637187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
817411ba422e3635d534928ffd81abf54f4f291c739James Dong    } else {
818411ba422e3635d534928ffd81abf54f4f291c739James Dong        if (!mWriterThreadStarted ||
819411ba422e3635d534928ffd81abf54f4f291c739James Dong            !mStarted) {
820411ba422e3635d534928ffd81abf54f4f291c739James Dong            if (mWriterThreadStarted) {
821411ba422e3635d534928ffd81abf54f4f291c739James Dong                stopWriterThread();
822411ba422e3635d534928ffd81abf54f4f291c739James Dong            }
823411ba422e3635d534928ffd81abf54f4f291c739James Dong            release();
824411ba422e3635d534928ffd81abf54f4f291c739James Dong            return OK;
825411ba422e3635d534928ffd81abf54f4f291c739James Dong        }
82620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
82720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
82837187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = OK;
8298f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t maxDurationUs = 0;
83065b3d76025c71d755b0fb3b6ead90255f25417edJames Dong    int64_t minDurationUs = 0x7fffffffffffffffLL;
83120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    for (List<Track *>::iterator it = mTracks.begin();
83220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber         it != mTracks.end(); ++it) {
83337187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = (*it)->stop();
83437187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (err == OK && status != OK) {
83537187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
83637187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
83720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
8388f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        int64_t durationUs = (*it)->getDurationUs();
8398f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        if (durationUs > maxDurationUs) {
8408f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong            maxDurationUs = durationUs;
84120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
84265b3d76025c71d755b0fb3b6ead90255f25417edJames Dong        if (durationUs < minDurationUs) {
84365b3d76025c71d755b0fb3b6ead90255f25417edJames Dong            minDurationUs = durationUs;
84465b3d76025c71d755b0fb3b6ead90255f25417edJames Dong        }
84565b3d76025c71d755b0fb3b6ead90255f25417edJames Dong    }
84665b3d76025c71d755b0fb3b6ead90255f25417edJames Dong
84765b3d76025c71d755b0fb3b6ead90255f25417edJames Dong    if (mTracks.size() > 1) {
848b8a805261bf0282e992d3608035e47d05a898710Steve Block        ALOGD("Duration from tracks range is [%lld, %lld] us",
84965b3d76025c71d755b0fb3b6ead90255f25417edJames Dong            minDurationUs, maxDurationUs);
85020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
85120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
8521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    stopWriterThread();
8537837c17063a4c50bc856ba59418516fdab731de7James Dong
85437187916a486504acaf83bea30147eb5fbf46ae5James Dong    // Do not write out movie header on error.
85537187916a486504acaf83bea30147eb5fbf46ae5James Dong    if (err != OK) {
856411ba422e3635d534928ffd81abf54f4f291c739James Dong        release();
85737187916a486504acaf83bea30147eb5fbf46ae5James Dong        return err;
85837187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
85937187916a486504acaf83bea30147eb5fbf46ae5James Dong
86020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    // Fix up the size of the 'mdat' chunk.
8611acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    if (mUse32BitOffset) {
862c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mMdatOffset, SEEK_SET);
8631acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset));
864c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &size, 4);
8651acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    } else {
866c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mMdatOffset + 8, SEEK_SET);
8671acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        int64_t size = mOffset - mMdatOffset;
8681acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        size = hton64(size);
869c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &size, 8);
8701acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong    }
871c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    lseek64(mFd, mOffset, SEEK_SET);
87220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
8737b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    // Construct moov box now
8747837c17063a4c50bc856ba59418516fdab731de7James Dong    mMoovBoxBufferOffset = 0;
8757b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    mWriteMoovBoxToMemory = mStreamableFile;
8767b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    if (mWriteMoovBoxToMemory) {
8777b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong        // There is no need to allocate in-memory cache
8787b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong        // for moov box if the file is not streamable.
8797b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong
8807b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong        mMoovBoxBuffer = (uint8_t *) malloc(mEstimatedMoovBoxSize);
8817b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong        CHECK(mMoovBoxBuffer != NULL);
8827b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    }
883b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeMoovBox(maxDurationUs);
88420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
8857b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    // mWriteMoovBoxToMemory could be set to false in
8867b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    // MPEG4Writer::write() method
8877b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    if (mWriteMoovBoxToMemory) {
8887b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong        mWriteMoovBoxToMemory = false;
8897b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong        // Content of the moov box is saved in the cache, and the in-memory
8907b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong        // moov box needs to be written to the file in a single shot.
8917b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong
89243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        CHECK_LE(mMoovBoxBufferOffset + 8, mEstimatedMoovBoxSize);
8937837c17063a4c50bc856ba59418516fdab731de7James Dong
8947837c17063a4c50bc856ba59418516fdab731de7James Dong        // Moov box
895c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mFreeBoxOffset, SEEK_SET);
8967837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset = mFreeBoxOffset;
897674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        write(mMoovBoxBuffer, 1, mMoovBoxBufferOffset);
8987837c17063a4c50bc856ba59418516fdab731de7James Dong
8997837c17063a4c50bc856ba59418516fdab731de7James Dong        // Free box
900c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mOffset, SEEK_SET);
9017837c17063a4c50bc856ba59418516fdab731de7James Dong        writeInt32(mEstimatedMoovBoxSize - mMoovBoxBufferOffset);
9027837c17063a4c50bc856ba59418516fdab731de7James Dong        write("free", 4);
9037b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    } else {
9047b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong        ALOGI("The mp4 file will not be streamable.");
9057b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    }
9067837c17063a4c50bc856ba59418516fdab731de7James Dong
9077b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    // Free in-memory cache for moov box
9087b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong    if (mMoovBoxBuffer != NULL) {
9097837c17063a4c50bc856ba59418516fdab731de7James Dong        free(mMoovBoxBuffer);
9107837c17063a4c50bc856ba59418516fdab731de7James Dong        mMoovBoxBuffer = NULL;
9117837c17063a4c50bc856ba59418516fdab731de7James Dong        mMoovBoxBufferOffset = 0;
9127837c17063a4c50bc856ba59418516fdab731de7James Dong    }
9137837c17063a4c50bc856ba59418516fdab731de7James Dong
9140c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(mBoxes.empty());
91520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
916411ba422e3635d534928ffd81abf54f4f291c739James Dong    release();
91737187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
91820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
91920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
920efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlssonuint32_t MPEG4Writer::getMpeg4Time() {
921b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    time_t now = time(NULL);
922efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson    // MP4 file uses time counting seconds since midnight, Jan. 1, 1904
923efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson    // while time function returns Unix epoch values which starts
924efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson    // at 1970-01-01. Lets add the number of seconds between them
925efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson    uint32_t mpeg4Time = now + (66 * 365 + 17) * (24 * 60 * 60);
926efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson    return mpeg4Time;
927efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson}
928efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson
929efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlssonvoid MPEG4Writer::writeMvhdBox(int64_t durationUs) {
930efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson    uint32_t now = getMpeg4Time();
931b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    beginBox("mvhd");
932b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // version=0, flags=0
933b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(now);           // creation time
934b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(now);           // modification time
935b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(mTimeScale);    // mvhd timescale
936b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t duration = (durationUs * mTimeScale + 5E5) / 1E6;
937b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(duration);
938b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0x10000);       // rate: 1.0
939b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt16(0x100);         // volume
940b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt16(0);             // reserved
941b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // reserved
942b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // reserved
943b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeCompositionMatrix(0); // matrix
944b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
945b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
946b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
947b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
948b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
949b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(0);             // predefined
950b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeInt32(mTracks.size() + 1);  // nextTrackID
951b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    endBox();  // mvhd
952b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
953b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
954b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::writeMoovBox(int64_t durationUs) {
955b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    beginBox("moov");
956b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeMvhdBox(durationUs);
95707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (mAreGeoTagsAvailable) {
95807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        writeUdtaBox();
95907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
960b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t id = 1;
961b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    for (List<Track *>::iterator it = mTracks.begin();
962b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        it != mTracks.end(); ++it, ++id) {
963b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        (*it)->writeTrackHeader(mUse32BitOffset);
964b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
965b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    endBox();  // moov
966b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
967b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
9682cf9c5073ca3342ee52673ad68763fadd2c2be79James Dongvoid MPEG4Writer::writeFtypBox(MetaData *param) {
969b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    beginBox("ftyp");
970b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
971b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t fileType;
972b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (param && param->findInt32(kKeyFileType, &fileType) &&
973b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fileType != OUTPUT_FORMAT_MPEG_4) {
974b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeFourcc("3gp4");
9758284de3be2ac07d8774b15e6565df5aba084db04Robert Shih        writeInt32(0);
9768284de3be2ac07d8774b15e6565df5aba084db04Robert Shih        writeFourcc("isom");
9778284de3be2ac07d8774b15e6565df5aba084db04Robert Shih        writeFourcc("3gp4");
978b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
9798284de3be2ac07d8774b15e6565df5aba084db04Robert Shih        writeFourcc("mp42");
9808284de3be2ac07d8774b15e6565df5aba084db04Robert Shih        writeInt32(0);
981b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeFourcc("isom");
9828284de3be2ac07d8774b15e6565df5aba084db04Robert Shih        writeFourcc("mp42");
983b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
984b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
985b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    endBox();
986b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
987b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
98807ec01904613a0bac32caaa8444b4690998faed7James Dongstatic bool isTestModeEnabled() {
98907ec01904613a0bac32caaa8444b4690998faed7James Dong#if (PROPERTY_VALUE_MAX < 5)
99007ec01904613a0bac32caaa8444b4690998faed7James Dong#error "PROPERTY_VALUE_MAX must be at least 5"
99107ec01904613a0bac32caaa8444b4690998faed7James Dong#endif
99207ec01904613a0bac32caaa8444b4690998faed7James Dong
99307ec01904613a0bac32caaa8444b4690998faed7James Dong    // Test mode is enabled only if rw.media.record.test system
99407ec01904613a0bac32caaa8444b4690998faed7James Dong    // property is enabled.
99507ec01904613a0bac32caaa8444b4690998faed7James Dong    char value[PROPERTY_VALUE_MAX];
99607ec01904613a0bac32caaa8444b4690998faed7James Dong    if (property_get("rw.media.record.test", value, NULL) &&
99707ec01904613a0bac32caaa8444b4690998faed7James Dong        (!strcasecmp(value, "true") || !strcasecmp(value, "1"))) {
99807ec01904613a0bac32caaa8444b4690998faed7James Dong        return true;
99907ec01904613a0bac32caaa8444b4690998faed7James Dong    }
100007ec01904613a0bac32caaa8444b4690998faed7James Dong    return false;
100107ec01904613a0bac32caaa8444b4690998faed7James Dong}
100207ec01904613a0bac32caaa8444b4690998faed7James Dong
100370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dongvoid MPEG4Writer::sendSessionSummary() {
100407ec01904613a0bac32caaa8444b4690998faed7James Dong    // Send session summary only if test mode is enabled
100507ec01904613a0bac32caaa8444b4690998faed7James Dong    if (!isTestModeEnabled()) {
100607ec01904613a0bac32caaa8444b4690998faed7James Dong        return;
100707ec01904613a0bac32caaa8444b4690998faed7James Dong    }
100807ec01904613a0bac32caaa8444b4690998faed7James Dong
100970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
101070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong         it != mChunkInfos.end(); ++it) {
101170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        int trackNum = it->mTrack->getTrackId() << 28;
101270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
101370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                trackNum | MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS,
101470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                it->mMaxInterChunkDurUs);
101570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    }
101670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong}
101770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
101813aec890216948b0c364f8f92792129d0335f506James Dongstatus_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) {
101913aec890216948b0c364f8f92792129d0335f506James Dong    mInterleaveDurationUs = durationUs;
102013aec890216948b0c364f8f92792129d0335f506James Dong    return OK;
102113aec890216948b0c364f8f92792129d0335f506James Dong}
102213aec890216948b0c364f8f92792129d0335f506James Dong
102313aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::lock() {
102413aec890216948b0c364f8f92792129d0335f506James Dong    mLock.lock();
102513aec890216948b0c364f8f92792129d0335f506James Dong}
102613aec890216948b0c364f8f92792129d0335f506James Dong
102713aec890216948b0c364f8f92792129d0335f506James Dongvoid MPEG4Writer::unlock() {
102813aec890216948b0c364f8f92792129d0335f506James Dong    mLock.unlock();
102913aec890216948b0c364f8f92792129d0335f506James Dong}
103020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1031c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addSample_l(MediaBuffer *buffer) {
1032c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t old_offset = mOffset;
103320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1034c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    ::write(mFd,
1035c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong          (const uint8_t *)buffer->data() + buffer->range_offset(),
1036c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong          buffer->range_length());
103720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
103820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mOffset += buffer->range_length();
103920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
104020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    return old_offset;
104120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
104220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
104303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatic void StripStartcode(MediaBuffer *buffer) {
104403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (buffer->range_length() < 4) {
104503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return;
104603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
104703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
104803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    const uint8_t *ptr =
104903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        (const uint8_t *)buffer->data() + buffer->range_offset();
105003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
105103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
105203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        buffer->set_range(
105303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                buffer->range_offset() + 4, buffer->range_length() - 4);
105403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
105503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber}
105603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
1057c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongoff64_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
1058c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t old_offset = mOffset;
105930ab66297501757d745b9ae10da61adcd891f497Andreas Huber
106030ab66297501757d745b9ae10da61adcd891f497Andreas Huber    size_t length = buffer->range_length();
106103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
1062b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    if (mUse4ByteNalLength) {
1063b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        uint8_t x = length >> 24;
1064c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
1065b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = (length >> 16) & 0xff;
1066c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
1067b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = (length >> 8) & 0xff;
1068c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
1069b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = length & 0xff;
1070c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
1071c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong
1072c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd,
1073c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong              (const uint8_t *)buffer->data() + buffer->range_offset(),
1074c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong              length);
1075b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong
1076b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        mOffset += length + 4;
1077b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    } else {
107843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        CHECK_LT(length, 65536);
107930ab66297501757d745b9ae10da61adcd891f497Andreas Huber
1080b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        uint8_t x = length >> 8;
1081c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
1082b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        x = length & 0xff;
1083c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, &x, 1);
1084c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        ::write(mFd, (const uint8_t *)buffer->data() + buffer->range_offset(), length);
1085b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        mOffset += length + 2;
1086b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    }
108730ab66297501757d745b9ae10da61adcd891f497Andreas Huber
108830ab66297501757d745b9ae10da61adcd891f497Andreas Huber    return old_offset;
108930ab66297501757d745b9ae10da61adcd891f497Andreas Huber}
109030ab66297501757d745b9ae10da61adcd891f497Andreas Huber
10917837c17063a4c50bc856ba59418516fdab731de7James Dongsize_t MPEG4Writer::write(
1092674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        const void *ptr, size_t size, size_t nmemb) {
10937837c17063a4c50bc856ba59418516fdab731de7James Dong
10947837c17063a4c50bc856ba59418516fdab731de7James Dong    const size_t bytes = size * nmemb;
10957837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mWriteMoovBoxToMemory) {
10967b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong
1097c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        off64_t moovBoxSize = 8 + mMoovBoxBufferOffset + bytes;
10981acfe8649f8169caf2ff098c2dc2de880d9a3760James Dong        if (moovBoxSize > mEstimatedMoovBoxSize) {
10997b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong            // The reserved moov box at the beginning of the file
11007b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong            // is not big enough. Moov box should be written to
11017b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong            // the end of the file from now on, but not to the
11027b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong            // in-memory cache.
11037b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong
11047b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong            // We write partial moov box that is in the memory to
11057b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong            // the file first.
1106c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong            for (List<off64_t>::iterator it = mBoxes.begin();
11077837c17063a4c50bc856ba59418516fdab731de7James Dong                 it != mBoxes.end(); ++it) {
11087837c17063a4c50bc856ba59418516fdab731de7James Dong                (*it) += mOffset;
11097837c17063a4c50bc856ba59418516fdab731de7James Dong            }
1110674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong            lseek64(mFd, mOffset, SEEK_SET);
1111674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong            ::write(mFd, mMoovBoxBuffer, mMoovBoxBufferOffset);
11127b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong            ::write(mFd, ptr, bytes);
11137837c17063a4c50bc856ba59418516fdab731de7James Dong            mOffset += (bytes + mMoovBoxBufferOffset);
11147b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong
11157b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong            // All subsequent moov box content will be written
11167b670d4a0a4fa560f536f132e0a3fc7247f6724cJames Dong            // to the end of the file.
11177837c17063a4c50bc856ba59418516fdab731de7James Dong            mWriteMoovBoxToMemory = false;
11187837c17063a4c50bc856ba59418516fdab731de7James Dong        } else {
11197837c17063a4c50bc856ba59418516fdab731de7James Dong            memcpy(mMoovBoxBuffer + mMoovBoxBufferOffset, ptr, bytes);
11207837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBufferOffset += bytes;
11217837c17063a4c50bc856ba59418516fdab731de7James Dong        }
11227837c17063a4c50bc856ba59418516fdab731de7James Dong    } else {
1123674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong        ::write(mFd, ptr, size * nmemb);
11247837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset += bytes;
11257837c17063a4c50bc856ba59418516fdab731de7James Dong    }
11267837c17063a4c50bc856ba59418516fdab731de7James Dong    return bytes;
11277837c17063a4c50bc856ba59418516fdab731de7James Dong}
11287837c17063a4c50bc856ba59418516fdab731de7James Dong
112920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::beginBox(const char *fourcc) {
11300c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK_EQ(strlen(fourcc), 4);
113120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
11327837c17063a4c50bc856ba59418516fdab731de7James Dong    mBoxes.push_back(mWriteMoovBoxToMemory?
11337837c17063a4c50bc856ba59418516fdab731de7James Dong            mMoovBoxBufferOffset: mOffset);
113420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
113520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    writeInt32(0);
113620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    writeFourcc(fourcc);
113720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
113820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
113920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::endBox() {
11400c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK(!mBoxes.empty());
114120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1142c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t offset = *--mBoxes.end();
114320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mBoxes.erase(--mBoxes.end());
114420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
11457837c17063a4c50bc856ba59418516fdab731de7James Dong    if (mWriteMoovBoxToMemory) {
11467837c17063a4c50bc856ba59418516fdab731de7James Dong       int32_t x = htonl(mMoovBoxBufferOffset - offset);
11477837c17063a4c50bc856ba59418516fdab731de7James Dong       memcpy(mMoovBoxBuffer + offset, &x, 4);
11487837c17063a4c50bc856ba59418516fdab731de7James Dong    } else {
1149c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, offset, SEEK_SET);
11507837c17063a4c50bc856ba59418516fdab731de7James Dong        writeInt32(mOffset - offset);
11517837c17063a4c50bc856ba59418516fdab731de7James Dong        mOffset -= 4;
1152c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        lseek64(mFd, mOffset, SEEK_SET);
11537837c17063a4c50bc856ba59418516fdab731de7James Dong    }
115420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
115520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
115620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt8(int8_t x) {
1157674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 1);
115820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
115920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
116020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt16(int16_t x) {
116120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = htons(x);
1162674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 2);
116320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
116420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
116520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt32(int32_t x) {
116620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = htonl(x);
1167674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 4);
116820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
116920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
117020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeInt64(int64_t x) {
117120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    x = hton64(x);
1172674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(&x, 1, 8);
117320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
117420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
117520111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeCString(const char *s) {
117620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    size_t n = strlen(s);
1177674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(s, 1, n + 1);
117820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
117920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
118020111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::writeFourcc(const char *s) {
11810c89199745bc1bf05b997fc7c342017807676b6fAndreas Huber    CHECK_EQ(strlen(s), 4);
1182674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(s, 1, 4);
118320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
118420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
118507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
118607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong// Written in +/-DD.DDDD format
118707b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeLatitude(int degreex10000) {
118807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    bool isNegative = (degreex10000 < 0);
118907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    char sign = isNegative? '-': '+';
119007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
119107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Handle the whole part
119207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    char str[9];
119307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    int wholePart = degreex10000 / 10000;
119407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (wholePart == 0) {
119507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        snprintf(str, 5, "%c%.2d.", sign, wholePart);
119607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    } else {
119707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        snprintf(str, 5, "%+.2d.", wholePart);
119807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
119907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
120007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Handle the fractional part
120107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    int fractionalPart = degreex10000 - (wholePart * 10000);
120207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (fractionalPart < 0) {
120307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        fractionalPart = -fractionalPart;
120407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
120507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    snprintf(&str[4], 5, "%.4d", fractionalPart);
120607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
120707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Do not write the null terminator
120807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    write(str, 1, 8);
120907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
121007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
121107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong// Written in +/- DDD.DDDD format
121207b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeLongitude(int degreex10000) {
121307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    bool isNegative = (degreex10000 < 0);
121407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    char sign = isNegative? '-': '+';
121507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
121607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Handle the whole part
121707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    char str[10];
121807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    int wholePart = degreex10000 / 10000;
121907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (wholePart == 0) {
122007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        snprintf(str, 6, "%c%.3d.", sign, wholePart);
122107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    } else {
122207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        snprintf(str, 6, "%+.3d.", wholePart);
122307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
122407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
122507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Handle the fractional part
122607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    int fractionalPart = degreex10000 - (wholePart * 10000);
122707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (fractionalPart < 0) {
122807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        fractionalPart = -fractionalPart;
122907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
123007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    snprintf(&str[5], 5, "%.4d", fractionalPart);
123107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
123207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Do not write the null terminator
123307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    write(str, 1, 9);
123407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
123507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
123607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong/*
123707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * Geodata is stored according to ISO-6709 standard.
123807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * latitudex10000 is latitude in degrees times 10000, and
123907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * longitudex10000 is longitude in degrees times 10000.
124007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * The range for the latitude is in [-90, +90], and
124107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * The range for the longitude is in [-180, +180]
124207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */
124307b1bb529a1ae76c46a71b01338c166f9490629dJames Dongstatus_t MPEG4Writer::setGeoData(int latitudex10000, int longitudex10000) {
124407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    // Is latitude or longitude out of range?
124507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    if (latitudex10000 < -900000 || latitudex10000 > 900000 ||
124607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        longitudex10000 < -1800000 || longitudex10000 > 1800000) {
124707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong        return BAD_VALUE;
124807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    }
124907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
125007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    mLatitudex10000 = latitudex10000;
125107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    mLongitudex10000 = longitudex10000;
125207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    mAreGeoTagsAvailable = true;
125307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    return OK;
125407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
125507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
125620111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid MPEG4Writer::write(const void *data, size_t size) {
1257674ebd0b4e1143e38392a4e3bb38b4679a4577bcJames Dong    write(data, 1, size);
125820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
125920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
126078a1a286f736888ae7af8860b2c424af0d978848James Dongbool MPEG4Writer::isFileStreamable() const {
126178a1a286f736888ae7af8860b2c424af0d978848James Dong    return mStreamableFile;
126278a1a286f736888ae7af8860b2c424af0d978848James Dong}
126378a1a286f736888ae7af8860b2c424af0d978848James Dong
1264d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileSizeLimit() {
1265d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    // No limit
1266d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    if (mMaxFileSizeLimitBytes == 0) {
1267d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        return false;
1268d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
1269d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
1270956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    int64_t nTotalBytesEstimate = static_cast<int64_t>(mEstimatedMoovBoxSize);
1271d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    for (List<Track *>::iterator it = mTracks.begin();
1272d599cd4573b5a2d5914c5040e0565ef866749b77James Dong         it != mTracks.end(); ++it) {
1273d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        nTotalBytesEstimate += (*it)->getEstimatedTrackSizeBytes();
1274d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
12751f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
127677e8ae9967a078770416619e99ddb5b010def312James Dong    if (!mStreamableFile) {
127777e8ae9967a078770416619e99ddb5b010def312James Dong        // Add 1024 bytes as error tolerance
127877e8ae9967a078770416619e99ddb5b010def312James Dong        return nTotalBytesEstimate + 1024 >= mMaxFileSizeLimitBytes;
127977e8ae9967a078770416619e99ddb5b010def312James Dong    }
1280acd234bba9f048971d66890009eeff9a8db94be3James Dong    // Be conservative in the estimate: do not exceed 95% of
1281acd234bba9f048971d66890009eeff9a8db94be3James Dong    // the target file limit. For small target file size limit, though,
1282acd234bba9f048971d66890009eeff9a8db94be3James Dong    // this will not help.
1283acd234bba9f048971d66890009eeff9a8db94be3James Dong    return (nTotalBytesEstimate >= (95 * mMaxFileSizeLimitBytes) / 100);
1284d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
1285d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
1286d599cd4573b5a2d5914c5040e0565ef866749b77James Dongbool MPEG4Writer::exceedsFileDurationLimit() {
1287d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    // No limit
1288d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    if (mMaxFileDurationLimitUs == 0) {
1289d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        return false;
1290d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
1291d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
1292d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    for (List<Track *>::iterator it = mTracks.begin();
1293d599cd4573b5a2d5914c5040e0565ef866749b77James Dong         it != mTracks.end(); ++it) {
1294d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if ((*it)->getDurationUs() >= mMaxFileDurationLimitUs) {
1295d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            return true;
1296d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
1297d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    }
1298d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    return false;
1299d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
1300d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
130125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::reachedEOS() {
130225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    bool allDone = true;
130325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    for (List<Track *>::iterator it = mTracks.begin();
130425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber         it != mTracks.end(); ++it) {
130525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        if (!(*it)->reachedEOS()) {
130625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber            allDone = false;
130725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber            break;
130825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        }
130925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    }
131025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
131125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return allDone;
131225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber}
131325b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
1314f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongvoid MPEG4Writer::setStartTimestampUs(int64_t timeUs) {
1315df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block    ALOGI("setStartTimestampUs: %lld", timeUs);
131643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GE(timeUs, 0ll);
13173c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    Mutex::Autolock autoLock(mLock);
1318065d1aff96818df54456053f1574aec8a234d0deJames Dong    if (mStartTimestampUs < 0 || mStartTimestampUs > timeUs) {
1319f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong        mStartTimestampUs = timeUs;
1320df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block        ALOGI("Earliest track starting time: %lld", mStartTimestampUs);
13213c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    }
13223c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong}
13233c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong
1324f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dongint64_t MPEG4Writer::getStartTimestampUs() {
13253c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    Mutex::Autolock autoLock(mLock);
13263c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong    return mStartTimestampUs;
13273c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong}
13283c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong
132958ae9c530247668f8af36e30d228c716c226b3d4James Dongsize_t MPEG4Writer::numTracks() {
133058ae9c530247668f8af36e30d228c716c226b3d4James Dong    Mutex::Autolock autolock(mLock);
133158ae9c530247668f8af36e30d228c716c226b3d4James Dong    return mTracks.size();
133258ae9c530247668f8af36e30d228c716c226b3d4James Dong}
133358ae9c530247668f8af36e30d228c716c226b3d4James Dong
133420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber////////////////////////////////////////////////////////////////////////////////
133520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
133620111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::Track(
1337bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId)
133820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    : mOwner(owner),
133925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber      mMeta(source->getFormat()),
134020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mSource(source),
134120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mDone(false),
1342a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mPaused(false),
1343a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong      mResumed(false),
1344eaae38445a340c4857c1c5569475879a728e63b7James Dong      mStarted(false),
1345bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong      mTrackId(trackId),
1346c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong      mTrackDurationUs(0),
1347956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong      mEstimatedTrackSizeBytes(0),
1348be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong      mSamplesHaveSameSize(true),
1349c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong      mStszTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
1350c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong      mStcoTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
1351c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong      mCo64TableEntries(new ListTableEntries<off64_t>(1000, 1)),
1352c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong      mStscTableEntries(new ListTableEntries<uint32_t>(1000, 3)),
1353c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong      mStssTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
1354c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong      mSttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)),
1355c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong      mCttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)),
135620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber      mCodecSpecificData(NULL),
135725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber      mCodecSpecificDataSize(0),
1358548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber      mGotAllCodecSpecificData(false),
135913f6284305e4b27395a23db7882d670bdb1bcae1James Dong      mReachedEOS(false),
136013f6284305e4b27395a23db7882d670bdb1bcae1James Dong      mRotation(0) {
136119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    getCodecSpecificDataFromInputFormatIfPossible();
13628f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
13631c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    const char *mime;
13641c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mMeta->findCString(kKeyMIMEType, &mime);
13651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
13661c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsAudio = !strncasecmp(mime, "audio/", 6);
13671c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
13681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong               !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
13691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1370c059860c73678a202bfa33062723e8f82fb779d9James Dong    setTimeScale();
1371c059860c73678a202bfa33062723e8f82fb779d9James Dong}
1372c059860c73678a202bfa33062723e8f82fb779d9James Dong
13731f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::updateTrackSizeEstimate() {
13741f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1375c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    uint32_t stcoBoxCount = (mOwner->use32BitFileOffset()
1376c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                            ? mStcoTableEntries->count()
1377c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                            : mCo64TableEntries->count());
1378c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    int64_t stcoBoxSizeBytes = stcoBoxCount * 4;
1379c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    int64_t stszBoxSizeBytes = mSamplesHaveSameSize? 4: (mStszTableEntries->count() * 4);
13801f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
138178a1a286f736888ae7af8860b2c424af0d978848James Dong    mEstimatedTrackSizeBytes = mMdatSizeBytes;  // media data size
138278a1a286f736888ae7af8860b2c424af0d978848James Dong    if (!mOwner->isFileStreamable()) {
138378a1a286f736888ae7af8860b2c424af0d978848James Dong        // Reserved free space is not large enough to hold
138478a1a286f736888ae7af8860b2c424af0d978848James Dong        // all meta data and thus wasted.
1385c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        mEstimatedTrackSizeBytes += mStscTableEntries->count() * 12 +  // stsc box size
1386c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                                    mStssTableEntries->count() * 4 +   // stss box size
1387c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                                    mSttsTableEntries->count() * 8 +   // stts box size
1388c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                                    mCttsTableEntries->count() * 8 +   // ctts box size
138978a1a286f736888ae7af8860b2c424af0d978848James Dong                                    stcoBoxSizeBytes +           // stco box size
139078a1a286f736888ae7af8860b2c424af0d978848James Dong                                    stszBoxSizeBytes;            // stsz box size
139178a1a286f736888ae7af8860b2c424af0d978848James Dong    }
13921f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
13931f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
13941f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStscTableEntry(
13951f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        size_t chunkId, size_t sampleId) {
13961f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1397c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        mStscTableEntries->add(htonl(chunkId));
1398c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        mStscTableEntries->add(htonl(sampleId));
1399c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        mStscTableEntries->add(htonl(1));
14001f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
14011f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
14021f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneStssTableEntry(size_t sampleId) {
1403c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mStssTableEntries->add(htonl(sampleId));
14041f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
14051f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
14061f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dongvoid MPEG4Writer::Track::addOneSttsTableEntry(
140779761ab096f57c3027fad9556c2bc436672d614eJames Dong        size_t sampleCount, int32_t duration) {
14081f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
14095a217fba010e801c255503602bda4b86ac5a6ac9James Dong    if (duration == 0) {
14105ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block        ALOGW("0-duration samples found: %d", sampleCount);
14115a217fba010e801c255503602bda4b86ac5a6ac9James Dong    }
1412c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mSttsTableEntries->add(htonl(sampleCount));
1413c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mSttsTableEntries->add(htonl(duration));
14141f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
14151f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1416965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dongvoid MPEG4Writer::Track::addOneCttsTableEntry(
1417965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        size_t sampleCount, int32_t duration) {
1418965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
1419965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    if (mIsAudio) {
1420965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        return;
1421965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    }
1422c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mCttsTableEntries->add(htonl(sampleCount));
1423c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mCttsTableEntries->add(htonl(duration));
1424965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong}
1425965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
1426c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dongvoid MPEG4Writer::Track::addChunkOffset(off64_t offset) {
1427c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    if (mOwner->use32BitFileOffset()) {
1428c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        uint32_t value = offset;
1429c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        mStcoTableEntries->add(htonl(value));
1430c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    } else {
1431c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        mCo64TableEntries->add(hton64(offset));
1432c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    }
14331f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong}
14341f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
1435c059860c73678a202bfa33062723e8f82fb779d9James Dongvoid MPEG4Writer::Track::setTimeScale() {
14363856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("setTimeScale");
1437c059860c73678a202bfa33062723e8f82fb779d9James Dong    // Default time scale
1438c059860c73678a202bfa33062723e8f82fb779d9James Dong    mTimeScale = 90000;
1439c059860c73678a202bfa33062723e8f82fb779d9James Dong
1440c059860c73678a202bfa33062723e8f82fb779d9James Dong    if (mIsAudio) {
1441c059860c73678a202bfa33062723e8f82fb779d9James Dong        // Use the sampling rate as the default time scale for audio track.
1442c059860c73678a202bfa33062723e8f82fb779d9James Dong        int32_t sampleRate;
1443c059860c73678a202bfa33062723e8f82fb779d9James Dong        bool success = mMeta->findInt32(kKeySampleRate, &sampleRate);
1444c059860c73678a202bfa33062723e8f82fb779d9James Dong        CHECK(success);
1445c059860c73678a202bfa33062723e8f82fb779d9James Dong        mTimeScale = sampleRate;
1446c059860c73678a202bfa33062723e8f82fb779d9James Dong    }
1447c059860c73678a202bfa33062723e8f82fb779d9James Dong
1448c059860c73678a202bfa33062723e8f82fb779d9James Dong    // If someone would like to overwrite the timescale, use user-supplied value.
1449c059860c73678a202bfa33062723e8f82fb779d9James Dong    int32_t timeScale;
1450c059860c73678a202bfa33062723e8f82fb779d9James Dong    if (mMeta->findInt32(kKeyTimeScale, &timeScale)) {
1451c059860c73678a202bfa33062723e8f82fb779d9James Dong        mTimeScale = timeScale;
1452c059860c73678a202bfa33062723e8f82fb779d9James Dong    }
1453c059860c73678a202bfa33062723e8f82fb779d9James Dong
145443089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GT(mTimeScale, 0);
145519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber}
145619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
145719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Hubervoid MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() {
145819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    const char *mime;
145919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
146019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
146119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
146219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        uint32_t type;
146319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        const void *data;
146419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        size_t size;
146519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        if (mMeta->findData(kKeyAVCC, &type, &data, &size)) {
146619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mCodecSpecificData = malloc(size);
146719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mCodecSpecificDataSize = size;
146819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            memcpy(mCodecSpecificData, data, size);
146919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            mGotAllCodecSpecificData = true;
147019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        }
147119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
147219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
147319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        uint32_t type;
147419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        const void *data;
147519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        size_t size;
147619c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        if (mMeta->findData(kKeyESDS, &type, &data, &size)) {
147719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            ESDS esds(data, size);
147819c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            if (esds.getCodecSpecificInfo(&data, &size) == OK) {
147919c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mCodecSpecificData = malloc(size);
148019c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mCodecSpecificDataSize = size;
148119c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                memcpy(mCodecSpecificData, data, size);
148219c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber                mGotAllCodecSpecificData = true;
148319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber            }
148419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        }
148519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    }
148620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
148720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
148820111aa043c5f404472bc63b90bc5aad906b1101Andreas HuberMPEG4Writer::Track::~Track() {
148920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    stop();
149020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
1491c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    delete mStszTableEntries;
1492c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    delete mStcoTableEntries;
1493c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    delete mCo64TableEntries;
1494c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    delete mStscTableEntries;
1495c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    delete mSttsTableEntries;
1496c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    delete mStssTableEntries;
1497c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    delete mCttsTableEntries;
1498c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
1499c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mStszTableEntries = NULL;
1500c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mStcoTableEntries = NULL;
1501c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mCo64TableEntries = NULL;
1502c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mStscTableEntries = NULL;
1503c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mSttsTableEntries = NULL;
1504c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mStssTableEntries = NULL;
1505c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mCttsTableEntries = NULL;
1506c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
150720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mCodecSpecificData != NULL) {
150820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        free(mCodecSpecificData);
150920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        mCodecSpecificData = NULL;
151020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
151120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
151220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
151393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongvoid MPEG4Writer::Track::initTrackingProgressStatus(MetaData *params) {
15143856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("initTrackingProgressStatus");
151593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mPreviousTrackTimeUs = -1;
151693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mTrackingProgressStatus = false;
151793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    mTrackEveryTimeDurationUs = 0;
151893d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    {
151993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        int64_t timeUs;
152093d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        if (params && params->findInt64(kKeyTrackTimeStatus, &timeUs)) {
15213856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            ALOGV("Receive request to track progress status for every %lld us", timeUs);
152293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            mTrackEveryTimeDurationUs = timeUs;
152393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            mTrackingProgressStatus = true;
152493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        }
152593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    }
152693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong}
152793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
15281c9747a4653aec1395c2bd6896c9b87cb5447837James Dong// static
15291c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid *MPEG4Writer::ThreadWrapper(void *me) {
15303856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("ThreadWrapper: %p", me);
15311c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    MPEG4Writer *writer = static_cast<MPEG4Writer *>(me);
15321c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    writer->threadFunc();
15331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    return NULL;
15341c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
15351c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
15361c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::bufferChunk(const Chunk& chunk) {
15373856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("bufferChunk: %p", chunk.mTrack);
15381c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Mutex::Autolock autolock(mLock);
15391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    CHECK_EQ(mDone, false);
15401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
15411c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
15421c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
15431c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
15441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (chunk.mTrack == it->mTrack) {  // Found owner
15451c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            it->mChunks.push_back(chunk);
15461c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            mChunkReadyCondition.signal();
15471c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            return;
15481c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
15491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
15501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
155143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK(!"Received a chunk for a unknown track");
15521c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
15531c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1554fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeChunkToFile(Chunk* chunk) {
15553856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("writeChunkToFile: %lld from %s track",
15565410afcbb0af5d29d9f710a1c2978c500f9792dcPannag Sanketi        chunk->mTimeStampUs, chunk->mTrack->isAudio()? "audio": "video");
1557fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1558fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    int32_t isFirstSample = true;
1559fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    while (!chunk->mSamples.empty()) {
1560fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        List<MediaBuffer *>::iterator it = chunk->mSamples.begin();
1561fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1562fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        off64_t offset = chunk->mTrack->isAvc()
1563fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong                                ? addLengthPrefixedSample_l(*it)
1564fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong                                : addSample_l(*it);
1565fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1566fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        if (isFirstSample) {
1567fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            chunk->mTrack->addChunkOffset(offset);
1568fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            isFirstSample = false;
15691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
15701c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
15711c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        (*it)->release();
15721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        (*it) = NULL;
1573fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        chunk->mSamples.erase(it);
15741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1575fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    chunk->mSamples.clear();
15761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
15771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1578fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongvoid MPEG4Writer::writeAllChunks() {
15793856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("writeAllChunks");
15801c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    size_t outstandingChunks = 0;
158170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    Chunk chunk;
158270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    while (findChunkToWrite(&chunk)) {
1583e9f6d0579603372fd2547e6c5ba6e114c6f8cba7James Dong        writeChunkToFile(&chunk);
158470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        ++outstandingChunks;
15851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
158670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
158770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    sendSessionSummary();
158870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
15891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mChunkInfos.clear();
1590b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("%d chunks are written in the last batch", outstandingChunks);
15911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
15921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1593fcac8fa9421f442f024018628a6042d7a14fbfb0James Dongbool MPEG4Writer::findChunkToWrite(Chunk *chunk) {
15943856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("findChunkToWrite");
15951c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
15961c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    int64_t minTimestampUs = 0x7FFFFFFFFFFFFFFFLL;
15971c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Track *track = NULL;
15981c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
15991c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
16001c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (!it->mChunks.empty()) {
16011c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            List<Chunk>::iterator chunkIt = it->mChunks.begin();
16021c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            if (chunkIt->mTimeStampUs < minTimestampUs) {
16031c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                minTimestampUs = chunkIt->mTimeStampUs;
16041c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                track = it->mTrack;
16051c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            }
16061c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
16071c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
16081c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
16091c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (track == NULL) {
16103856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("Nothing to be written after all");
1611fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        return false;
16121c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
16131c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
16141c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    if (mIsFirstChunk) {
16151c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mIsFirstChunk = false;
16161c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1617fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
16181c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
16191c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mChunkInfos.end(); ++it) {
16201c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (it->mTrack == track) {
1621fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            *chunk = *(it->mChunks.begin());
1622fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            it->mChunks.erase(it->mChunks.begin());
1623fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            CHECK_EQ(chunk->mTrack, track);
162470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
162570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            int64_t interChunkTimeUs =
162670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                chunk->mTimeStampUs - it->mPrevChunkTimestampUs;
162770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            if (interChunkTimeUs > it->mPrevChunkTimestampUs) {
162870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                it->mMaxInterChunkDurUs = interChunkTimeUs;
162970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            }
163070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
1631fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            return true;
16321c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
16331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1634fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1635fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    return false;
16361c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
16371c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
16381c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::threadFunc() {
16393856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("threadFunc");
16401c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1641a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    prctl(PR_SET_NAME, (unsigned long)"MPEG4Writer", 0, 0, 0);
1642fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1643fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    Mutex::Autolock autoLock(mLock);
16441c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    while (!mDone) {
1645fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        Chunk chunk;
1646fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        bool chunkFound = false;
1647fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1648fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        while (!mDone && !(chunkFound = findChunkToWrite(&chunk))) {
16491c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            mChunkReadyCondition.wait(mLock);
16501c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        }
16511c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
1652de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui        // In real time recording mode, write without holding the lock in order
1653de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui        // to reduce the blocking time for media track threads.
1654de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui        // Otherwise, hold the lock until the existing chunks get written to the
1655de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui        // file.
1656fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        if (chunkFound) {
1657de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui            if (mIsRealTimeRecording) {
1658de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui                mLock.unlock();
1659de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui            }
1660fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong            writeChunkToFile(&chunk);
1661de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui            if (mIsRealTimeRecording) {
1662de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui                mLock.lock();
1663de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui            }
1664fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong        }
16651c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
1666fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong
1667fcac8fa9421f442f024018628a6042d7a14fbfb0James Dong    writeAllChunks();
16681c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
16691c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
16701c9747a4653aec1395c2bd6896c9b87cb5447837James Dongstatus_t MPEG4Writer::startWriterThread() {
16713856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("startWriterThread");
16721c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
16731c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mDone = false;
16741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mIsFirstChunk = true;
1675e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    mDriftTimeUs = 0;
16761c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    for (List<Track *>::iterator it = mTracks.begin();
16771c9747a4653aec1395c2bd6896c9b87cb5447837James Dong         it != mTracks.end(); ++it) {
16781c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        ChunkInfo info;
16791c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        info.mTrack = *it;
168070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        info.mPrevChunkTimestampUs = 0;
168170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        info.mMaxInterChunkDurUs = 0;
16821c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mChunkInfos.push_back(info);
16831c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    }
16841c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
16851c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_t attr;
16861c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_init(&attr);
16871c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
16881c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_create(&mThread, &attr, ThreadWrapper, this);
16891c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    pthread_attr_destroy(&attr);
1690411ba422e3635d534928ffd81abf54f4f291c739James Dong    mWriterThreadStarted = true;
16911c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    return OK;
16921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong}
16931c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
16941f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
169593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dongstatus_t MPEG4Writer::Track::start(MetaData *params) {
1696a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    if (!mDone && mPaused) {
1697a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        mPaused = false;
1698a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        mResumed = true;
1699a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        return OK;
1700a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    }
170125b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
170293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    int64_t startTimeUs;
170319c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    if (params == NULL || !params->findInt64(kKeyTime, &startTimeUs)) {
170419c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber        startTimeUs = 0;
170519c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber    }
170670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong    mStartTimeRealUs = startTimeUs;
170719c9a1e2bb6ead5e1e895aea8be573fe0f8cc7bbAndreas Huber
170813f6284305e4b27395a23db7882d670bdb1bcae1James Dong    int32_t rotationDegrees;
170913f6284305e4b27395a23db7882d670bdb1bcae1James Dong    if (!mIsAudio && params && params->findInt32(kKeyRotation, &rotationDegrees)) {
171013f6284305e4b27395a23db7882d670bdb1bcae1James Dong        mRotation = rotationDegrees;
171113f6284305e4b27395a23db7882d670bdb1bcae1James Dong    }
171213f6284305e4b27395a23db7882d670bdb1bcae1James Dong
171393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    initTrackingProgressStatus(params);
171493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
1715f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    sp<MetaData> meta = new MetaData;
1716de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui    if (mOwner->isRealTimeRecording() && mOwner->numTracks() > 1) {
1717a472613aec322e25891abf5c77bf3f7e3c244920James Dong        /*
1718a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * This extra delay of accepting incoming audio/video signals
1719a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * helps to align a/v start time at the beginning of a recording
1720a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * session, and it also helps eliminate the "recording" sound for
1721a472613aec322e25891abf5c77bf3f7e3c244920James Dong         * camcorder applications.
1722a472613aec322e25891abf5c77bf3f7e3c244920James Dong         *
172386b7f47aa7482424cf8fd248f1315311919be3b0James Dong         * If client does not set the start time offset, we fall back to
172486b7f47aa7482424cf8fd248f1315311919be3b0James Dong         * use the default initial delay value.
1725a472613aec322e25891abf5c77bf3f7e3c244920James Dong         */
172686b7f47aa7482424cf8fd248f1315311919be3b0James Dong        int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL;
172786b7f47aa7482424cf8fd248f1315311919be3b0James Dong        if (startTimeOffsetUs < 0) {  // Start time offset was not set
172886b7f47aa7482424cf8fd248f1315311919be3b0James Dong            startTimeOffsetUs = kInitialDelayTimeUs;
172986b7f47aa7482424cf8fd248f1315311919be3b0James Dong        }
173086b7f47aa7482424cf8fd248f1315311919be3b0James Dong        startTimeUs += startTimeOffsetUs;
1731df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block        ALOGI("Start time offset: %lld us", startTimeOffsetUs);
1732a472613aec322e25891abf5c77bf3f7e3c244920James Dong    }
1733a472613aec322e25891abf5c77bf3f7e3c244920James Dong
1734f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    meta->setInt64(kKeyTime, startTimeUs);
1735a472613aec322e25891abf5c77bf3f7e3c244920James Dong
1736f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong    status_t err = mSource->start(meta.get());
173725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    if (err != OK) {
173825b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        mDone = mReachedEOS = true;
173925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber        return err;
174025b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    }
174120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
174220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_t attr;
174320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_init(&attr);
174420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
174520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
174620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mDone = false;
1747eaae38445a340c4857c1c5569475879a728e63b7James Dong    mStarted = true;
1748c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    mTrackDurationUs = 0;
174925b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    mReachedEOS = false;
1750956c553ab0ce72f8074ad0fda2ffd66a0305700cJames Dong    mEstimatedTrackSizeBytes = 0;
17511f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong    mMdatSizeBytes = 0;
175243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mMaxChunkDurationUs = 0;
175320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
175425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    pthread_create(&mThread, &attr, ThreadWrapper, this);
175520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_attr_destroy(&attr);
175625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
175725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return OK;
175820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
175920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
176037187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::pause() {
1761a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    mPaused = true;
176237187916a486504acaf83bea30147eb5fbf46ae5James Dong    return OK;
1763a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong}
1764a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
176537187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::stop() {
1766b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("Stopping %s track", mIsAudio? "Audio": "Video");
1767eaae38445a340c4857c1c5569475879a728e63b7James Dong    if (!mStarted) {
176829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Stop() called but track is not started");
1769eaae38445a340c4857c1c5569475879a728e63b7James Dong        return ERROR_END_OF_STREAM;
1770eaae38445a340c4857c1c5569475879a728e63b7James Dong    }
1771eaae38445a340c4857c1c5569475879a728e63b7James Dong
177220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    if (mDone) {
177337187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
177420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
177520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    mDone = true;
177620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
177720111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    void *dummy;
177820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    pthread_join(mThread, &dummy);
177920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
178037187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = (status_t) dummy;
178137187916a486504acaf83bea30147eb5fbf46ae5James Dong
1782b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("Stopping %s track source", mIsAudio? "Audio": "Video");
178337187916a486504acaf83bea30147eb5fbf46ae5James Dong    {
178437187916a486504acaf83bea30147eb5fbf46ae5James Dong        status_t status = mSource->stop();
178537187916a486504acaf83bea30147eb5fbf46ae5James Dong        if (err == OK && status != OK && status != ERROR_END_OF_STREAM) {
178637187916a486504acaf83bea30147eb5fbf46ae5James Dong            err = status;
178737187916a486504acaf83bea30147eb5fbf46ae5James Dong        }
178837187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
178937187916a486504acaf83bea30147eb5fbf46ae5James Dong
1790b8a805261bf0282e992d3608035e47d05a898710Steve Block    ALOGD("%s track stopped", mIsAudio? "Audio": "Video");
179137187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
179220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
179320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
179425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huberbool MPEG4Writer::Track::reachedEOS() {
179525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    return mReachedEOS;
179625b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber}
179725b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
179820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber// static
179920111aa043c5f404472bc63b90bc5aad906b1101Andreas Hubervoid *MPEG4Writer::Track::ThreadWrapper(void *me) {
180020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    Track *track = static_cast<Track *>(me);
180120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
180237187916a486504acaf83bea30147eb5fbf46ae5James Dong    status_t err = track->threadEntry();
180337187916a486504acaf83bea30147eb5fbf46ae5James Dong    return (void *) err;
180420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
180520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
18063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic void getNalUnitType(uint8_t byte, uint8_t* type) {
18073856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("getNalUnitType: %d", byte);
18083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // nal_unit_type: 5-bit unsigned integer
18103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    *type = (byte & 0x1F);
18113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
18123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18133266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatic const uint8_t *findNextStartCode(
18143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length) {
18153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18163856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("findNextStartCode: %p %d", data, length);
18173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t bytesLeft = length;
18193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    while (bytesLeft > 4  &&
18203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            memcmp("\x00\x00\x00\x01", &data[length - bytesLeft], 4)) {
18213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        --bytesLeft;
18223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
18233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (bytesLeft <= 4) {
18243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        bytesLeft = 0; // Last parameter set
18253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
18263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return &data[length - bytesLeft];
18273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
18283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongconst uint8_t *MPEG4Writer::Track::parseParamSet(
18303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t length, int type, size_t *paramSetLen) {
18313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18323856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("parseParamSet");
18333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    CHECK(type == kNalUnitTypeSeqParamSet ||
18343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong          type == kNalUnitTypePicParamSet);
18353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *nextStartCode = findNextStartCode(data, length);
18373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    *paramSetLen = nextStartCode - data;
18383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (*paramSetLen == 0) {
183929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Param set is malformed, since its length is 0");
18403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return NULL;
18413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
18423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    AVCParamSet paramSet(*paramSetLen, data);
18443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (type == kNalUnitTypeSeqParamSet) {
18453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (*paramSetLen < 4) {
184629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Seq parameter set malformed");
18473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return NULL;
18483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
18493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (mSeqParamSets.empty()) {
18503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileIdc = data[1];
18513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileCompatible = data[2];
18523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mLevelIdc = data[3];
18533266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else {
18543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (mProfileIdc != data[1] ||
18553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                mProfileCompatible != data[2] ||
18563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                mLevelIdc != data[3]) {
185729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("Inconsistent profile/level found in seq parameter sets");
18583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return NULL;
18593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
18603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
18613266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mSeqParamSets.push_back(paramSet);
18623266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    } else {
18633266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mPicParamSets.push_back(paramSet);
18643266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
18653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return nextStartCode;
18663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
18673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::copyAVCCodecSpecificData(
18693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t size) {
18703856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("copyAVCCodecSpecificData");
18713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 2 bytes for each of the parameter set length field
18733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // plus the 7 bytes for the header
18743266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (size < 4 + 7) {
187529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Codec specific data length too short: %d", size);
18763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return ERROR_MALFORMED;
18773266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
18783266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18793266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize = size;
18803266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificData = malloc(size);
18813266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    memcpy(mCodecSpecificData, data, size);
18823266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return OK;
18833266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
18843266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18853266b2c04867f687e1e1b7b86088d6eb83077fd0James Dongstatus_t MPEG4Writer::Track::parseAVCCodecSpecificData(
18863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        const uint8_t *data, size_t size) {
18873266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
18883856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("parseAVCCodecSpecificData");
18893266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Data starts with a start code.
18903266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // SPS and PPS are separated with start codes.
18913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Also, SPS must come before PPS
18923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    uint8_t type = kNalUnitTypeSeqParamSet;
18933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    bool gotSps = false;
18943266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    bool gotPps = false;
18953266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *tmp = data;
18963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    const uint8_t *nextStartCode = data;
18973266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t bytesLeft = size;
18983266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    size_t paramSetLen = 0;
18993266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize = 0;
19003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) {
19013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        getNalUnitType(*(tmp + 4), &type);
19023266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (type == kNalUnitTypeSeqParamSet) {
19033266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (gotPps) {
190429357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("SPS must come before PPS");
19053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return ERROR_MALFORMED;
19063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
19073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotSps) {
19083266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                gotSps = true;
19093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
19103266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
19113266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else if (type == kNalUnitTypePicParamSet) {
19123266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotSps) {
191329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                ALOGE("SPS must come before PPS");
19143266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                return ERROR_MALFORMED;
19153266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
19163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            if (!gotPps) {
19173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong                gotPps = true;
19183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            }
19193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            nextStartCode = parseParamSet(tmp + 4, bytesLeft - 4, type, &paramSetLen);
19203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        } else {
192129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Only SPS and PPS Nal units are expected");
19223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
19233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
19243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
19253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nextStartCode == NULL) {
19263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
19273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
19283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
19293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Move on to find the next parameter set
19303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        bytesLeft -= nextStartCode - tmp;
19313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        tmp = nextStartCode;
19323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        mCodecSpecificDataSize += (2 + paramSetLen);
19333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
19343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
19353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
19363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the number of seq parameter sets
19373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        size_t nSeqParamSets = mSeqParamSets.size();
19383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nSeqParamSets == 0) {
193929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Cound not find sequence parameter set");
19403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
19413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
19423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
19433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nSeqParamSets > 0x1F) {
194429357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Too many seq parameter sets (%d) found", nSeqParamSets);
19453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
19463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
19473266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
19483266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
19493266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
19503266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the number of pic parameter sets
19513266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        size_t nPicParamSets = mPicParamSets.size();
19523266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nPicParamSets == 0) {
195329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Cound not find picture parameter set");
19543266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
19553266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
19563266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (nPicParamSets > 0xFF) {
195729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Too many pic parameter sets (%d) found", nPicParamSets);
19583266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return ERROR_MALFORMED;
19593266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
19603266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
19611374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket// FIXME:
19621374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket// Add chromat_format_idc, bit depth values, etc for AVC/h264 high profile and above
19631374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket// and remove #if 0
19641374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket#if 0
19653266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    {
19663266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // Check on the profiles
19673266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // These profiles requires additional parameter set extensions
19683266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        if (mProfileIdc == 100 || mProfileIdc == 110 ||
19693266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            mProfileIdc == 122 || mProfileIdc == 144) {
197029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Sorry, no support for profile_idc: %d!", mProfileIdc);
19713266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong            return BAD_VALUE;
19723266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        }
19733266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
19741374eddc4455b26d1dffdca10fc70534b3f08c1dDandawate Saket#endif
19753266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    return OK;
19763266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong}
1977548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
197803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huberstatus_t MPEG4Writer::Track::makeAVCCodecSpecificData(
197903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        const uint8_t *data, size_t size) {
1980548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
198103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    if (mCodecSpecificData != NULL) {
198229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Already have codec specific data");
198303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
198403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
198503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
19863266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (size < 4) {
198729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Codec specific data length too short: %d", size);
198803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
198903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
199003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
19913266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // Data is in the form of AVCCodecSpecificData
19923266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (memcmp("\x00\x00\x00\x01", data, 4)) {
19933266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        return copyAVCCodecSpecificData(data, size);
199403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
199503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
19963266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    if (parseAVCCodecSpecificData(data, size) != OK) {
199703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        return ERROR_MALFORMED;
199803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    }
199903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
20003266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // ISO 14496-15: AVC file format
20013266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    mCodecSpecificDataSize += 7;  // 7 more bytes in the header
200203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    mCodecSpecificData = malloc(mCodecSpecificDataSize);
200303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    uint8_t *header = (uint8_t *)mCodecSpecificData;
20043266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[0] = 1;                     // version
20053266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[1] = mProfileIdc;           // profile indication
20063266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[2] = mProfileCompatible;    // profile compatibility
20073266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[3] = mLevelIdc;
200803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
20093266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne
2010b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    if (mOwner->useNalLengthFour()) {
2011b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        header[4] = 0xfc | 3;  // length size == 4 bytes
2012b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    } else {
2013b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        header[4] = 0xfc | 1;  // length size == 2 bytes
2014b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    }
201503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
20163266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 3-bit '111' followed by 5-bit numSequenceParameterSets
20173266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    int nSequenceParamSets = mSeqParamSets.size();
20183266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[5] = 0xe0 | nSequenceParamSets;
20193266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header += 6;
20203266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    for (List<AVCParamSet>::iterator it = mSeqParamSets.begin();
20213266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong         it != mSeqParamSets.end(); ++it) {
20223266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // 16-bit sequence parameter set length
20233266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t seqParamSetLength = it->mLength;
20243266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[0] = seqParamSetLength >> 8;
20253266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[1] = seqParamSetLength & 0xff;
20263266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
20273266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // SPS NAL unit (sequence parameter length bytes)
20283266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        memcpy(&header[2], it->mData, seqParamSetLength);
20293266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header += (2 + seqParamSetLength);
20303266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
20313266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
20323266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    // 8-bit nPictureParameterSets
20333266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    int nPictureParamSets = mPicParamSets.size();
20343266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header[0] = nPictureParamSets;
20353266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    header += 1;
20363266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    for (List<AVCParamSet>::iterator it = mPicParamSets.begin();
20373266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong         it != mPicParamSets.end(); ++it) {
20383266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // 16-bit picture parameter set length
20393266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        uint16_t picParamSetLength = it->mLength;
20403266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[0] = picParamSetLength >> 8;
20413266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header[1] = picParamSetLength & 0xff;
20423266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong
20433266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        // PPS Nal unit (picture parameter set length bytes)
20443266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        memcpy(&header[2], it->mData, picParamSetLength);
20453266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong        header += (2 + picParamSetLength);
20463266b2c04867f687e1e1b7b86088d6eb83077fd0James Dong    }
204703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
204803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber    return OK;
204903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber}
205003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber
2051872a481558350634a3fd5cb67939de288af00ecbJames Dong/*
2052872a481558350634a3fd5cb67939de288af00ecbJames Dong * Updates the drift time from the audio track so that
2053872a481558350634a3fd5cb67939de288af00ecbJames Dong * the video track can get the updated drift time information
2054872a481558350634a3fd5cb67939de288af00ecbJames Dong * from the file writer. The fluctuation of the drift time of the audio
2055872a481558350634a3fd5cb67939de288af00ecbJames Dong * encoding path is smoothed out with a simple filter by giving a larger
2056872a481558350634a3fd5cb67939de288af00ecbJames Dong * weight to more recently drift time. The filter coefficients, 0.5 and 0.5,
2057872a481558350634a3fd5cb67939de288af00ecbJames Dong * are heuristically determined.
2058872a481558350634a3fd5cb67939de288af00ecbJames Dong */
2059872a481558350634a3fd5cb67939de288af00ecbJames Dongvoid MPEG4Writer::Track::updateDriftTime(const sp<MetaData>& meta) {
2060872a481558350634a3fd5cb67939de288af00ecbJames Dong    int64_t driftTimeUs = 0;
2061872a481558350634a3fd5cb67939de288af00ecbJames Dong    if (meta->findInt64(kKeyDriftTime, &driftTimeUs)) {
2062872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t prevDriftTimeUs = mOwner->getDriftTimeUs();
2063872a481558350634a3fd5cb67939de288af00ecbJames Dong        int64_t timeUs = (driftTimeUs + prevDriftTimeUs) >> 1;
2064872a481558350634a3fd5cb67939de288af00ecbJames Dong        mOwner->setDriftTimeUs(timeUs);
2065872a481558350634a3fd5cb67939de288af00ecbJames Dong    }
2066872a481558350634a3fd5cb67939de288af00ecbJames Dong}
2067872a481558350634a3fd5cb67939de288af00ecbJames Dong
206837187916a486504acaf83bea30147eb5fbf46ae5James Dongstatus_t MPEG4Writer::Track::threadEntry() {
206930ab66297501757d745b9ae10da61adcd891f497Andreas Huber    int32_t count = 0;
207013aec890216948b0c364f8f92792129d0335f506James Dong    const int64_t interleaveDurationUs = mOwner->interleaveDuration();
207143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    const bool hasMultipleTracks = (mOwner->numTracks() > 1);
207213aec890216948b0c364f8f92792129d0335f506James Dong    int64_t chunkTimestampUs = 0;
207313aec890216948b0c364f8f92792129d0335f506James Dong    int32_t nChunks = 0;
207413aec890216948b0c364f8f92792129d0335f506James Dong    int32_t nZeroLengthFrames = 0;
2075965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    int64_t lastTimestampUs = 0;      // Previous sample time stamp
2076965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    int64_t lastDurationUs = 0;       // Between the previous two samples
2077965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    int64_t currDurationTicks = 0;    // Timescale based ticks
2078965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    int64_t lastDurationTicks = 0;    // Timescale based ticks
2079965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    int32_t sampleCount = 1;          // Sample count in the current stts table entry
2080000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    uint32_t previousSampleSize = 0;  // Size of the previous sample
2081a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong    int64_t previousPausedDurationUs = 0;
2082965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    int64_t timestampUs = 0;
2083000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    int64_t cttsOffsetTimeUs = 0;
2084000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    int64_t currCttsOffsetTimeTicks = 0;   // Timescale based ticks
2085000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    int64_t lastCttsOffsetTimeTicks = -1;  // Timescale based ticks
208643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    int32_t cttsSampleCount = 0;           // Sample count in the current ctts table entry
2087c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    uint32_t lastSamplesPerChunk = 0;
2088e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
2089a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    if (mIsAudio) {
2090a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong        prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
2091a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    } else {
2092a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong        prctl(PR_SET_NAME, (unsigned long)"VideoTrackEncoding", 0, 0, 0);
2093a6f61fc8e3d06373c17f0a38ff600e2b71c414faJames Dong    }
2094de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui
2095de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui    if (mOwner->isRealTimeRecording()) {
2096de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui        androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
2097de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui    }
2098985f838934510983d8a887461e98dca60a6e858fJames Dong
2099d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong    sp<MetaData> meta_data;
210020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
210193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    status_t err = OK;
210220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    MediaBuffer *buffer;
210393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    while (!mDone && (err = mSource->read(&buffer)) == OK) {
210420111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        if (buffer->range_length() == 0) {
210520111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            buffer->release();
210620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            buffer = NULL;
210713aec890216948b0c364f8f92792129d0335f506James Dong            ++nZeroLengthFrames;
210820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber            continue;
210920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber        }
211020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2111a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // If the codec specific data has not been received yet, delay pause.
2112a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // After the codec specific data is received, discard what we received
2113a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        // when the track is to be paused.
2114a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mPaused && !mResumed) {
2115a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            buffer->release();
2116a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            buffer = NULL;
2117a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            continue;
2118a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
2119a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
212030ab66297501757d745b9ae10da61adcd891f497Andreas Huber        ++count;
212130ab66297501757d745b9ae10da61adcd891f497Andreas Huber
212203b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        int32_t isCodecConfig;
212303b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
212403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                && isCodecConfig) {
2125548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            CHECK(!mGotAllCodecSpecificData);
2126548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber
21271c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            if (mIsAvc) {
212803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                status_t err = makeAVCCodecSpecificData(
212903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        (const uint8_t *)buffer->data()
213003b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                            + buffer->range_offset(),
213103b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        buffer->range_length());
213243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                CHECK_EQ((status_t)OK, err);
21331c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            } else if (mIsMPEG4) {
213403b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                mCodecSpecificDataSize = buffer->range_length();
213503b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                mCodecSpecificData = malloc(mCodecSpecificDataSize);
213603b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                memcpy(mCodecSpecificData,
213703b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                        (const uint8_t *)buffer->data()
213803b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                            + buffer->range_offset(),
213903b268eac37ca2589bfff0bf58daf79d29cc14f4Andreas Huber                       buffer->range_length());
214030ab66297501757d745b9ae10da61adcd891f497Andreas Huber            }
214130ab66297501757d745b9ae10da61adcd891f497Andreas Huber
214230ab66297501757d745b9ae10da61adcd891f497Andreas Huber            buffer->release();
214330ab66297501757d745b9ae10da61adcd891f497Andreas Huber            buffer = NULL;
214430ab66297501757d745b9ae10da61adcd891f497Andreas Huber
2145548e31844937b37518fbb62ff69e9ff1f794183bAndreas Huber            mGotAllCodecSpecificData = true;
214630ab66297501757d745b9ae10da61adcd891f497Andreas Huber            continue;
2147a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
2148a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
2149d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        // Make a deep copy of the MediaBuffer and Metadata and release
2150d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        // the original as soon as we can
2151d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        MediaBuffer *copy = new MediaBuffer(buffer->range_length());
2152d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(),
2153d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong                buffer->range_length());
2154d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        copy->set_range(0, buffer->range_length());
2155d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        meta_data = new MetaData(*buffer->meta_data().get());
2156d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        buffer->release();
2157d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        buffer = NULL;
2158d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
21591c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        if (mIsAvc) StripStartcode(copy);
2160e136c3bb38e88315bf8797a464ebf2c788296b22James Dong
2161b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        size_t sampleSize = copy->range_length();
2162b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        if (mIsAvc) {
2163b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong            if (mOwner->useNalLengthFour()) {
2164b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong                sampleSize += 4;
2165b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong            } else {
2166b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong                sampleSize += 2;
2167b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong            }
2168b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong        }
2169050b28a593350047845a45a14cc5026221ac1620James Dong
2170d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        // Max file size or duration handling
21711f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        mMdatSizeBytes += sampleSize;
21721f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        updateTrackSizeEstimate();
21731f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong
2174d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if (mOwner->exceedsFileSizeLimit()) {
2175d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED, 0);
2176d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            break;
2177d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
2178d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        if (mOwner->exceedsFileDurationLimit()) {
2179d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            mOwner->notify(MEDIA_RECORDER_EVENT_INFO, MEDIA_RECORDER_INFO_MAX_DURATION_REACHED, 0);
2180d599cd4573b5a2d5914c5040e0565ef866749b77James Dong            break;
2181d599cd4573b5a2d5914c5040e0565ef866749b77James Dong        }
2182d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
2183050b28a593350047845a45a14cc5026221ac1620James Dong
2184d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        int32_t isSync = false;
2185d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        meta_data->findInt32(kKeyIsSyncFrame, &isSync);
2186d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        CHECK(meta_data->findInt64(kKeyTime, &timestampUs));
2187d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
2188d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong////////////////////////////////////////////////////////////////////////////////
2189c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        if (mStszTableEntries->count() == 0) {
219070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            mFirstSampleTimeRealUs = systemTime() / 1000;
2191f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong            mStartTimestampUs = timestampUs;
2192f60cafe0e6aad8f9ce54660fa88b651ae4e749e6James Dong            mOwner->setStartTimestampUs(mStartTimestampUs);
21938428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            previousPausedDurationUs = mStartTimestampUs;
21943c0131f02b6f008321608044c53bccce2ac5f6ddJames Dong        }
219548c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber
2196a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        if (mResumed) {
21978428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            int64_t durExcludingEarlierPausesUs = timestampUs - previousPausedDurationUs;
219843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            CHECK_GE(durExcludingEarlierPausesUs, 0ll);
21998428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            int64_t pausedDurationUs = durExcludingEarlierPausesUs - mTrackDurationUs;
220043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            CHECK_GE(pausedDurationUs, lastDurationUs);
22018428af5381e835cc783b7ecb0d71cb60961c99c2James Dong            previousPausedDurationUs += pausedDurationUs - lastDurationUs;
2202a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong            mResumed = false;
2203a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        }
2204a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong
2205a7d1a2dd776bf356c228785a94ba8e0ff6a2ec7fJames Dong        timestampUs -= previousPausedDurationUs;
220643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        CHECK_GE(timestampUs, 0ll);
2207000e18370baae60ffd9f25b509501dd8c26deabfJames Dong        if (!mIsAudio) {
2208965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong            /*
2209965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong             * Composition time: timestampUs
2210965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong             * Decoding time: decodingTimeUs
2211000e18370baae60ffd9f25b509501dd8c26deabfJames Dong             * Composition time offset = composition time - decoding time
2212965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong             */
2213965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong            int64_t decodingTimeUs;
2214965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong            CHECK(meta_data->findInt64(kKeyDecodingTime, &decodingTimeUs));
2215965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong            decodingTimeUs -= previousPausedDurationUs;
2216000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            cttsOffsetTimeUs =
2217000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                    timestampUs + kMaxCttsOffsetTimeUs - decodingTimeUs;
221843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            CHECK_GE(cttsOffsetTimeUs, 0ll);
2219965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong            timestampUs = decodingTimeUs;
2220000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            ALOGV("decoding time: %lld and ctts offset time: %lld",
2221000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                timestampUs, cttsOffsetTimeUs);
2222000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
2223000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            // Update ctts box table if necessary
2224000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            currCttsOffsetTimeTicks =
2225000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                    (cttsOffsetTimeUs * mTimeScale + 500000LL) / 1000000LL;
222643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            CHECK_LE(currCttsOffsetTimeTicks, 0x0FFFFFFFFLL);
2227c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            if (mStszTableEntries->count() == 0) {
222843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                // Force the first ctts table entry to have one single entry
222943089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                // so that we can do adjustment for the initial track start
223043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                // time offset easily in writeCttsBox().
223143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
223243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                addOneCttsTableEntry(1, currCttsOffsetTimeTicks);
223343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                cttsSampleCount = 0;      // No sample in ctts box is pending
223443089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            } else {
223543089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                if (currCttsOffsetTimeTicks != lastCttsOffsetTimeTicks) {
223643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                    addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
223743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                    lastCttsOffsetTimeTicks = currCttsOffsetTimeTicks;
223843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                    cttsSampleCount = 1;  // One sample in ctts box is pending
223943089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                } else {
224043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                    ++cttsSampleCount;
224143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong                }
224243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            }
2243000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
2244000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            // Update ctts time offset range
2245c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            if (mStszTableEntries->count() == 0) {
2246000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2247000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2248000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            } else {
2249000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                if (currCttsOffsetTimeTicks > mMaxCttsOffsetTimeUs) {
2250000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                    mMaxCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2251000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                } else if (currCttsOffsetTimeTicks < mMinCttsOffsetTimeUs) {
2252000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                    mMinCttsOffsetTimeUs = currCttsOffsetTimeTicks;
2253000e18370baae60ffd9f25b509501dd8c26deabfJames Dong                }
2254000e18370baae60ffd9f25b509501dd8c26deabfJames Dong            }
2255000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
2256965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        }
2257872a481558350634a3fd5cb67939de288af00ecbJames Dong
2258de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui        if (mOwner->isRealTimeRecording()) {
2259872a481558350634a3fd5cb67939de288af00ecbJames Dong            if (mIsAudio) {
2260872a481558350634a3fd5cb67939de288af00ecbJames Dong                updateDriftTime(meta_data);
2261e259531ce59ab1f31de5a23124b22536f6a5a767James Dong            }
2262e259531ce59ab1f31de5a23124b22536f6a5a767James Dong        }
2263872a481558350634a3fd5cb67939de288af00ecbJames Dong
226443089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        CHECK_GE(timestampUs, 0ll);
22653856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("%s media time stamp: %lld and previous paused duration %lld",
22668428af5381e835cc783b7ecb0d71cb60961c99c2James Dong                mIsAudio? "Audio": "Video", timestampUs, previousPausedDurationUs);
2267c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong        if (timestampUs > mTrackDurationUs) {
2268c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong            mTrackDurationUs = timestampUs;
22693b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber        }
22703b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huber
22715a217fba010e801c255503602bda4b86ac5a6ac9James Dong        // We need to use the time scale based ticks, rather than the
22725a217fba010e801c255503602bda4b86ac5a6ac9James Dong        // timestamp itself to determine whether we have to use a new
22735a217fba010e801c255503602bda4b86ac5a6ac9James Dong        // stts entry, since we may have rounding errors.
22745a217fba010e801c255503602bda4b86ac5a6ac9James Dong        // The calculation is intended to reduce the accumulated
22755a217fba010e801c255503602bda4b86ac5a6ac9James Dong        // rounding errors.
22765a217fba010e801c255503602bda4b86ac5a6ac9James Dong        currDurationTicks =
22775a217fba010e801c255503602bda4b86ac5a6ac9James Dong            ((timestampUs * mTimeScale + 500000LL) / 1000000LL -
22785a217fba010e801c255503602bda4b86ac5a6ac9James Dong                (lastTimestampUs * mTimeScale + 500000LL) / 1000000LL);
2279c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        if (currDurationTicks < 0ll) {
2280c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            ALOGE("timestampUs %lld < lastTimestampUs %lld for %s track",
2281c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                timestampUs, lastTimestampUs, mIsAudio? "Audio": "Video");
2282c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            return UNKNOWN_ERROR;
22838c460498c028888c533ab442be12b6d4b669b965James Dong        }
22848c460498c028888c533ab442be12b6d4b669b965James Dong
2285c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        mStszTableEntries->add(htonl(sampleSize));
2286c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        if (mStszTableEntries->count() > 2) {
2287c059860c73678a202bfa33062723e8f82fb779d9James Dong
2288a472613aec322e25891abf5c77bf3f7e3c244920James Dong            // Force the first sample to have its own stts entry so that
2289a472613aec322e25891abf5c77bf3f7e3c244920James Dong            // we can adjust its value later to maintain the A/V sync.
2290c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            if (mStszTableEntries->count() == 3 || currDurationTicks != lastDurationTicks) {
229179761ab096f57c3027fad9556c2bc436672d614eJames Dong                addOneSttsTableEntry(sampleCount, lastDurationTicks);
2292be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                sampleCount = 1;
2293be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            } else {
2294be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                ++sampleCount;
2295be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            }
2296965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
2297be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        }
2298be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        if (mSamplesHaveSameSize) {
2299c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            if (mStszTableEntries->count() >= 2 && previousSampleSize != sampleSize) {
2300be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong                mSamplesHaveSameSize = false;
2301be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong            }
23028644c14618d30d9e57a69df40ed939986ebf02c4James Dong            previousSampleSize = sampleSize;
2303be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        }
23043856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("%s timestampUs/lastTimestampUs: %lld/%lld",
2305a472613aec322e25891abf5c77bf3f7e3c244920James Dong                mIsAudio? "Audio": "Video", timestampUs, lastTimestampUs);
23068644c14618d30d9e57a69df40ed939986ebf02c4James Dong        lastDurationUs = timestampUs - lastTimestampUs;
2307c059860c73678a202bfa33062723e8f82fb779d9James Dong        lastDurationTicks = currDurationTicks;
23088644c14618d30d9e57a69df40ed939986ebf02c4James Dong        lastTimestampUs = timestampUs;
230920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2310d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        if (isSync != 0) {
2311c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            addOneStssTableEntry(mStszTableEntries->count());
2312d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong        }
2313d07139e2e817a9b3ae9c87ba4e1e8d65d3e549daJames Dong
231493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        if (mTrackingProgressStatus) {
231593d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            if (mPreviousTrackTimeUs <= 0) {
231693d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong                mPreviousTrackTimeUs = mStartTimestampUs;
231793d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong            }
2318faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong            trackProgressStatus(timestampUs);
231993d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        }
232043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong        if (!hasMultipleTracks) {
2321c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong            off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy)
232258ae9c530247668f8af36e30d228c716c226b3d4James Dong                                 : mOwner->addSample_l(copy);
2323c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
2324c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            uint32_t count = (mOwner->use32BitFileOffset()
2325c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                        ? mStcoTableEntries->count()
2326c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                        : mCo64TableEntries->count());
2327c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
2328c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            if (count == 0) {
23291f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong                addChunkOffset(offset);
233058ae9c530247668f8af36e30d228c716c226b3d4James Dong            }
233158ae9c530247668f8af36e30d228c716c226b3d4James Dong            copy->release();
233258ae9c530247668f8af36e30d228c716c226b3d4James Dong            copy = NULL;
233358ae9c530247668f8af36e30d228c716c226b3d4James Dong            continue;
233458ae9c530247668f8af36e30d228c716c226b3d4James Dong        }
233513aec890216948b0c364f8f92792129d0335f506James Dong
233613aec890216948b0c364f8f92792129d0335f506James Dong        mChunkSamples.push_back(copy);
233713aec890216948b0c364f8f92792129d0335f506James Dong        if (interleaveDurationUs == 0) {
23381f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong            addOneStscTableEntry(++nChunks, 1);
23391c9747a4653aec1395c2bd6896c9b87cb5447837James Dong            bufferChunk(timestampUs);
234013aec890216948b0c364f8f92792129d0335f506James Dong        } else {
234113aec890216948b0c364f8f92792129d0335f506James Dong            if (chunkTimestampUs == 0) {
234213aec890216948b0c364f8f92792129d0335f506James Dong                chunkTimestampUs = timestampUs;
234313aec890216948b0c364f8f92792129d0335f506James Dong            } else {
234443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                int64_t chunkDurationUs = timestampUs - chunkTimestampUs;
234543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                if (chunkDurationUs > interleaveDurationUs) {
234643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    if (chunkDurationUs > mMaxChunkDurationUs) {
234743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                        mMaxChunkDurationUs = chunkDurationUs;
234843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    }
234913aec890216948b0c364f8f92792129d0335f506James Dong                    ++nChunks;
235013aec890216948b0c364f8f92792129d0335f506James Dong                    if (nChunks == 1 ||  // First chunk
2351c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                        lastSamplesPerChunk != mChunkSamples.size()) {
2352c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                        lastSamplesPerChunk = mChunkSamples.size();
2353c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                        addOneStscTableEntry(nChunks, lastSamplesPerChunk);
235413aec890216948b0c364f8f92792129d0335f506James Dong                    }
23551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong                    bufferChunk(timestampUs);
235613aec890216948b0c364f8f92792129d0335f506James Dong                    chunkTimestampUs = timestampUs;
235713aec890216948b0c364f8f92792129d0335f506James Dong                }
235813aec890216948b0c364f8f92792129d0335f506James Dong            }
235913aec890216948b0c364f8f92792129d0335f506James Dong        }
236013aec890216948b0c364f8f92792129d0335f506James Dong
236120111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber    }
236225b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
236345c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    if (isTrackMalFormed()) {
2364690f546b0ee548dbfe997df36418e5302ec2d786James Dong        err = ERROR_MALFORMED;
2365f0ce2fb0c7bf3a414279e5aba61105f3d9025c0eJames Dong    }
236645c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong
2367bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    mOwner->trackProgressStatus(mTrackId, -1, err);
2368be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong
236913aec890216948b0c364f8f92792129d0335f506James Dong    // Last chunk
237043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    if (!hasMultipleTracks) {
2371c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        addOneStscTableEntry(1, mStszTableEntries->count());
237258ae9c530247668f8af36e30d228c716c226b3d4James Dong    } else if (!mChunkSamples.empty()) {
23731f90c4b3fda9dbd2824d67fd679f850572f114dcJames Dong        addOneStscTableEntry(++nChunks, mChunkSamples.size());
23741c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        bufferChunk(timestampUs);
237513aec890216948b0c364f8f92792129d0335f506James Dong    }
237613aec890216948b0c364f8f92792129d0335f506James Dong
2377be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // We don't really know how long the last frame lasts, since
2378be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // there is no frame time after it, just repeat the previous
2379be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    // frame's duration.
2380c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    if (mStszTableEntries->count() == 1) {
23818f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong        lastDurationUs = 0;  // A single sample's duration
238279761ab096f57c3027fad9556c2bc436672d614eJames Dong        lastDurationTicks = 0;
2383be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    } else {
2384be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong        ++sampleCount;  // Count for the last sample
2385be83c9e8c71ce16c0d0e9ed9df525510a49a541bJames Dong    }
2386a472613aec322e25891abf5c77bf3f7e3c244920James Dong
2387c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    if (mStszTableEntries->count() <= 2) {
238879761ab096f57c3027fad9556c2bc436672d614eJames Dong        addOneSttsTableEntry(1, lastDurationTicks);
2389a472613aec322e25891abf5c77bf3f7e3c244920James Dong        if (sampleCount - 1 > 0) {
239079761ab096f57c3027fad9556c2bc436672d614eJames Dong            addOneSttsTableEntry(sampleCount - 1, lastDurationTicks);
2391a472613aec322e25891abf5c77bf3f7e3c244920James Dong        }
2392a472613aec322e25891abf5c77bf3f7e3c244920James Dong    } else {
239379761ab096f57c3027fad9556c2bc436672d614eJames Dong        addOneSttsTableEntry(sampleCount, lastDurationTicks);
2394a472613aec322e25891abf5c77bf3f7e3c244920James Dong    }
2395a472613aec322e25891abf5c77bf3f7e3c244920James Dong
239643089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    // The last ctts box may not have been written yet, and this
239743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    // is to make sure that we write out the last ctts box.
239843089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    if (currCttsOffsetTimeTicks == lastCttsOffsetTimeTicks) {
239943089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        if (cttsSampleCount > 0) {
240043089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong            addOneCttsTableEntry(cttsSampleCount, lastCttsOffsetTimeTicks);
240143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        }
240243089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    }
240343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong
2404c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    mTrackDurationUs += lastDurationUs;
240525b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber    mReachedEOS = true;
240643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
240743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    sendTrackSummary(hasMultipleTracks);
240843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
2409df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block    ALOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s",
2410c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            count, nZeroLengthFrames, mStszTableEntries->count(), mIsAudio? "audio": "video");
2411872a481558350634a3fd5cb67939de288af00ecbJames Dong    if (mIsAudio) {
2412df64d15042bbd5e0e4933ac49bf3c177dd94752cSteve Block        ALOGI("Audio track drift time: %lld us", mOwner->getDriftTimeUs());
2413872a481558350634a3fd5cb67939de288af00ecbJames Dong    }
2414365a963142093a1cd8efdcea76b5f65096a5b115James Dong
241537187916a486504acaf83bea30147eb5fbf46ae5James Dong    if (err == ERROR_END_OF_STREAM) {
241637187916a486504acaf83bea30147eb5fbf46ae5James Dong        return OK;
241737187916a486504acaf83bea30147eb5fbf46ae5James Dong    }
241837187916a486504acaf83bea30147eb5fbf46ae5James Dong    return err;
2419365a963142093a1cd8efdcea76b5f65096a5b115James Dong}
2420365a963142093a1cd8efdcea76b5f65096a5b115James Dong
242145c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dongbool MPEG4Writer::Track::isTrackMalFormed() const {
2422c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    if (mStszTableEntries->count() == 0) {                      // no samples written
242329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("The number of recorded samples is 0");
242445c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong        return true;
242545c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    }
242645c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong
2427c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    if (!mIsAudio && mStssTableEntries->count() == 0) {  // no sync frames for video
242829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("There are no sync frames for video track");
242945c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong        return true;
243045c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    }
243145c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong
243245c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    if (OK != checkCodecSpecificData()) {         // no codec specific data
243345c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong        return true;
243445c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    }
243545c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong
243645c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong    return false;
243745c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong}
243845c254c0c535e1d62f23d14cab7385d536c1e2bfJames Dong
243943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dongvoid MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) {
244007ec01904613a0bac32caaa8444b4690998faed7James Dong
244107ec01904613a0bac32caaa8444b4690998faed7James Dong    // Send track summary only if test mode is enabled.
244207ec01904613a0bac32caaa8444b4690998faed7James Dong    if (!isTestModeEnabled()) {
244307ec01904613a0bac32caaa8444b4690998faed7James Dong        return;
244407ec01904613a0bac32caaa8444b4690998faed7James Dong    }
244507ec01904613a0bac32caaa8444b4690998faed7James Dong
244643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    int trackNum = (mTrackId << 28);
244743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
244843ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
244943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_TYPE,
245043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    mIsAudio? 0: 1);
245143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
245243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
245343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_DURATION_MS,
245443ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    mTrackDurationUs / 1000);
245543ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
245643ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
245743ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES,
2458c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong                    mStszTableEntries->count());
245943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
246086b7f47aa7482424cf8fd248f1315311919be3b0James Dong    {
246186b7f47aa7482424cf8fd248f1315311919be3b0James Dong        // The system delay time excluding the requested initial delay that
246286b7f47aa7482424cf8fd248f1315311919be3b0James Dong        // is used to eliminate the recording sound.
246386b7f47aa7482424cf8fd248f1315311919be3b0James Dong        int64_t startTimeOffsetUs = mOwner->getStartTimeOffsetMs() * 1000LL;
246486b7f47aa7482424cf8fd248f1315311919be3b0James Dong        if (startTimeOffsetUs < 0) {  // Start time offset was not set
246586b7f47aa7482424cf8fd248f1315311919be3b0James Dong            startTimeOffsetUs = kInitialDelayTimeUs;
246686b7f47aa7482424cf8fd248f1315311919be3b0James Dong        }
246786b7f47aa7482424cf8fd248f1315311919be3b0James Dong        int64_t initialDelayUs =
246886b7f47aa7482424cf8fd248f1315311919be3b0James Dong            mFirstSampleTimeRealUs - mStartTimeRealUs - startTimeOffsetUs;
246986b7f47aa7482424cf8fd248f1315311919be3b0James Dong
247086b7f47aa7482424cf8fd248f1315311919be3b0James Dong        mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
247170ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS,
247270ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    (initialDelayUs) / 1000);
247386b7f47aa7482424cf8fd248f1315311919be3b0James Dong    }
247470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
247507ec01904613a0bac32caaa8444b4690998faed7James Dong    mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
247607ec01904613a0bac32caaa8444b4690998faed7James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES,
247707ec01904613a0bac32caaa8444b4690998faed7James Dong                    mMdatSizeBytes / 1024);
247807ec01904613a0bac32caaa8444b4690998faed7James Dong
247943ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    if (hasMultipleTracks) {
248043ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong        mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
248143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS,
248243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong                    mMaxChunkDurationUs / 1000);
248370ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong
248470ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
248570ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        if (mStartTimestampUs != moovStartTimeUs) {
248670ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            int64_t startTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
248770ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong            mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
248870ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    trackNum | MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS,
248970ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong                    startTimeOffsetUs / 1000);
249070ccfd44c4bfe95ddecc2df6c3695efc48229d72James Dong        }
249143ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong    }
249243ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong}
249343ec1dfc5dc3934680a52a026c5519ddc51bdbd3James Dong
2494faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::Track::trackProgressStatus(int64_t timeUs, status_t err) {
24953856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("trackProgressStatus: %lld us", timeUs);
2496c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong
2497215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong    if (mTrackEveryTimeDurationUs > 0 &&
2498215381ea729086b8359b7f59bdc2bd7cf55a0c45James Dong        timeUs - mPreviousTrackTimeUs >= mTrackEveryTimeDurationUs) {
24993856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("Fire time tracking progress status at %lld us", timeUs);
2500bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        mOwner->trackProgressStatus(mTrackId, timeUs - mPreviousTrackTimeUs, err);
250193d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong        mPreviousTrackTimeUs = timeUs;
250293d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong    }
250393d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong}
250493d6b102a13afa23bfa80d74c399d93d542e6ad6James Dong
2505faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dongvoid MPEG4Writer::trackProgressStatus(
2506bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        size_t trackId, int64_t timeUs, status_t err) {
2507faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    Mutex::Autolock lock(mLock);
2508bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong    int32_t trackNum = (trackId << 28);
2509faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
2510faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    // Error notification
2511faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    // Do not consider ERROR_END_OF_STREAM an error
2512faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    if (err != OK && err != ERROR_END_OF_STREAM) {
2513bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_ERROR,
2514bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong               trackNum | MEDIA_RECORDER_TRACK_ERROR_GENERAL,
2515faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               err);
2516faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        return;
2517faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    }
2518faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
2519faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    if (timeUs == -1) {
2520faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        // Send completion notification
2521bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2522bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong               trackNum | MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS,
2523faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               err);
2524faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    } else {
2525faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong        // Send progress status
2526bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong        notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
2527bc07bcc65e91c7aea9713631ae67760dcf1b0286James Dong               trackNum | MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME,
2528faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong               timeUs / 1000);
2529faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong    }
2530faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong}
2531faed5cd124a54b8db3429f4c26b3220bbec4c8bbJames Dong
2532d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dongvoid MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) {
25333856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("setDriftTimeUs: %lld us", driftTimeUs);
2534e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    Mutex::Autolock autolock(mLock);
2535d707fcb3e29707ca4a5935c294ef0b38eb5aba5fJames Dong    mDriftTimeUs = driftTimeUs;
2536e259531ce59ab1f31de5a23124b22536f6a5a767James Dong}
2537e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
2538e259531ce59ab1f31de5a23124b22536f6a5a767James Dongint64_t MPEG4Writer::getDriftTimeUs() {
25393856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("getDriftTimeUs: %lld us", mDriftTimeUs);
2540e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    Mutex::Autolock autolock(mLock);
2541e259531ce59ab1f31de5a23124b22536f6a5a767James Dong    return mDriftTimeUs;
2542e259531ce59ab1f31de5a23124b22536f6a5a767James Dong}
2543e259531ce59ab1f31de5a23124b22536f6a5a767James Dong
2544de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghuibool MPEG4Writer::isRealTimeRecording() const {
2545de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui    return mIsRealTimeRecording;
2546de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui}
2547de05c8eab188e98798f2b9c3dfac53dbc18ef584ztenghui
2548b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dongbool MPEG4Writer::useNalLengthFour() {
2549b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong    return mUse4ByteNalLength;
2550b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong}
2551b4d5320bda29cd9694461c9b61d0211f801ff0afJames Dong
25521c9747a4653aec1395c2bd6896c9b87cb5447837James Dongvoid MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
25533856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("bufferChunk");
25541c9747a4653aec1395c2bd6896c9b87cb5447837James Dong
25551c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    Chunk chunk(this, timestampUs, mChunkSamples);
25561c9747a4653aec1395c2bd6896c9b87cb5447837James Dong    mOwner->bufferChunk(chunk);
255713aec890216948b0c364f8f92792129d0335f506James Dong    mChunkSamples.clear();
255820111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
255920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
25603b240d6bf235f6f6b40ee4c37a2862de286ca1e4Andreas Huberint64_t MPEG4Writer::Track::getDurationUs() const {
2561c5f0c714dc4225cd2ec305d5ddd297964a3dd3dcJames Dong    return mTrackDurationUs;
256220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
256320111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2564d599cd4573b5a2d5914c5040e0565ef866749b77James Dongint64_t MPEG4Writer::Track::getEstimatedTrackSizeBytes() const {
2565d599cd4573b5a2d5914c5040e0565ef866749b77James Dong    return mEstimatedTrackSizeBytes;
2566d599cd4573b5a2d5914c5040e0565ef866749b77James Dong}
2567d599cd4573b5a2d5914c5040e0565ef866749b77James Dong
2568690f546b0ee548dbfe997df36418e5302ec2d786James Dongstatus_t MPEG4Writer::Track::checkCodecSpecificData() const {
2569690f546b0ee548dbfe997df36418e5302ec2d786James Dong    const char *mime;
2570690f546b0ee548dbfe997df36418e5302ec2d786James Dong    CHECK(mMeta->findCString(kKeyMIMEType, &mime));
2571690f546b0ee548dbfe997df36418e5302ec2d786James Dong    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) ||
2572690f546b0ee548dbfe997df36418e5302ec2d786James Dong        !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
2573690f546b0ee548dbfe997df36418e5302ec2d786James Dong        !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2574690f546b0ee548dbfe997df36418e5302ec2d786James Dong        if (!mCodecSpecificData ||
2575690f546b0ee548dbfe997df36418e5302ec2d786James Dong            mCodecSpecificDataSize <= 0) {
257629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Missing codec specific data");
2577690f546b0ee548dbfe997df36418e5302ec2d786James Dong            return ERROR_MALFORMED;
2578690f546b0ee548dbfe997df36418e5302ec2d786James Dong        }
2579690f546b0ee548dbfe997df36418e5302ec2d786James Dong    } else {
2580690f546b0ee548dbfe997df36418e5302ec2d786James Dong        if (mCodecSpecificData ||
2581690f546b0ee548dbfe997df36418e5302ec2d786James Dong            mCodecSpecificDataSize > 0) {
258229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            ALOGE("Unexepected codec specific data found");
2583690f546b0ee548dbfe997df36418e5302ec2d786James Dong            return ERROR_MALFORMED;
2584690f546b0ee548dbfe997df36418e5302ec2d786James Dong        }
2585690f546b0ee548dbfe997df36418e5302ec2d786James Dong    }
2586690f546b0ee548dbfe997df36418e5302ec2d786James Dong    return OK;
2587690f546b0ee548dbfe997df36418e5302ec2d786James Dong}
2588690f546b0ee548dbfe997df36418e5302ec2d786James Dong
2589b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeTrackHeader(bool use32BitOffset) {
259020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
25913856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    ALOGV("%s track time scale: %d",
25921c9747a4653aec1395c2bd6896c9b87cb5447837James Dong        mIsAudio? "Audio": "Video", mTimeScale);
25938f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong
2594efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlsson    uint32_t now = getMpeg4Time();
2595b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("trak");
2596b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeTkhdBox(now);
2597b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("mdia");
2598b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            writeMdhdBox(now);
2599b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            writeHdlrBox();
2600b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->beginBox("minf");
2601b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                if (mIsAudio) {
2602b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                    writeSmhdBox();
2603b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                } else {
2604b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                    writeVmhdBox();
2605b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                }
2606b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                writeDinfBox();
2607b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong                writeStblBox(use32BitOffset);
2608b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong            mOwner->endBox();  // minf
2609b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->endBox();  // mdia
2610b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // trak
2611b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2612b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2613b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStblBox(bool use32BitOffset) {
2614b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stbl");
2615b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stsd");
2616b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);               // version=0, flags=0
2617b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1);               // entry count
2618b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mIsAudio) {
2619b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeAudioFourCCBox();
2620b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2621b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeVideoFourCCBox();
2622b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2623b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stsd
2624b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeSttsBox();
2625965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    writeCttsBox();
2626b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!mIsAudio) {
2627b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeStssBox();
2628b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2629b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeStszBox();
2630b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeStscBox();
2631b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeStcoBox(use32BitOffset);
2632b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stbl
2633b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2634b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2635b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVideoFourCCBox() {
2636b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    const char *mime;
2637b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    bool success = mMeta->findCString(kKeyMIMEType, &mime);
2638b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2639b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2640b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("mp4v");
2641b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2642b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("s263");
2643b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2644b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->beginBox("avc1");
2645b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
264629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Unknown mime type '%s'.", mime);
2647b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(!"should not be here, unknown mime type.");
2648b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2649b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2650b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2651b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2652b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(1);           // data ref index
2653b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // predefined
2654b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2655b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // predefined
2656b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // predefined
2657b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // predefined
2658b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2659b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t width, height;
2660b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    success = mMeta->findInt32(kKeyWidth, &width);
2661b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    success = success && mMeta->findInt32(kKeyHeight, &height);
2662b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2663b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2664b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(width);
2665b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(height);
2666b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x480000);    // horiz resolution
2667b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x480000);    // vert resolution
2668b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2669b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(1);           // frame count
2670c30a88a273b47bef6728ae1dddea11641090939aMartin Storsjo    mOwner->writeInt8(0);            // compressor string length
2671c30a88a273b47bef6728ae1dddea11641090939aMartin Storsjo    mOwner->write("                               ", 31);
2672b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x18);        // depth
2673b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(-1);          // predefined
2674b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
267543089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_LT(23 + mCodecSpecificDataSize, 128);
2676b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2677b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
2678b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeMp4vEsdsBox();
2679b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
2680b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeD263Box();
2681b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
2682b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeAvccBox();
2683b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2684b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2685b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writePaspBox();
2686b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // mp4v, s263 or avc1
2687b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2688b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2689b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAudioFourCCBox() {
2690b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    const char *mime;
2691b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    bool success = mMeta->findCString(kKeyMIMEType, &mime);
2692b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2693b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    const char *fourcc = NULL;
2694b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
2695b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fourcc = "samr";
2696b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2697b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fourcc = "sawb";
2698b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2699b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        fourcc = "mp4a";
2700b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
270129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Unknown mime type '%s'.", mime);
2702b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(!"should not be here, unknown mime type.");
2703b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2704b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2705b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox(fourcc);        // audio format
2706b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2707b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2708b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x1);         // data ref index
2709b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2710b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // reserved
2711b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t nChannels;
2712b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels));
2713b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(nChannels);   // channel count
2714b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(16);          // sample size
2715b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // predefined
2716b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2717b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2718b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t samplerate;
2719b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    success = mMeta->findInt32(kKeySampleRate, &samplerate);
2720b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(success);
2721b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(samplerate << 16);
2722b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
2723b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeMp4aEsdsBox();
2724b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) ||
2725b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong               !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
2726b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        writeDamrBox();
2727b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2728b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2729b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2730b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2731b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4aEsdsBox() {
2732b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("esds");
2733b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificData);
273443089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GT(mCodecSpecificDataSize, 0);
2735b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2736b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Make sure all sizes encode to a single byte.
273743089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_LT(mCodecSpecificDataSize + 23, 128);
2738b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2739b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);     // version=0, flags=0
2740b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x03);   // ES_DescrTag
2741b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(23 + mCodecSpecificDataSize);
2742b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x0000);// ES_ID
2743b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x00);
2744b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2745b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x04);   // DecoderConfigDescrTag
2746b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(15 + mCodecSpecificDataSize);
2747b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x40);   // objectTypeIndication ISO/IEC 14492-2
2748b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x15);   // streamType AudioStream
2749b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2750b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x03);  // XXX
2751b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x00);   // buffer size 24-bit
2752b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(96000); // max bit rate
2753b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(96000); // avg bit rate
2754b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2755b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x05);   // DecoderSpecificInfoTag
2756b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(mCodecSpecificDataSize);
2757b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2758b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2759b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    static const uint8_t kData2[] = {
2760b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x06,  // SLConfigDescriptorTag
2761b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x01,
2762b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x02
2763b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    };
2764b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(kData2, sizeof(kData2));
2765b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2766b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // esds
2767b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2768b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2769b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeMp4vEsdsBox() {
2770b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificData);
277143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GT(mCodecSpecificDataSize, 0);
2772b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("esds");
2773b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2774b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);    // version=0, flags=0
2775b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2776b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x03);  // ES_DescrTag
2777b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(23 + mCodecSpecificDataSize);
2778b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x0000);  // ES_ID
2779b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x1f);
2780b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2781b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x04);  // DecoderConfigDescrTag
2782b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(15 + mCodecSpecificDataSize);
2783b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x20);  // objectTypeIndication ISO/IEC 14492-2
2784b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x11);  // streamType VisualStream
2785b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2786b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    static const uint8_t kData[] = {
2787b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x01, 0x77, 0x00,
2788b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x00, 0x03, 0xe8, 0x00,
2789b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x00, 0x03, 0xe8, 0x00
2790b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    };
2791b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(kData, sizeof(kData));
2792b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2793b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
2794b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2795b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(mCodecSpecificDataSize);
2796b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2797b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2798b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    static const uint8_t kData2[] = {
2799b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x06,  // SLConfigDescriptorTag
2800b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x01,
2801b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        0x02
2802b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    };
2803b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(kData2, sizeof(kData2));
2804b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2805b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // esds
2806b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2807b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2808efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlssonvoid MPEG4Writer::Track::writeTkhdBox(uint32_t now) {
2809b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("tkhd");
2810b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Flags = 7 to indicate that the track is enabled, and
2811b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // part of the presentation
2812b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x07);          // version=0, flags=7
2813b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // creation time
2814b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // modification time
2815219f195159f93d627af2b243732e3f9020511a46James Dong    mOwner->writeInt32(mTrackId);      // track id starts with 1
2816b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
28178f5f2fcee5c12d08df71d17017410c50951fc2e3James Dong    int64_t trakDurationUs = getDurationUs();
2818b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t mvhdTimeScale = mOwner->getTimeScale();
2819b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t tkhdDuration =
2820b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        (trakDurationUs * mvhdTimeScale + 5E5) / 1E6;
2821b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(tkhdDuration);  // in mvhd timescale
2822b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2823b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2824b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // layer
2825b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // alternate group
2826b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(mIsAudio ? 0x100 : 0);  // volume
2827b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // reserved
2828b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2829b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeCompositionMatrix(mRotation);       // matrix
283020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2831b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mIsAudio) {
2832b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(0);
2833b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(0);
2834b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    } else {
2835b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        int32_t width, height;
2836b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        bool success = mMeta->findInt32(kKeyWidth, &width);
2837b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        success = success && mMeta->findInt32(kKeyHeight, &height);
2838b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        CHECK(success);
2839b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2840b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(width << 16);   // 32-bit fixed-point value
2841b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        mOwner->writeInt32(height << 16);  // 32-bit fixed-point value
2842b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2843b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // tkhd
2844b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2845b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2846b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeVmhdBox() {
2847b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("vmhd");
2848b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0x01);        // version=0, flags=1
2849b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // graphics mode
2850b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // opcolor
2851b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);
2852b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);
2853b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2854b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2855b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2856b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeSmhdBox() {
2857b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("smhd");
2858b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);           // version=0, flags=0
2859b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // balance
2860b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);           // reserved
2861b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2862b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2863b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2864b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeHdlrBox() {
2865b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("hdlr");
2866b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // version=0, flags=0
2867b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // component type: should be mhlr
2868b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeFourcc(mIsAudio ? "soun" : "vide");  // component subtype
2869b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2870b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2871b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // reserved
2872b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Removing "r" for the name string just makes the string 4 byte aligned
2873b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeCString(mIsAudio ? "SoundHandle": "VideoHandle");  // name
2874b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2875b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2876b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2877efcdf187baab9ec29e12adcf85e63fe3e6d5aa4dJohannes Carlssonvoid MPEG4Writer::Track::writeMdhdBox(uint32_t now) {
2878b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int64_t trakDurationUs = getDurationUs();
2879b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("mdhd");
2880b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);             // version=0, flags=0
2881b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // creation time
2882b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(now);           // modification time
2883b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mTimeScale);    // media timescale
2884b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int32_t mdhdDuration = (trakDurationUs * mTimeScale + 5E5) / 1E6;
2885b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(mdhdDuration);  // use media timescale
2886b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Language follows the three letter standard ISO-639-2/T
2887b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // 'e', 'n', 'g' for "English", for instance.
2888b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Each character is packed as the difference between its ASCII value and 0x60.
2889b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // For "English", these are 00101, 01110, 00111.
2890b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // XXX: Where is the padding bit located: 0x15C7?
2891b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // language code
2892b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0);             // predefined
2893b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2894b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2895b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2896b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDamrBox() {
2897b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // 3gpp2 Spec AMRSampleEntry fields
2898b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("damr");
2899b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeCString("   ");  // vendor: 4 bytes
2900b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);         // decoder version
2901b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt16(0x83FF);   // mode set: all enabled
2902b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);         // mode change period
2903b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(1);         // frames per sample
2904b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();
2905b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2906b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2907b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeUrlBox() {
2908b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // The table index here refers to the sample description index
2909b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // in the sample table entries.
2910b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("url ");
2911b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1);  // version=0, flags=1 (self-contained)
2912b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // url
2913b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2914b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2915b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDrefBox() {
2916b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("dref");
2917b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2918b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1);  // entry count (either url or urn)
2919b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeUrlBox();
2920b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // dref
2921b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2922b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2923b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeDinfBox() {
2924b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("dinf");
2925b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    writeDrefBox();
2926b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // dinf
2927b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2928b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2929b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeAvccBox() {
2930b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    CHECK(mCodecSpecificData);
293143089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong    CHECK_GE(mCodecSpecificDataSize, 5);
2932b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2933b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // Patch avcc's lengthSize field to match the number
2934b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    // of bytes we use to indicate the size of a nal unit.
2935b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    uint8_t *ptr = (uint8_t *)mCodecSpecificData;
2936b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    ptr[4] = (ptr[4] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1);
2937b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("avcC");
2938b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
2939b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // avcC
2940b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2941b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2942b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeD263Box() {
2943b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("d263");
2944b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // vendor
2945b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);   // decoder version
2946b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(10);  // level: 10
2947b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt8(0);   // profile: 0
2948b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // d263
2949b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2950b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2951b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong// This is useful if the pixel is not square
2952b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writePaspBox() {
2953b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("pasp");
2954b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1 << 16);  // hspacing
2955b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(1 << 16);  // vspacing
2956b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // pasp
2957b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
2958b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong
2959000e18370baae60ffd9f25b509501dd8c26deabfJames Dongint32_t MPEG4Writer::Track::getStartTimeOffsetScaledTime() const {
2960a472613aec322e25891abf5c77bf3f7e3c244920James Dong    int64_t trackStartTimeOffsetUs = 0;
2961b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    int64_t moovStartTimeUs = mOwner->getStartTimestampUs();
2962b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    if (mStartTimestampUs != moovStartTimeUs) {
296343089daaf82bd2b8e5f9a29b80af5abaae4657b3James Dong        CHECK_GT(mStartTimestampUs, moovStartTimeUs);
2964b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong        trackStartTimeOffsetUs = mStartTimestampUs - moovStartTimeUs;
2965b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
2966000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    return (trackStartTimeOffsetUs *  mTimeScale + 500000LL) / 1000000LL;
2967000e18370baae60ffd9f25b509501dd8c26deabfJames Dong}
2968000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
2969000e18370baae60ffd9f25b509501dd8c26deabfJames Dongvoid MPEG4Writer::Track::writeSttsBox() {
2970000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    mOwner->beginBox("stts");
2971000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
2972c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    uint32_t duration;
2973c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    CHECK(mSttsTableEntries->get(duration, 1));
2974c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    duration = htonl(duration);  // Back to host byte order
2975c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mSttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime()), 1);
2976c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mSttsTableEntries->write(mOwner);
2977b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stts
2978b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
297920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
2980965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dongvoid MPEG4Writer::Track::writeCttsBox() {
2981965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    if (mIsAudio) {  // ctts is not for audio
2982965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        return;
2983965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    }
2984965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
2985000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    // There is no B frame at all
2986000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    if (mMinCttsOffsetTimeUs == mMaxCttsOffsetTimeUs) {
2987000e18370baae60ffd9f25b509501dd8c26deabfJames Dong        return;
2988000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    }
2989000e18370baae60ffd9f25b509501dd8c26deabfJames Dong
2990965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    // Do not write ctts box when there is no need to have it.
2991c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    if (mCttsTableEntries->count() == 0) {
2992965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong        return;
2993965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    }
2994965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
2995c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    ALOGV("ctts box has %d entries with range [%lld, %lld]",
2996c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong            mCttsTableEntries->count(), mMinCttsOffsetTimeUs, mMaxCttsOffsetTimeUs);
2997965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
2998965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    mOwner->beginBox("ctts");
2999000e18370baae60ffd9f25b509501dd8c26deabfJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
3000c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    uint32_t duration;
3001c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    CHECK(mCttsTableEntries->get(duration, 1));
3002c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    duration = htonl(duration);  // Back host byte order
3003c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mCttsTableEntries->set(htonl(duration + getStartTimeOffsetScaledTime() - mMinCttsOffsetTimeUs), 1);
3004c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mCttsTableEntries->write(mOwner);
3005965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong    mOwner->endBox();  // ctts
3006965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong}
3007965e4239ca1cf6c824c1f8ce23116f9ba8cf6ebdJames Dong
3008b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStssBox() {
3009b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stss");
3010b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
3011c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mStssTableEntries->write(mOwner);
3012b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stss
3013b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
301425b130939339d57789a86fac837a2a8cedbcb7d8Andreas Huber
3015b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStszBox() {
3016b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stsz");
3017b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
3018c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mOwner->writeInt32(0);
3019c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mStszTableEntries->write(mOwner);
3020b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stsz
3021b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
302220111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
3023b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStscBox() {
3024b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox("stsc");
3025b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
3026c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    mStscTableEntries->write(mOwner);
3027b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stsc
3028b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong}
302920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
3030b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dongvoid MPEG4Writer::Track::writeStcoBox(bool use32BitOffset) {
3031b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->beginBox(use32BitOffset? "stco": "co64");
3032b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->writeInt32(0);  // version=0, flags=0
3033c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    if (use32BitOffset) {
3034c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        mStcoTableEntries->write(mOwner);
3035c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong    } else {
3036c620cbd7f8dc75f6819e2b862d3c09970560bc63James Dong        mCo64TableEntries->write(mOwner);
3037b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    }
3038b21c564ce47041f9dd3ab65e36fed57c4937a42dJames Dong    mOwner->endBox();  // stco or co64
303920111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}
304020111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber
304107b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeUdtaBox() {
304207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    beginBox("udta");
304307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeGeoDataBox();
304407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    endBox();
304507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
304607b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
304707b1bb529a1ae76c46a71b01338c166f9490629dJames Dong/*
304807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong * Geodata is stored according to ISO-6709 standard.
304907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong */
305007b1bb529a1ae76c46a71b01338c166f9490629dJames Dongvoid MPEG4Writer::writeGeoDataBox() {
305107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    beginBox("\xA9xyz");
305207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    /*
305307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong     * For historical reasons, any user data start
305407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong     * with "\0xA9", must be followed by its assoicated
305507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong     * language code.
3056432ec3768cc4a3b1b01afedc456689d75c89ee2bJames Dong     * 0x0012: text string length
3057432ec3768cc4a3b1b01afedc456689d75c89ee2bJames Dong     * 0x15c7: lang (locale) code: en
305807b1bb529a1ae76c46a71b01338c166f9490629dJames Dong     */
305907b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeInt32(0x001215c7);
306007b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeLatitude(mLatitudex10000);
306107b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeLongitude(mLongitudex10000);
306207b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    writeInt8(0x2F);
306307b1bb529a1ae76c46a71b01338c166f9490629dJames Dong    endBox();
306407b1bb529a1ae76c46a71b01338c166f9490629dJames Dong}
306507b1bb529a1ae76c46a71b01338c166f9490629dJames Dong
306620111aa043c5f404472bc63b90bc5aad906b1101Andreas Huber}  // namespace android
3067